Handle Unix domain socket connections from outside our namespace
authorEelco Dolstra <eelco.dolstra@logicblox.com>
Wed, 16 Apr 2014 16:39:07 +0000 (18:39 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 17 Apr 2014 02:24:28 +0000 (22:24 -0400)
NixOS uses Unix domain sockets for certain host <-> container
interaction; i.e. the host connects to a socket visible in the
container's directory tree, where the container uses a .socket unit to
spawn the handler program on demand. This worked in systemd 203, but
in 212 fails with "foo.socket failed to queue service startup job
(Maybe the service file is missing or not a template unit?): No data
available".

The reason is that getpeercred() now returns ENODATA if it can't get
the PID of the client, which happens in this case because the client
is not in the same PID namespace. Since getpeercred() is only used to
generate the instance name, this patch simply handles ENODATA by
creating an instance name "<nr>-unknown".

[zj: reorder clauses and remove (unsigned long) casts.]

src/core/socket.c

index 7c18a2b..d57e770 100644 (file)
@@ -663,17 +663,21 @@ static int instance_from_socket(int fd, unsigned nr, char **instance) {
                 int k;
 
                 k = getpeercred(fd, &ucred);
-                if (k < 0)
+                if (k >= 0) {
+                        if (asprintf(&r,
+                                     "%u-"PID_FMT"-"UID_FMT,
+                                     nr, ucred.pid, ucred.uid) < 0)
+                                return -ENOMEM;
+                } else if (k == -ENODATA) {
+                        /* This handles the case where somebody is
+                         * connecting from another pid/uid namespace
+                         * (e.g. from outside of our container). */
+                        if (asprintf(&r,
+                                     "%u-unknown",
+                                     nr) < 0)
+                                return -ENOMEM;
+                } else
                         return k;
-
-                if (asprintf(&r,
-                             "%u-%lu-%lu",
-                             nr,
-                             (unsigned long) ucred.pid,
-                             (unsigned long) ucred.uid) < 0)
-                        return -ENOMEM;
-
-                break;
         }
 
         default: