Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list