From 468bb1f9df45e773cdb6662b27d609c0287ebe6d Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Mon, 18 Sep 2006 17:42:28 +0000 Subject: [PATCH] Disallow writes to filesystems mounted read-only via NULLFS. In this case the ncp->nc_mount in the namecache must be checked since the vnode's mount point is the actual filesystem and not the NULLFS mount. Reported-by: Joerg Sonnenberger --- sys/kern/kern_fp.c | 4 ++-- sys/kern/vfs_syscalls.c | 11 ++++++----- sys/kern/vfs_vnops.c | 39 +++++++++++++++++++++++++++++++++------ sys/sys/vnode.h | 4 ++-- 4 files changed, 43 insertions(+), 15 deletions(-) diff --git a/sys/kern/kern_fp.c b/sys/kern/kern_fp.c index 3df86f7019..ed30e649bf 100644 --- a/sys/kern/kern_fp.c +++ b/sys/kern/kern_fp.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/kern/kern_fp.c,v 1.17 2006/06/13 08:12:03 dillon Exp $ + * $DragonFly: src/sys/kern/kern_fp.c,v 1.18 2006/09/18 17:42:27 dillon Exp $ */ /* @@ -160,7 +160,7 @@ fp_vpopen(struct vnode *vp, int flags, file_t *fpp) error = EISDIR; goto bad2; } - error = vn_writechk(vp); + error = vn_writechk(vp, NULL); if (error) goto bad2; vmode |= VWRITE; diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 004a3dca4a..70017ce276 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -37,7 +37,7 @@ * * @(#)vfs_syscalls.c 8.13 (Berkeley) 4/15/94 * $FreeBSD: src/sys/kern/vfs_syscalls.c,v 1.151.2.18 2003/04/04 20:35:58 tegge Exp $ - * $DragonFly: src/sys/kern/vfs_syscalls.c,v 1.102 2006/09/05 00:55:45 dillon Exp $ + * $DragonFly: src/sys/kern/vfs_syscalls.c,v 1.103 2006/09/18 17:42:27 dillon Exp $ */ #include @@ -1916,7 +1916,8 @@ retry: flags |= VWRITE; if (aflags & X_OK) flags |= VEXEC; - if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) + if ((flags & VWRITE) == 0 || + (error = vn_writechk(vp, nd->nl_ncp)) == 0) error = VOP_ACCESS(vp, flags, nd->nl_cred); /* @@ -2558,7 +2559,7 @@ kern_truncate(struct nlookupdata *nd, off_t length) } if (vp->v_type == VDIR) { error = EISDIR; - } else if ((error = vn_writechk(vp)) == 0 && + } else if ((error = vn_writechk(vp, nd->nl_ncp)) == 0 && (error = VOP_ACCESS(vp, VWRITE, nd->nl_cred)) == 0) { VATTR_NULL(&vattr); vattr.va_size = length; @@ -2608,7 +2609,7 @@ kern_ftruncate(int fd, off_t length) vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); if (vp->v_type == VDIR) { error = EISDIR; - } else if ((error = vn_writechk(vp)) == 0) { + } else if ((error = vn_writechk(vp, NULL)) == 0) { VATTR_NULL(&vattr); vattr.va_size = length; error = VOP_SETATTR(vp, &vattr, fp->f_cred); @@ -3190,7 +3191,7 @@ sys_fhopen(struct fhopen_args *uap) error = EISDIR; goto bad; } - error = vn_writechk(vp); + error = vn_writechk(vp, NULL); if (error) goto bad; mode |= VWRITE; diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 774e42d794..9e0cffb547 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -37,7 +37,7 @@ * * @(#)vfs_vnops.c 8.2 (Berkeley) 1/21/94 * $FreeBSD: src/sys/kern/vfs_vnops.c,v 1.87.2.13 2002/12/29 18:19:53 dillon Exp $ - * $DragonFly: src/sys/kern/vfs_vnops.c,v 1.46 2006/09/10 01:26:39 dillon Exp $ + * $DragonFly: src/sys/kern/vfs_vnops.c,v 1.47 2006/09/18 17:42:27 dillon Exp $ */ #include @@ -55,6 +55,8 @@ #include #include +static int ncp_writechk(struct namecache *ncp); + static int vn_closefile (struct file *fp); static int vn_ioctl (struct file *fp, u_long com, caddr_t data, struct ucred *cred); @@ -176,6 +178,8 @@ vn_open(struct nlookupdata *nd, struct file *fp, int fmode, int cmode) again: if (fmode & O_CREAT) { if (ncp->nc_vp == NULL) { + if ((error = ncp_writechk(ncp)) != 0) + return (error); VATTR_NULL(vap); vap->va_type = VREG; vap->va_mode = cmode; @@ -222,7 +226,7 @@ again: error = EISDIR; goto bad; } - error = vn_writechk(vp); + error = vn_writechk(vp, ncp); if (error) { /* * Special stale handling, re-resolve the @@ -338,13 +342,10 @@ bad: /* * Check for write permissions on the specified vnode. - * Prototype text segments cannot be written. */ int -vn_writechk(vp) - struct vnode *vp; +vn_writechk(struct vnode *vp, struct namecache *ncp) { - /* * If there's shared text associated with * the vnode, try to free it up once. If @@ -352,9 +353,35 @@ vn_writechk(vp) */ if (vp->v_flag & VTEXT) return (ETXTBSY); + + /* + * If the vnode represents a regular file, check the mount + * point via the ncp. This may be a different mount point + * then the one embedded in the vnode (e.g. nullfs). + * + * We can still write to non-regular files (e.g. devices) + * via read-only mounts. + */ + if (ncp && vp->v_type == VREG) + return (ncp_writechk(ncp)); return (0); } +/* + * Check whether the underlying mount is read-only. The mount point + * referenced by the namecache may be different from the mount point + * used by the underlying vnode in the case of NULLFS, so a separate + * check is needed. + */ +static +int +ncp_writechk(struct namecache *ncp) +{ + if (ncp->nc_mount && (ncp->nc_mount->mnt_flag & MNT_RDONLY)) + return (EROFS); + return(0); +} + /* * Vnode close call */ diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 64cb7631b7..340e513e81 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -32,7 +32,7 @@ * * @(#)vnode.h 8.7 (Berkeley) 2/4/94 * $FreeBSD: src/sys/sys/vnode.h,v 1.111.2.19 2002/12/29 18:19:53 dillon Exp $ - * $DragonFly: src/sys/sys/vnode.h,v 1.68 2006/09/10 01:26:40 dillon Exp $ + * $DragonFly: src/sys/sys/vnode.h,v 1.69 2006/09/18 17:42:28 dillon Exp $ */ #ifndef _SYS_VNODE_H_ @@ -509,7 +509,7 @@ int vn_rdwr_inchunks (enum uio_rw rw, struct vnode *vp, caddr_t base, int vn_stat (struct vnode *vp, struct stat *sb, struct ucred *cred); cdev_t vn_todev (struct vnode *vp); void vfs_timestamp (struct timespec *); -int vn_writechk (struct vnode *vp); +int vn_writechk (struct vnode *vp, struct namecache *ncp); int vop_stdopen (struct vop_open_args *ap); int vop_stdclose (struct vop_close_args *ap); int vop_nopoll (struct vop_poll_args *ap); -- 2.41.0