Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 22 Apr 2002 13:40:02 -0700 (PDT)
From:      "peter.edwards@openet-telecom.com" <petere@openet-telecom.com>
To:        freebsd-bugs@FreeBSD.org
Subject:   Re: kern/37057: Problem with rlimits on filesystem mounted from /dev/vn0c
Message-ID:  <200204222040.g3MKe2N38958@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/37057; it has been noted by GNATS.

From: "peter.edwards@openet-telecom.com" <petere@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




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200204222040.g3MKe2N38958>