[Libvir] PATCH: Allow control over UNIX socket perms & group in libvirtd

Daniel P. Berrange berrange at redhat.com
Tue Sep 18 04:38:09 UTC 2007


When I submitted  the patches for PolicyKit[1] support a few weeks back Rich
suggested that we should have the ability to set UNIX socket permissions
and group ownership regardless. So this patch adds that ability. The default
setting is still,  group=root, and mode=0700 for R/W socket and mode=0777
for the R/O socket.

It is possible to override this via the config file

eg, Don't allow R/O monitoring

   unix_sock_ro_perms="0700"

eg, Allow any user in 'admin' group to manage VMs

   unix_sock_group="admin"
   unix_sock_rw_perms="0770"

eg, Allow anyone todo anything

   unix_sock_rw_perms="0777"


NB, the fchgrp, and fchown syscalls don't have any effect on sockets, so
to set the group ownership & desired mode, I have to play games with the
setgid() and umask() calls prior to bind(), and then restore them to their
original values.


NB, the virConf apis don't seem to recognise Octal numbers when parsing
the config file, so I've used strings for the permissions. Not a big deal
really unless someone desperately wants to fix the config file parser...

Dan.

[1] A new set of patches will be forthcoming soon...
-- 
|=- Red Hat, Engineering, Emerging Technologies, Boston.  +1 978 392 2496 -=|
|=-           Perl modules: http://search.cpan.org/~danberr/              -=|
|=-               Projects: http://freshmeat.net/~danielpb/               -=|
|=-  GnuPG: 7D3B9505   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505  -=| 
-------------- next part --------------
diff -r 4ba90e72c54e docs/libvir.html
--- a/docs/libvir.html	Mon Sep 17 15:13:41 2007 -0400
+++ b/docs/libvir.html	Mon Sep 17 16:53:42 2007 -0400
@@ -2192,6 +2192,53 @@ Blank lines and comments beginning with 
 </tr>
 
 <tr>
+<td> unix_sock_group <i>"groupname"</i> </td>
+<td> "root" </td>
+<td>
+  The UNIX group to own the UNIX domain socket. If the socket permissions allow
+  group access, then applications running under matching group can access the
+  socket. Only valid if running as root
+</td>
+</tr>
+
+<tr>
+<td> unix_sock_ro_perms <i>"octal-perms"</i> </td>
+<td> "0777" </td>
+<td>
+  The permissions for the UNIX domain socket for read-only client connections.
+  The default allows any user to monitor domains.
+</td>
+</tr>
+
+<tr>
+<td> unix_sock_rw_perms <i>"octal-perms"</i> </td>
+<td> "0700" </td>
+<td>
+  The permissions for the UNIX domain socket for read-write client connections.
+  The default allows only root to manage domains.
+</td>
+</tr>
+
+<tr>
+<td> mdns_adv <i>[0|1]</i> </td>
+<td> 1 (advertise with mDNS) </td>
+<td>
+  If set to 1 then the virtualization service will be advertised over
+  mDNS to hosts on the local LAN segment.
+</td>
+</tr>
+
+<tr>
+<td> mdns_name <i>"name"</i> </td>
+<td> "Virtualization Host HOSTNAME" </td>
+<td>
+  The name to advertise for this host with Avahi mDNS. The default
+  includes the machine's short hostname. This must be unique to the
+  local LAN segment.
+</td>
+</tr>
+
+<tr>
 <td> tls_no_verify_certificate <i>[0|1]</i> </td>
 <td> 0 (certificates are verified) </td>
 <td>
diff -r 4ba90e72c54e qemud/qemud.c
--- a/qemud/qemud.c	Mon Sep 17 15:13:41 2007 -0400
+++ b/qemud/qemud.c	Mon Sep 17 16:51:15 2007 -0400
@@ -48,6 +48,7 @@
 #include <getopt.h>
 #include <assert.h>
 #include <fnmatch.h>
+#include <grp.h>
 
 #include <libvirt/virterror.h>
 
@@ -71,6 +72,10 @@ static int listen_tcp = 0;
 static int listen_tcp = 0;
 static const char *tls_port = LIBVIRTD_TLS_PORT;
 static const char *tcp_port = LIBVIRTD_TCP_PORT;
+
+static gid_t unix_sock_gid = 0; /* Only root by default */
+static int unix_sock_rw_perms = 0700; /* Allow user only */
+static int unix_sock_ro_perms = 0777; /* Allow world */
 
 #if HAVE_AVAHI
 static int mdns_adv = 1;
@@ -449,6 +454,7 @@ static int qemudListenUnix(struct qemud_
     struct qemud_socket *sock = calloc(1, sizeof(struct qemud_socket));
     struct sockaddr_un addr;
     mode_t oldmask;
+    gid_t oldgrp;
 
     if (!sock) {
         qemudLog(QEMUD_ERR, "Failed to allocate memory for struct qemud_socket");
@@ -475,16 +481,19 @@ static int qemudListenUnix(struct qemud_
         addr.sun_path[0] = '\0';
 
 
-    if (readonly)
-        oldmask = umask(~(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH));
-    else
-        oldmask = umask(~(S_IRUSR | S_IWUSR));
+    oldgrp = getgid();
+    oldmask = umask(readonly ? ~unix_sock_ro_perms : ~unix_sock_rw_perms);
+    if (getuid() == 0)
+        setgid(unix_sock_gid);
+
     if (bind(sock->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
         qemudLog(QEMUD_ERR, "Failed to bind socket to '%s': %s",
                  path, strerror(errno));
         goto cleanup;
     }
     umask(oldmask);
+    if (getuid() == 0)
+        setgid(oldgrp);
 
     if (listen(sock->fd, 30) < 0) {
         qemudLog(QEMUD_ERR, "Failed to listen for connections on '%s': %s",
@@ -1556,6 +1565,43 @@ remoteReadConfigFile (const char *filena
     p = virConfGetValue (conf, "tcp_port");
     CHECK_TYPE ("tcp_port", VIR_CONF_STRING);
     tcp_port = p ? strdup (p->str) : tcp_port;
+
+    p = virConfGetValue (conf, "unix_sock_group");
+    CHECK_TYPE ("unix_sock_group", VIR_CONF_STRING);
+    if (p && p->str) {
+        if (getuid() != 0) {
+            qemudLog (QEMUD_WARN, "Cannot set group when not running as root");
+        } else {
+            struct group *grp = getgrnam(p->str);
+            if (!grp) {
+                qemudLog (QEMUD_ERR, "Failed to lookup group '%s'", p->str);
+                return -1;
+            }
+            unix_sock_gid = grp->gr_gid;
+        }
+    }
+
+    p = virConfGetValue (conf, "unix_sock_ro_perms");
+    CHECK_TYPE ("unix_sock_ro_perms", VIR_CONF_STRING);
+    if (p && p->str) {
+        char *tmp = NULL;
+        unix_sock_ro_perms = strtol(p->str, &tmp, 8);
+        if (*tmp) {
+            qemudLog (QEMUD_ERR, "Failed to parse mode '%s'", p->str);
+            return -1;
+        }
+    }
+
+    p = virConfGetValue (conf, "unix_sock_rw_perms");
+    CHECK_TYPE ("unix_sock_rw_perms", VIR_CONF_STRING);
+    if (p && p->str) {
+        char *tmp = NULL;
+        unix_sock_rw_perms = strtol(p->str, &tmp, 8);
+        if (*tmp) {
+            qemudLog (QEMUD_ERR, "Failed to parse mode '%s'", p->str);
+            return -1;
+        }
+    }
 
 #if HAVE_AVAHI
     p = virConfGetValue (conf, "mdns_adv");


More information about the libvir-list mailing list