Allow fchdir() from non-O_PATH fds If you chdir to an open FD, later when you did something like create a file from DOT, we'd panic. The FD in current->dot was opened and not O_PATH, which you can't walk from (see devclone()). The regular sys_chdir does a namec(Atodir), which does not call the device's open, so that chan is a kernel-internal, non-open chan (to use the parlance of devclone()). The current fix works for most cases. If you do something like dfd = open(some_dir, O_READ); unlink(some_dir); fchdir(dfd);, the lookup will fail. Using O_PATH instead of O_READ should work. Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/kern/src/ns/sysfile.c b/kern/src/ns/sysfile.c index c1a6780..dc6cf1f 100644 --- a/kern/src/ns/sysfile.c +++ b/kern/src/ns/sysfile.c
@@ -177,7 +177,27 @@ } c = fdtochan(¤t->open_files, fd, -1, 0, 1); poperror(); - set_dot(c); + + /* This is a little hokey. Ideally, we'd only allow O_PATH fds to be + * fchdir'd. Linux/POSIX lets you do arbitrary FDs. Luckily, we stored the + * name when we walked (__namec_from), so we should be able to recreate the + * chan. Using namec() with channame() is a more heavy-weight cclone(), but + * also might have issues if the chan has since been removed or the + * namespace is otherwise different from when the original fd/chan was first + * created. */ + if (c->flag & O_PATH) { + set_dot(c); + return 0; + } + if (waserror()) { + cclose(c); + poperror(); + return -1; + } + syschdir(channame(c)); + cclose(c); + poperror(); + return 0; }