btrfs: fix signed overflows in btrfs_sync_file
The calculation of range length in btrfs_sync_file leads to signed overflow. This was caught by PaX gcc SIZE_OVERFLOW plugin. https://forums.grsecurity.net/viewtopic.php?f=1&t=4284 The fsync call passes 0 and LLONG_MAX, the range length does not fit to loff_t and overflows, but the value is converted to u64 so it silently works as expected. The minimal fix is a typecast to u64, switching functions to take (start, end) instead of (start, len) would be more intrusive. Coccinelle script found that there's one more opencoded calculation of the length. <smpl> @@ loff_t start, end; @@ * end - start </smpl> CC: stable@vger.kernel.org Signed-off-by: David Sterba <dsterba@suse.com> Signed-off-by: Chris Mason <clm@fb.com>
This commit is contained in:
parent
d5f2e33b92
commit
9dcbeed4d7
|
@ -1882,8 +1882,13 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
|||
struct btrfs_log_ctx ctx;
|
||||
int ret = 0;
|
||||
bool full_sync = 0;
|
||||
const u64 len = end - start + 1;
|
||||
u64 len;
|
||||
|
||||
/*
|
||||
* The range length can be represented by u64, we have to do the typecasts
|
||||
* to avoid signed overflow if it's [0, LLONG_MAX] eg. from fsync()
|
||||
*/
|
||||
len = (u64)end - (u64)start + 1;
|
||||
trace_btrfs_sync_file(file, datasync);
|
||||
|
||||
/*
|
||||
|
@ -2071,8 +2076,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
|||
}
|
||||
}
|
||||
if (!full_sync) {
|
||||
ret = btrfs_wait_ordered_range(inode, start,
|
||||
end - start + 1);
|
||||
ret = btrfs_wait_ordered_range(inode, start, len);
|
||||
if (ret) {
|
||||
btrfs_end_transaction(trans, root);
|
||||
goto out;
|
||||
|
|
Loading…
Reference in New Issue