]> xenbits.xensource.com Git - libvirt.git/commitdiff
util: generate a persistent system token
authorDaniel P. Berrangé <berrange@redhat.com>
Thu, 29 Apr 2021 14:40:33 +0000 (15:40 +0100)
committerDaniel P. Berrangé <berrange@redhat.com>
Thu, 13 May 2021 10:07:16 +0000 (11:07 +0100)
When creating the system identity set the system token. The system
token is currently stored in a local path

   /var/run/libvirt/common/system.token

Obviously with only traditional UNIX DAC in effect, this is largely
security through obscurity, if the client is running at the same
privilege level as the daemon. It does, however, reliably distinguish
an unprivileged client from the system daemons.

With a MAC system like SELinux though, or possible use of containers,
access can be further restricted.

A possible future improvement for Linux would be to populate the
kernel keyring with a secret for libvirt daemons to share.

Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
src/libvirt_private.syms
src/util/viridentity.c
src/util/viridentitypriv.h [new file with mode: 0644]
tests/viridentitytest.c

index aaae1c80023b5dc78d9b32d4fe4de0d814ac57d0..9c3c473c1c8804e68df4cca33dc5ac55cc23f6b0 100644 (file)
@@ -2396,6 +2396,7 @@ virHostGetBootTime;
 
 
 # util/viridentity.h
+virIdentityEnsureSystemToken;
 virIdentityGetCurrent;
 virIdentityGetGroupName;
 virIdentityGetParameters;
index 7da4ea12f571eb75599d1f97ea068d1e2ebaef62..5174f5a2d39dc408484e9d40b294c230857f7343 100644 (file)
 #include <config.h>
 
 #include <unistd.h>
+#include <fcntl.h>
 #if WITH_SELINUX
 # include <selinux/selinux.h>
 #endif
 
+#define LIBVIRT_VIRIDENTITYPRIV_H_ALLOW
+
 #include "internal.h"
 #include "viralloc.h"
 #include "virerror.h"
-#include "viridentity.h"
+#include "viridentitypriv.h"
 #include "virlog.h"
 #include "virobject.h"
+#include "virrandom.h"
 #include "virthread.h"
 #include "virutil.h"
 #include "virstring.h"
 #include "virprocess.h"
 #include "virtypedparam.h"
+#include "virfile.h"
+#include "configmake.h"
 
 #define VIR_FROM_THIS VIR_FROM_IDENTITY
 
@@ -55,6 +61,7 @@ struct _virIdentity {
 G_DEFINE_TYPE(virIdentity, vir_identity, G_TYPE_OBJECT)
 
 static virThreadLocal virIdentityCurrent;
+static char *systemToken;
 
 static void virIdentityFinalize(GObject *obj);
 
@@ -73,6 +80,9 @@ static int virIdentityOnceInit(void)
         return -1;
     }
 
+    if (!(systemToken = virIdentityEnsureSystemToken()))
+        return -1;
+
     return 0;
 }
 
@@ -144,6 +154,101 @@ int virIdentitySetCurrent(virIdentity *ident)
 }
 
 
+#define TOKEN_BYTES 16
+#define TOKEN_STRLEN (TOKEN_BYTES * 2)
+
+static char *
+virIdentityConstructSystemTokenPath(void)
+{
+    g_autofree char *commondir = NULL;
+    if (geteuid() == 0) {
+        commondir = g_strdup(RUNSTATEDIR "/libvirt/common");
+    } else {
+        g_autofree char *rundir = virGetUserRuntimeDirectory();
+        commondir = g_strdup_printf("%s/common", rundir);
+    }
+
+    if (g_mkdir_with_parents(commondir, 0700) < 0) {
+        virReportSystemError(errno,
+                             _("Cannot create daemon common directory '%s'"),
+                             commondir);
+        return NULL;
+    }
+
+    return g_strdup_printf("%s/system.token", commondir);
+}
+
+
+char *
+virIdentityEnsureSystemToken(void)
+{
+    g_autofree char *tokenfile = virIdentityConstructSystemTokenPath();
+    g_autofree char *token = NULL;
+    VIR_AUTOCLOSE fd = -1;
+    struct stat st;
+
+    if (!tokenfile)
+        return NULL;
+
+    fd = open(tokenfile, O_RDWR|O_APPEND|O_CREAT, 0600);
+    if (fd < 0) {
+        virReportSystemError(errno,
+                             _("Unable to open system token %s"),
+                             tokenfile);
+        return NULL;
+    }
+
+    if (virSetCloseExec(fd) < 0) {
+        virReportSystemError(errno,
+                             _("Failed to set close-on-exec flag '%s'"),
+                             tokenfile);
+        return NULL;
+    }
+
+    if (virFileLock(fd, false, 0, 1, true) < 0) {
+        virReportSystemError(errno,
+                             _("Failed to lock system token '%s'"),
+                             tokenfile);
+        return NULL;
+    }
+
+    if (fstat(fd, &st) < 0) {
+        virReportSystemError(errno,
+                             _("Failed to check system token '%s'"),
+                             tokenfile);
+        return NULL;
+    }
+
+    /* Ok, we're the first one here, so we must populate it */
+    if (st.st_size == 0) {
+        if (!(token = virRandomToken(TOKEN_BYTES))) {
+            return NULL;
+        }
+        if (safewrite(fd, token, TOKEN_STRLEN) != TOKEN_STRLEN) {
+            virReportSystemError(errno,
+                                 _("Failed to write system token '%s'"),
+                                 tokenfile);
+            return NULL;
+        }
+    } else {
+        if (virFileReadLimFD(fd, TOKEN_STRLEN, &token) < 0) {
+            virReportSystemError(errno,
+                                 _("Failed to write system token '%s'"),
+                                 tokenfile);
+            return NULL;
+        }
+        if (strlen(token) != TOKEN_STRLEN) {
+            virReportSystemError(errno,
+                                 _("System token in %s was corrupt"),
+                                 tokenfile);
+            return NULL;
+        }
+    }
+
+    return g_steal_pointer(&token);
+}
+
+
 /**
  * virIdentityGetSystem:
  *
diff --git a/src/util/viridentitypriv.h b/src/util/viridentitypriv.h
new file mode 100644 (file)
index 0000000..e5ca843
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * viridentitypriv.h: helper APIs for managing user identities
+ *
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBVIRT_VIRIDENTITYPRIV_H_ALLOW
+# error "viridentitypriv.h may only be included by viridentity.c or test suites"
+#endif /* LIBVIRT_VIRIDENTITYPRIV_H_ALLOW */
+
+#pragma once
+
+#include "viridentity.h"
+
+char *
+virIdentityEnsureSystemToken(void) G_GNUC_NO_INLINE;
index afb9fdaec4b60153d64c5c300c4b5e99b0328243..99c7899ed763ccb8a66505060cc4a5ec7f535562 100644 (file)
@@ -25,7 +25,9 @@
 
 #include "testutils.h"
 
-#include "viridentity.h"
+#define LIBVIRT_VIRIDENTITYPRIV_H_ALLOW
+
+#include "viridentitypriv.h"
 #include "virerror.h"
 #include "viralloc.h"
 #include "virlog.h"
 
 VIR_LOG_INIT("tests.identitytest");
 
+char *
+virIdentityEnsureSystemToken(void)
+{
+    return g_strdup("3de80bcbf22d4833897f1638e01be9b2");
+}
+
+
 static int testIdentityAttrs(const void *data G_GNUC_UNUSED)
 {
     g_autoptr(virIdentity) ident = virIdentityNew();