Hi,

Matthew Dillon wrote:
I like the concept, but the (FreeBSD) implementation does not look
    quite correct.

The FreeBSD implementation is correct, I made a typo :)

    I'm thinking we want something like this.  Notice the change I made
    to the hardlink_check_gid code?

        if (suser_cred(cred, PRISON_ROOT) == 0)
                return (0);
        
        error = VOP_GETATTR(vp, &va, td);
        if (error != 0)
                return (error);

        if (hardlink_check_uid) {
                if (cred->cr_uid != va.va_uid)
                        return (EPERM);
        }
        
        if (hardlink_check_gid) {
                if (cred->cr_uid != va.va_uid && !groupmember(va.va_gid, cred))
                        return (EPERM);
        }

I changed the code, tested it and generated a new diff (attached).

Greets

        Matthias
diff -urN sys.orig/kern/vfs_syscalls.c sys/kern/vfs_syscalls.c
--- sys.orig/kern/vfs_syscalls.c        2005-09-17 09:43:00.000000000 +0200
+++ sys/kern/vfs_syscalls.c     2005-09-28 16:51:23.000000000 +0200
@@ -1569,6 +1569,43 @@
        return (error);
 }
 
+static int hardlink_check_uid = 0;
+SYSCTL_INT(_kern, OID_AUTO, hardlink_check_uid, CTLFLAG_RW,
+    &hardlink_check_uid, 0, 
+    "Unprivileged processes cannot create hard links to files owned by other "
+    "users");
+static int hardlink_check_gid = 0;
+SYSCTL_INT(_kern, OID_AUTO, hardlink_check_gid, CTLFLAG_RW,
+    &hardlink_check_gid, 0,
+    "Unprivileged processes cannot create hard links to files owned by other "
+    "groups");
+
+static int
+can_hardlink(struct vnode *vp, struct thread *td, struct ucred *cred)
+{
+       struct vattr va;
+       int error;
+
+       if (suser_cred(cred, PRISON_ROOT) == 0)
+               return (0);
+       
+       error = VOP_GETATTR(vp, &va, td);
+       if (error != 0)
+               return (error);
+       
+       if (hardlink_check_uid) {
+               if (cred->cr_uid != va.va_uid)
+                       return (EPERM);
+       }
+       
+       if (hardlink_check_gid) {
+               if (cred->cr_uid != va.va_uid && !groupmember(va.va_gid, cred))
+                       return (EPERM);
+       }
+
+       return (0);
+}
+
 int
 kern_link(struct nlookupdata *nd, struct nlookupdata *linknd)
 {
@@ -1613,7 +1650,9 @@
        /*
         * Finally run the new API VOP.
         */
-       error = VOP_NLINK(linknd->nl_ncp, vp, linknd->nl_cred);
+       error = can_hardlink(vp, td, td->td_proc->p_ucred);
+       if (error == 0)
+               error = VOP_NLINK(linknd->nl_ncp, vp, linknd->nl_cred);
        vput(vp);
        return (error);
 }

Reply via email to