btrfs-progs: check: add check for overlong xattr names

While working on my Windows driver, I found that it was inadvertently
allowing users to create xattrs with names longer than 255 bytes, which
wasn't being picked up by btrfs-check.

If the Linux driver encounters a file with an invalid xattr like this,
it makes the whole directory it's in inaccessible. If it's the root
directory, it'll refuse to mount the filesystem entirely.

Pull-request: #456
Signed-off-by: Mark Harmstone <mark@harmstone.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Mark Harmstone 2022-03-16 17:56:53 +00:00 committed by David Sterba
parent f9659c7235
commit ef194732d5
2 changed files with 50 additions and 0 deletions

View File

@ -627,6 +627,8 @@ static void print_inode_error(struct btrfs_root *root, struct inode_record *rec)
if (errors & I_ERR_INVALID_NLINK)
fprintf(stderr, ", directory has invalid nlink %d",
rec->nlink);
if (errors & I_ERR_INVALID_XATTR)
fprintf(stderr, ", invalid xattr");
fprintf(stderr, "\n");
/* Print the holes if needed */
@ -1473,6 +1475,50 @@ next:
return 0;
}
static int process_xattr_item(struct extent_buffer *eb,
int slot, struct btrfs_key *key,
struct shared_node *active_node)
{
u32 total;
u32 cur = 0;
struct btrfs_dir_item *di;
struct inode_record *rec;
rec = active_node->current;
di = btrfs_item_ptr(eb, slot, struct btrfs_dir_item);
total = btrfs_item_size(eb, slot);
while (cur < total) {
u32 name_len = btrfs_dir_name_len(eb, di);
u32 data_len = btrfs_dir_data_len(eb, di);
u32 len;
if (name_len > BTRFS_NAME_LEN) {
char *name = malloc(name_len);
if (!name)
return -ENOMEM;
read_extent_buffer(eb, name,
(unsigned long)(di + 1), name_len);
fprintf(stderr,
"inode %llu has overlong xattr name %.*s\n",
key->objectid, name_len, name);
free(name);
rec->errors |= I_ERR_INVALID_XATTR;
}
len = sizeof(*di) + name_len + data_len;
di = (struct btrfs_dir_item *)((char *)di + len);
cur += len;
}
return 0;
}
static int process_inode_ref(struct extent_buffer *eb,
int slot, struct btrfs_key *key,
struct shared_node *active_node)
@ -1740,6 +1786,9 @@ static int process_one_leaf(struct btrfs_root *root, struct extent_buffer *eb,
ret = process_file_extent(root, eb, i, &key,
active_node);
break;
case BTRFS_XATTR_ITEM_KEY:
ret = process_xattr_item(eb, i, &key, active_node);
break;
default:
break;
};

View File

@ -187,6 +187,7 @@ struct unaligned_extent_rec_t {
#define I_ERR_INVALID_IMODE (1 << 19)
#define I_ERR_INVALID_GEN (1 << 20)
#define I_ERR_INVALID_NLINK (1 << 21)
#define I_ERR_INVALID_XATTR (1 << 22)
struct inode_record {
struct list_head backrefs;