devcons: implement hostownerwrite()
authorFergus Simpson <afergs@google.com>
Thu, 5 Jan 2017 20:37:42 +0000 (12:37 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 18 Jan 2017 18:27:54 +0000 (13:27 -0500)
The hostowner can now change its name by writing to '#cons/hostowner',
like shown here:
echo -n nanwan > /dev/hostowner

Notes:
-eve's initial value has been changed to "", since that is the first
 process's user; otherwise the first process ISN'T the hostowner
-eve can only be changed if its value is "" and the owner of the
 process changing it is user "" (ie. write once at boot)
-the user of the process doing the write is updated so it remains the
 hostowner
-all processes with username "" are updated to be owned by the new
 hostowner as well
-added __set_username to allow caller to implement their own
 locking

Change-Id: I0834ec570e5fd0d35813a0d7271f6928422e2ff2
Signed-off-by: Fergus Simpson <afergs@google.com>
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/drivers/dev/cons.c
kern/include/env.h
kern/src/env.c

index a2833dc..ec4069e 100644 (file)
@@ -63,7 +63,7 @@ int iseve(void)
        return strcmp(eve.name, current->user.name) == 0;
 }
 
-struct username eve = {.name = "eve", .name_lock = SPINLOCK_INITIALIZER};
+struct username eve = {.name = "", .name_lock = SPINLOCK_INITIALIZER};
 char hostdomain[256] = "akaros.org";
 
 static struct {
@@ -93,6 +93,7 @@ static int readtime(uint32_t, char *, int);
 static int readbintime(char *, int);
 static int writetime(char *, int);
 static int writebintime(char *, int);
+static int hostownerwrite(char *, size_t);
 static void killkid(void);
 
 enum {
@@ -1115,10 +1116,10 @@ static long conswrite(struct chan *c, void *va, long n, int64_t off)
                                error(EPERM, ERROR_FIXME);
                        return writebintime(a, n);
 
-#if 0
                case Qhostowner:
                        return hostownerwrite(a, n);
 
+#if 0
                case Qhostdomain:
                        return hostdomainwrite(a, n);
 
@@ -1532,6 +1533,64 @@ static int writebintime(char *buf, int n)
 }
 
 /*
+ * set the hostowner, but only if current is the hostowner and the new value
+ * isn't too long
+ */
+static int hostownerwrite(char *buf, size_t n)
+{
+       ERRSTACK(1);
+
+       if (!iseve())
+               error(EPERM, "only hostowner can change hostowner");
+
+       if (strlen(buf) < 1)
+               error(EINVAL, "hostowner cannot be set to \"\"");
+
+       spin_lock(&eve.name_lock);
+
+       if (waserror()) {
+               spin_unlock(&eve.name_lock);
+               nexterror();
+       }
+
+       // value at boot is ""
+       if (eve.name[0] != 0)
+               error(EPERM, "hostowner can only be set once");
+
+       __set_username(&eve, buf);
+
+       poperror();
+       spin_unlock(&eve.name_lock);
+
+       // Set this username first so it gets set regardless of an error below
+       proc_set_username(current, buf);
+
+       // Update all other hostowner processes
+       // This is costly, but should only happen very early on
+       struct process_set pset;
+
+       proc_get_set(&pset);
+       if (waserror()) {
+               proc_free_set(&pset);
+               nexterror();
+       }
+
+       for (size_t i = 0; i < pset.num_processes; i++) {
+               // Won't update current again
+               // Note: if a name is being written to the user field as it is read
+               //       here, it will appear as ""; but no other writes should occur
+               //       as early as this should be run
+               if (strcmp(pset.procs[i]->user.name, "") == 0)
+                       proc_set_username(pset.procs[i], buf);
+       }
+
+       poperror();
+       proc_free_set(&pset);
+
+       return n;
+}
+
+/*
  * find_first_kid finds your immediate descendant. Not because we're
  * trying to give it a check from the estate, mind you. We're here on
  * much more unpleasant business. To make it easy to call this
index bbecd07..3c0fa6e 100644 (file)
@@ -30,6 +30,7 @@ struct username {
        char name[128];
        spinlock_t name_lock;
 };
+void __set_username(struct username *u, char *name);
 void set_username(struct username *u, char *name);
 
 #define PROC_PROGNAME_SZ 20
index 3eb6767..c2382f3 100644 (file)
@@ -124,6 +124,27 @@ void env_user_mem_free(env_t* e, void* start, size_t len)
 
 void set_username(struct username *u, char *name)
 {
+       ERRSTACK(1);
+
+       spin_lock(&u->name_lock);
+
+       if (waserror()) {
+               spin_unlock(&u->name_lock);
+               nexterror();
+       }
+
+       __set_username(u, name);
+
+       poperror();
+       spin_unlock(&u->name_lock);
+}
+
+/*
+ * This function exists so that you can do your own locking - do not use it
+ * without locking the username's spinlock yourself.
+ */
+void __set_username(struct username *u, char *name)
+{
        if (!name)
                error(EINVAL, "New username is NULL");
 
@@ -131,14 +152,10 @@ void set_username(struct username *u, char *name)
                error(EINVAL, "New username for process more than %d chars long",
                      sizeof(u->name) - 1);
 
-       spin_lock(&u->name_lock);
-
        // 'backward' copy since reads aren't protected
        u->name[0] = 0;
        wmb(); // ensure user.name="" before writing the rest of the new name
        strlcpy(&u->name[1], &name[1], sizeof(u->name));
        wmb(); // ensure new name is written before writing first byte
        u->name[0] = name[0];
-
-       spin_unlock(&u->name_lock);
 }