]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: create a hook to set rootcontext=@target
authorKarel Zak <kzak@redhat.com>
Wed, 22 Feb 2023 12:00:29 +0000 (13:00 +0100)
committerKarel Zak <kzak@redhat.com>
Wed, 22 Feb 2023 12:00:29 +0000 (13:00 +0100)
The final target (mountpoint) depends on others libmount functionality
(X-mount.mkdir or --target-prefix). It means we cannot assume target
when the library calls fix_opts() and translates selinux contexts.

The solution is extra hook executed after mkdir.

Signed-off-by: Karel Zak <kzak@redhat.com>
libmount/meson.build
libmount/src/Makemodule.am
libmount/src/context_mount.c
libmount/src/hook_selinux_target.c [new file with mode: 0644]
libmount/src/hooks.c
libmount/src/mountP.h

index 4764fcd70fd3268863021bd1491179820dc86dbb..49b9ea7bf9ea1588a91cbc92401b6974147fb137 100644 (file)
@@ -47,6 +47,7 @@ if LINUX
     src/hook_mount.c
     src/hook_mount_legacy.c
     src/hook_mkdir.c
+    src/hook_selinux_target.c
     src/hook_loopdev.c
     src/hook_idmap.c
     src/context_umount.c
index 437e47006de64edd38ca99c2b42d5e6af7664153..d0c1d2236ba787e5461bec994bd442a57fbc5c9b 100644 (file)
@@ -34,6 +34,7 @@ libmount_la_SOURCES += \
        libmount/src/hook_mount.c \
        libmount/src/hook_mount_legacy.c \
        libmount/src/hook_mkdir.c \
+       libmount/src/hook_selinux_target.c \
        libmount/src/hook_subdir.c \
        libmount/src/hook_owner.c \
        libmount/src/hook_idmap.c \
index eba64b6c2497b38eaa6c4377a115869a46bc8533..16741c9fd4de041b47065ccddf269df2f40b5934 100644 (file)
@@ -164,13 +164,14 @@ static int fix_optstr(struct libmnt_context *cxt)
                                const char *val = mnt_opt_get_value(opt);
                                char *raw = NULL;
 
-                               if (strcmp(opt_name, "rootcontext") == 0 && strcmp(val, "@target") == 0) {
-                                       rc = getfilecon_raw(cxt->fs->target, &raw);
-                                       if (rc <= 0 || !raw)
-                                               rc = errno ? -errno : -EINVAL;
-                                       else
-                                               rc = 0;  /* getfilecon_raw(3) returns the size of the extended attribute value */
-                               } else {
+                               /* @target placeholder is replaced in hook_selinux_target.c,
+                                * because the mountpoint does not have to existe yet
+                                * (for example "-o X-mount.mkdir=" or --target-prefix).
+                                */
+                               if (strcmp(opt_name, "rootcontext") == 0 &&
+                                   strcmp(val, "@target") == 0)
+                                       continue;
+                               else {
                                        rc = selinux_trans_to_raw_context(val, &raw);
                                        if (rc == -1 || !raw)
                                                rc = -EINVAL;
diff --git a/libmount/src/hook_selinux_target.c b/libmount/src/hook_selinux_target.c
new file mode 100644 (file)
index 0000000..d66e55a
--- /dev/null
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * This file is part of libmount from util-linux project.
+ *
+ * Copyright (C) 2023 Karel Zak <kzak@redhat.com>
+ *
+ * libmount 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.
+ *
+ *
+ * Please, see the comment in libmount/src/hooks.c to understand how hooks work.
+ */
+#include "mountP.h"
+#include "fileutils.h"
+
+#ifdef HAVE_LIBSELINUX
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+
+static int hookset_deinit(struct libmnt_context *cxt, const struct libmnt_hookset *hs)
+{
+       void *data = NULL;
+
+       DBG(HOOK, ul_debugobj(hs, "deinit '%s'", hs->name));
+
+       /* remove all our hooks and free hook data */
+       while (mnt_context_remove_hook(cxt, hs, 0, &data) == 0) {
+               if (data)
+                       free(data);
+               data = NULL;
+       }
+
+       return 0;
+}
+
+static int hook_prepare_target(
+                       struct libmnt_context *cxt,
+                       const struct libmnt_hookset *hs __attribute__((__unused__)),
+                       void *data __attribute__((__unused__)))
+{
+       int rc = 0;
+       const char *tgt, *val;
+       char *raw = NULL;
+       struct libmnt_optlist *ol;
+       struct libmnt_opt *opt;
+
+       assert(cxt);
+
+       tgt = mnt_fs_get_target(cxt->fs);
+       if (!tgt)
+               return 0;
+       if (cxt->action != MNT_ACT_MOUNT)
+               return 0;
+
+       ol = mnt_context_get_optlist(cxt);
+       if (!ol)
+               return -EINVAL;
+
+       opt = mnt_optlist_get_named(ol, "rootcontext", NULL);
+       if (!opt)
+               return 0;
+       val = mnt_opt_get_value(opt);
+       if (!val || strcmp(val, "@target") != 0)
+               return 0;
+
+       rc = getfilecon_raw(tgt, &raw);
+       if (rc <= 0 || !raw)
+               rc = errno ? -errno : -EINVAL;
+       else
+               rc = 0; /* getfilecon_raw(3) returns the size of the extended attribute value */
+
+       if (!rc)
+               rc = mnt_opt_set_quoted_value(opt, raw);
+       if (raw)
+               freecon(raw);
+
+       return rc;
+}
+
+const struct libmnt_hookset hookset_selinux_target =
+{
+       .name = "__selinux_target",
+
+       .firststage = MNT_STAGE_PREP_TARGET,
+       .firstcall = hook_prepare_target,
+
+       .deinit = hookset_deinit
+};
+
+#endif /* HAVE_LIBSELINUX */
index 539d440f652de170cef5a0894cdf65ace84a2da5..2dd795590b428721ef3aa3adbb0829c72e554a44 100644 (file)
@@ -38,6 +38,9 @@ static const struct libmnt_hookset *hooksets[] =
        &hookset_veritydev,
 #endif
        &hookset_mkdir,
+#ifdef HAVE_LIBSELINUX
+       &hookset_selinux_target,
+#endif
        &hookset_subdir,
 #ifdef USE_LIBMOUNT_MOUNTFD_SUPPORT
        &hookset_mount,
index 80015f94c346d72d00a08712e4020ab5ca1d7bc2..38c0a6d5123e27b61f47fcc19bde4921488640da 100644 (file)
@@ -323,6 +323,9 @@ extern const struct libmnt_hookset hookset_loopdev;
 #ifdef HAVE_CRYPTSETUP
 extern const struct libmnt_hookset hookset_veritydev;
 #endif
+#ifdef HAVE_LIBSELINUX
+extern const struct libmnt_hookset hookset_selinux_target;
+#endif
 
 extern int mnt_context_deinit_hooksets(struct libmnt_context *cxt);
 extern const struct libmnt_hookset *mnt_context_get_hookset(struct libmnt_context *cxt, const char *name);