X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/b5e5c7928c3c69241fc8e32f6475880c824578d6..1a7bccf6251d2e3a04b364630a80a7f1760cb09b:/usr/src/sys/kern/vfs_syscalls.c diff --git a/usr/src/sys/kern/vfs_syscalls.c b/usr/src/sys/kern/vfs_syscalls.c index 3c76b93c28..deb34b982c 100644 --- a/usr/src/sys/kern/vfs_syscalls.c +++ b/usr/src/sys/kern/vfs_syscalls.c @@ -9,7 +9,7 @@ * * %sccs.include.redist.c% * - * @(#)vfs_syscalls.c 8.16 (Berkeley) %G% + * @(#)vfs_syscalls.c 8.21 (Berkeley) %G% */ #include @@ -63,13 +63,9 @@ mount(p, uap, retval) register struct vnode *vp; register struct mount *mp; int error, flag; + struct vattr va; struct nameidata nd; - /* - * Must be super user - */ - if (error = suser(p->p_ucred, &p->p_acflag)) - return (error); /* * Get vnode to be covered */ @@ -95,9 +91,50 @@ mount(p, uap, retval) } mp->mnt_flag |= uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); + /* + * Only root, or the user that did the original mount is + * permitted to update it. + */ + if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid && + (error = suser(p->p_ucred, &p->p_acflag))) { + vput(vp); + return (error); + } + /* + * Do not allow NFS export by non-root users. Silently + * enforce MNT_NOSUID and MNT_NODEV for non-root users. + */ + if (p->p_ucred->cr_uid != 0) { + if (uap->flags & MNT_EXPORTED) { + vput(vp); + return (EPERM); + } + uap->flags |= MNT_NOSUID | MNT_NODEV; + } VOP_UNLOCK(vp); goto update; } + /* + * If the user is not root, ensure that they own the directory + * onto which we are attempting to mount. + */ + if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || + (va.va_uid != p->p_ucred->cr_uid && + (error = suser(p->p_ucred, &p->p_acflag)))) { + vput(vp); + return (error); + } + /* + * Do not allow NFS export by non-root users. Silently + * enforce MNT_NOSUID and MNT_NODEV for non-root users. + */ + if (p->p_ucred->cr_uid != 0) { + if (uap->flags & MNT_EXPORTED) { + vput(vp); + return (EPERM); + } + uap->flags |= MNT_NOSUID | MNT_NODEV; + } if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) return (error); if (vp->v_type != VDIR) { @@ -129,6 +166,7 @@ mount(p, uap, retval) } vp->v_mountedhere = mp; mp->mnt_vnodecovered = vp; + mp->mnt_stat.f_owner = p->p_ucred->cr_uid; update: /* * Set the mount level flags. @@ -198,12 +236,13 @@ unmount(p, uap, retval) if (error = namei(&nd)) return (error); vp = nd.ni_vp; + mp = vp->v_mount; /* - * Unless this is a user mount, then must - * have suser privilege. + * Only root, or the user that did the original mount is + * permitted to unmount this filesystem. */ - if (((vp->v_mount->mnt_flag & MNT_USER) == 0) && + if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) && (error = suser(p->p_ucred, &p->p_acflag))) { vput(vp); return (error); @@ -216,7 +255,6 @@ unmount(p, uap, retval) vput(vp); return (EINVAL); } - mp = vp->v_mount; vput(vp); return (dounmount(mp, uap->flags, p)); } @@ -282,6 +320,10 @@ sync(p, uap, retval) int asyncflag; for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) { + /* + * Get the next pointer in case we hang on vfs_busy + * while we are being unmounted. + */ nmp = mp->mnt_list.tqe_next; /* * The lock check below is to avoid races with mount @@ -294,6 +336,11 @@ sync(p, uap, retval) VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); if (asyncflag) mp->mnt_flag |= MNT_ASYNC; + /* + * Get the next pointer again, as the next filesystem + * might have been unmounted while we were sync'ing. + */ + nmp = mp->mnt_list.tqe_next; vfs_unbusy(mp); } } @@ -661,6 +708,7 @@ mknod(p, uap, retval) register struct vnode *vp; struct vattr vattr; int error; + int whiteout; struct nameidata nd; CHECKPOINTREF; @@ -676,6 +724,7 @@ mknod(p, uap, retval) VATTR_NULL(&vattr); vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; vattr.va_rdev = uap->dev; + whiteout = 0; switch (uap->mode & S_IFMT) { case S_IFMT: /* used by badsect to flag bad sectors */ @@ -687,13 +736,19 @@ mknod(p, uap, retval) case S_IFBLK: vattr.va_type = VBLK; break; + case S_IFWHT: + whiteout = 1; + break; default: error = EINVAL; break; } } - if (!error) { - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + if (whiteout) { + error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); + vput(nd.ni_dvp); + } else if (!error) { + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); } else { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); @@ -743,7 +798,7 @@ mkfifo(p, uap, retval) VATTR_NULL(&vattr); vattr.va_type = VFIFO; vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); #endif /* FIFO */ } @@ -779,10 +834,9 @@ link(p, uap, retval) if (nd.ni_vp != NULL) error = EEXIST; if (!error) { - LEASE_CHECK(nd.ni_dvp, - p, p->p_ucred, LEASE_WRITE); - LEASE_CHECK(vp, - p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, + LEASE_WRITE); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); } else { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); @@ -837,7 +891,7 @@ symlink(p, uap, retval) } VATTR_NULL(&vattr); vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); out: FREE(path, M_NAMEI); @@ -845,6 +899,45 @@ out: return (error); } +/* + * Delete a whiteout from the filesystem. + */ +struct unwhiteout_args { + char *path; +}; +/* ARGSUSED */ +unwhiteout(p, uap, retval) + struct proc *p; + struct unwhiteout_args *uap; + int *retval; +{ + int error; + struct nameidata nd; + + NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, uap->path, p); + error = namei(&nd); + if (error) + return (error); + + if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + if (nd.ni_dvp == nd.ni_vp) + vrele(nd.ni_dvp); + else + vput(nd.ni_dvp); + if (nd.ni_vp) + vrele(nd.ni_vp); + return (EEXIST); + } + + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE); + if (error != 0) + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + vput(nd.ni_dvp); + return (error); +} + /* * Delete a name from the filesystem. */ @@ -866,7 +959,7 @@ unlink(p, uap, retval) if (error = namei(&nd)) return (error); vp = nd.ni_vp; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); if (vp->v_type != VDIR || @@ -881,7 +974,7 @@ unlink(p, uap, retval) } if (!error) { - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); } else { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); @@ -889,7 +982,8 @@ unlink(p, uap, retval) vrele(nd.ni_dvp); else vput(nd.ni_dvp); - vput(vp); + if (vp != NULLVP) + vput(vp); } CHECKREFS("unlink"); return (error); @@ -1279,7 +1373,7 @@ chflags(p, uap, retval) if (error = namei(&nd)) return (error); vp = nd.ni_vp; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); if (vp->v_mount->mnt_flag & MNT_RDONLY) error = EROFS; @@ -1313,7 +1407,7 @@ fchflags(p, uap, retval) if (error = getvnode(p->p_fd, uap->fd, &fp)) return (error); vp = (struct vnode *)fp->f_data; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); if (vp->v_mount->mnt_flag & MNT_RDONLY) error = EROFS; @@ -1348,7 +1442,7 @@ chmod(p, uap, retval) if (error = namei(&nd)) return (error); vp = nd.ni_vp; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); if (vp->v_mount->mnt_flag & MNT_RDONLY) error = EROFS; @@ -1382,7 +1476,7 @@ fchmod(p, uap, retval) if (error = getvnode(p->p_fd, uap->fd, &fp)) return (error); vp = (struct vnode *)fp->f_data; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); if (vp->v_mount->mnt_flag & MNT_RDONLY) error = EROFS; @@ -1418,7 +1512,7 @@ chown(p, uap, retval) if (error = namei(&nd)) return (error); vp = nd.ni_vp; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); if (vp->v_mount->mnt_flag & MNT_RDONLY) error = EROFS; @@ -1454,7 +1548,7 @@ fchown(p, uap, retval) if (error = getvnode(p->p_fd, uap->fd, &fp)) return (error); vp = (struct vnode *)fp->f_data; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); if (vp->v_mount->mnt_flag & MNT_RDONLY) error = EROFS; @@ -1498,7 +1592,7 @@ utimes(p, uap, retval) if (error = namei(&nd)) return (error); vp = nd.ni_vp; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); if (vp->v_mount->mnt_flag & MNT_RDONLY) error = EROFS; @@ -1536,7 +1630,7 @@ truncate(p, uap, retval) if (error = namei(&nd)) return (error); vp = nd.ni_vp; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); if (vp->v_type == VDIR) error = EISDIR; @@ -1574,7 +1668,7 @@ ftruncate(p, uap, retval) if ((fp->f_flag & FWRITE) == 0) return (EINVAL); vp = (struct vnode *)fp->f_data; - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); VOP_LOCK(vp); if (vp->v_type == VDIR) error = EISDIR; @@ -1711,11 +1805,11 @@ rename(p, uap, retval) error = -1; out: if (!error) { - LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); if (fromnd.ni_dvp != tdvp) - LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); if (tvp) - LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE); error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); } else { @@ -1780,7 +1874,7 @@ mkdir(p, uap, retval) VATTR_NULL(&vattr); vattr.va_type = VDIR; vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask; - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); if (!error) vput(nd.ni_vp); @@ -1827,8 +1921,8 @@ rmdir(p, uap, retval) error = EBUSY; out: if (!error) { - LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); - LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); } else { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); @@ -1949,6 +2043,20 @@ unionread: struct vnode *lvp; lvp = union_lowervp(vp); + if (lvp != NULLVP) { + struct vattr va; + + /* + * If the directory is opaque, + * then don't show lower entries + */ + error = VOP_GETATTR(vp, &va, fp->f_cred, p); + if (va.va_flags & OPAQUE) { + vrele(lvp); + lvp = NULL; + } + } + if (lvp != NULLVP) { VOP_LOCK(lvp); error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); @@ -2042,6 +2150,20 @@ unionread: struct vnode *lvp; lvp = union_lowervp(vp); + if (lvp != NULLVP) { + struct vattr va; + + /* + * If the directory is opaque, + * then don't show lower entries + */ + error = VOP_GETATTR(vp, &va, fp->f_cred, p); + if (va.va_flags & OPAQUE) { + vrele(lvp); + lvp = NULL; + } + } + if (lvp != NULLVP) { VOP_LOCK(lvp); error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);