Subject: kern/1043: unlink(2) should not let superuser remove directories
To: None <gnats-admin@sun-lamp.cs.berkeley.edu>
From: John Kohl <jtk@kolvir.blrc.ma.us>
List: netbsd-bugs
Date: 05/11/1995 16:20:07
>Number: 1043
>Category: kern
>Synopsis: root can unlink directories, causing FS corruption
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people (Kernel Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Thu May 11 16:20:04 1995
>Originator: John Kohl
>Organization:
NetBSD Kernel Hackers `R` Us
>Release: 1.0A (-current)
>Environment:
System: NetBSD kolvir 1.0A NetBSD 1.0A (KOLVIR) #318: Mon May 8 23:09:33 EDT 1995 jtk@kolvir:/u1/NetBSD-current/src/sys/arch/i386/compile/KOLVIR i386
>Description:
The superuser can remove directories with the unlink(2) system call,
even if the directory is not empty. This can lead to unreferenced files
on a filesystem which will never be detected if fsck(8) doesn't run on
the filesystems (it won't, at least not until its timeout expires, if
things are unmounted cleanly at each reboot).
>How-To-Repeat:
main(int argc, char *argv[])
{
unlink(argv[1]);
}
>Fix:
===================================================================
RCS file: RCS/vfs_syscalls.c,v
retrieving revision 1.1.1.5
diff -u18 -r1.1.1.5 vfs_syscalls.c
--- 1.1.1.5 1995/05/11 22:41:59
+++ sys/kern/vfs_syscalls.c 1995/05/11 22:42:13
@@ -1044,45 +1044,48 @@
unlink(p, uap, retval)
struct proc *p;
struct unlink_args /* {
syscallarg(char *) path;
} */ *uap;
register_t *retval;
{
register struct vnode *vp;
int error;
struct nameidata nd;
NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
if (error = namei(&nd))
return (error);
vp = nd.ni_vp;
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
VOP_LOCK(vp);
- if (vp->v_type != VDIR ||
- (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
+ if (vp->v_type == VDIR) {
+ error = EISDIR;
+ } else {
/*
* The root of a mounted filesystem cannot be deleted.
*/
if (vp->v_flag & VROOT)
error = EBUSY;
- else
+ else {
(void)vnode_pager_uncache(vp);
+ error = 0;
+ }
}
if (!error) {
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);
if (nd.ni_dvp == vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
if (vp != NULLVP)
vput(vp);
}
return (error);
}
/*
>Audit-Trail:
>Unformatted: