tools/virtiofsd: xattr name mappings: Map server xattr names

Map xattr names coming from the server, i.e. the host filesystem;
currently this is only from listxattr.

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Message-Id: <20201023165812.36028-4-dgilbert@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
This commit is contained in:
Dr. David Alan Gilbert 2020-10-23 17:58:10 +01:00
parent 4f088dbf98
commit 6409cf19ca

View File

@ -2229,6 +2229,44 @@ static int xattr_map_client(const struct lo_data *lo, const char *client_name,
return -EPERM;
}
/*
* For use with listxattr where the server fs gives us a name and we may need
* to sanitize this for the client.
* Returns a pointer to the result in *out_name
* This is always the original string or the current string with some prefix
* removed; no reallocation is done.
* Returns 0 on success
* Can return -ENODATA to indicate the name should be dropped from the list.
*/
static int xattr_map_server(const struct lo_data *lo, const char *server_name,
const char **out_name)
{
size_t i;
const char *end;
for (i = 0; i < lo->xattr_map_nentries; i++) {
const XattrMapEntry *cur_entry = lo->xattr_map_list + i;
if ((cur_entry->flags & XATTR_MAP_FLAG_SERVER) &&
(strstart(server_name, cur_entry->prepend, &end))) {
if (cur_entry->flags & XATTR_MAP_FLAG_BAD) {
return -ENODATA;
}
if (cur_entry->flags & XATTR_MAP_FLAG_OK) {
*out_name = server_name;
return 0;
}
if (cur_entry->flags & XATTR_MAP_FLAG_PREFIX) {
/* Remove prefix */
*out_name = end;
return 0;
}
}
}
return -ENODATA;
}
static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *in_name,
size_t size)
{
@ -2383,8 +2421,60 @@ static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
if (ret == 0) {
goto out;
}
if (lo->xattr_map_list) {
/*
* Map the names back, some attributes might be dropped,
* some shortened, but not increased, so we shouldn't
* run out of room.
*/
size_t out_index, in_index;
out_index = 0;
in_index = 0;
while (in_index < ret) {
const char *map_out;
char *in_ptr = value + in_index;
/* Length of current attribute name */
size_t in_len = strlen(value + in_index) + 1;
int mapret = xattr_map_server(lo, in_ptr, &map_out);
if (mapret != -ENODATA && mapret != 0) {
/* Shouldn't happen */
saverr = -mapret;
goto out;
}
if (mapret == 0) {
/* Either unchanged, or truncated */
size_t out_len;
if (map_out != in_ptr) {
/* +1 copies the NIL */
out_len = strlen(map_out) + 1;
} else {
/* No change */
out_len = in_len;
}
/*
* Move result along, may still be needed for an unchanged
* entry if a previous entry was changed.
*/
memmove(value + out_index, map_out, out_len);
out_index += out_len;
}
in_index += in_len;
}
ret = out_index;
if (ret == 0) {
goto out;
}
}
fuse_reply_buf(req, value, ret);
} else {
/*
* xattrmap only ever shortens the result,
* so we don't need to do anything clever with the
* allocation length here.
*/
fuse_reply_xattr(req, ret);
}
out_free: