]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: move selinux stuff to hook module
authorKarel Zak <kzak@redhat.com>
Wed, 22 Feb 2023 20:26:11 +0000 (21:26 +0100)
committerKarel Zak <kzak@redhat.com>
Wed, 22 Feb 2023 20:30:01 +0000 (21:30 +0100)
 * convert selinux contexts to raw format during "prep-options" stage

 * convert rootcontext=@target to raw context when final mountpoint
   path is available (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.c [new file with mode: 0644]
libmount/src/hook_selinux_target.c [deleted file]
libmount/src/hooks.c
libmount/src/mountP.h

index 49b9ea7bf9ea1588a91cbc92401b6974147fb137..42b6b75e67fa82a4475e18c6fea181d3b70e2e3f 100644 (file)
@@ -47,7 +47,7 @@ if LINUX
     src/hook_mount.c
     src/hook_mount_legacy.c
     src/hook_mkdir.c
-    src/hook_selinux_target.c
+    src/hook_selinux.c
     src/hook_loopdev.c
     src/hook_idmap.c
     src/context_umount.c
index d0c1d2236ba787e5461bec994bd442a57fbc5c9b..d474aea0c71895226a889905e5ca4cc0a915aa44 100644 (file)
@@ -34,7 +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_selinux.c \
        libmount/src/hook_subdir.c \
        libmount/src/hook_owner.c \
        libmount/src/hook_idmap.c \
index 16741c9fd4de041b47065ccddf269df2f40b5934..614cf1901b1a868cde204c360528fd8c676a1e88 100644 (file)
  * @title: Mount context
  * @short_description: high-level API to mount operation.
  */
-
-#ifdef HAVE_LIBSELINUX
-#include <selinux/selinux.h>
-#include <selinux/context.h>
-#endif
-
 #include <sys/wait.h>
 #include <sys/mount.h>
 
-#include "linux_version.h"
 #include "mountP.h"
 #include "strutils.h"
 
-#if defined(HAVE_LIBSELINUX) || defined(HAVE_SMACK)
+#if defined(HAVE_SMACK)
 static int is_option(const char *name, const char *const *names)
 {
        const char *const *p;
@@ -39,7 +32,7 @@ static int is_option(const char *name, const char *const *names)
        }
        return 0;
 }
-#endif /* HAVE_LIBSELINUX || HAVE_SMACK */
+#endif /* HAVE_SMACK */
 
 /*
  * this has to be called after mnt_context_evaluate_permissions()
@@ -51,9 +44,7 @@ static int fix_optstr(struct libmnt_context *cxt)
        struct libmnt_ns *ns_old;
        const char *val;
        int rc = 0;
-#ifdef HAVE_LIBSELINUX
-       int se_fix = 0, se_rem = 0;
-#endif
+
        assert(cxt);
        assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
 
@@ -120,76 +111,6 @@ static int fix_optstr(struct libmnt_context *cxt)
        if (!mnt_context_switch_ns(cxt, ns_old))
                return -MNT_ERR_NAMESPACE;
 
-#ifdef HAVE_LIBSELINUX
-       if (!is_selinux_enabled())
-               /* Always remove SELinux garbage if SELinux disabled */
-               se_rem = 1;
-       else if (mnt_optlist_is_remount(ol))
-               /*
-                * Linux kernel < 2.6.39 does not support remount operation
-                * with any selinux specific mount options.
-                *
-                * Kernel 2.6.39 commits:  ff36fe2c845cab2102e4826c1ffa0a6ebf487c65
-                *                         026eb167ae77244458fa4b4b9fc171209c079ba7
-                * fix this odd behavior, so we don't have to care about it in
-                * userspace.
-                */
-               se_rem = get_linux_version() < KERNEL_VERSION(2, 6, 39);
-       else
-               /* For normal mount, contexts are translated */
-               se_fix = 1;
-
-       /* Fix SELinux contexts */
-       if (se_rem || se_fix) {
-               static const char *const selinux_options[] = {
-                       "context",
-                       "fscontext",
-                       "defcontext",
-                       "rootcontext",
-                       "seclabel",
-                       NULL
-               };
-               struct libmnt_iter itr;
-
-               mnt_reset_iter(&itr, MNT_ITER_FORWARD);
-
-               while (mnt_optlist_next_opt(ol, &itr, &opt) == 0) {
-                       const char *opt_name = mnt_opt_get_name(opt);
-
-                       if (!is_option(opt_name, selinux_options))
-                               continue;
-                       if (se_rem)
-                               rc = mnt_optlist_remove_opt(ol, opt);
-                       else if (se_fix && mnt_opt_has_value(opt)) {
-                               const char *val = mnt_opt_get_value(opt);
-                               char *raw = NULL;
-
-                               /* @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;
-                               }
-                               if (!rc)
-                                       rc = mnt_opt_set_quoted_value(opt, raw);
-                               if (raw)
-                                       freecon(raw);
-
-                               /* temporary for broken fsconfig() syscall */
-                               cxt->has_selinux_opt = 1;
-                       }
-                       if (rc)
-                               goto done;
-               }
-       }
-#endif
-
 #ifdef HAVE_SMACK
        /* Fix Smack */
        if (access("/sys/fs/smackfs", F_OK) != 0) {
diff --git a/libmount/src/hook_selinux.c b/libmount/src/hook_selinux.c
new file mode 100644 (file)
index 0000000..d6bae95
--- /dev/null
@@ -0,0 +1,203 @@
+/* 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.
+ */
+#ifdef HAVE_LIBSELINUX
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+
+#include "mountP.h"
+#include "fileutils.h"
+#include "linux_version.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 inline int is_option(const char *name, const char *const *names)
+{
+       const char *const *p;
+
+       for (p = names; p && *p; p++) {
+               if (strcmp(name, *p) == 0)
+                       return 1;
+       }
+       return 0;
+}
+
+/* Converts rootcontext=@target to the real selinxu context
+ */
+static int hook_selinux_target(
+                       struct libmnt_context *cxt,
+                       const struct libmnt_hookset *hs,
+                       void *data __attribute__((__unused__)))
+{
+       struct libmnt_optlist *ol;
+       struct libmnt_opt *opt;
+       const char *tgt, *val;
+       char *raw = NULL;
+       int rc = 0;
+
+       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;
+               DBG(HOOK, ul_debugobj(hs, " SELinux fix @target failed [rc=%d]", rc));
+       } else {
+               DBG(HOOK, ul_debugobj(hs, " SELinux fix @target to %s", raw));
+               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 != 0 ? -MNT_ERR_MOUNTOPT : 0;
+}
+
+static int hook_prepare_options(
+                       struct libmnt_context *cxt,
+                       const struct libmnt_hookset *hs,
+                       void *data __attribute__((__unused__)))
+{
+       int rc = 0, se_fix = 0, se_rem = 0;
+       struct libmnt_optlist *ol;
+
+       assert(cxt);
+
+       ol = mnt_context_get_optlist(cxt);
+       if (!ol)
+               return -EINVAL;
+
+       if (!is_selinux_enabled())
+               /* Always remove SELinux garbage if SELinux disabled */
+               se_rem = 1;
+       else if (mnt_optlist_is_remount(ol))
+               /*
+                * Linux kernel < 2.6.39 does not support remount operation
+                * with any selinux specific mount options.
+                *
+                * Kernel 2.6.39 commits:  ff36fe2c845cab2102e4826c1ffa0a6ebf487c65
+                *                         026eb167ae77244458fa4b4b9fc171209c079ba7
+                * fix this odd behavior, so we don't have to care about it in
+                * userspace.
+                */
+               se_rem = get_linux_version() < KERNEL_VERSION(2, 6, 39);
+       else
+               /* For normal mount, contexts are translated */
+               se_fix = 1;
+
+       DBG(HOOK, ul_debugobj(hs, " SELinux fix options"));
+
+       /* Fix SELinux contexts */
+       if (se_rem || se_fix) {
+               static const char *const selinux_options[] = {
+                       "context",
+                       "fscontext",
+                       "defcontext",
+                       "rootcontext",
+                       "seclabel",
+                       NULL
+               };
+               struct libmnt_iter itr;
+               struct libmnt_opt *opt;
+
+               mnt_reset_iter(&itr, MNT_ITER_FORWARD);
+
+               while (mnt_optlist_next_opt(ol, &itr, &opt) == 0) {
+                       const char *opt_name = mnt_opt_get_name(opt);
+
+                       if (!is_option(opt_name, selinux_options))
+                               continue;
+                       if (se_rem)
+                               rc = mnt_optlist_remove_opt(ol, opt);
+                       else if (se_fix && mnt_opt_has_value(opt)) {
+                               const char *val = mnt_opt_get_value(opt);
+                               char *raw = NULL;
+
+                               /* @target placeholder is replaced later when target
+                                * is already avalable. The mountpoint does not have to exist
+                                * yet (for example "-o X-mount.mkdir=" or --target-prefix).
+                                */
+                               if (strcmp(opt_name, "rootcontext") == 0 &&
+                                   strcmp(val, "@target") == 0) {
+                                       rc = mnt_context_insert_hook(cxt, "__mkdir",
+                                                      hs, MNT_STAGE_PREP_TARGET, NULL,
+                                                      hook_selinux_target);
+                                       continue;
+                               } else {
+                                       rc = selinux_trans_to_raw_context(val, &raw);
+                                       if (rc == -1 || !raw)
+                                               rc = -EINVAL;
+                               }
+                               if (!rc) {
+                                       DBG(HOOK, ul_debugobj(hs, "  %s: %s to %s",
+                                                               opt_name, val, raw));
+                                       rc = mnt_opt_set_quoted_value(opt, raw);
+                               }
+                               if (raw)
+                                       freecon(raw);
+
+                               /* temporary for broken fsconfig() syscall */
+                               cxt->has_selinux_opt = 1;
+                       }
+                       if (rc)
+                               break;
+               }
+       }
+
+       return rc != 0 ? -MNT_ERR_MOUNTOPT : 0;
+}
+
+const struct libmnt_hookset hookset_selinux =
+{
+       .name = "__selinux",
+
+       .firststage = MNT_STAGE_PREP_OPTIONS,
+       .firstcall = hook_prepare_options,
+
+       .deinit = hookset_deinit
+};
+
+#endif /* HAVE_LIBSELINUX */
diff --git a/libmount/src/hook_selinux_target.c b/libmount/src/hook_selinux_target.c
deleted file mode 100644 (file)
index d66e55a..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/* 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 db204ec28ec92a47d62b40c555846c8484c015a9..c8d45d47915842ca17ea94d5f7d8554e1e81c318 100644 (file)
@@ -39,7 +39,7 @@ static const struct libmnt_hookset *hooksets[] =
 #endif
        &hookset_mkdir,
 #ifdef HAVE_LIBSELINUX
-       &hookset_selinux_target,
+       &hookset_selinux,
 #endif
        &hookset_subdir,
 #ifdef USE_LIBMOUNT_MOUNTFD_SUPPORT
index e390f39b28960f3eb38b8f0e539b9f8fc2dd3b26..d522799c59cf56540b0b49da690aac8846d59a09 100644 (file)
@@ -324,7 +324,7 @@ extern const struct libmnt_hookset hookset_loopdev;
 extern const struct libmnt_hookset hookset_veritydev;
 #endif
 #ifdef HAVE_LIBSELINUX
-extern const struct libmnt_hookset hookset_selinux_target;
+extern const struct libmnt_hookset hookset_selinux;
 #endif
 
 extern int mnt_context_deinit_hooksets(struct libmnt_context *cxt);