312 lines
12 KiB
Diff
312 lines
12 KiB
Diff
From 1c0b56158aa63359d1e53f7a31b483194f235a34 Mon Sep 17 00:00:00 2001
|
|
From: "Richard W.M. Jones" <rjones@redhat.com>
|
|
Date: Tue, 12 Aug 2025 13:27:32 +0100
|
|
Subject: [PATCH] daemon: Deprecate guestfs_selinux_relabel, replace with
|
|
guestfs_setfiles
|
|
|
|
The guestfs_selinux_relabel function was very hard to use. In
|
|
particular it didn't just do an SELinux relabel as you might expect.
|
|
Instead you have to write a whole bunch of code around it (example[1])
|
|
to make it useful.
|
|
|
|
Another problem is that it doesn't let you pass multiple paths to the
|
|
setfiles command, but the command itself does permit that (and, as it
|
|
turns out, will require it). There is no backwards compatible way to
|
|
extend the existing definition to allow a list parameter without
|
|
breaking API.
|
|
|
|
So deprecate guestfs_selinux_relabel. Reimplement it as
|
|
guestfs_setfiles. The new function is basically the same as the old
|
|
one, but allows you to pass a list of paths. The old function calls
|
|
the new function with a single path parameter.
|
|
|
|
[1] https://github.com/libguestfs/libguestfs-common/blob/master/mlcustomize/SELinux_relabel.ml
|
|
---
|
|
daemon/selinux.ml | 117 ++++++++++++++-------------
|
|
generator/actions_core.ml | 49 +++++------
|
|
generator/actions_core_deprecated.ml | 24 ++++++
|
|
generator/proc_nr.ml | 1 +
|
|
gobject/Makefile.inc | 2 +
|
|
lib/MAX_PROC_NR | 2 +-
|
|
tests/relabel/test-relabel.pl | 2 +-
|
|
7 files changed, 117 insertions(+), 80 deletions(-)
|
|
|
|
diff --git a/daemon/selinux.ml b/daemon/selinux.ml
|
|
index d954fdead..db0d71455 100644
|
|
--- a/daemon/selinux.ml
|
|
+++ b/daemon/selinux.ml
|
|
@@ -44,58 +44,65 @@ let setfiles_has_option_m,
|
|
(fun () -> Lazy.force setfiles_has_option_C),
|
|
(fun () -> Lazy.force setfiles_has_option_T)
|
|
|
|
-let selinux_relabel ?(force = false) specfile path =
|
|
- (* Prefix /sysroot on all paths. *)
|
|
- let ignored_paths =
|
|
- [ "/dev"; "/proc"; "/selinux"; "/sys" ] |>
|
|
- List.map sysroot_path in
|
|
- let specfile = sysroot_path specfile in
|
|
- let path = sysroot_path path in
|
|
-
|
|
- let args = ref [] in
|
|
- if force then List.push_back args "-F";
|
|
- List.iter (
|
|
- fun ignored_path ->
|
|
- List.push_back_list args [ "-e"; ignored_path ]
|
|
- ) ignored_paths;
|
|
-
|
|
- (* You have to use the -m option (where available) otherwise
|
|
- * setfiles puts all the mountpoints on the excludes list for no
|
|
- * useful reason (RHBZ#1433577).
|
|
- *)
|
|
- if setfiles_has_option_m () then List.push_back args "-m";
|
|
-
|
|
- (* Not only do we want setfiles to trudge through individual relabeling
|
|
- * errors, we also want the setfiles exit status to differentiate a fatal
|
|
- * error from "relabeling errors only". See RHBZ#1794518.
|
|
- *)
|
|
- if setfiles_has_option_C () then List.push_back args "-C";
|
|
-
|
|
- (* If the appliance is being run with multiple vCPUs, running setfiles
|
|
- * in multithreading mode might speeds up the process. Option "-T" was
|
|
- * introduced in SELinux userspace v3.4, and we need to check whether it's
|
|
- * supported. Passing "-T 0" creates as many threads as there're available
|
|
- * vCPU cores.
|
|
- * https://github.com/SELinuxProject/selinux/releases/tag/3.4
|
|
- *)
|
|
- if setfiles_has_option_T () then
|
|
- List.push_back_list args [ "-T"; "0" ];
|
|
-
|
|
- (* Relabelling in a chroot. *)
|
|
- if sysroot () <> "/" then
|
|
- List.push_back_list args [ "-r"; sysroot () ];
|
|
-
|
|
- if verbose () then
|
|
- List.push_back args "-v"
|
|
- else
|
|
- (* Suppress non-error output. *)
|
|
- List.push_back args "-q";
|
|
-
|
|
- (* Add parameters. *)
|
|
- List.push_back_list args [ specfile; path ];
|
|
-
|
|
- let args = !args in
|
|
- let r, _, err = commandr "setfiles" args in
|
|
-
|
|
- let ok = r = 0 || r = 1 && setfiles_has_option_C () in
|
|
- if not ok then failwithf "setfiles: %s" err
|
|
+let setfiles ?(force = false) specfile paths =
|
|
+ if paths = [] then ()
|
|
+ else (
|
|
+ (* Prefix /sysroot on all paths. *)
|
|
+ let ignored_paths =
|
|
+ [ "/dev"; "/proc"; "/selinux"; "/sys" ] |>
|
|
+ List.map sysroot_path in
|
|
+ let specfile = sysroot_path specfile in
|
|
+ let paths = List.map sysroot_path paths in
|
|
+
|
|
+ let args = ref [] in
|
|
+ if force then List.push_back args "-F";
|
|
+ List.iter (
|
|
+ fun ignored_path ->
|
|
+ List.push_back_list args [ "-e"; ignored_path ]
|
|
+ ) ignored_paths;
|
|
+
|
|
+ (* You have to use the -m option (where available) otherwise
|
|
+ * setfiles puts all the mountpoints on the excludes list for no
|
|
+ * useful reason (RHBZ#1433577).
|
|
+ *)
|
|
+ if setfiles_has_option_m () then List.push_back args "-m";
|
|
+
|
|
+ (* Not only do we want setfiles to trudge through individual relabeling
|
|
+ * errors, we also want the setfiles exit status to differentiate a fatal
|
|
+ * error from "relabeling errors only". See RHBZ#1794518.
|
|
+ *)
|
|
+ if setfiles_has_option_C () then List.push_back args "-C";
|
|
+
|
|
+ (* If the appliance is being run with multiple vCPUs, running setfiles
|
|
+ * in multithreading mode might speeds up the process. Option "-T" was
|
|
+ * introduced in SELinux userspace v3.4, and we need to check whether it's
|
|
+ * supported. Passing "-T 0" creates as many threads as there're available
|
|
+ * vCPU cores.
|
|
+ * https://github.com/SELinuxProject/selinux/releases/tag/3.4
|
|
+ *)
|
|
+ if setfiles_has_option_T () then
|
|
+ List.push_back_list args [ "-T"; "0" ];
|
|
+
|
|
+ (* Relabelling in a chroot. *)
|
|
+ if sysroot () <> "/" then
|
|
+ List.push_back_list args [ "-r"; sysroot () ];
|
|
+
|
|
+ if verbose () then
|
|
+ List.push_back args "-v"
|
|
+ else
|
|
+ (* Suppress non-error output. *)
|
|
+ List.push_back args "-q";
|
|
+
|
|
+ (* Add parameters. *)
|
|
+ List.push_back args specfile;
|
|
+ List.push_back_list args paths;
|
|
+
|
|
+ let args = !args in
|
|
+ let r, _, err = commandr "setfiles" args in
|
|
+
|
|
+ let ok = r = 0 || r = 1 && setfiles_has_option_C () in
|
|
+ if not ok then failwithf "setfiles: %s" err
|
|
+ )
|
|
+
|
|
+(* This is the deprecated selinux_relabel function from libguestfs <= 1.56. *)
|
|
+let selinux_relabel ?force specfile path = setfiles ?force specfile [path]
|
|
diff --git a/generator/actions_core.ml b/generator/actions_core.ml
|
|
index 128cbe0e9..60d3140ed 100644
|
|
--- a/generator/actions_core.ml
|
|
+++ b/generator/actions_core.ml
|
|
@@ -9356,29 +9356,6 @@ Show all the devices where the filesystems in C<device> is spanned over.
|
|
If not all the devices for the filesystems are present, then this function
|
|
fails and the C<errno> is set to C<ENODEV>." };
|
|
|
|
- { defaults with
|
|
- name = "selinux_relabel"; added = (1, 33, 43);
|
|
- style = RErr, [String (PlainString, "specfile"); String (Pathname, "path")], [OBool "force"];
|
|
- impl = OCaml "Selinux.selinux_relabel";
|
|
- optional = Some "selinuxrelabel";
|
|
- test_excuse = "tests are in the tests/relabel directory";
|
|
- shortdesc = "relabel parts of the filesystem";
|
|
- longdesc = "\
|
|
-SELinux relabel parts of the filesystem.
|
|
-
|
|
-The C<specfile> parameter controls the policy spec file used.
|
|
-You have to parse C</etc/selinux/config> to find the correct
|
|
-SELinux policy and then pass the spec file, usually:
|
|
-C</etc/selinux/> + I<selinuxtype> + C</contexts/files/file_contexts>.
|
|
-
|
|
-The required C<path> parameter is the top level directory where
|
|
-relabelling starts. Normally you should pass C<path> as C</>
|
|
-to relabel the whole guest filesystem.
|
|
-
|
|
-The optional C<force> boolean controls whether the context
|
|
-is reset for customizable files, and also whether the
|
|
-user, role and range parts of the file context is changed." };
|
|
-
|
|
{ defaults with
|
|
name = "mksquashfs"; added = (1, 35, 25);
|
|
style = RErr, [String (Pathname, "path"); String (FileOut, "filename")], [OString "compress"; OStringList "excludes"];
|
|
@@ -9820,4 +9797,30 @@ them visible.
|
|
|
|
Use C<guestfs_list_dm_devices> to list all device mapper devices." };
|
|
|
|
+ { defaults with
|
|
+ name = "setfiles"; added = (1, 57, 1);
|
|
+ style = RErr, [String (PlainString, "specfile"); StringList (Pathname, "paths")], [OBool "force"];
|
|
+ impl = OCaml "Selinux.setfiles";
|
|
+ optional = Some "selinuxrelabel";
|
|
+ test_excuse = "tests are in the tests/relabel directory";
|
|
+ shortdesc = "low level relabel parts of the filesystem";
|
|
+ longdesc = "\
|
|
+This invokes the SELinux C<setfiles> command which is a low
|
|
+level tool used to relabel parts of the filesystem.
|
|
+
|
|
+The C<specfile> parameter controls the policy spec file used.
|
|
+You have to parse C</etc/selinux/config> to find the correct
|
|
+SELinux policy and then pass the spec file, usually:
|
|
+C</etc/selinux/> + I<selinuxtype> + C</contexts/files/file_contexts>.
|
|
+
|
|
+The required C<paths> parameter is the list of top level directories
|
|
+where relabelling starts. C<setfiles> will only relabel up to
|
|
+filesystem boundaries so, for example, passing just C<\"/\"> will
|
|
+relabel the whole root filesystem, but no other mounted filesystems.
|
|
+If the list is empty, setfiles is not called.
|
|
+
|
|
+The optional C<force> boolean controls whether the context
|
|
+is reset for customizable files, and also whether the
|
|
+user, role and range parts of the file context is changed." };
|
|
+
|
|
]
|
|
diff --git a/generator/actions_core_deprecated.ml b/generator/actions_core_deprecated.ml
|
|
index 9d4b29f9d..2b1f5cdb4 100644
|
|
--- a/generator/actions_core_deprecated.ml
|
|
+++ b/generator/actions_core_deprecated.ml
|
|
@@ -942,4 +942,28 @@ This call does nothing and returns an error." };
|
|
Used to check a btrfs filesystem, C<device> is the device file where the
|
|
filesystem is stored." };
|
|
|
|
+ { defaults with
|
|
+ name = "selinux_relabel"; added = (1, 33, 43);
|
|
+ style = RErr, [String (PlainString, "specfile"); String (Pathname, "path")], [OBool "force"];
|
|
+ impl = OCaml "Selinux.selinux_relabel";
|
|
+ optional = Some "selinuxrelabel";
|
|
+ deprecated_by = Replaced_by "setfiles";
|
|
+ test_excuse = "tests are in the tests/relabel directory";
|
|
+ shortdesc = "relabel parts of the filesystem";
|
|
+ longdesc = "\
|
|
+SELinux relabel parts of the filesystem.
|
|
+
|
|
+The C<specfile> parameter controls the policy spec file used.
|
|
+You have to parse C</etc/selinux/config> to find the correct
|
|
+SELinux policy and then pass the spec file, usually:
|
|
+C</etc/selinux/> + I<selinuxtype> + C</contexts/files/file_contexts>.
|
|
+
|
|
+The required C<path> parameter is the top level directory where
|
|
+relabelling starts. Normally you should pass C<path> as C</>
|
|
+to relabel the whole guest filesystem.
|
|
+
|
|
+The optional C<force> boolean controls whether the context
|
|
+is reset for customizable files, and also whether the
|
|
+user, role and range parts of the file context is changed." };
|
|
+
|
|
]
|
|
diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml
|
|
index 63cd72a3c..42624afef 100644
|
|
--- a/generator/proc_nr.ml
|
|
+++ b/generator/proc_nr.ml
|
|
@@ -521,6 +521,7 @@ let proc_nr = [
|
|
516, "command_out";
|
|
517, "sh_out";
|
|
518, "btrfs_scrub_full";
|
|
+519, "setfiles";
|
|
]
|
|
|
|
(* End of list. If adding a new entry, add it at the end of the list
|
|
diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc
|
|
index b54245977..b828113c6 100644
|
|
--- a/gobject/Makefile.inc
|
|
+++ b/gobject/Makefile.inc
|
|
@@ -106,6 +106,7 @@ guestfs_gobject_headers= \
|
|
include/guestfs-gobject/optargs-rsync_out.h \
|
|
include/guestfs-gobject/optargs-selinux_relabel.h \
|
|
include/guestfs-gobject/optargs-set_e2attrs.h \
|
|
+ include/guestfs-gobject/optargs-setfiles.h \
|
|
include/guestfs-gobject/optargs-syslinux.h \
|
|
include/guestfs-gobject/optargs-tar_in.h \
|
|
include/guestfs-gobject/optargs-tar_out.h \
|
|
@@ -201,6 +202,7 @@ guestfs_gobject_sources= \
|
|
src/optargs-rsync_out.c \
|
|
src/optargs-selinux_relabel.c \
|
|
src/optargs-set_e2attrs.c \
|
|
+ src/optargs-setfiles.c \
|
|
src/optargs-syslinux.c \
|
|
src/optargs-tar_in.c \
|
|
src/optargs-tar_out.c \
|
|
diff --git a/lib/MAX_PROC_NR b/lib/MAX_PROC_NR
|
|
index 9a26b94d0..08f851b6e 100644
|
|
--- a/lib/MAX_PROC_NR
|
|
+++ b/lib/MAX_PROC_NR
|
|
@@ -1 +1 @@
|
|
-518
|
|
+519
|
|
diff --git a/tests/relabel/test-relabel.pl b/tests/relabel/test-relabel.pl
|
|
index 06fb0840b..4d4f6c7ba 100755
|
|
--- a/tests/relabel/test-relabel.pl
|
|
+++ b/tests/relabel/test-relabel.pl
|
|
@@ -87,7 +87,7 @@ $g->write ("/etc/file_contexts", <<'EOF');
|
|
EOF
|
|
|
|
# Do the relabel.
|
|
-$g->selinux_relabel ("/etc/file_contexts", "/", force => 1);
|
|
+$g->setfiles ("/etc/file_contexts", ["/"], force => 1);
|
|
|
|
# Check the labels were set correctly.
|
|
my $errors = 0;
|
|
--
|
|
2.47.1
|
|
|