Module Name: src Committed By: riastradh Date: Sun Mar 13 13:52:53 UTC 2022
Modified Files: src/sys/kern: vfs_vnops.c Log Message: vfs(9): Avoid arithmetic overflow in vn_seek. Reported-by: syzbot+b9f9a02148a40675c...@syzkaller.appspotmail.com To generate a diff of this commit: cvs rdiff -u -r1.224 -r1.225 src/sys/kern/vfs_vnops.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/vfs_vnops.c diff -u src/sys/kern/vfs_vnops.c:1.224 src/sys/kern/vfs_vnops.c:1.225 --- src/sys/kern/vfs_vnops.c:1.224 Wed Oct 20 03:08:18 2021 +++ src/sys/kern/vfs_vnops.c Sun Mar 13 13:52:53 2022 @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_vnops.c,v 1.224 2021/10/20 03:08:18 thorpej Exp $ */ +/* $NetBSD: vfs_vnops.c,v 1.225 2022/03/13 13:52:53 riastradh Exp $ */ /*- * Copyright (c) 2009 The NetBSD Foundation, Inc. @@ -66,7 +66,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.224 2021/10/20 03:08:18 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.225 2022/03/13 13:52:53 riastradh Exp $"); #include "veriexec.h" @@ -1117,6 +1117,8 @@ static int vn_seek(struct file *fp, off_t delta, int whence, off_t *newoffp, int flags) { + const off_t OFF_MIN = __type_min(off_t); + const off_t OFF_MAX = __type_max(off_t); kauth_cred_t cred = fp->f_cred; off_t oldoff, newoff; struct vnode *vp = fp->f_vnode; @@ -1132,13 +1134,29 @@ vn_seek(struct file *fp, off_t delta, in oldoff = fp->f_offset; switch (whence) { case SEEK_CUR: - newoff = oldoff + delta; /* XXX arithmetic overflow */ + if (delta > 0) { + if (oldoff > 0 && delta > OFF_MAX - oldoff) { + newoff = OFF_MAX; + break; + } + } else { + if (oldoff < 0 && delta < OFF_MIN - oldoff) { + newoff = OFF_MIN; + break; + } + } + newoff = oldoff + delta; break; case SEEK_END: error = VOP_GETATTR(vp, &vattr, cred); if (error) goto out; - newoff = delta + vattr.va_size; /* XXX arithmetic overflow */ + if (vattr.va_size > OFF_MAX || + delta > OFF_MAX - (off_t)vattr.va_size) { + newoff = OFF_MAX; + break; + } + newoff = delta + vattr.va_size; break; case SEEK_SET: newoff = delta;