From owner-freebsd-bugs Mon Apr 22 13:49:53 2002 Delivered-To: freebsd-bugs@hub.freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.org [216.136.204.21]) by hub.freebsd.org (Postfix) with ESMTP id E796537B4FF for ; Mon, 22 Apr 2002 13:47:51 -0700 (PDT) Received: (from gnats@localhost) by freefall.freebsd.org (8.11.6/8.11.6) id g3MKe2N38958; Mon, 22 Apr 2002 13:40:02 -0700 (PDT) (envelope-from gnats) Date: Mon, 22 Apr 2002 13:40:02 -0700 (PDT) Message-Id: <200204222040.g3MKe2N38958@freefall.freebsd.org> To: freebsd-bugs@FreeBSD.org Cc: From: "peter.edwards@openet-telecom.com" Subject: Re: kern/37057: Problem with rlimits on filesystem mounted from /dev/vn0c Reply-To: "peter.edwards@openet-telecom.com" Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.org The following reply was made to PR kern/37057; it has been noted by GNATS. From: "peter.edwards@openet-telecom.com" To: freebsd-gnats-submit@FreeBSD.org, xi@borderworlds.dk Cc: Subject: Re: kern/37057: Problem with rlimits on filesystem mounted from /dev/vn0c Date: Mon, 22 Apr 2002 15:51:30 +0100 (IST) This comes from the filesystem on which the VN device's file lies, rather from anything above it. To explain: When you write to a file on a filesystem hosted by a VN device, which is in turn hosted by a file on a UFS filesystem, you get a layering like this: (1) UFS filesystem for /dev/vnX (2) VN device (3) UFS filesystem for file hosting VN device (4) disk device/swap The filesystem (1) is the one you are explicitly writing to. Filesystem (3) is the one generating the error: each filesystem implementation's write() method checks if it needs to generate SIGXFSZ, and the VN device calls VOP_WRITE(). Of course, the VN device is accessing the entire file on which the filesystem is laid out, so, its not surprising that it attempts to write where it shouldn't. There's a comment in ufs/ufs/ufs_readwrite.c which indicates what /* * Maybe this should be above the vnode op call, but so long as * file servers have no limits, I don't think it matters. */ (This is present in rev 1.1, so its quite old) I wonder if: The vn device could use VOP_STRATEGY to do its I/O and If the best place for the check isn't in the write(2) system call, where we know which object the user is acting on. However, its not quite trivial to move this to the VOP operation or write system call, because each filesystem implementation currently updates uio_offset for IO_APPEND mode writes, and only the filesystem-internal representation of the vnode has the current length of the file available, so you don't have enough information in VOP_WRITE or dofilewrite() to do the rlimits check, unlesee you call VOP_GETATTR() and that would probably be Bad. In the meantime, you can hack your way around by noting that user requests are to UIO_USERSPACE, while kernel requests to UIO_SYSSPACE/UIO_NOCOPY, and adding that to the check for sending SIGXFSZ (patch attached). Security could be an issue here. However, I think the only way to extend a file from user-land at all is via write[v](2) or truncate(2), and the only UIO_USERSPACEs I can find that can ever hit VOP_WRITE come from write[v](2). mmap(2) and strategy interactions never extend the file, so they are not an issue. (Which actually brings up another point: you can currently modify a file at an offset beyond your maximum filesize with mmap(), but not with write(). Of course, you can't make the file any bigger with mmap(), but its still "weaker" security in mmap() than write()) So I don't think there's any loss of security with the following patch, but I'm not an expert, so beware... The patch updates the checks done by SMBFS, EXT2FS, MSDOSFS NFS, NWFS, and, of course UFS/FFS. -------------->8-------------- Cut Here -------------->8-------------- Index: fs/smbfs/smbfs_io.c =================================================================== RCS file: /pub/FreeBSD/development/FreeBSD-CVS/src/sys/fs/smbfs/smbfs_io.c,v retrieving revision 1.3.2.1 diff -u -r1.3.2.1 smbfs_io.c --- fs/smbfs/smbfs_io.c 22 May 2001 08:32:26 -0000 1.3.2.1 +++ fs/smbfs/smbfs_io.c 22 Apr 2002 13:42:59 -0000 @@ -270,7 +270,8 @@ } if (uiop->uio_resid == 0) return 0; - if (p && uiop->uio_offset + uiop->uio_resid > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { + if (p && uiop->uio_segflg == UIO_USERSPACE && uiop->uio_offset + + uiop->uio_resid > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { psignal(p, SIGXFSZ); return EFBIG; } Index: gnu/ext2fs/ext2_readwrite.c =================================================================== RCS file: /pub/FreeBSD/development/FreeBSD-CVS/src/sys/gnu/ext2fs/ext2_readwrite.c,v retrieving revision 1.18.2.2 diff -u -r1.18.2.2 ext2_readwrite.c --- gnu/ext2fs/ext2_readwrite.c 22 Dec 2000 18:44:33 -0000 1.18.2.2 +++ gnu/ext2fs/ext2_readwrite.c 22 Apr 2002 13:43:26 -0000 @@ -218,6 +218,7 @@ */ p = uio->uio_procp; if (vp->v_type == VREG && p && + uio->segflg == UIO_USERSPACE && uio->uio_offset + uio->uio_resid > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { psignal(p, SIGXFSZ); Index: msdosfs/msdosfs_vnops.c =================================================================== RCS file: /pub/FreeBSD/development/FreeBSD-CVS/src/sys/msdosfs/Attic/msdosfs_vnops.c,v retrieving revision 1.95.2.1 diff -u -r1.95.2.1 msdosfs_vnops.c --- msdosfs/msdosfs_vnops.c 18 Jul 2000 13:19:13 -0000 1.95.2.1 +++ msdosfs/msdosfs_vnops.c 22 Apr 2002 14:26:49 -0000 @@ -688,6 +688,7 @@ * If they've exceeded their filesize limit, tell them about it. */ if (p && + uio->uio_segflg == UIO_USERSPACE && ((uoff_t)uio->uio_offset + uio->uio_resid > p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) { psignal(p, SIGXFSZ); Index: nfs/nfs_bio.c =================================================================== RCS file: /pub/FreeBSD/development/FreeBSD-CVS/src/sys/nfs/Attic/nfs_bio.c,v retrieving revision 1.83.2.2 diff -u -r1.83.2.2 nfs_bio.c --- nfs/nfs_bio.c 20 Dec 2001 19:56:28 -0000 1.83.2.2 +++ nfs/nfs_bio.c 22 Apr 2002 13:44:51 -0000 @@ -822,8 +822,8 @@ * Maybe this should be above the vnode op call, but so long as * file servers have no limits, i don't think it matters */ - if (p && uio->uio_offset + uio->uio_resid > - p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { + if (p && uio->uio_segflg == UIO_USERSPACE && uio->uio_offset + + uio->uio_resid > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { psignal(p, SIGXFSZ); if (haverslock) nfs_rsunlock(np, p); Index: nwfs/nwfs_io.c =================================================================== RCS file: /pub/FreeBSD/development/FreeBSD-CVS/src/sys/nwfs/Attic/nwfs_io.c,v retrieving revision 1.6.2.1 diff -u -r1.6.2.1 nwfs_io.c --- nwfs/nwfs_io.c 25 Oct 2000 02:11:10 -0000 1.6.2.1 +++ nwfs/nwfs_io.c 22 Apr 2002 13:45:23 -0000 @@ -235,7 +235,8 @@ } } if (uiop->uio_resid == 0) return 0; - if (p && uiop->uio_offset + uiop->uio_resid > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { + if (p && uiop->uio_segflg == UIO_USERSPACE && + uiop->uio_offset + uiop->uio_resid > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { psignal(p, SIGXFSZ); return (EFBIG); } Index: ufs/ufs/ufs_readwrite.c =================================================================== RCS file: /pub/FreeBSD/development/FreeBSD-CVS/src/sys/ufs/ufs/ufs_readwrite.c,v retrieving revision 1.65.2.10 diff -u -r1.65.2.10 ufs_readwrite.c --- ufs/ufs/ufs_readwrite.c 6 Mar 2002 19:53:08 -0000 1.65.2.10 +++ ufs/ufs/ufs_readwrite.c 22 Apr 2002 14:36:14 -0000 @@ -382,6 +382,7 @@ /* * Vnode op for writing. */ + int WRITE(ap) struct vop_write_args /* { @@ -451,9 +452,12 @@ /* * Maybe this should be above the vnode op call, but so long as * file servers have no limits, I don't think it matters. + * XXX: Only check !UIO_USERSPACE requests: we assume requests + * initiated by the kernel will be valid. */ p = uio->uio_procp; if (vp->v_type == VREG && p && + uio->uio_segflg == UIO_USERSPACE && uio->uio_offset + uio->uio_resid > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { psignal(p, SIGXFSZ); To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message