From 90e23b4e566f88595ac697b45d2531de851be6df Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 24 Jan 2014 19:38:26 +0000 Subject: [PATCH] builder: Add --selinux-relabel option to perform SELinux relabelling. This adds the --selinux-relabel option which enables selinux in the appliance and runs: if load_policy && fixfiles restore; then rm -f /.autorelabel else touch /.autorelabel fi at the end of installation. When possible this fixes SELinux labels in the guest and makes the autorelabel step unnecessary. Notes: - The previous commit is required so that load_policy works. - During the build, SELinux is enabled but no policy is loaded. This works because SELinux is in permissive mode. - This flag does not work if the appliance kernel and the guest have greatly differing versions, eg. a RHEL 6 guest with a Fedora 20 appliance. This is because SELinux changes the policy format and breaks backwards compatibility. You would see errors like this: libsepol.policydb_write: policy version 15 cannot support MLS libsepol.policydb_to_image: could not compute policy length libsepol.policydb_to_image: could not create policy image SELinux: Could not downgrade policy file /etc/selinux/targeted/policy/policy.24, searching for an older version. SELinux: Could not open policy file <= /etc/selinux/targeted/policy/policy.24: No such file or directory These errors are ignored (they go to the log file) and relabelling is done at boot instead. - It's not clear if loading guest policy is safe. You should trust the virt-builder templates and to use libguestfs confinement for additional protection. --- builder/builder.ml | 19 ++++++++++-- builder/cmdline.ml | 8 +++-- builder/virt-builder.pod | 63 ++++++++++++++++++++++++++-------------- 3 files changed, 65 insertions(+), 25 deletions(-) diff --git a/builder/builder.ml b/builder/builder.ml index f3ada9585..3c45fa5e6 100644 --- a/builder/builder.ml +++ b/builder/builder.ml @@ -40,8 +40,8 @@ let main () = edit, firstboot, run, format, gpg, hostname, install, list_format, links, memsize, mkdirs, network, output, password_crypto, quiet, root_password, scrub, - scrub_logfile, size, smp, sources, sync, timezone, update, upload, - writes = + scrub_logfile, selinux_relabel, size, smp, sources, sync, timezone, + update, upload, writes = parse_cmdline () in (* Timestamped messages in ordinary, non-debug non-quiet mode. *) @@ -578,6 +578,8 @@ let main () = (match smp with None -> () | Some smp -> g#set_smp smp); g#set_network network; + g#set_selinux selinux_relabel; + (* The output disk is being created, so use cache=unsafe here. *) g#add_drive_opts ~format:output_format ~cachemode:"unsafe" output_filename; @@ -890,6 +892,19 @@ exec >>%s 2>&1 do_run ~display:cmd cmd ) run; + if selinux_relabel then ( + msg (f_"SELinux relabelling"); + let cmd = sprintf " + if load_policy && fixfiles restore; then + rm -f /.autorelabel + else + touch /.autorelabel + echo '%s: SELinux relabelling failed, will relabel at boot instead.' + fi + " prog in + do_run ~display:"load_policy && fixfiles restore" cmd + ); + (* Clean up the log file: * * If debugging, dump out the log file. diff --git a/builder/cmdline.ml b/builder/cmdline.ml index e3b14844f..a6cb6c507 100644 --- a/builder/cmdline.ml +++ b/builder/cmdline.ml @@ -180,6 +180,7 @@ let parse_cmdline () = let add_scrub s = scrub := s :: !scrub in let scrub_logfile = ref false in + let selinux_relabel = ref false in let size = ref None in let set_size arg = size := Some (parse_size ~prog arg) in @@ -287,6 +288,8 @@ let parse_cmdline () = "--run", Arg.String add_run, "script" ^ " " ^ s_"Run script in disk image"; "--run-command", Arg.String add_run_cmd, "cmd+args" ^ " " ^ s_"Run command in disk image"; "--scrub", Arg.String add_scrub, "name" ^ " " ^ s_"Scrub a file"; + "--selinux-relabel", Arg.Set selinux_relabel, + " " ^ s_"Relabel files with correct SELinux labels"; "--size", Arg.String set_size, "size" ^ " " ^ s_"Set output disk size"; "--smp", Arg.Int set_smp, "vcpus" ^ " " ^ s_"Set number of vCPUs"; "--source", Arg.String add_source, "URL" ^ " " ^ s_"Set source URL"; @@ -351,6 +354,7 @@ read the man page virt-builder(1). let root_password = !root_password in let scrub = List.rev !scrub in let scrub_logfile = !scrub_logfile in + let selinux_relabel = !selinux_relabel in let size = !size in let smp = !smp in let sources = List.rev !sources in @@ -457,5 +461,5 @@ read the man page virt-builder(1). edit, firstboot, run, format, gpg, hostname, install, list_format, links, memsize, mkdirs, network, output, password_crypto, quiet, root_password, scrub, - scrub_logfile, size, smp, sources, sync, timezone, update, upload, - writes + scrub_logfile, selinux_relabel, size, smp, sources, sync, timezone, + update, upload, writes diff --git a/builder/virt-builder.pod b/builder/virt-builder.pod index f72ab3067..de12c0f47 100644 --- a/builder/virt-builder.pod +++ b/builder/virt-builder.pod @@ -27,6 +27,7 @@ virt-builder - Build virtual machine images quickly [--link TARGET:LINK[:LINK]] [--edit FILE:EXPR] [--delete FILE] [--scrub FILE] + [--selinux-relabel] [--run SCRIPT] [--run-command 'CMD ARGS ...'] [--firstboot SCRIPT] [--firstboot-command 'CMD ARGS ...'] [--firstboot-install PKG,[PKG...]] @@ -136,6 +137,16 @@ To install packages from the ordinary (guest) software repository (In Fedora, C<@> is used to install groups of packages. On Debian you would install a meta-package instead.) +To update the core packages to the latest version: + + virt-builder debian-7 --update + +For guests which use SELinux, like Fedora and Red Hat Enterprise +Linux, you may need to do SELinux relabelling after installing or +updating packages (see L below): + + virt-builder fedora-20 --update --selinux-relabel + =head2 Customizing the installation There are many options that let you customize the installation. These @@ -593,6 +604,12 @@ It cannot delete directories, only regular files. =back +=item B<--selinux-relabel> + +Relabel files in the guest so that they have the correct SELinux label. + +You should only use this option for guests which support SELinux. + =item B<--size> SIZE Select the size of the output disk, where the size can be specified @@ -1029,6 +1046,10 @@ Scripts are run (I<--run>, I<--run-command>). Scripts run in the order they appear on the command line. +=item * + +SELinux relabelling is done (I<--selinux-relabel>). + =back =head2 IMPORTING THE DISK IMAGE @@ -1714,30 +1735,29 @@ raw-format guests. Guests which use SELinux (such as Fedora and Red Hat Enterprise Linux) require that each file has a correct SELinux label. -Since virt-builder does not know how to give new files a correct -label, the guest templates have an empty file C and -this causes the guest to relabel itself at first boot. +Virt-builder does not know how to give new files a label, so there are +two possible strategies it can use to ensure correct labelling: -This usually means that these guests will reboot themselves once the -first time you use them. B However if -you want to perform the relabelling at build time instead of delaying -it to the first boot, you can boot the guest with the qemu -I<-no-reboot> option (which means it will shut down after the relabel -is complete without booting "for real"). Only do this if you are sure -it is an SELinux guest: +=over 4 - qemu-system-x86_64 \ - -no-reboot \ - -nographic \ - -machine accel=kvm:tcg \ - -cpu host \ - -m 2048 \ - -drive file=disk.img,format=raw,if=virtio \ - -serial stdio \ - -monitor none +=item Using I<--selinux-relabel> -(For further information on the topic of SELinux labelling, see: -L) +This runs L just before finalizing the guest, which sets +SELinux labels correctly in the disk image. + +Sometimes fixfiles is not possible during installation, in which case +this option falls back on: + +=item Touching C + +Guest templates may already contain a file called C, or +it is touched if I<--selinux-relabel> cannot run fixfiles. + +For guests that use SELinux, this causes fixfiles to run at first +boot. Guests will reboot themselves once the first time you use them, +which is normal and harmless. + +=back =head1 ENVIRONMENT VARIABLES @@ -1795,6 +1815,7 @@ L, L, L, L, +L, L. =head1 AUTHOR