Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/security/security_selinux.c | 193 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 190 insertions(+), 3 deletions(-)
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index fec19b98c..af226bff6 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -78,6 +78,22 @@ struct _virSecuritySELinuxCallbackData {
virDomainDefPtr def;
};
+typedef struct _virSecuritySELinuxContextItem virSecuritySELinuxContextItem;
+typedef virSecuritySELinuxContextItem *virSecuritySELinuxContextItemPtr;
+struct _virSecuritySELinuxContextItem {
+ const char *path;
+ const char *tcon;
+ bool optional;
+};
+
+typedef struct _virSecuritySELinuxContextList virSecuritySELinuxContextList;
+typedef virSecuritySELinuxContextList *virSecuritySELinuxContextListPtr;
+struct _virSecuritySELinuxContextList {
+ bool privileged;
+ virSecuritySELinuxContextItemPtr *items;
+ size_t nItems;
+};
+
#define SECURITY_SELINUX_VOID_DOI "0"
#define SECURITY_SELINUX_NAME "selinux"
@@ -87,6 +103,94 @@ virSecuritySELinuxRestoreTPMFileLabelInt(virSecurityManagerPtr mgr,
virDomainTPMDefPtr tpm);
+virThreadLocal contextList;
+
+static int
+virSecuritySELinuxContextListAppend(virSecuritySELinuxContextListPtr list,
+ const char *path,
+ const char *tcon,
+ bool optional)
+{
+ virSecuritySELinuxContextItemPtr item;
+
+ if (VIR_ALLOC(item) < 0)
+ return -1;
+
+ item->path = path;
+ item->tcon = tcon;
+ item->optional = optional;
+
+ if (VIR_APPEND_ELEMENT(list->items, list->nItems, item) < 0) {
+ VIR_FREE(item);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+virSecuritySELinuxContextListFree(void *opaque)
+{
+ virSecuritySELinuxContextListPtr list = opaque;
+ size_t i;
+
+ if (!list)
+ return;
+
+ for (i = 0; i < list->nItems; i++)
+ VIR_FREE(list->items[i]);
+ VIR_FREE(list);
+}
+
+
+static int
+virSecuritySELinuxTransactionAppend(const char *path,
+ const char *tcon,
+ bool optional)
+{
+ virSecuritySELinuxContextListPtr list;
+ int ret = -1;
+
+ list = virThreadLocalGet(&contextList);
+ if (!list)
+ return 0;
+
+ if (virSecuritySELinuxContextListAppend(list, path, tcon, optional) < 0)
+ goto cleanup;
+
+ ret = 0;
+ cleanup:
+ return ret;
+}
+
+
+static int virSecuritySELinuxSetFileconHelper(const char *path,
+ const char *tcon,
+ bool optional,
+ bool privileged);
+
+static int
+virSecuritySELinuxTransactionRun(pid_t pid ATTRIBUTE_UNUSED,
+ void *opaque)
+{
+ virSecuritySELinuxContextListPtr list = opaque;
+ size_t i;
+
+ ignore_value(virThreadLocalSet(&contextList, NULL));
+ for (i = 0; i < list->nItems; i++) {
+ virSecuritySELinuxContextItemPtr item = list->items[i];
+
+ if (virSecuritySELinuxSetFileconHelper(item->path,
+ item->tcon,
+ item->optional,
+ list->privileged) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+
/*
* Returns 0 on success, 1 if already reserved, or -1 on fatal error
*/
@@ -560,6 +664,14 @@ static int
virSecuritySELinuxInitialize(virSecurityManagerPtr mgr)
{
VIR_DEBUG("SELinuxInitialize %s", virSecurityManagerGetDriver(mgr));
+
+ if (virThreadLocalInit(&contextList,
+ virSecuritySELinuxContextListFree) < 0) {
+ virReportSystemError(errno, "%s",
+ _("Unable to initialize thread local variable"));
+ return -1;
+ }
+
if (STREQ(virSecurityManagerGetDriver(mgr), "LXC")) {
return virSecuritySELinuxLXCInitialize(mgr);
} else {
@@ -843,6 +955,68 @@ virSecuritySELinuxGetDOI(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
return SECURITY_SELINUX_VOID_DOI;
}
+static int
+virSecuritySELinuxTransactionStart(virSecurityManagerPtr mgr)
+{
+ bool privileged = virSecurityManagerGetPrivileged(mgr);
+ virSecuritySELinuxContextListPtr list;
+
+ list = virThreadLocalGet(&contextList);
+ if (list) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Another relabel transaction is already started"));
+ return -1;
+ }
+
+ if (VIR_ALLOC(list) < 0)
+ return -1;
+
+ list->privileged = privileged;
+
+ if (virThreadLocalSet(&contextList, list) < 0) {
+ virReportSystemError(errno, "%s",
+ _("Unable to set thread local variable"));
+ VIR_FREE(list);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+virSecuritySELinuxTransactionCommit(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ pid_t pid)
+{
+ virSecuritySELinuxContextListPtr list;
+ int ret = 0;
+
+ list = virThreadLocalGet(&contextList);
+ if (!list)
+ return 0;
+
+ if (virProcessRunInMountNamespace(pid,
+ virSecuritySELinuxTransactionRun,
+ list) < 0)
+ ret = -1;
+
+ ignore_value(virThreadLocalSet(&contextList, NULL));
+ virSecuritySELinuxContextListFree(list);
+ return ret;
+}
+
+static void
+virSecuritySELinuxTransactionAbort(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
+{
+ virSecuritySELinuxContextListPtr list;
+
+ list = virThreadLocalGet(&contextList);
+ if (!list)
+ return;
+
+ ignore_value(virThreadLocalSet(&contextList, NULL));
+ virSecuritySELinuxContextListFree(list);
+}
+
static int
virSecuritySELinuxGetProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
virDomainDefPtr def ATTRIBUTE_UNUSED,
@@ -885,10 +1059,19 @@ virSecuritySELinuxGetProcessLabel(virSecurityManagerPtr mgr
ATTRIBUTE_UNUSED,
* return 1 if labelling was not possible. Otherwise, require a label
* change, and return 0 for success, -1 for failure. */
static int
-virSecuritySELinuxSetFileconHelper(const char *path, char *tcon,
+virSecuritySELinuxSetFileconHelper(const char *path, const char *tcon,
bool optional, bool privileged)
{
security_context_t econ;
+ int rc;
+
+ /* Be aware that this function might run in a separate process.
+ * Therefore, any driver state changes would be thrown away. */
+
+ if ((rc = virSecuritySELinuxTransactionAppend(path, tcon, optional)) < 0)
+ return -1;
+ else if (rc > 0)
+ return 0;
VIR_INFO("Setting SELinux context on '%s' to '%s'", path,
tcon);
@@ -945,7 +1128,7 @@ virSecuritySELinuxSetFileconHelper(const char *path, char *tcon,
static int
virSecuritySELinuxSetFileconOptional(virSecurityManagerPtr mgr,
- const char *path, char *tcon)
+ const char *path, const char *tcon)
{
bool privileged = virSecurityManagerGetPrivileged(mgr);
return virSecuritySELinuxSetFileconHelper(path, tcon, true, privileged);
@@ -953,7 +1136,7 @@ virSecuritySELinuxSetFileconOptional(virSecurityManagerPtr mgr,
static int
virSecuritySELinuxSetFilecon(virSecurityManagerPtr mgr,
- const char *path, char *tcon)
+ const char *path, const char *tcon)
{
bool privileged = virSecurityManagerGetPrivileged(mgr);
return virSecuritySELinuxSetFileconHelper(path, tcon, false, privileged);
@@ -2667,6 +2850,10 @@ virSecurityDriver virSecurityDriverSELinux = {
.getModel = virSecuritySELinuxGetModel,
.getDOI = virSecuritySELinuxGetDOI,
+ .transactionStart = virSecuritySELinuxTransactionStart,
+ .transactionCommit = virSecuritySELinuxTransactionCommit,
+ .transactionAbort = virSecuritySELinuxTransactionAbort,
+
.domainSecurityVerify = virSecuritySELinuxVerify,
.domainSetSecurityDiskLabel = virSecuritySELinuxSetDiskLabel,
--
2.11.0