public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: Laine Stump <laine@redhat.com>
To: libvir-list@redhat.com
Cc: passt-dev@passt.top
Subject: [libvirt PATCH 3/4] security: make it possible to set SELinux label of child process from its binary
Date: Wed,  8 Mar 2023 23:49:07 -0500	[thread overview]
Message-ID: <20230309044908.29316-4-laine@redhat.com> (raw)
In-Reply-To: <20230309044908.29316-1-laine@redhat.com>

Normally when a child process is started by libvirt, the SELinux label
of that process is set to virtd_t (plus an MCS range). In at least one
case (passt) we need for the SELinux label of a child process label to
match the label that the binary would have transitioned to
automatically if it had been run standalone (in the case of passt,
that label is passt_t).

This patch modifies virSecuritySELinuxSetChildProcessLabel() (and all
the functions above it in the call chain) so that the toplevel
function can set a new argument "useBinarySpecificLabel" to true. If
it is true, then virSecuritySELinuxSetChildProcessLabel() will call
the new function virSecuritySELinuxContextSetFromFile(), which uses
the selinux library function security_compute_create() to determine
what would be the label of the new process if it had been run
standalone (rather than being run by libvirt) - the MCS range from the
normally-used label is added to this newly derived label, and that is
what is used for the new process rather than whatever is in the
domain's security label (which will usually be virtd_t).

In order to easily verify that nothing was broken by these changes to
the call chain, all callers currently set useBinarySpecificPath =
false, so all behavior should be completely unchanged. (The next
patch will set it to true only for the case of running passt.)

https://bugzilla.redhat.com/2172267
Signed-off-by: Laine Stump <laine@redhat.com>
---
 src/qemu/qemu_dbus.c             |  2 +-
 src/qemu/qemu_passt.c            |  2 +-
 src/qemu/qemu_process.c          |  2 +-
 src/qemu/qemu_security.c         |  5 ++-
 src/qemu/qemu_security.h         |  1 +
 src/qemu/qemu_slirp.c            |  2 +-
 src/qemu/qemu_tpm.c              |  3 +-
 src/qemu/qemu_vhost_user_gpu.c   |  2 +-
 src/security/security_apparmor.c |  1 +
 src/security/security_dac.c      |  1 +
 src/security/security_driver.h   |  1 +
 src/security/security_manager.c  |  8 +++-
 src/security/security_manager.h  |  1 +
 src/security/security_nop.c      |  1 +
 src/security/security_selinux.c  | 73 +++++++++++++++++++++++++++++++-
 src/security/security_stack.c    |  5 ++-
 16 files changed, 99 insertions(+), 11 deletions(-)

diff --git a/src/qemu/qemu_dbus.c b/src/qemu/qemu_dbus.c
index a6dc802637..2e4067e704 100644
--- a/src/qemu/qemu_dbus.c
+++ b/src/qemu/qemu_dbus.c
@@ -217,7 +217,7 @@ qemuDBusStart(virQEMUDriver *driver,
     virCommandDaemonize(cmd);
     virCommandAddArgFormat(cmd, "--config-file=%s", configfile);
 
-    if (qemuSecurityCommandRun(driver, vm, cmd, -1, -1, NULL) < 0)
+    if (qemuSecurityCommandRun(driver, vm, cmd, -1, -1, false, NULL) < 0)
         goto cleanup;
 
     if (virPidFileReadPath(pidfile, &cpid) < 0) {
diff --git a/src/qemu/qemu_passt.c b/src/qemu/qemu_passt.c
index 0afa8bdb3a..fd0076077e 100644
--- a/src/qemu/qemu_passt.c
+++ b/src/qemu/qemu_passt.c
@@ -281,7 +281,7 @@ qemuPasstStart(virDomainObj *vm,
     if (qemuExtDeviceLogCommand(driver, vm, cmd, "passt") < 0)
         return -1;
 
-    if (qemuSecurityCommandRun(driver, vm, cmd, -1, -1, NULL) < 0)
+    if (qemuSecurityCommandRun(driver, vm, cmd, -1, -1, false, NULL) < 0)
         goto error;
 
     return 0;
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index deebd03717..be418ad8e6 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -7747,7 +7747,7 @@ qemuProcessLaunch(virConnectPtr conn,
 
     VIR_DEBUG("Setting up security labelling");
     if (qemuSecuritySetChildProcessLabel(driver->securityManager,
-                                         vm->def, cmd) < 0)
+                                         vm->def, false, cmd) < 0)
         goto cleanup;
 
     virCommandSetOutputFD(cmd, &logfile);
diff --git a/src/qemu/qemu_security.c b/src/qemu/qemu_security.c
index ee03e2225e..8bcef14d08 100644
--- a/src/qemu/qemu_security.c
+++ b/src/qemu/qemu_security.c
@@ -636,6 +636,7 @@ qemuSecurityCommandRun(virQEMUDriver *driver,
                        virCommand *cmd,
                        uid_t uid,
                        gid_t gid,
+                       bool useBinarySpecificLabel,
                        int *exitstatus)
 {
     g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
@@ -643,8 +644,10 @@ qemuSecurityCommandRun(virQEMUDriver *driver,
     int ret = -1;
 
     if (virSecurityManagerSetChildProcessLabel(driver->securityManager,
-                                               vm->def, cmd) < 0)
+                                               vm->def, useBinarySpecificLabel,
+                                               cmd) < 0) {
         return -1;
+    }
 
     if (uid != (uid_t) -1)
         virCommandSetUID(cmd, uid);
diff --git a/src/qemu/qemu_security.h b/src/qemu/qemu_security.h
index dc8e67cc81..10f11771b4 100644
--- a/src/qemu/qemu_security.h
+++ b/src/qemu/qemu_security.h
@@ -115,6 +115,7 @@ int qemuSecurityCommandRun(virQEMUDriver *driver,
                            virCommand *cmd,
                            uid_t uid,
                            gid_t gid,
+                           bool useBinarySpecificLabel,
                            int *exitstatus);
 
 /* Please note that for these APIs there is no wrapper yet. Do NOT blindly add
diff --git a/src/qemu/qemu_slirp.c b/src/qemu/qemu_slirp.c
index 9697542cd3..fdf0823d03 100644
--- a/src/qemu/qemu_slirp.c
+++ b/src/qemu/qemu_slirp.c
@@ -325,7 +325,7 @@ qemuSlirpStart(virDomainObj *vm,
     if (qemuExtDeviceLogCommand(driver, vm, cmd, "slirp") < 0)
         goto error;
 
-    if (qemuSecurityCommandRun(driver, vm, cmd, -1, -1, NULL) < 0)
+    if (qemuSecurityCommandRun(driver, vm, cmd, -1, -1, false, NULL) < 0)
         goto error;
 
     rc = virPidFileReadPath(pidfile, &pid);
diff --git a/src/qemu/qemu_tpm.c b/src/qemu/qemu_tpm.c
index 982e5f13b6..abe0ba7429 100644
--- a/src/qemu/qemu_tpm.c
+++ b/src/qemu/qemu_tpm.c
@@ -962,8 +962,9 @@ qemuTPMEmulatorStart(virQEMUDriver *driver,
         return -1;
 
     if (qemuSecurityCommandRun(driver, vm, cmd, cfg->swtpm_user,
-                               cfg->swtpm_group, NULL) < 0)
+                               cfg->swtpm_group, false, NULL) < 0) {
         goto error;
+    }
 
     if (virPidFileReadPath(pidfile, &pid) < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
diff --git a/src/qemu/qemu_vhost_user_gpu.c b/src/qemu/qemu_vhost_user_gpu.c
index 5b49ef4e28..ced41b0466 100644
--- a/src/qemu/qemu_vhost_user_gpu.c
+++ b/src/qemu/qemu_vhost_user_gpu.c
@@ -152,7 +152,7 @@ int qemuExtVhostUserGPUStart(virQEMUDriver *driver,
             virCommandAddArgFormat(cmd, "--render-node=%s", video->accel->rendernode);
     }
 
-    if (qemuSecurityCommandRun(driver, vm, cmd, -1, -1, NULL) < 0)
+    if (qemuSecurityCommandRun(driver, vm, cmd, -1, -1, false, NULL) < 0)
         goto error;
 
     rc = virPidFileReadPath(pidfile, &pid);
diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c
index b63b248975..b5642c9a28 100644
--- a/src/security/security_apparmor.c
+++ b/src/security/security_apparmor.c
@@ -570,6 +570,7 @@ AppArmorSetSecurityProcessLabel(virSecurityManager *mgr G_GNUC_UNUSED,
 static int
 AppArmorSetSecurityChildProcessLabel(virSecurityManager *mgr G_GNUC_UNUSED,
                                      virDomainDef *def,
+                                     bool useBinarySpecificLabel G_GNUC_UNUSED,
                                      virCommand *cmd)
 {
     g_autofree char *profile_name = NULL;
diff --git a/src/security/security_dac.c b/src/security/security_dac.c
index 9be8f458d1..ca3f4d2dc5 100644
--- a/src/security/security_dac.c
+++ b/src/security/security_dac.c
@@ -2273,6 +2273,7 @@ virSecurityDACSetProcessLabel(virSecurityManager *mgr,
 static int
 virSecurityDACSetChildProcessLabel(virSecurityManager *mgr,
                                    virDomainDef *def,
+                                   bool useBinarySpecificLabel G_GNUC_UNUSED,
                                    virCommand *cmd)
 {
     virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr);
diff --git a/src/security/security_driver.h b/src/security/security_driver.h
index fe6982ceca..aa1fb2125d 100644
--- a/src/security/security_driver.h
+++ b/src/security/security_driver.h
@@ -96,6 +96,7 @@ typedef int (*virSecurityDomainSetProcessLabel) (virSecurityManager *mgr,
                                                  virDomainDef *def);
 typedef int (*virSecurityDomainSetChildProcessLabel) (virSecurityManager *mgr,
                                                       virDomainDef *def,
+                                                      bool useBinarySpecificLabel,
                                                       virCommand *cmd);
 typedef int (*virSecurityDomainSecurityVerify) (virSecurityManager *mgr,
                                                 virDomainDef *def);
diff --git a/src/security/security_manager.c b/src/security/security_manager.c
index 2f8e89cb04..b0578d7209 100644
--- a/src/security/security_manager.c
+++ b/src/security/security_manager.c
@@ -885,10 +885,14 @@ virSecurityManagerSetProcessLabel(virSecurityManager *mgr,
 int
 virSecurityManagerSetChildProcessLabel(virSecurityManager *mgr,
                                        virDomainDef *vm,
+                                       bool useBinarySpecificLabel,
                                        virCommand *cmd)
 {
-    if (mgr->drv->domainSetSecurityChildProcessLabel)
-       return mgr->drv->domainSetSecurityChildProcessLabel(mgr, vm, cmd);
+    if (mgr->drv->domainSetSecurityChildProcessLabel) {
+       return mgr->drv->domainSetSecurityChildProcessLabel(mgr, vm,
+                                                           useBinarySpecificLabel,
+                                                           cmd);
+    }
 
     virReportUnsupportedError();
     return -1;
diff --git a/src/security/security_manager.h b/src/security/security_manager.h
index 4afdcc167b..97add3294d 100644
--- a/src/security/security_manager.h
+++ b/src/security/security_manager.h
@@ -145,6 +145,7 @@ int virSecurityManagerSetProcessLabel(virSecurityManager *mgr,
                                       virDomainDef *def);
 int virSecurityManagerSetChildProcessLabel(virSecurityManager *mgr,
                                            virDomainDef *def,
+                                           bool useBinarySpecificLabel,
                                            virCommand *cmd);
 int virSecurityManagerVerify(virSecurityManager *mgr,
                              virDomainDef *def);
diff --git a/src/security/security_nop.c b/src/security/security_nop.c
index 0dbc547feb..1413f43d57 100644
--- a/src/security/security_nop.c
+++ b/src/security/security_nop.c
@@ -152,6 +152,7 @@ virSecurityDomainSetProcessLabelNop(virSecurityManager *mgr G_GNUC_UNUSED,
 static int
 virSecurityDomainSetChildProcessLabelNop(virSecurityManager *mgr G_GNUC_UNUSED,
                                          virDomainDef *vm G_GNUC_UNUSED,
+                                         bool useBinarySpecificLabel G_GNUC_UNUSED,
                                          virCommand *cmd G_GNUC_UNUSED)
 {
     return 0;
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index cd1d9d14f7..7f409af525 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -560,6 +560,52 @@ virSecuritySELinuxContextAddRange(const char *src,
     return ret;
 }
 
+
+static char *
+virSecuritySELinuxContextSetFromFile(const char *origLabel,
+                                     const char *binaryPath)
+{
+    g_autofree char *currentCon = NULL;
+    g_autofree char *binaryCon = NULL;
+    g_autofree char *naturalLabel = NULL;
+    g_autofree char *updatedLabel = NULL;
+
+    /* First learn what would be the context set
+     * if binaryPath was exec'ed from this process.
+     */
+    if (getcon(&currentCon) < 0) {
+        virReportSystemError(errno, "%s",
+                             _("unable to get SELinux context for current process"));
+        return NULL;
+    }
+
+    if (getfilecon(binaryPath, &binaryCon) < 0) {
+        virReportSystemError(errno, _("unable to get SELinux context for '%s'"),
+                             binaryPath);
+        return NULL;
+    }
+
+    if (security_compute_create(currentCon, binaryCon,
+                                string_to_security_class("process"),
+                                &naturalLabel) < 0) {
+        virReportSystemError(errno,
+                             _("unable create new SELinux label based on label '%s' and file '%s'"),
+                             origLabel, binaryPath);
+        return NULL;
+    }
+
+    /* now get the type from the original label
+     * (which already has proper MCS set) and add it to
+     * the new label
+     */
+    updatedLabel = virSecuritySELinuxContextAddRange(origLabel, naturalLabel);
+
+    VIR_DEBUG("original label: '%s' binary: '%s' binary-specific label: '%s'",
+              origLabel, binaryPath, NULLSTR(updatedLabel));
+    return g_steal_pointer(&updatedLabel);
+}
+
+
 static char *
 virSecuritySELinuxGenNewContext(const char *basecontext,
                                 const char *mcs,
@@ -2986,10 +3032,13 @@ virSecuritySELinuxSetProcessLabel(virSecurityManager *mgr G_GNUC_UNUSED,
 static int
 virSecuritySELinuxSetChildProcessLabel(virSecurityManager *mgr G_GNUC_UNUSED,
                                        virDomainDef *def,
+                                       bool useBinarySpecificLabel G_GNUC_UNUSED,
                                        virCommand *cmd)
 {
     /* TODO: verify DOI */
     virSecurityLabelDef *secdef;
+    g_autofree char *tmpLabel = NULL;
+    const char *label = NULL;
 
     secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
     if (!secdef || !secdef->label)
@@ -3006,8 +3055,30 @@ virSecuritySELinuxSetChildProcessLabel(virSecurityManager *mgr G_GNUC_UNUSED,
             return -1;
     }
 
+    /* pick either the common label used by most binaries exec'ed by
+     * libvirt, or the specific label of this binary.
+     */
+    if (useBinarySpecificLabel) {
+        const char *binaryPath = virCommandGetBinaryPath(cmd);
+
+        if (!binaryPath)
+            return -1; /* error was already logged */
+
+        tmpLabel = virSecuritySELinuxContextSetFromFile(secdef->label,
+                                                        binaryPath);
+        if (!tmpLabel)
+            return -1;
+
+        label = tmpLabel;
+
+    } else {
+
+        label = secdef->label;
+
+    }
+
     /* save in cmd to be set after fork/before child process is exec'ed */
-    virCommandSetSELinuxLabel(cmd, secdef->label);
+    virCommandSetSELinuxLabel(cmd, label);
     return 0;
 }
 
diff --git a/src/security/security_stack.c b/src/security/security_stack.c
index 560f797030..369b5dd3a6 100644
--- a/src/security/security_stack.c
+++ b/src/security/security_stack.c
@@ -458,6 +458,7 @@ virSecurityStackSetProcessLabel(virSecurityManager *mgr,
 static int
 virSecurityStackSetChildProcessLabel(virSecurityManager *mgr,
                                      virDomainDef *vm,
+                                     bool useBinarySpecificLabel,
                                      virCommand *cmd)
 {
     virSecurityStackData *priv = virSecurityManagerGetPrivateData(mgr);
@@ -465,8 +466,10 @@ virSecurityStackSetChildProcessLabel(virSecurityManager *mgr,
     int rc = 0;
 
     for (; item; item = item->next) {
-        if (virSecurityManagerSetChildProcessLabel(item->securityManager, vm, cmd) < 0)
+        if (virSecurityManagerSetChildProcessLabel(item->securityManager, vm,
+                                                   useBinarySpecificLabel, cmd) < 0) {
             rc = -1;
+        }
     }
 
     return rc;
-- 
@@ -458,6 +458,7 @@ virSecurityStackSetProcessLabel(virSecurityManager *mgr,
 static int
 virSecurityStackSetChildProcessLabel(virSecurityManager *mgr,
                                      virDomainDef *vm,
+                                     bool useBinarySpecificLabel,
                                      virCommand *cmd)
 {
     virSecurityStackData *priv = virSecurityManagerGetPrivateData(mgr);
@@ -465,8 +466,10 @@ virSecurityStackSetChildProcessLabel(virSecurityManager *mgr,
     int rc = 0;
 
     for (; item; item = item->next) {
-        if (virSecurityManagerSetChildProcessLabel(item->securityManager, vm, cmd) < 0)
+        if (virSecurityManagerSetChildProcessLabel(item->securityManager, vm,
+                                                   useBinarySpecificLabel, cmd) < 0) {
             rc = -1;
+        }
     }
 
     return rc;
-- 
2.39.2


  parent reply	other threads:[~2023-03-09  4:49 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-03-09  4:49 [libvirt PATCH 0/4] qemu/security: start passt process with correct SELinux label Laine Stump
2023-03-09  4:49 ` [libvirt PATCH 1/4] util: add an API to retrieve the resolved path to a virCommand's binary Laine Stump
2023-03-09  4:49 ` [libvirt PATCH 2/4] security: make args to virSecuritySELinuxContextAddRange() const Laine Stump
2023-03-09  4:49 ` Laine Stump [this message]
2023-03-09  4:49 ` [libvirt PATCH 4/4] qemu: set SELinux label of passt process to its own binary's label Laine Stump
2023-03-09  5:06 ` [libvirt PATCH 0/4] qemu/security: start passt process with correct SELinux label Laine Stump
2023-03-10 11:58 ` Michal Prívozník
2023-03-10 14:39   ` Andrea Bolognani

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230309044908.29316-4-laine@redhat.com \
    --to=laine@redhat.com \
    --cc=libvir-list@redhat.com \
    --cc=passt-dev@passt.top \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://passt.top/passt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).