Re: [PATCH 1/2] btrfs-progs: check: Detect file extent end overflow

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On 2020/2/19 下午5:19, Nikolay Borisov wrote:
>
>
> On 19.02.20 г. 9:04 ч., Qu Wenruo wrote:
>> There is a report about tree-checker rejecting some leaves due to bad
>> EXTENT_DATA.
>>
>> The offending EXTENT_DATA looks like:
>> 	item 72 key (1359622 EXTENT_DATA 475136) itemoff 11140 itemsize 53
>> 		generation 954719 type 1 (regular)
>> 		extent data disk byte 0 nr 0
>> 		extent data offset 0 nr 18446744073709486080 ram 18446744073709486080
>> 		extent compression 0 (none)
>>
>> Add such check to both original and lowmem mode to detect such problem.
>>
>> Reported-by: Samir Benmendil <me@xxxxxx>
>> Signed-off-by: Qu Wenruo <wqu@xxxxxxxx>
>> ---
>>  check/main.c          | 4 ++++
>>  check/mode-common.h   | 7 +++++++
>>  check/mode-lowmem.c   | 7 +++++++
>>  check/mode-original.h | 1 +
>>  4 files changed, 19 insertions(+)
>>
>> diff --git a/check/main.c b/check/main.c
>> index d02dd1636852..f71bf4f74129 100644
>> --- a/check/main.c
>> +++ b/check/main.c
>> @@ -597,6 +597,8 @@ static void print_inode_error(struct btrfs_root *root, struct inode_record *rec)
>>  		fprintf(stderr, ", odd file extent");
>>  	if (errors & I_ERR_BAD_FILE_EXTENT)
>>  		fprintf(stderr, ", bad file extent");
>> +	if (errors & I_ERR_FILE_EXTENT_OVERFLOW)
>> +		fprintf(stderr, ", file extent end overflow");
>>  	if (errors & I_ERR_FILE_EXTENT_OVERLAP)
>>  		fprintf(stderr, ", file extent overlap");
>>  	if (errors & I_ERR_FILE_EXTENT_TOO_LARGE)
>> @@ -1595,6 +1597,8 @@ static int process_file_extent(struct btrfs_root *root,
>>  		num_bytes = btrfs_file_extent_num_bytes(eb, fi);
>>  		disk_bytenr = btrfs_file_extent_disk_bytenr(eb, fi);
>>  		extent_offset = btrfs_file_extent_offset(eb, fi);
>> +		if (u64_add_overflow(key->offset, num_bytes))
>> +			rec->errors |= I_ERR_FILE_EXTENT_OVERFLOW;
>>  		if (num_bytes == 0 || (num_bytes & mask))
>>  			rec->errors |= I_ERR_BAD_FILE_EXTENT;
>>  		if (num_bytes + extent_offset >
>> diff --git a/check/mode-common.h b/check/mode-common.h
>> index edf9257edaf0..daa5741e1d67 100644
>> --- a/check/mode-common.h
>> +++ b/check/mode-common.h
>> @@ -173,4 +173,11 @@ static inline u32 btrfs_type_to_imode(u8 type)
>>
>>  	return imode_by_btrfs_type[(type)];
>>  }
>> +
>> +static inline bool u64_add_overflow(u64 a, u64 b)
>
> Rename this to check_add_overflow and use the generic version from the
> kernel :

That's also my first idea.

But I'm not a fan of the 3rd parameter, and there is no other type other
than u64, so I hesitate to use the generic one.

However since you mentioned the kernel one, I guess it's time to
backport it to user space.

Thanks,
Qu

>
> #define check_add_overflow(a, b, d) ({          \
>
>         typeof(a) __a = (a);                    \
>
>         typeof(b) __b = (b);                    \
>
>         typeof(d) __d = (d);                    \
>
>         (void) (&__a == &__b);                  \
>
>         (void) (&__a == __d);                   \
>
>         __builtin_add_overflow(__a, __b, __d);  \
>
> })
>
>> +{
>> +	if (a > (u64)-1 - b)
>> +		return true;
>> +	return false;
>> +}
>>  #endif
>> diff --git a/check/mode-lowmem.c b/check/mode-lowmem.c
>> index 630fabf66919..d257a44f3086 100644
>> --- a/check/mode-lowmem.c
>> +++ b/check/mode-lowmem.c
>> @@ -2085,6 +2085,13 @@ static int check_file_extent(struct btrfs_root *root, struct btrfs_path *path,
>>  		err |= INVALID_GENERATION;
>>  	}
>>
>> +	/* Extent end shouldn't overflow */
>> +	if (u64_add_overflow(fkey.offset, extent_num_bytes)) {
>> +		error(
>> +	"file extent end over flow, file offset %llu extent num bytes %llu",
>> +			fkey.offset, extent_num_bytes);
>> +		err |= FILE_EXTENT_ERROR;
>> +	}
>>  	/*
>>  	 * Check EXTENT_DATA csum
>>  	 *
>> diff --git a/check/mode-original.h b/check/mode-original.h
>> index b075a95c9757..07d741f4a1b5 100644
>> --- a/check/mode-original.h
>> +++ b/check/mode-original.h
>> @@ -186,6 +186,7 @@ struct unaligned_extent_rec_t {
>>  #define I_ERR_MISMATCH_DIR_HASH		(1 << 18)
>>  #define I_ERR_INVALID_IMODE		(1 << 19)
>>  #define I_ERR_INVALID_GEN		(1 << 20)
>> +#define I_ERR_FILE_EXTENT_OVERFLOW	(1 << 21)
>>
>>  struct inode_record {
>>  	struct list_head backrefs;
>>




[Index of Archives]     [Linux Filesystem Development]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux