[PATCH 0/4] Couple of qemusecuritytest and security_util improvements

These were sparked by a discussion on the list where the test is failing on macOS. Michal Prívozník (4): security_util: Don't error on macOS when getting/setting/moving XATTRs qemusecuritytest: Test SELinux too qemusecuritytest: Skip on non supported platforms qemu_conf: Don't even attempt to enable rememberOwner if unsupported src/libvirt_private.syms | 4 + src/qemu/qemu_conf.c | 7 +- src/security/security_util.c | 26 ++- src/security/security_util.h | 3 + tests/qemusecuritydata/virtual_domain_context | 2 + tests/qemusecuritydata/virtual_image_context | 2 + tests/qemusecuritymock.c | 195 +++++++++++++++++- tests/qemusecuritytest.c | 57 ++++- 8 files changed, 282 insertions(+), 14 deletions(-) create mode 100644 tests/qemusecuritydata/virtual_domain_context create mode 100644 tests/qemusecuritydata/virtual_image_context -- 2.26.2

There are three internal APIs implemented in this security_util file: virSecurityGetRememberedLabel(), virSecuritySetRememberedLabel() and virSecurityMoveRememberedLabel() for getting, setting and moving remembered seclabel. All three have a special return value of -2 when XATTRs are not supported (for whatever reason) and callers are expected to handle it gracefully. However, after my commit of v5.7.0-rc1~115 it may happen that one of the three functions returned -1 even though XATTRs are not supported (and thus -2 should have been returned). Fixes: 7cfb7aab573a031880a1f4fd20747843fea109ba Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/security/security_util.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/security/security_util.c b/src/security/security_util.c index 7fa5163fe4..622bd901ee 100644 --- a/src/security/security_util.c +++ b/src/security/security_util.c @@ -269,8 +269,11 @@ virSecurityGetRememberedLabel(const char *name, *label = NULL; - if (!(ref_name = virSecurityGetRefCountAttrName(name))) + if (!(ref_name = virSecurityGetRefCountAttrName(name))) { + if (errno == ENOSYS) + return -2; return -1; + } if (virFileGetXAttrQuiet(path, ref_name, &value) < 0) { if (errno == ENOSYS || errno == ENODATA || errno == ENOTSUP) @@ -364,8 +367,11 @@ virSecuritySetRememberedLabel(const char *name, g_autofree char *value = NULL; unsigned int refcount = 0; - if (!(ref_name = virSecurityGetRefCountAttrName(name))) + if (!(ref_name = virSecurityGetRefCountAttrName(name))) { + if (errno == ENOSYS) + return -2; return -1; + } if (virFileGetXAttrQuiet(path, ref_name, &value) < 0) { if (errno == ENOSYS || errno == ENOTSUP) { @@ -452,8 +458,11 @@ virSecurityMoveRememberedLabel(const char *name, if (!(ref_name = virSecurityGetRefCountAttrName(name)) || !(attr_name = virSecurityGetAttrName(name)) || - !(timestamp_name = virSecurityGetTimestampAttrName(name))) + !(timestamp_name = virSecurityGetTimestampAttrName(name))) { + if (errno == ENOSYS) + return -2; return -1; + } if (virFileGetXAttrQuiet(src, ref_name, &ref_value) < 0) { if (errno == ENOSYS || errno == ENOTSUP) { -- 2.26.2

On Tue, Nov 03, 2020 at 02:13:26PM +0100, Michal Privoznik wrote:
There are three internal APIs implemented in this security_util file: virSecurityGetRememberedLabel(), virSecuritySetRememberedLabel() and virSecurityMoveRememberedLabel() for getting, setting and moving remembered seclabel. All three have a special return value of -2 when XATTRs are not supported (for whatever reason) and callers are expected to handle it gracefully. However, after my commit of v5.7.0-rc1~115 it may happen that one of the three functions returned -1 even though XATTRs are not supported (and thus -2 should have been returned).
Fixes: 7cfb7aab573a031880a1f4fd20747843fea109ba Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/security/security_util.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/src/security/security_util.c b/src/security/security_util.c index 7fa5163fe4..622bd901ee 100644 --- a/src/security/security_util.c +++ b/src/security/security_util.c @@ -269,8 +269,11 @@ virSecurityGetRememberedLabel(const char *name,
*label = NULL;
- if (!(ref_name = virSecurityGetRefCountAttrName(name))) + if (!(ref_name = virSecurityGetRefCountAttrName(name))) { + if (errno == ENOSYS) + return -2; return -1; + }
if (virFileGetXAttrQuiet(path, ref_name, &value) < 0) { if (errno == ENOSYS || errno == ENODATA || errno == ENOTSUP) @@ -364,8 +367,11 @@ virSecuritySetRememberedLabel(const char *name, g_autofree char *value = NULL; unsigned int refcount = 0;
- if (!(ref_name = virSecurityGetRefCountAttrName(name))) + if (!(ref_name = virSecurityGetRefCountAttrName(name))) { + if (errno == ENOSYS) + return -2; return -1; + }
if (virFileGetXAttrQuiet(path, ref_name, &value) < 0) { if (errno == ENOSYS || errno == ENOTSUP) { @@ -452,8 +458,11 @@ virSecurityMoveRememberedLabel(const char *name,
if (!(ref_name = virSecurityGetRefCountAttrName(name)) || !(attr_name = virSecurityGetAttrName(name)) || - !(timestamp_name = virSecurityGetTimestampAttrName(name))) + !(timestamp_name = virSecurityGetTimestampAttrName(name))) { + if (errno == ENOSYS) + return -2; return -1; + }
if (virFileGetXAttrQuiet(src, ref_name, &ref_value) < 0) { if (errno == ENOSYS || errno == ENOTSUP) { -- 2.26.2
Reviewed-by: Roman Bolshakov <r.bolshakov@yadro.com> It might be a separate issue, but I wonder if we can report a warning instead of system error if protected xattrs aren't supported to avoid confusion: static char * virSecurityGetAttrName(const char *name G_GNUC_UNUSED) { char *ret = NULL; #ifdef XATTR_NAMESPACE ret = g_strdup_printf(XATTR_NAMESPACE".libvirt.security.%s", name); #else errno = ENOSYS; virReportSystemError(errno, "%s", _("Extended attributes are not supported on this system")); #endif return ret; } Thanks, Roman

The qemusecuritytest checks for random domain XMLs from qemuxml2argvdata/ whether set+restore seclabels leaves something behind. It can be an XATTR that we forgot to remove or a file that the owner was not restored on. But so far only DAC driver is checked. Implement missing pieces and enable SELinux testing too. This is done by mocking some libselinux APIs and following the same logic used for DAC - everything is implemented in memory, there is new hash table introduced that holds SELinux labels for paths that were setfilecon_raw()-ed and in the end the hash table is checked for entries that don't have the default SELinux label (i.e. were not restored). Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- tests/qemusecuritydata/virtual_domain_context | 2 + tests/qemusecuritydata/virtual_image_context | 2 + tests/qemusecuritymock.c | 195 +++++++++++++++++- tests/qemusecuritytest.c | 51 ++++- 4 files changed, 240 insertions(+), 10 deletions(-) create mode 100644 tests/qemusecuritydata/virtual_domain_context create mode 100644 tests/qemusecuritydata/virtual_image_context diff --git a/tests/qemusecuritydata/virtual_domain_context b/tests/qemusecuritydata/virtual_domain_context new file mode 100644 index 0000000000..150f281d10 --- /dev/null +++ b/tests/qemusecuritydata/virtual_domain_context @@ -0,0 +1,2 @@ +system_u:system_r:svirt_t:s0 +system_u:system_r:svirt_tcg_t:s0 diff --git a/tests/qemusecuritydata/virtual_image_context b/tests/qemusecuritydata/virtual_image_context new file mode 100644 index 0000000000..8ab1e27ea2 --- /dev/null +++ b/tests/qemusecuritydata/virtual_image_context @@ -0,0 +1,2 @@ +system_u:object_r:svirt_image_t:s0 +system_u:object_r:virt_content_t:s0 diff --git a/tests/qemusecuritymock.c b/tests/qemusecuritymock.c index 543a5f7f3f..db03572dbe 100644 --- a/tests/qemusecuritymock.c +++ b/tests/qemusecuritymock.c @@ -24,6 +24,11 @@ #include <unistd.h> #include <fcntl.h> +#ifdef WITH_SELINUX +# include <selinux/selinux.h> +# include <selinux/label.h> +#endif + #include "virmock.h" #include "virfile.h" #include "virthread.h" @@ -41,7 +46,8 @@ * work as expected. Therefore there is a lot we have to mock * (chown, stat, XATTR APIs, etc.). Since the test won't run as * root chown() would fail, therefore we have to keep everything - * in memory. By default, all files are owned by 1:2. + * in memory. By default, all files are owned by 1:2 and have a + * SELinux label. * By the way, since there are some cases where real stat needs * to be called, the mocked functions are effective only if * $ENVVAR is set. @@ -49,11 +55,16 @@ #define DEFAULT_UID 1 #define DEFAULT_GID 2 +#define DEFAULT_SELINUX_LABEL "system_u:object_r:default_t:s0" static int (*real_chown)(const char *path, uid_t uid, gid_t gid); static int (*real_open)(const char *path, int flags, ...); static int (*real_close)(int fd); +#ifdef WITH_SELINUX +static int (*real_setfilecon_raw)(const char *path, const char *context); +static int (*real_getfilecon_raw)(const char *path, char **context); +#endif /* Global mutex to avoid races */ @@ -71,6 +82,10 @@ virHashTablePtr xattr_paths = NULL; * the lower half is UID and the higher is GID. */ virHashTablePtr chown_paths = NULL; +/* The SELinux label is stored in a hash table. For simplicity, + * the path os the key and the value is the label. */ +virHashTablePtr selinux_paths = NULL; + static void init_hash(void) @@ -94,6 +109,11 @@ init_hash(void) fprintf(stderr, "Unable to create hash table for chowned paths\n"); abort(); } + + if (!(selinux_paths = virHashNew(g_free))) { + fprintf(stderr, "Unable to create hash table for selinux labels\n"); + abort(); + } } @@ -106,6 +126,10 @@ init_syms(void) VIR_MOCK_REAL_INIT(chown); VIR_MOCK_REAL_INIT(open); VIR_MOCK_REAL_INIT(close); +#ifdef WITH_SELINUX + VIR_MOCK_REAL_INIT(setfilecon_raw); + VIR_MOCK_REAL_INIT(getfilecon_raw); +#endif /* Intentionally not calling init_hash() here */ } @@ -376,9 +400,30 @@ typedef struct _checkOwnerData checkOwnerData; struct _checkOwnerData { const char **paths; bool chown_fail; + bool selinux_fail; }; +static int +checkSELinux(void *payload, + const char *name, + void *opaque) +{ + checkOwnerData *data = opaque; + char *label = payload; + + if (STRNEQ(label, DEFAULT_SELINUX_LABEL) && + !virStringListHasString(data->paths, name)) { + fprintf(stderr, + "Path %s wasn't restored back to its original SELinux label\n", + name); + data->selinux_fail = true; + } + + return 0; +} + + static int checkOwner(void *payload, const char *name, @@ -431,7 +476,7 @@ printXATTR(void *payload, int checkPaths(const char **paths) { int ret = -1; - checkOwnerData data = { .paths = paths, .chown_fail = false }; + checkOwnerData data = { .paths = paths, .chown_fail = false, .selinux_fail = false }; bool xattr_fail = false; size_t i; @@ -445,13 +490,16 @@ int checkPaths(const char **paths) } } - if ((virHashForEach(chown_paths, checkOwner, &data)) < 0) + if (virHashForEach(selinux_paths, checkSELinux, &data) < 0) goto cleanup; - if ((virHashForEach(xattr_paths, printXATTR, &xattr_fail)) < 0) + if (virHashForEach(chown_paths, checkOwner, &data) < 0) goto cleanup; - if (data.chown_fail || xattr_fail) + if (virHashForEach(xattr_paths, printXATTR, &xattr_fail) < 0) + goto cleanup; + + if (data.chown_fail || data.selinux_fail || xattr_fail) goto cleanup; ret = 0; @@ -466,9 +514,10 @@ void freePaths(void) virMutexLock(&m); init_hash(); + virHashFree(selinux_paths); virHashFree(chown_paths); virHashFree(xattr_paths); - chown_paths = xattr_paths = NULL; + selinux_paths = chown_paths = xattr_paths = NULL; virMutexUnlock(&m); } @@ -490,3 +539,137 @@ virHostGetBootTime(unsigned long long *when) *when = 1234567890; return 0; } + + +#ifdef WITH_SELINUX +int +is_selinux_enabled(void) +{ + return 1; +} + + +struct selabel_handle * +selabel_open(unsigned int backend G_GNUC_UNUSED, + const struct selinux_opt *opts G_GNUC_UNUSED, + unsigned nopts G_GNUC_UNUSED) +{ + return (void*)((intptr_t) 0x1); +} + + +void +selabel_close(struct selabel_handle *rec G_GNUC_UNUSED) +{ + /* nada */ +} + + +const char * +selinux_virtual_domain_context_path(void) +{ + return abs_srcdir "/qemusecuritydata/virtual_domain_context"; +} + + +const char * +selinux_virtual_image_context_path(void) +{ + return abs_srcdir "/qemusecuritydata/virtual_image_context"; +} + + +int getcon_raw(char **context) +{ + *context = g_strdup("system_u:system_r:virtd_t:s0-s0:c0.c1023"); + return 0; +} + + +static int +mock_setfilecon_raw(const char *path, + const char *context) +{ + g_autofree char *val = g_strdup(context); + int ret = -1; + + virMutexLock(&m); + init_hash(); + + if (virHashUpdateEntry(selinux_paths, path, val) < 0) + goto cleanup; + val = NULL; + + ret = 0; + cleanup: + virMutexUnlock(&m); + return ret; +} + + +static int +mock_getfilecon_raw(const char *path, + char **context) +{ + const char *val; + + virMutexLock(&m); + init_hash(); + + val = virHashLookup(selinux_paths, path); + if (!val) + val = DEFAULT_SELINUX_LABEL; + + *context = g_strdup(val); + virMutexUnlock(&m); + return 0; +} + + +int +setfilecon_raw(const char *path, + const char *context) +{ + int ret; + + init_syms(); + + if (getenv(ENVVAR)) + ret = mock_setfilecon_raw(path, context); + else + ret = real_setfilecon_raw(path, context); + + return ret; +} + + +int +getfilecon_raw(const char *path, + char **context) +{ + int ret; + + init_syms(); + + if (getenv(ENVVAR)) + ret = mock_getfilecon_raw(path, context); + else + ret = real_getfilecon_raw(path, context); + + return ret; +} + + +int +selabel_lookup_raw(struct selabel_handle *hnd G_GNUC_UNUSED, + char **context, + const char *key G_GNUC_UNUSED, + int type G_GNUC_UNUSED) +{ + /* This function will be called only if we haven't found original label in + * XATTRs. Return something else than DEFAULT_SELINUX_LABEL so that it is + * considered as error. */ + *context = g_strdup("system_u:object_r:default_t:s1"); + return 0; +} +#endif diff --git a/tests/qemusecuritytest.c b/tests/qemusecuritytest.c index 297200d9ad..7ee1ccd1b6 100644 --- a/tests/qemusecuritytest.c +++ b/tests/qemusecuritytest.c @@ -73,6 +73,9 @@ prepareObjects(virQEMUDriverPtr driver, 0))) return -1; + if (virSecurityManagerGenLabel(driver->securityManager, vm->def) < 0) + return -1; + *vm_ret = g_steal_pointer(&vm); return 0; } @@ -134,6 +137,11 @@ static int mymain(void) { virQEMUDriver driver; + virSecurityManagerPtr stack = NULL; + virSecurityManagerPtr dac = NULL; +#ifdef WITH_SELINUX + virSecurityManagerPtr selinux = NULL; +#endif int ret = 0; if (virInitialize() < 0 || @@ -142,15 +150,45 @@ mymain(void) /* Now fix the secdriver */ virObjectUnref(driver.securityManager); - if (!(driver.securityManager = virSecurityManagerNewDAC("test", 1000, 1000, - VIR_SECURITY_MANAGER_PRIVILEGED | - VIR_SECURITY_MANAGER_DYNAMIC_OWNERSHIP, - NULL))) { + + if (!(dac = virSecurityManagerNewDAC("test", 1000, 1000, + VIR_SECURITY_MANAGER_PRIVILEGED | + VIR_SECURITY_MANAGER_DYNAMIC_OWNERSHIP, + NULL))) { fprintf(stderr, "Cannot initialize DAC security driver"); ret = -1; goto cleanup; } + if (!(stack = virSecurityManagerNewStack(dac))) { + fprintf(stderr, "Cannot initialize stack security driver"); + ret = -1; + goto cleanup; + } + dac = NULL; + +#if WITH_SELINUX + selinux = virSecurityManagerNew("selinux", "test", + VIR_SECURITY_MANAGER_PRIVILEGED | + VIR_SECURITY_MANAGER_DEFAULT_CONFINED | + VIR_SECURITY_MANAGER_REQUIRE_CONFINED); + if (!selinux) { + fprintf(stderr, "Cannot initialize selinux security driver"); + ret = -1; + goto cleanup; + } + + if (virSecurityManagerStackAddNested(stack, selinux) < 0) { + fprintf(stderr, "Cannot add selinux security driver onto stack"); + ret = -1; + goto cleanup; + } + selinux = NULL; +#endif + + driver.securityManager = g_steal_pointer(&stack); + + #define DO_TEST_DOMAIN(f) \ do { \ struct testData data = {.driver = &driver, .file = f}; \ @@ -214,6 +252,11 @@ mymain(void) cleanup: qemuTestDriverFree(&driver); +#ifdef WITH_SELINUX + virObjectUnref(selinux); +#endif + virObjectUnref(dac); + virObjectUnref(stack); return ret; } -- 2.26.2

On Tue, 2020-11-03 at 14:13 +0100, Michal Privoznik wrote:
+++ b/tests/qemusecuritymock.c @@ -71,6 +82,10 @@ virHashTablePtr xattr_paths = NULL; * the lower half is UID and the higher is GID. */ virHashTablePtr chown_paths = NULL;
+/* The SELinux label is stored in a hash table. For simplicity, + * the path os the key and the value is the label. */
s/path os/path is/ -- Andrea Bolognani / Red Hat / Virtualization

For seclabel remembering we need to have XATTRs and a special namespace that is accessibly to CAP_SYS_ADMIN only (we don't want regular users to trick us into restoring to a different label). And what qemusecuritytest does is it checks whether we have not left any path behind with XATTRs or not restored to original seclabel after setAll + restoreAll round trip. But it can hardly do so if ran on a platform where there's no XATTR namespace we can use. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/libvirt_private.syms | 4 ++++ src/security/security_util.c | 11 +++++++++++ src/security/security_util.h | 3 +++ tests/qemusecuritytest.c | 6 ++++++ 4 files changed, 24 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 95e50835ad..eb588a9357 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1609,6 +1609,10 @@ virSecurityManagerTransactionStart; virSecurityManagerVerify; +# security/security_util.h +virSecurityXATTRNamespaceDefined; + + # util/glibcompat.h vir_g_canonicalize_filename; vir_g_fsync; diff --git a/src/security/security_util.c b/src/security/security_util.c index 622bd901ee..26a7861e29 100644 --- a/src/security/security_util.c +++ b/src/security/security_util.c @@ -107,6 +107,17 @@ virSecurityGetTimestampAttrName(const char *name G_GNUC_UNUSED) #endif /* !XATTR_NAMESPACE */ +bool +virSecurityXATTRNamespaceDefined(void) +{ +#ifdef XATTR_NAMESPACE + return true; +#else + return false; +#endif +} + + static char * virSecurityGetTimestamp(void) { diff --git a/src/security/security_util.h b/src/security/security_util.h index 91de704e62..7af6f009e2 100644 --- a/src/security/security_util.h +++ b/src/security/security_util.h @@ -32,3 +32,6 @@ int virSecurityMoveRememberedLabel(const char *name, const char *src, const char *dst); + +bool +virSecurityXATTRNamespaceDefined(void); diff --git a/tests/qemusecuritytest.c b/tests/qemusecuritytest.c index 7ee1ccd1b6..dc3deb37d2 100644 --- a/tests/qemusecuritytest.c +++ b/tests/qemusecuritytest.c @@ -22,6 +22,7 @@ #include "testutils.h" #include "testutilsqemu.h" #include "security/security_manager.h" +#include "security/security_util.h" #include "conf/domain_conf.h" #include "qemu/qemu_domain.h" #include "qemu/qemu_security.h" @@ -148,6 +149,11 @@ mymain(void) qemuTestDriverInit(&driver) < 0) return -1; + if (!virSecurityXATTRNamespaceDefined()) { + ret = EXIT_AM_SKIP; + goto cleanup; + } + /* Now fix the secdriver */ virObjectUnref(driver.securityManager); -- 2.26.2

On Tue, Nov 03, 2020 at 02:13:28PM +0100, Michal Privoznik wrote:
For seclabel remembering we need to have XATTRs and a special namespace that is accessibly to CAP_SYS_ADMIN only (we don't want regular users to trick us into restoring to a different label). And what qemusecuritytest does is it checks whether we have not left any path behind with XATTRs or not restored to original seclabel after setAll + restoreAll round trip. But it can hardly do so if ran on a platform where there's no XATTR namespace we can use.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/libvirt_private.syms | 4 ++++ src/security/security_util.c | 11 +++++++++++ src/security/security_util.h | 3 +++ tests/qemusecuritytest.c | 6 ++++++ 4 files changed, 24 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 95e50835ad..eb588a9357 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1609,6 +1609,10 @@ virSecurityManagerTransactionStart; virSecurityManagerVerify;
+# security/security_util.h +virSecurityXATTRNamespaceDefined; + + # util/glibcompat.h vir_g_canonicalize_filename; vir_g_fsync; diff --git a/src/security/security_util.c b/src/security/security_util.c index 622bd901ee..26a7861e29 100644 --- a/src/security/security_util.c +++ b/src/security/security_util.c @@ -107,6 +107,17 @@ virSecurityGetTimestampAttrName(const char *name G_GNUC_UNUSED) #endif /* !XATTR_NAMESPACE */
+bool +virSecurityXATTRNamespaceDefined(void) +{ +#ifdef XATTR_NAMESPACE + return true; +#else + return false; +#endif +} + + static char * virSecurityGetTimestamp(void) { diff --git a/src/security/security_util.h b/src/security/security_util.h index 91de704e62..7af6f009e2 100644 --- a/src/security/security_util.h +++ b/src/security/security_util.h @@ -32,3 +32,6 @@ int virSecurityMoveRememberedLabel(const char *name, const char *src, const char *dst); + +bool +virSecurityXATTRNamespaceDefined(void); diff --git a/tests/qemusecuritytest.c b/tests/qemusecuritytest.c index 7ee1ccd1b6..dc3deb37d2 100644 --- a/tests/qemusecuritytest.c +++ b/tests/qemusecuritytest.c @@ -22,6 +22,7 @@ #include "testutils.h" #include "testutilsqemu.h" #include "security/security_manager.h" +#include "security/security_util.h" #include "conf/domain_conf.h" #include "qemu/qemu_domain.h" #include "qemu/qemu_security.h" @@ -148,6 +149,11 @@ mymain(void) qemuTestDriverInit(&driver) < 0) return -1;
+ if (!virSecurityXATTRNamespaceDefined()) { + ret = EXIT_AM_SKIP; + goto cleanup; + } + /* Now fix the secdriver */ virObjectUnref(driver.securityManager);
-- 2.26.2
Reviewed-by: Roman Bolshakov <r.bolshakov@yadro.com>

The remember owner feature uses XATTRs to store original seclabels. But that means we don't want a regular user to be able to change what we stored and thus trick us into setting different seclabel. Therefore, we use namespaces that are reserved to CAP_SYS_ADMIN only. Such namespaces exist on Linux and FreeBSD. That also means, that the whole feature is enabled only for qemu:///system. Now, while the secdriver code is capable of dealing with XATTRs being unsupported (it has to, not all filesystems support them) if the feature is enabled users will get an harmless error message in the logs and the feature disables itself. Since we have virSecurityXATTRNamespaceDefined() we can use it to make a wiser decision on the default state of the feature. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_conf.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index ead9d1ee99..923aea8bd7 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -49,6 +49,7 @@ #include "storage_conf.h" #include "virutil.h" #include "configmake.h" +#include "security/security_util.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -131,7 +132,11 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged, cfg->group = (gid_t)-1; } cfg->dynamicOwnership = privileged; - cfg->rememberOwner = privileged; + + if (privileged) + cfg->rememberOwner = virSecurityXATTRNamespaceDefined(); + else + cfg->rememberOwner = false; cfg->cgroupControllers = -1; /* -1 == auto-detect */ -- 2.26.2

On Tue, Nov 03, 2020 at 02:13:29PM +0100, Michal Privoznik wrote:
The remember owner feature uses XATTRs to store original seclabels. But that means we don't want a regular user to be able to change what we stored and thus trick us into setting different seclabel. Therefore, we use namespaces that are reserved to CAP_SYS_ADMIN only. Such namespaces exist on Linux and FreeBSD. That also means, that the whole feature is enabled only for qemu:///system. Now, while the secdriver code is capable of dealing with XATTRs being unsupported (it has to, not all filesystems support them) if the feature is enabled users will get an harmless error message in the logs and the feature disables itself.
Since we have virSecurityXATTRNamespaceDefined() we can use it to make a wiser decision on the default state of the feature.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com> --- src/qemu/qemu_conf.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index ead9d1ee99..923aea8bd7 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -49,6 +49,7 @@ #include "storage_conf.h" #include "virutil.h" #include "configmake.h" +#include "security/security_util.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -131,7 +132,11 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged, cfg->group = (gid_t)-1; } cfg->dynamicOwnership = privileged; - cfg->rememberOwner = privileged; + + if (privileged) + cfg->rememberOwner = virSecurityXATTRNamespaceDefined(); + else + cfg->rememberOwner = false;
cfg->cgroupControllers = -1; /* -1 == auto-detect */
-- 2.26.2
Reviewed-by: Roman Bolshakov <r.bolshakov@yadro.com> Thanks, Roman

On Tue, Nov 03, 2020 at 02:13:25PM +0100, Michal Privoznik wrote:
These were sparked by a discussion on the list where the test is failing on macOS.
Hi Michal, Thanks for helping with the issue. I have applied the series and qemusecuritytest doesn't fail anymore. So, for the series: Tested-By: Roman Bolshakov <r.bolshakov@yadro.com> Regards, Roman

On Tue, 2020-11-03 at 14:13 +0100, Michal Privoznik wrote:
These were sparked by a discussion on the list where the test is failing on macOS.
Michal Prívozník (4): security_util: Don't error on macOS when getting/setting/moving XATTRs qemusecuritytest: Test SELinux too qemusecuritytest: Skip on non supported platforms qemu_conf: Don't even attempt to enable rememberOwner if unsupported
Reviewed-by: Andrea Bolognani <abologna@redhat.com> -- Andrea Bolognani / Red Hat / Virtualization
participants (3)
-
Andrea Bolognani
-
Michal Privoznik
-
Roman Bolshakov