Skip to content

Commit 19c6dcb

Browse files
Su Yuekdave
authored andcommitted
btrfs: Introduce btrfs_is_name_len_valid to avoid reading beyond boundary
Introduce function btrfs_is_name_len_valid. The function compares parameter @name_len with item boundary then returns true if name_len is valid. Signed-off-by: Su Yue <[email protected]> Reviewed-by: David Sterba <[email protected]> [ s/btrfs_leaf_data/BTRFS_LEAF_DATA_OFFSET/ ] Signed-off-by: David Sterba <[email protected]>
1 parent 66b4993 commit 19c6dcb

File tree

2 files changed

+74
-0
lines changed

2 files changed

+74
-0
lines changed

fs/btrfs/ctree.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3042,6 +3042,8 @@ struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info,
30423042
struct btrfs_path *path,
30433043
const char *name,
30443044
int name_len);
3045+
bool btrfs_is_name_len_valid(struct extent_buffer *leaf, int slot,
3046+
unsigned long start, u16 name_len);
30453047

30463048
/* orphan.c */
30473049
int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans,

fs/btrfs/dir-item.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,3 +484,75 @@ int verify_dir_item(struct btrfs_fs_info *fs_info,
484484

485485
return 0;
486486
}
487+
488+
bool btrfs_is_name_len_valid(struct extent_buffer *leaf, int slot,
489+
unsigned long start, u16 name_len)
490+
{
491+
struct btrfs_fs_info *fs_info = leaf->fs_info;
492+
struct btrfs_key key;
493+
u32 read_start;
494+
u32 read_end;
495+
u32 item_start;
496+
u32 item_end;
497+
u32 size;
498+
bool ret = true;
499+
500+
ASSERT(start > BTRFS_LEAF_DATA_OFFSET);
501+
502+
read_start = start - BTRFS_LEAF_DATA_OFFSET;
503+
read_end = read_start + name_len;
504+
item_start = btrfs_item_offset_nr(leaf, slot);
505+
item_end = btrfs_item_end_nr(leaf, slot);
506+
507+
btrfs_item_key_to_cpu(leaf, &key, slot);
508+
509+
switch (key.type) {
510+
case BTRFS_DIR_ITEM_KEY:
511+
case BTRFS_XATTR_ITEM_KEY:
512+
case BTRFS_DIR_INDEX_KEY:
513+
size = sizeof(struct btrfs_dir_item);
514+
break;
515+
case BTRFS_INODE_REF_KEY:
516+
size = sizeof(struct btrfs_inode_ref);
517+
break;
518+
case BTRFS_INODE_EXTREF_KEY:
519+
size = sizeof(struct btrfs_inode_extref);
520+
break;
521+
case BTRFS_ROOT_REF_KEY:
522+
case BTRFS_ROOT_BACKREF_KEY:
523+
size = sizeof(struct btrfs_root_ref);
524+
break;
525+
default:
526+
ret = false;
527+
goto out;
528+
}
529+
530+
if (read_start < item_start) {
531+
ret = false;
532+
goto out;
533+
}
534+
if (read_end > item_end) {
535+
ret = false;
536+
goto out;
537+
}
538+
539+
/* there shall be item(s) before name */
540+
if (read_start - item_start < size) {
541+
ret = false;
542+
goto out;
543+
}
544+
545+
/*
546+
* This may be the last item in the slot
547+
* Or same type item(s) is left between read_end and item_end
548+
*/
549+
if (item_end != read_end && item_end - read_end < size) {
550+
ret = false;
551+
goto out;
552+
}
553+
out:
554+
if (!ret)
555+
btrfs_crit(fs_info, "invalid dir item name len: %u",
556+
(unsigned int)name_len);
557+
return ret;
558+
}

0 commit comments

Comments
 (0)