Have the spawn interface for the process manager require cap_procmng.
authorRazvan Damachi <razvan.damachi@gmail.com>
Mon, 26 Jun 2017 12:07:22 +0000 (14:07 +0200)
committerSimon Gerber <simon.gerber@inf.ethz.ch>
Thu, 31 Aug 2017 14:35:08 +0000 (16:35 +0200)
The process manager now sends cap_procmng with spawn requests. Spawnd then
identifies the capability and only proceeds with obliging the request if the
latter is indeed of ObjType_ProcessManager.

The idea behind this change is that, even if spawnd does not register with the
nameservice anymore (hence its iref is not publicly retrievable), a malicious
domain could still attempt to bypass process management spawn validation by
brute-force sending spawn requests to a range of irefs. If one of those irefs
happened to belong to a spawnd, then the latter would assume the spawn request
to be valid. Having the spawn API require cap_procmng ensures that only
requests issued by the process manager and entities it trusts will be obliged.

Signed-off-by: Razvan Damachi <razvan.damachi@gmail.com>

errors/errno.fugu
if/spawn.if
usr/proc_mgmt/service.c
usr/spawnd/service.c

index 89ba6be..fb9c118 100755 (executable)
@@ -664,6 +664,9 @@ errors spawn SPAWN_ERR_ {
     failure DOMAIN_NOTFOUND    "Domain not found",
     failure DOMAIN_RUNNING    "Domain is running",
     
+    failure IDENTIFY_PROC_MNGR_CAP "Failed to identify process manager cap",
+    failure NOT_PROC_MNGR          "Request did not come from the process manager",
+
     failure CREATE_DOMAIN_TABLE  "Failed to create domain hash table",
     failure DOMAIN_CAP_HASH      "Failed to compute hash code for domain cap",
     failure DOMAIN_TABLE_FIND    "Failed to find requested domain in domain table",
index cf1ea52..1d0e0aa 100644 (file)
@@ -21,20 +21,23 @@ interface spawn "Interface to spawn domains" {
                                out domainid domain_id);
 
     // Messages for the async interface with the process manager.
-    message spawn_request(cap domain_cap,
+    message spawn_request(cap procmng_cap,
+                          cap domain_cap,
                           String path[2048],
                           char argvbuf[argvbytes, 2048],
                           char envbuf[envbytes, 2048],
                           uint8 flags);
-    message spawn_with_caps_request(cap domain_cap,
+    message spawn_with_caps_request(cap procmng_cap,
+                                    cap domain_cap,
                                     String path[2048],
                                     char argvbuf[argvbytes, 2048],
                                     char envbuf[envbytes, 2048],
                                     cap inheritcn_cap,
                                     cap argcn_cap,
                                     uint8 flags);
-    message span_request(cap domain_cap, cap vroot, cap dispframe);
-    message kill_request(cap domain_cap);
+    message span_request(cap procmng_cap, cap domain_cap, cap vroot,
+                         cap dispframe);
+    message kill_request(cap procmng_cap, cap domain_cap);
     message spawn_reply(cap domain_cap, errval err);
 
     rpc spawn_proc_mgmt_domain(in cap domain_cap,
index 6117447..563658e 100644 (file)
@@ -229,7 +229,8 @@ static void spawn_reply_handler(struct spawn_binding *b,
             struct spawn_binding *spb = state->b;
             assert(spb != NULL);
 
-            err = spb->tx_vtbl.kill_request(spb, NOP_CONT, domain_cap);
+            err = spb->tx_vtbl.kill_request(spb, NOP_CONT, cap_procmng, 
+                                            domain_cap);
             if (err_is_fail(err)) {
                 // XXX: How severe is this? Maybe we want something more
                 // assertive than logging an error message.
@@ -286,12 +287,13 @@ static errval_t spawn_handler_common(struct proc_mgmt_binding *b,
 
     cl->rx_vtbl.spawn_reply = spawn_reply_handler;
     if (capref_is_null(inheritcn_cap) && capref_is_null(argcn_cap)) {
-        err = cl->tx_vtbl.spawn_request(cl, NOP_CONT, domain_cap, path, argvbuf,
-                                        argvbytes, envbuf, envbytes, flags);
+        err = cl->tx_vtbl.spawn_request(cl, NOP_CONT, cap_procmng, domain_cap,
+                                        path, argvbuf, argvbytes, envbuf,
+                                        envbytes, flags);
     } else {
-        err = cl->tx_vtbl.spawn_with_caps_request(cl, NOP_CONT, domain_cap,
-                                                  path, argvbuf, argvbytes,
-                                                  envbuf, envbytes,
+        err = cl->tx_vtbl.spawn_with_caps_request(cl, NOP_CONT, cap_procmng,
+                                                  domain_cap, path, argvbuf,
+                                                  argvbytes, envbuf, envbytes,
                                                   inheritcn_cap, argcn_cap,
                                                   flags);
     }
@@ -375,7 +377,8 @@ static void span_handler(struct proc_mgmt_binding *b, struct capref domain_cap,
     }
 
     cl->rx_vtbl.spawn_reply = spawn_reply_handler;
-    err = cl->tx_vtbl.span_request(cl, NOP_CONT, domain_cap, vroot, dispframe);
+    err = cl->tx_vtbl.span_request(cl, NOP_CONT, cap_procmng, domain_cap, vroot,
+                                   dispframe);
     if (err_is_ok(err)) {
         // Will respond to client when we get the reply from spawnd.
         return;
@@ -418,7 +421,8 @@ static errval_t kill_handler_common(struct proc_mgmt_binding *b,
 
         struct spawn_binding *spb = entry->spawnds[i]->b;
         spb->rx_vtbl.spawn_reply = spawn_reply_handler;
-        errval_t req_err = spb->tx_vtbl.kill_request(spb, NOP_CONT, domain_cap);
+        errval_t req_err = spb->tx_vtbl.kill_request(spb, NOP_CONT, cap_procmng,
+                                                     domain_cap);
         if (err_is_fail(req_err)) {
             DEBUG_ERR(req_err, "failed to send kill_request to spawnd %u\n", i);
         }
index 742ee91..36232fb 100644 (file)
@@ -16,6 +16,7 @@
 #include <string.h>
 #include <barrelfish/barrelfish.h>
 #include <spawndomain/spawndomain.h>
+#include <barrelfish/monitor_client.h>
 #include <barrelfish/nameservice_client.h>
 #include <barrelfish/cpu_arch.h>
 #include <vfs/vfs.h>
@@ -355,6 +356,7 @@ static errval_t spawn_handler(struct spawn_binding *b, const char *path,
 }
 
 static void spawn_with_caps_request_handler(struct spawn_binding *b,
+                                            struct capref procmng_cap,
                                             struct capref domain_cap,
                                             const char *path,
                                             const char *argvbuf,
@@ -365,39 +367,83 @@ static void spawn_with_caps_request_handler(struct spawn_binding *b,
                                             struct capref argcn_cap,
                                             uint8_t flags)
 {
+    errval_t err, reply_err;
+    struct capability ret;
+    err = monitor_cap_identify_remote(procmng_cap, &ret);
+    if (err_is_fail(err)) {
+        err = err_push(err, SPAWN_ERR_IDENTIFY_PROC_MNGR_CAP);
+        goto reply;
+    }
+
+    if (ret.type != ObjType_ProcessManager) {
+        err = SPAWN_ERR_NOT_PROC_MNGR;
+        goto reply;
+    }
+
     spawn_domainid_t dummy_domain_id;
-    errval_t err = spawn_with_caps_common(domain_cap, path, argvbuf, argvbytes,
-                                          envbuf, envbytes, inheritcn_cap,
-                                          argcn_cap, flags, &dummy_domain_id);
-    errval_t reply_err = b->tx_vtbl.spawn_reply(b, NOP_CONT, domain_cap, err);
+    err = spawn_with_caps_common(domain_cap, path, argvbuf, argvbytes, envbuf,
+                                 envbytes, inheritcn_cap, argcn_cap, flags,
+                                 &dummy_domain_id);
+
+reply:
+    reply_err = b->tx_vtbl.spawn_reply(b, NOP_CONT, domain_cap, err);
     if (err_is_fail(reply_err)) {
         DEBUG_ERR(err, "failed to send spawn_reply");
     }
 }
 
 static void spawn_request_handler(struct spawn_binding *b,
+                                  struct capref procmng_cap,
                                   struct capref domain_cap, const char *path,
                                   const char *argvbuf, size_t argvbytes,
                                   const char *envbuf, size_t envbytes,
                                   uint8_t flags)
 {
+
+    errval_t err, reply_err;
+    struct capability ret;
+    err = monitor_cap_identify_remote(procmng_cap, &ret);
+    if (err_is_fail(err)) {
+        err = err_push(err, SPAWN_ERR_IDENTIFY_PROC_MNGR_CAP);
+        goto reply;
+    }
+
+    if (ret.type != ObjType_ProcessManager) {
+        err = SPAWN_ERR_NOT_PROC_MNGR;
+        goto reply;
+    }
+    
     spawn_domainid_t dummy_domain_id;
-    errval_t err = spawn_with_caps_common(domain_cap, path, argvbuf, argvbytes,
-                                          envbuf, envbytes, NULL_CAP, NULL_CAP,
-                                          flags, &dummy_domain_id);
-    errval_t reply_err = b->tx_vtbl.spawn_reply(b, NOP_CONT, domain_cap, err);
+    err = spawn_with_caps_common(domain_cap, path, argvbuf, argvbytes, envbuf,
+                                 envbytes, NULL_CAP, NULL_CAP, flags,
+                                 &dummy_domain_id);
+
+reply:
+    reply_err = b->tx_vtbl.spawn_reply(b, NOP_CONT, domain_cap, err);
     if (err_is_fail(reply_err)) {
         DEBUG_ERR(err, "failed to send spawn_reply");
     }
 }
 
 static void span_request_handler(struct spawn_binding *b,
+                                 struct capref procmng_cap,
                                  struct capref domain_cap, struct capref vroot,
                                  struct capref dispframe)
 {
-    struct spawninfo si;
     errval_t err, mon_err, reply_err;
+    struct capability ret;
+    err = monitor_cap_identify_remote(procmng_cap, &ret);
+    if (err_is_fail(err)) {
+        err = err_push(err, SPAWN_ERR_IDENTIFY_PROC_MNGR_CAP);
+        goto reply;
+    }
 
+    if (ret.type != ObjType_ProcessManager) {
+        err = SPAWN_ERR_NOT_PROC_MNGR;
+        goto reply;
+    }
+
+    struct spawninfo si;
     memset(&si, 0, sizeof(si));
 
     debug_printf("Spanning domain to core %d\n", disp_get_core_id());
@@ -539,9 +585,22 @@ static void cleanup_cap(struct capref cap)
 }
 
 static void kill_request_handler(struct spawn_binding *b,
+                                 struct capref procmng_cap,
                                  struct capref domain_cap)
 {
     errval_t err, reply_err;
+    struct capability ret;
+    err = monitor_cap_identify_remote(procmng_cap, &ret);
+    if (err_is_fail(err)) {
+        err = err_push(err, SPAWN_ERR_IDENTIFY_PROC_MNGR_CAP);
+        goto reply;
+    }
+
+    if (ret.type != ObjType_ProcessManager) {
+        err = SPAWN_ERR_NOT_PROC_MNGR;
+        goto reply;
+    }
+
     struct ps_entry *pe;
     err = ps_release_domain(domain_cap, &pe);
     if (err_is_fail(err)) {