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: