From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp.gentoo.org (woodpecker.gentoo.org [140.211.166.183]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id E2AD51581FD for ; Fri, 12 Sep 2025 17:00:03 +0000 (UTC) Received: from lists.gentoo.org (bobolink.gentoo.org [140.211.166.189]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (No client certificate requested) (Authenticated sender: relay-lists.gentoo.org@gentoo.org) by smtp.gentoo.org (Postfix) with ESMTPSA id CEF6533BF39 for ; Fri, 12 Sep 2025 17:00:03 +0000 (UTC) Received: from bobolink.gentoo.org (localhost [127.0.0.1]) by bobolink.gentoo.org (Postfix) with ESMTP id A39E411056F; Fri, 12 Sep 2025 16:59:59 +0000 (UTC) Received: from smtp.gentoo.org (mail.gentoo.org [IPv6:2001:470:ea4a:1:5054:ff:fec7:86e4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (No client certificate requested) by bobolink.gentoo.org (Postfix) with ESMTPS id 954A71104B5 for ; Fri, 12 Sep 2025 16:59:59 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 3CC72340F81 for ; Fri, 12 Sep 2025 16:59:59 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id 7943C3935 for ; Fri, 12 Sep 2025 16:59:57 +0000 (UTC) From: "Kerin Millar" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Kerin Millar" Message-ID: <1757696048.42eb5eaf744f5561e86458ba242f2514cfa80595.kfm@gentoo> Subject: [gentoo-commits] proj/locale-gen:master commit in: / X-VCS-Repository: proj/locale-gen X-VCS-Files: locale-gen X-VCS-Directories: / X-VCS-Committer: kfm X-VCS-Committer-Name: Kerin Millar X-VCS-Revision: 42eb5eaf744f5561e86458ba242f2514cfa80595 X-VCS-Branch: master Date: Fri, 12 Sep 2025 16:59:57 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply X-Archives-Salt: 0bdf1e53-7434-4428-91ed-8ae3023a2d30 X-Archives-Hash: cab25dee3608d3d9c7966d726d6770f0 commit: 42eb5eaf744f5561e86458ba242f2514cfa80595 Author: Kerin Millar plushkava net> AuthorDate: Fri Sep 12 16:31:14 2025 +0000 Commit: Kerin Millar plushkava net> CommitDate: Fri Sep 12 16:54:08 2025 +0000 URL: https://gitweb.gentoo.org/proj/locale-gen.git/commit/?id=42eb5eaf Add support for preserving/restoring SELinux contexts Among the changes brought by locale-gen v3.0 was the following: - During the archive generation phase, localedef(1) is made to generate its archive in a temporary directory. Only if it succeeds shall any existing archive be replaced, with locale-gen(1) now assuming that responsibility. The existing archive is guaranteed to be replaced atomically or not at all. Such is problematic for operating environments in which SELinux is enabled because the newly created archive ends up lacking the appropriate label. Consequently, programs are unable to read the archive until such time as the user restores the label. Address this issue in a manner twofold. Firstly, in the event that a prior archive exists, execute the chcon(1) utility so as to copy the label from the old archive to the new archive, just before the former is replaced by a rename(2) syscall. Secondly, in the event that a prior archive does not exist, execute the restorecon(8) utility in an attempt to apply the appropriate label. No labelling shall be attempted unless the underlying filesystem is found to be mounted with the "seclabel" option in effect. Further, restorecon(8) shall only be executed if is found in PATH and the --prefix option was either a) unspecified b) specified as "/". Signed-off-by: Kerin Millar plushkava.net> Tested-by: Nicolas PARLANT parhuet.fr> Tested-by: Kenton Groombridge gentoo.org> Closes: https://bugs.gentoo.org/962753 locale-gen | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/locale-gen b/locale-gen index 0d180f3..4cb43e8 100755 --- a/locale-gen +++ b/locale-gen @@ -10,9 +10,10 @@ use v5.36; use Cwd qw(getcwd); use Errno qw(ENOENT); use Fcntl qw(SEEK_SET); -use File::Spec::Functions qw(canonpath catfile catdir splitpath); +use File::Spec::Functions qw(canonpath catfile catdir path splitpath); use File::Temp qw(tempdir); use Getopt::Long (); +use List::Util qw(any); # Formally stable as of v5.40; sufficiently functional in both v5.36 and v5.38. use experimental qw(try); @@ -485,7 +486,8 @@ sub generate_archive ($prefix, $gentoo_prefix, $locale_dir, $do_update, @canonic print "The location of the archive shall be '$final_path'.\n"; # If --update was specified, make a copy of the existing archive. - if ($do_update && -e $final_path) { + my $has_archive = -e $final_path; + if ($do_update && $has_archive) { run('cp', '--', $final_path, "$output_dir/"); } @@ -517,6 +519,9 @@ sub generate_archive ($prefix, $gentoo_prefix, $locale_dir, $do_update, @canonic throw_child_error('localedef', 1 << 8); } + # Determine whether the underlying filesystem supports SELinux labels. + my $has_seclabels = has_mount_option(dirname($final_path), 'seclabel'); + # The process of replacing the old archive must not be interrupted. local @SIG{'INT', 'TERM'} = ('IGNORE', 'IGNORE'); @@ -525,6 +530,11 @@ sub generate_archive ($prefix, $gentoo_prefix, $locale_dir, $do_update, @canonic my $interim_path = "$final_path.$$"; run('mv', '--', catfile($output_dir, 'locale-archive'), $interim_path); + # If a prior archive exists, attempt to preserve its SELinux label. + if ($has_archive && $has_seclabels) { + run('chcon', "--reference=$final_path", '--', $interim_path); + } + # Atomically replace the old archive. if (! rename $interim_path, $final_path) { { @@ -534,6 +544,11 @@ sub generate_archive ($prefix, $gentoo_prefix, $locale_dir, $do_update, @canonic die "$PROGRAM: Can't rename '$interim_path' to '$final_path': $!\n"; } + # If no prior archive existed, restore the appropriate SELinux label. + if (! $has_archive && $has_seclabels && $prefix =~ m/^\/?\z/ && can_run('restorecon')) { + run('restorecon', '-Fmv', '--', $final_path); + } + # Return the size of the archive, in bytes. if (! (my @stat = stat $final_path)) { die "$PROGRAM: Can't stat '$final_path': $!\n"; @@ -633,6 +648,27 @@ sub basename ($path) { return (splitpath($path))[2]; } +sub dirname ($path) { + return (splitpath($path))[1]; +} + +sub has_mount_option ($target, $option) { + if (! open my $pipe, '-|', qw( findmnt -no options -T ), $target) { + exit 1; + } else { + chomp(my $stdout = do { local $/; readline $pipe }); + if (! close $pipe && $! == 0) { + throw_child_error('findmnt'); + } + return ",$stdout," =~ m/\Q,$option,/; + } +} + +sub can_run ($bin) { + my @paths = path(); + return any(sub { -f $_ && -x _ }, map +( "$_/$bin" ), @paths); +} + END { if ($$ == $PID) { if (length $TEMPDIR) {