Message ID | 20240513-b4-sio-vfs_fallocate-v2-1-db415872fb16@google.com (mailing list archive) |
---|---|
State | Mainlined |
Commit | 23cc6ef6fd453b13502caae23130844e7d6ed0fe |
Headers | show |
Series | [v2] fs: remove accidental overflow during wraparound check | expand |
On Mon 13-05-24 17:50:30, Justin Stitt wrote: > Running syzkaller with the newly enabled signed integer overflow > sanitizer produces this report: > > [ 195.401651] ------------[ cut here ]------------ > [ 195.404808] UBSAN: signed-integer-overflow in ../fs/open.c:321:15 > [ 195.408739] 9223372036854775807 + 562984447377399 cannot be represented in type 'loff_t' (aka 'long long') > [ 195.414683] CPU: 1 PID: 703 Comm: syz-executor.0 Not tainted 6.8.0-rc2-00039-g14de58dbe653-dirty #11 > [ 195.420138] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 > [ 195.425804] Call Trace: > [ 195.427360] <TASK> > [ 195.428791] dump_stack_lvl+0x93/0xd0 > [ 195.431150] handle_overflow+0x171/0x1b0 > [ 195.433640] vfs_fallocate+0x459/0x4f0 > ... > [ 195.490053] ------------[ cut here ]------------ > [ 195.493146] UBSAN: signed-integer-overflow in ../fs/open.c:321:61 > [ 195.497030] 9223372036854775807 + 562984447377399 cannot be represented in type 'loff_t' (aka 'long long) > [ 195.502940] CPU: 1 PID: 703 Comm: syz-executor.0 Not tainted 6.8.0-rc2-00039-g14de58dbe653-dirty #11 > [ 195.508395] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 > [ 195.514075] Call Trace: > [ 195.515636] <TASK> > [ 195.517000] dump_stack_lvl+0x93/0xd0 > [ 195.519255] handle_overflow+0x171/0x1b0 > [ 195.521677] vfs_fallocate+0x4cb/0x4f0 > [ 195.524033] __x64_sys_fallocate+0xb2/0xf0 > > Historically, the signed integer overflow sanitizer did not work in the > kernel due to its interaction with `-fwrapv` but this has since been > changed [1] in the newest version of Clang. It was re-enabled in the > kernel with Commit 557f8c582a9ba8ab ("ubsan: Reintroduce signed overflow > sanitizer"). > > Let's use the check_add_overflow helper to first verify the addition > stays within the bounds of its type (long long); then we can use that > sum for the following check. > > Link: https://github.com/llvm/llvm-project/pull/82432 [1] > Closes: https://github.com/KSPP/linux/issues/356 > Cc: linux-hardening@vger.kernel.org > Reviewed-by: Kees Cook <keescook@chromium.org> > Signed-off-by: Justin Stitt <justinstitt@google.com> Looks good. Feel free to add: Reviewed-by: Jan Kara <jack@suse.cz> Honza > --- > Changes in v2: > - drop the sum < 0 check (thanks Jan) > - carry along Kees' RB tag > - Link to v1: https://lore.kernel.org/r/20240507-b4-sio-vfs_fallocate-v1-1-322f84b97ad5@google.com > --- > Here's the syzkaller reproducer: > r0 = openat(0xffffffffffffff9c, &(0x7f0000000040)='./file1\x00', 0x42, 0x0) > fallocate(r0, 0x10, 0x7fffffffffffffff, 0x2000807fffff7) > > ... which was used against Kees' tree here (v6.8rc2): > https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/log/?h=wip/v6.9-rc2/unsigned-overflow-sanitizer > > ... with this config: > https://gist.github.com/JustinStitt/824976568b0f228ccbcbe49f3dee9bf4 > --- > fs/open.c | 8 ++++++-- > 1 file changed, 6 insertions(+), 2 deletions(-) > > diff --git a/fs/open.c b/fs/open.c > index ee8460c83c77..23849d487479 100644 > --- a/fs/open.c > +++ b/fs/open.c > @@ -247,6 +247,7 @@ int vfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len) > { > struct inode *inode = file_inode(file); > long ret; > + loff_t sum; > > if (offset < 0 || len <= 0) > return -EINVAL; > @@ -319,8 +320,11 @@ int vfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len) > if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) > return -ENODEV; > > - /* Check for wrap through zero too */ > - if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0)) > + /* Check for wraparound */ > + if (check_add_overflow(offset, len, &sum)) > + return -EFBIG; > + > + if (sum > inode->i_sb->s_maxbytes) > return -EFBIG; > > if (!file->f_op->fallocate) > > --- > base-commit: 0106679839f7c69632b3b9833c3268c316c0a9fc > change-id: 20240507-b4-sio-vfs_fallocate-7b5223ba3a81 > > Best regards, > -- > Justin Stitt <justinstitt@google.com> >
On Mon, 13 May 2024 17:50:30 +0000, Justin Stitt wrote: > Running syzkaller with the newly enabled signed integer overflow > sanitizer produces this report: > > [ 195.401651] ------------[ cut here ]------------ > [ 195.404808] UBSAN: signed-integer-overflow in ../fs/open.c:321:15 > [ 195.408739] 9223372036854775807 + 562984447377399 cannot be represented in type 'loff_t' (aka 'long long') > [ 195.414683] CPU: 1 PID: 703 Comm: syz-executor.0 Not tainted 6.8.0-rc2-00039-g14de58dbe653-dirty #11 > [ 195.420138] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 > [ 195.425804] Call Trace: > [ 195.427360] <TASK> > [ 195.428791] dump_stack_lvl+0x93/0xd0 > [ 195.431150] handle_overflow+0x171/0x1b0 > [ 195.433640] vfs_fallocate+0x459/0x4f0 > ... > [ 195.490053] ------------[ cut here ]------------ > [ 195.493146] UBSAN: signed-integer-overflow in ../fs/open.c:321:61 > [ 195.497030] 9223372036854775807 + 562984447377399 cannot be represented in type 'loff_t' (aka 'long long) > [ 195.502940] CPU: 1 PID: 703 Comm: syz-executor.0 Not tainted 6.8.0-rc2-00039-g14de58dbe653-dirty #11 > [ 195.508395] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 > [ 195.514075] Call Trace: > [ 195.515636] <TASK> > [ 195.517000] dump_stack_lvl+0x93/0xd0 > [ 195.519255] handle_overflow+0x171/0x1b0 > [ 195.521677] vfs_fallocate+0x4cb/0x4f0 > [ 195.524033] __x64_sys_fallocate+0xb2/0xf0 > > [...] Applied to the vfs.misc branch of the vfs/vfs.git tree. Patches in the vfs.misc branch should appear in linux-next soon. Please report any outstanding bugs that were missed during review in a new review to the original patch series allowing us to drop it. It's encouraged to provide Acked-bys and Reviewed-bys even though the patch has now been applied. If possible patch trailers will be updated. Note that commit hashes shown below are subject to change due to rebase, trailer updates or similar. If in doubt, please check the listed branch. tree: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git branch: vfs.misc [1/1] fs: remove accidental overflow during wraparound check https://git.kernel.org/vfs/vfs/c/c01a23b6fbd1
diff --git a/fs/open.c b/fs/open.c index ee8460c83c77..23849d487479 100644 --- a/fs/open.c +++ b/fs/open.c @@ -247,6 +247,7 @@ int vfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len) { struct inode *inode = file_inode(file); long ret; + loff_t sum; if (offset < 0 || len <= 0) return -EINVAL; @@ -319,8 +320,11 @@ int vfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len) if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) return -ENODEV; - /* Check for wrap through zero too */ - if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0)) + /* Check for wraparound */ + if (check_add_overflow(offset, len, &sum)) + return -EFBIG; + + if (sum > inode->i_sb->s_maxbytes) return -EFBIG; if (!file->f_op->fallocate)