Our chdir() takes a pid.  A controlling process (e.g. a parent) can change
the directory of a child.  This is meant to be done after proc_create and
before proc_run; the parent can set up the child before it starts running,
which avoids all sorts of nasty issues that happen in the fork() world.

Unfortunately, our chdir wasn't doing that since we got rid of the VFS.
This fixes a Go test that we had always skipped (TestStartProcess).

Signed-off-by: Barret Rhoden <b...@cs.berkeley.edu>
---
 kern/include/ns.h     |  4 ++--
 kern/src/ns/sysfile.c | 16 +++++++++-------
 kern/src/syscall.c    | 18 ++++++++++++++----
 3 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/kern/include/ns.h b/kern/include/ns.h
index f861d46638db..657098542db3 100644
--- a/kern/include/ns.h
+++ b/kern/include/ns.h
@@ -1068,8 +1068,8 @@ struct chan *fdtochan(struct fd_table *fdt, int fd, int 
mode, int chkmnt,
 long kchanio(void *vc, void *buf, int n, int mode);
 int openmode(uint32_t o);
 void fdclose(struct fd_table *fdt, int fd);
-int syschdir(char *path);
-int sysfchdir(int fd);
+int syschdir(struct proc *target, char *path);
+int sysfchdir(struct proc *target, int fd);
 int grpclose(struct fd_table *fdt, int fd);
 int sysclose(int fd);
 int syscreate(char *path, int mode, uint32_t perm);
diff --git a/kern/src/ns/sysfile.c b/kern/src/ns/sysfile.c
index 86c4fa984112..ad13b8be6aae 100644
--- a/kern/src/ns/sysfile.c
+++ b/kern/src/ns/sysfile.c
@@ -144,14 +144,15 @@ void fdclose(struct fd_table *fdt, int fd)
        close_fd(fdt, fd);
 }
 
-static void set_dot(struct chan *c)
+static void set_dot(struct proc *p, struct chan *c)
 {
-       c = atomic_swap_ptr((void**)&current->dot, c);
+       c = atomic_swap_ptr((void**)&p->dot, c);
        synchronize_rcu();
        cclose(c);
 }
 
-int syschdir(char *path)
+/* Note namec() happens in the namespace of the caller. */
+int syschdir(struct proc *target, char *path)
 {
        ERRSTACK(1);
        struct chan *c;
@@ -162,11 +163,12 @@ int syschdir(char *path)
        }
        c = namec(path, Atodir, 0, 0, NULL);
        poperror();
-       set_dot(c);
+       set_dot(target, c);
        return 0;
 }
 
-int sysfchdir(int fd)
+/* Note fdtochan() happens with the FDs of the caller. */
+int sysfchdir(struct proc *target, int fd)
 {
        ERRSTACK(1);
        struct chan *c;
@@ -186,7 +188,7 @@ int sysfchdir(int fd)
         * namespace is otherwise different from when the original fd/chan was 
first
         * created. */
        if (c->flag & O_PATH) {
-               set_dot(c);
+               set_dot(target, c);
                return 0;
        }
        if (waserror()) {
@@ -194,7 +196,7 @@ int sysfchdir(int fd)
                poperror();
                return -1;
        }
-       syschdir(channame(c));
+       syschdir(target, channame(c));
        cclose(c);
        poperror();
 
diff --git a/kern/src/syscall.c b/kern/src/syscall.c
index b3dabcb5492b..677408ad9cb5 100644
--- a/kern/src/syscall.c
+++ b/kern/src/syscall.c
@@ -557,11 +557,11 @@ static struct proc *get_controllable_proc(struct proc *p, 
pid_t pid)
 {
        struct proc *target = pid2proc(pid);
        if (!target) {
-               set_errno(ESRCH);
+               set_error(ESRCH, "no proc for pid %d", pid);
                return 0;
        }
        if (!proc_controls(p, target)) {
-               set_errno(EPERM);
+               set_error(EPERM, "can't control pid %d", pid);
                proc_decref(target);
                return 0;
        }
@@ -1981,12 +1981,17 @@ static intreg_t sys_chdir(struct proc *p, pid_t pid, 
const char *path,
 
        if (!target)
                return -1;
+       if ((target != p) && (target->state != PROC_CREATED)) {
+               proc_decref(target);
+               set_error(EINVAL, "pid %d has already started", pid);
+               return -1;
+       }
        t_path = copy_in_path(p, path, path_l);
        if (!t_path) {
                proc_decref(target);
                return -1;
        }
-       retval = syschdir(t_path);
+       retval = syschdir(target, t_path);
        free_path(p, t_path);
        proc_decref(target);
        return retval;
@@ -1999,7 +2004,12 @@ static intreg_t sys_fchdir(struct proc *p, pid_t pid, 
int fd)
 
        if (!target)
                return -1;
-       retval = sysfchdir(fd);
+       if ((target != p) && (target->state != PROC_CREATED)) {
+               proc_decref(target);
+               set_error(EINVAL, "pid %d has already started", pid);
+               return -1;
+       }
+       retval = sysfchdir(target, fd);
        proc_decref(target);
        return retval;
 }
-- 
2.19.0.605.g01d371f741-goog

-- 
You received this message because you are subscribed to the Google Groups 
"Akaros" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to akaros+unsubscr...@googlegroups.com.
To post to this group, send email to akaros@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/akaros/20181002210435.9453-1-brho%40cs.berkeley.edu.
For more options, visit https://groups.google.com/d/optout.

Reply via email to