Module Name: src Committed By: pooka Date: Fri Apr 23 15:38:47 UTC 2010
Modified Files: src/sys/fs/msdosfs: msdosfs_vnops.c src/sys/fs/smbfs: smbfs_io.c src/sys/fs/tmpfs: tmpfs_vnops.c src/sys/kern: vfs_vnops.c src/sys/nfs: nfs_bio.c src/sys/ufs/ext2fs: ext2fs_readwrite.c src/sys/ufs/ufs: ufs_readwrite.c Log Message: Enforce RLIMIT_FSIZE before VOP_WRITE. This adds support to file system drivers where it was missing from and fixes one buggy implementation. The arguably weird semantics of the check are maintained (v_size vs. va_bytes, overwrite). To generate a diff of this commit: cvs rdiff -u -r1.64 -r1.65 src/sys/fs/msdosfs/msdosfs_vnops.c cvs rdiff -u -r1.33 -r1.34 src/sys/fs/smbfs/smbfs_io.c cvs rdiff -u -r1.68 -r1.69 src/sys/fs/tmpfs/tmpfs_vnops.c cvs rdiff -u -r1.170 -r1.171 src/sys/kern/vfs_vnops.c cvs rdiff -u -r1.183 -r1.184 src/sys/nfs/nfs_bio.c cvs rdiff -u -r1.55 -r1.56 src/sys/ufs/ext2fs/ext2fs_readwrite.c cvs rdiff -u -r1.94 -r1.95 src/sys/ufs/ufs/ufs_readwrite.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/fs/msdosfs/msdosfs_vnops.c diff -u src/sys/fs/msdosfs/msdosfs_vnops.c:1.64 src/sys/fs/msdosfs/msdosfs_vnops.c:1.65 --- src/sys/fs/msdosfs/msdosfs_vnops.c:1.64 Fri Apr 9 08:09:18 2010 +++ src/sys/fs/msdosfs/msdosfs_vnops.c Fri Apr 23 15:38:46 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: msdosfs_vnops.c,v 1.64 2010/04/09 08:09:18 hannken Exp $ */ +/* $NetBSD: msdosfs_vnops.c,v 1.65 2010/04/23 15:38:46 pooka Exp $ */ /*- * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. @@ -48,7 +48,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: msdosfs_vnops.c,v 1.64 2010/04/09 08:09:18 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: msdosfs_vnops.c,v 1.65 2010/04/23 15:38:46 pooka Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -564,7 +564,6 @@ vsize_t bytelen; off_t oldoff; struct uio *uio = ap->a_uio; - struct proc *p = curproc; struct vnode *vp = ap->a_vp; struct denode *dep = VTODE(vp); struct msdosfsmount *pmp = dep->de_pmp; @@ -599,17 +598,6 @@ if (uio->uio_offset + uio->uio_resid > MSDOSFS_FILESIZE_MAX) return (EFBIG); - /* - * If they've exceeded their filesize limit, tell them about it. - */ - if (((uio->uio_offset + uio->uio_resid) > - p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) { - mutex_enter(proc_lock); - psignal(p, SIGXFSZ); - mutex_exit(proc_lock); - return (EFBIG); - } - fstrans_start(vp->v_mount, FSTRANS_SHARED); /* * If the offset we are starting the write at is beyond the end of Index: src/sys/fs/smbfs/smbfs_io.c diff -u src/sys/fs/smbfs/smbfs_io.c:1.33 src/sys/fs/smbfs/smbfs_io.c:1.34 --- src/sys/fs/smbfs/smbfs_io.c:1.33 Mon Jun 22 21:13:50 2009 +++ src/sys/fs/smbfs/smbfs_io.c Fri Apr 23 15:38:47 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: smbfs_io.c,v 1.33 2009/06/22 21:13:50 njoly Exp $ */ +/* $NetBSD: smbfs_io.c,v 1.34 2010/04/23 15:38:47 pooka Exp $ */ /* * Copyright (c) 2000-2001, Boris Popov @@ -36,7 +36,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: smbfs_io.c,v 1.33 2009/06/22 21:13:50 njoly Exp $"); +__KERNEL_RCSID(0, "$NetBSD: smbfs_io.c,v 1.34 2010/04/23 15:38:47 pooka Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -244,9 +244,8 @@ { struct smbmount *smp = VTOSMBFS(vp); struct smbnode *np = VTOSMB(vp); - struct smb_cred scred; struct lwp *l = curlwp; - struct proc *p = l->l_proc; + struct smb_cred scred; int error = 0; int extended = 0; size_t resid = uiop->uio_resid; @@ -270,6 +269,8 @@ } if (ioflag & IO_APPEND) { #if notyet + struct proc *p = curproc; + /* * File size can be changed by another client */ @@ -277,18 +278,19 @@ error = VOP_GETATTR(vp, &vattr, cred, td); if (error) return (error); + if (np->n_size + uiop->uio_resid > + p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { + mutex_enter(proc_lock); + psignal(p, SIGXFSZ); + mutex_exit(proc_lock); + return EFBIG; + } #endif uiop->uio_offset = np->n_size; } } if (uiop->uio_resid == 0) return 0; - if (p && uiop->uio_offset + uiop->uio_resid > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { - mutex_enter(proc_lock); - psignal(p, SIGXFSZ); - mutex_exit(proc_lock); - return EFBIG; - } smb_makescred(&scred, l, cred); error = smb_write(smp->sm_share, np->n_fid, uiop, &scred); SMBVDEBUG("after: ofs=%lld,resid=%zu,err=%d\n", Index: src/sys/fs/tmpfs/tmpfs_vnops.c diff -u src/sys/fs/tmpfs/tmpfs_vnops.c:1.68 src/sys/fs/tmpfs/tmpfs_vnops.c:1.69 --- src/sys/fs/tmpfs/tmpfs_vnops.c:1.68 Mon Mar 29 13:11:33 2010 +++ src/sys/fs/tmpfs/tmpfs_vnops.c Fri Apr 23 15:38:47 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: tmpfs_vnops.c,v 1.68 2010/03/29 13:11:33 pooka Exp $ */ +/* $NetBSD: tmpfs_vnops.c,v 1.69 2010/04/23 15:38:47 pooka Exp $ */ /* * Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: tmpfs_vnops.c,v 1.68 2010/03/29 13:11:33 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: tmpfs_vnops.c,v 1.69 2010/04/23 15:38:47 pooka Exp $"); #include <sys/param.h> #include <sys/dirent.h> @@ -594,7 +594,6 @@ bool extended; int error; off_t oldsize; - struct proc *p = curproc; struct tmpfs_node *node; struct uvm_object *uobj; @@ -613,15 +612,6 @@ goto out; } - if (((uio->uio_offset + uio->uio_resid) > - p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) { - mutex_enter(proc_lock); - psignal(p, SIGXFSZ); - mutex_exit(proc_lock); - error = EFBIG; - goto out; - } - if (ioflag & IO_APPEND) uio->uio_offset = node->tn_size; Index: src/sys/kern/vfs_vnops.c diff -u src/sys/kern/vfs_vnops.c:1.170 src/sys/kern/vfs_vnops.c:1.171 --- src/sys/kern/vfs_vnops.c:1.170 Mon Mar 29 13:11:32 2010 +++ src/sys/kern/vfs_vnops.c Fri Apr 23 15:38:46 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_vnops.c,v 1.170 2010/03/29 13:11:32 pooka Exp $ */ +/* $NetBSD: vfs_vnops.c,v 1.171 2010/04/23 15:38:46 pooka 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.170 2010/03/29 13:11:32 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.171 2010/04/23 15:38:46 pooka Exp $"); #include "veriexec.h" @@ -351,6 +351,32 @@ return (error); } +static int +enforce_rlimit_fsize(struct vnode *vp, struct uio *uio, int ioflag) +{ + struct lwp *l = curlwp; + off_t testoff; + + if (uio->uio_rw != UIO_WRITE || vp->v_type != VREG) + return 0; + + KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); + if (ioflag & IO_APPEND) + testoff = vp->v_size; + else + testoff = uio->uio_offset; + + if (testoff + uio->uio_resid > + l->l_proc->p_rlimit[RLIMIT_FSIZE].rlim_cur) { + mutex_enter(proc_lock); + psignal(l->l_proc, SIGXFSZ); + mutex_exit(proc_lock); + return EFBIG; + } + + return 0; +} + /* * Package up an I/O request on a vnode into a uio and do it. */ @@ -382,16 +408,23 @@ } else { auio.uio_vmspace = l->l_proc->p_vmspace; } + + if ((error = enforce_rlimit_fsize(vp, &auio, ioflg)) != 0) + goto out; + if (rw == UIO_READ) { error = VOP_READ(vp, &auio, ioflg, cred); } else { error = VOP_WRITE(vp, &auio, ioflg, cred); } + if (aresid) *aresid = auio.uio_resid; else if (auio.uio_resid && error == 0) error = EIO; + + out: if ((ioflg & IO_NODELOCKED) == 0) { VOP_UNLOCK(vp, 0); } @@ -520,7 +553,12 @@ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); uio->uio_offset = *offset; count = uio->uio_resid; + + if ((error = enforce_rlimit_fsize(vp, uio, ioflag)) != 0) + goto out; + error = VOP_WRITE(vp, uio, ioflag, cred); + if (flags & FOF_UPDATE_OFFSET) { if (ioflag & IO_APPEND) { /* @@ -535,6 +573,8 @@ } else *offset += count - uio->uio_resid; } + + out: VOP_UNLOCK(vp, 0); return (error); } Index: src/sys/nfs/nfs_bio.c diff -u src/sys/nfs/nfs_bio.c:1.183 src/sys/nfs/nfs_bio.c:1.184 --- src/sys/nfs/nfs_bio.c:1.183 Sat Mar 14 14:46:11 2009 +++ src/sys/nfs/nfs_bio.c Fri Apr 23 15:38:47 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: nfs_bio.c,v 1.183 2009/03/14 14:46:11 dsl Exp $ */ +/* $NetBSD: nfs_bio.c,v 1.184 2010/04/23 15:38:47 pooka Exp $ */ /* * Copyright (c) 1989, 1993 @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: nfs_bio.c,v 1.183 2009/03/14 14:46:11 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: nfs_bio.c,v 1.184 2010/04/23 15:38:47 pooka Exp $"); #ifdef _KERNEL_OPT #include "opt_nfs.h" @@ -480,6 +480,19 @@ if (error) return (error); uio->uio_offset = np->n_size; + + /* + * This is already checked above VOP_WRITE, but recheck + * the append case here to make sure our idea of the + * file size is as fresh as possible. + */ + if (uio->uio_offset + uio->uio_resid > + l->l_proc->p_rlimit[RLIMIT_FSIZE].rlim_cur) { + mutex_enter(proc_lock); + psignal(l->l_proc, SIGXFSZ); + mutex_exit(proc_lock); + return (EFBIG); + } } if (uio->uio_offset < 0) return (EINVAL); @@ -487,17 +500,6 @@ return (EFBIG); if (uio->uio_resid == 0) return (0); - /* - * 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 (l && l->l_proc && uio->uio_offset + uio->uio_resid > - l->l_proc->p_rlimit[RLIMIT_FSIZE].rlim_cur) { - mutex_enter(proc_lock); - psignal(l->l_proc, SIGXFSZ); - mutex_exit(proc_lock); - return (EFBIG); - } origoff = uio->uio_offset; do { Index: src/sys/ufs/ext2fs/ext2fs_readwrite.c diff -u src/sys/ufs/ext2fs/ext2fs_readwrite.c:1.55 src/sys/ufs/ext2fs/ext2fs_readwrite.c:1.56 --- src/sys/ufs/ext2fs/ext2fs_readwrite.c:1.55 Mon Oct 19 18:41:17 2009 +++ src/sys/ufs/ext2fs/ext2fs_readwrite.c Fri Apr 23 15:38:46 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: ext2fs_readwrite.c,v 1.55 2009/10/19 18:41:17 bouyer Exp $ */ +/* $NetBSD: ext2fs_readwrite.c,v 1.56 2010/04/23 15:38:46 pooka Exp $ */ /*- * Copyright (c) 1993 @@ -60,7 +60,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ext2fs_readwrite.c,v 1.55 2009/10/19 18:41:17 bouyer Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ext2fs_readwrite.c,v 1.56 2010/04/23 15:38:46 pooka Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -224,7 +224,6 @@ struct inode *ip; struct m_ext2fs *fs; struct buf *bp; - struct proc *p; struct ufsmount *ump; daddr_t lbn; off_t osize; @@ -270,19 +269,6 @@ if (uio->uio_offset < 0 || (uint64_t)uio->uio_offset + uio->uio_resid > ump->um_maxfilesize) return (EFBIG); - /* - * Maybe this should be above the vnode op call, but so long as - * file servers have no limits, I don't think it matters. - */ - p = curproc; - if (vp->v_type == VREG && p && - uio->uio_offset + uio->uio_resid > - p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { - mutex_enter(proc_lock); - psignal(p, SIGXFSZ); - mutex_exit(proc_lock); - return (EFBIG); - } if (uio->uio_resid == 0) return (0); Index: src/sys/ufs/ufs/ufs_readwrite.c diff -u src/sys/ufs/ufs/ufs_readwrite.c:1.94 src/sys/ufs/ufs/ufs_readwrite.c:1.95 --- src/sys/ufs/ufs/ufs_readwrite.c:1.94 Sun Feb 22 20:28:07 2009 +++ src/sys/ufs/ufs/ufs_readwrite.c Fri Apr 23 15:38:46 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: ufs_readwrite.c,v 1.94 2009/02/22 20:28:07 ad Exp $ */ +/* $NetBSD: ufs_readwrite.c,v 1.95 2010/04/23 15:38:46 pooka Exp $ */ /*- * Copyright (c) 1993 @@ -32,7 +32,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(1, "$NetBSD: ufs_readwrite.c,v 1.94 2009/02/22 20:28:07 ad Exp $"); +__KERNEL_RCSID(1, "$NetBSD: ufs_readwrite.c,v 1.95 2010/04/23 15:38:46 pooka Exp $"); #ifdef LFS_READWRITE #define FS struct lfs @@ -217,7 +217,6 @@ struct inode *ip; FS *fs; struct buf *bp; - struct lwp *l; kauth_cred_t cred; daddr_t lbn; off_t osize, origoff, oldoff, preallocoff, endallocoff, nsize; @@ -272,19 +271,6 @@ if (vp == fs->lfs_ivnode) return (EPERM); #endif - /* - * Maybe this should be above the vnode op call, but so long as - * file servers have no limits, I don't think it matters. - */ - l = curlwp; - if (vp->v_type == VREG && l && - uio->uio_offset + uio->uio_resid > - l->l_proc->p_rlimit[RLIMIT_FSIZE].rlim_cur) { - mutex_enter(proc_lock); - psignal(l->l_proc, SIGXFSZ); - mutex_exit(proc_lock); - return (EFBIG); - } if (uio->uio_resid == 0) return (0);