From 3bceb391d14aeebb21dd9742108fa98945a32c5c Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 5 May 2020 16:44:14 +0100 Subject: [PATCH] mlcustomize: Refactor SELinux_relabel code. This shouldn't change the effect of this code. Cherry picked from libguestfs-common commit 3493d9fcaab6de1c09528e55a01bc24f0fb6c03c and backported to libguestfs 1.40 branch (which predates the common submodule). --- customize/SELinux_relabel.ml | 127 +++++++++++++++++++---------------- 1 file changed, 68 insertions(+), 59 deletions(-) diff --git a/customize/SELinux_relabel.ml b/customize/SELinux_relabel.ml index 44995df6b..5df1f0895 100644 --- a/customize/SELinux_relabel.ml +++ b/customize/SELinux_relabel.ml @@ -28,65 +28,74 @@ module G = Guestfs let array_find a l = List.mem a (Array.to_list l) -let relabel (g : G.guestfs) = - (* Is the guest using SELinux? *) - if g#is_file ~followsymlinks:true "/usr/sbin/load_policy" && - g#is_file ~followsymlinks:true "/etc/selinux/config" then ( - (* Is setfiles / SELinux relabelling functionality available? *) - if g#feature_available [| "selinuxrelabel" |] then ( - (* Use Augeas to parse /etc/selinux/config. *) - g#aug_init "/" (16+32) (* AUG_SAVE_NOOP | AUG_NO_LOAD *); - (* See: https://bugzilla.redhat.com/show_bug.cgi?id=975412#c0 *) - ignore (g#aug_rm "/augeas/load/*[\"/etc/selinux/config/\" !~ regexp('^') + glob(incl) + regexp('/.*')]"); - g#aug_load (); - debug_augeas_errors g; - - (* Get the SELinux policy name, eg. "targeted", "minimum". - * Use "targeted" if not specified, just like libselinux does. - *) - let policy = - let config_path = "/files/etc/selinux/config" in - let selinuxtype_path = config_path ^ "/SELINUXTYPE" in - let keys = g#aug_ls config_path in - if array_find selinuxtype_path keys then - g#aug_get selinuxtype_path - else - "targeted" in - - g#aug_close (); - - (* Get the spec file name. *) - let specfile = - sprintf "/etc/selinux/%s/contexts/files/file_contexts" policy in - - (* RHEL 6.2 - 6.5 had a malformed specfile that contained the - * invalid regular expression "/var/run/spice-vdagentd.\pid" - * (instead of "\.p"). This stops setfiles from working on - * the guest. - * - * Because an SELinux relabel writes all over the filesystem, - * it seems reasonable to fix this problem in the specfile - * at the same time. (RHBZ#1374232) - *) - if g#grep ~fixed:true "vdagentd.\\pid" specfile <> [||] then ( - debug "fixing invalid regular expression in %s" specfile; - let old_specfile = specfile ^ "~" in - g#mv specfile old_specfile; - let content = g#read_file old_specfile in - let content = - String.replace content "vdagentd.\\pid" "vdagentd\\.pid" in - g#write specfile content; - g#copy_attributes ~all:true old_specfile specfile - ); - - (* Relabel everything. *) - g#selinux_relabel ~force:true specfile "/"; - - (* If that worked, we don't need to autorelabel. *) +let rec relabel (g : G.guestfs) = + (* Is the guest using SELinux? (Otherwise this is a no-op). *) + if is_selinux_guest g then ( + try + use_setfiles g; + (* That worked, so we don't need to autorelabel. *) g#rm_f "/.autorelabel" - ) - else ( - (* SELinux guest, but not SELinux host. Fallback to this. *) + with Failure _ -> + (* This is the fallback in case something in the setfiles + * method didn't work. That includes the case where a non-SELinux + * host is processing an SELinux guest, and other things. + *) g#touch "/.autorelabel" - ) ) + +and is_selinux_guest g = + g#is_file ~followsymlinks:true "/usr/sbin/load_policy" && + g#is_file ~followsymlinks:true "/etc/selinux/config" + +and use_setfiles g = + (* Is setfiles / SELinux relabelling functionality available? *) + if not (g#feature_available [| "selinuxrelabel" |]) then + failwith "no selinux relabel feature"; + + (* Use Augeas to parse /etc/selinux/config. *) + g#aug_init "/" (16+32) (* AUG_SAVE_NOOP | AUG_NO_LOAD *); + (* See: https://bugzilla.redhat.com/show_bug.cgi?id=975412#c0 *) + ignore (g#aug_rm "/augeas/load/*[\"/etc/selinux/config/\" !~ regexp('^') + glob(incl) + regexp('/.*')]"); + g#aug_load (); + debug_augeas_errors g; + + (* Get the SELinux policy name, eg. "targeted", "minimum". + * Use "targeted" if not specified, just like libselinux does. + *) + let policy = + let config_path = "/files/etc/selinux/config" in + let selinuxtype_path = config_path ^ "/SELINUXTYPE" in + let keys = g#aug_ls config_path in + if array_find selinuxtype_path keys then + g#aug_get selinuxtype_path + else + "targeted" in + + g#aug_close (); + + (* Get the spec file name. *) + let specfile = + sprintf "/etc/selinux/%s/contexts/files/file_contexts" policy in + + (* RHEL 6.2 - 6.5 had a malformed specfile that contained the + * invalid regular expression "/var/run/spice-vdagentd.\pid" + * (instead of "\.p"). This stops setfiles from working on + * the guest. + * + * Because an SELinux relabel writes all over the filesystem, + * it seems reasonable to fix this problem in the specfile + * at the same time. (RHBZ#1374232) + *) + if g#grep ~fixed:true "vdagentd.\\pid" specfile <> [||] then ( + debug "fixing invalid regular expression in %s" specfile; + let old_specfile = specfile ^ "~" in + g#mv specfile old_specfile; + let content = g#read_file old_specfile in + let content = + String.replace content "vdagentd.\\pid" "vdagentd\\.pid" in + g#write specfile content; + g#copy_attributes ~all:true old_specfile specfile + ); + + (* Relabel everything. *) + g#selinux_relabel ~force:true specfile "/" -- 2.18.4