9ns: Sort out when to not follow symlinks
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 27 Feb 2018 19:13:28 +0000 (14:13 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 6 Apr 2018 19:23:01 +0000 (15:23 -0400)
The classic example is unlink/remove: the operation targets the symlink
itself, not its target.

I figure any of the bind/mount family of calls also want to target the
symlink.  They are changing the namespace, and operate on names, regardless
of directories/files/whatever.

Note that if you try to remove a symlink with a trailing slash with our
busybox, it *won't* fail.  e.g.

$ rm some_link_to_dir/

That should fail, but busybox won't send the trailing slash.  If you
manually call unlink/remove, we'll catch it and you'll get an error.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/src/ns/chan.c
kern/src/ns/sysfile.c

index 3b9193b..c3e39a7 100644 (file)
@@ -1079,6 +1079,14 @@ static struct chan *__namec_from(struct chan *c, char *aname, int amode,
                 * sure if there are any legit reasons to have O_NOFOLLOW with create.*/
                omode &= ~O_NOFOLLOW;
        }
+       switch (amode) {
+       /* the difference for stat and lstat (Aaccess) are handled in sysfile.c */
+       case Abind:
+       case Amount:
+       case Aremove:
+               omode |= O_NOFOLLOW;
+               break;
+       }
        if (omode & O_NOFOLLOW)
                wh->no_follow = true;
 
index 182bb07..3922b34 100644 (file)
@@ -546,6 +546,9 @@ int sysopenat(int fromfd, char *path, int vfs_flags)
                        error(EINVAL, "Cannot openat from a non-O_PATH FD");
                c = namec_from(from, path, Aopen, vfs_flags, 0, NULL);
        }
+       /* Devices should catch this, but just in case, we'll catch it. */
+       if ((c->qid.type & QTSYMLINK) && (vfs_flags & O_NOFOLLOW))
+               error(ELOOP, "no-follow open of a symlink");
        fd = newfd(c, 0, vfs_flags, FALSE);
        if (fd < 0)
                error(-fd, ERROR_FIXME);