commit:     4e8b871a3f592ed66c82fb32e99e9d7c1b92b598
Author:     Kerin Millar <kfm <AT> plushkava <DOT> net>
AuthorDate: Sun Sep 14 04:01:30 2025 +0000
Commit:     Kerin Millar <kfm <AT> plushkava <DOT> net>
CommitDate: Sun Sep 14 04:17:51 2025 +0000
URL:        https://gitweb.gentoo.org/proj/locale-gen.git/commit/?id=4e8b871a

Disregard chcon(1) errors caused by ENOTSUP

Version 3.5 introduced support for preserving and restoring SELinux
security contexts. Where an existing archive is found to exist,
locale-gen(8) executes the chcon(1) utility so as to copy the context
from the old archive to the new archive, just before the former is
replaced by a rename(2) syscall. This only happens in the case that the
underlying filesystem is mounted with the "seclabel" option in effect.

However, the presence of the mount option does not prove that the
chcon(1) utility can be successfully employed. Consider a scenario in
which someone installs Gentoo from an SELinux-enabled operating
environment, such as Fedora. The chroot environment depicted below is
one that was prepared from an ordinary "stage3-arm64-systemd" tarball.

# chroot /mnt/gentoo /bin/bash
# findmnt -no options -T /usr/lib/locale-archive
rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota
# locale-gen
Found 1 locale declaration in '/etc/locale.gen'.
Compiling 2 locales with 2 workers ...
[1/2] Compiling locale: C.UTF-8
[2/2] Compiling locale: en_GB.UTF-8
Waiting for active workers to finish their jobs ...
The location of the archive shall be '/usr/lib/locale/locale-archive'.
Adding 2 locales to the locale archive ...
chcon: failed to get security context of '/usr/lib/locale/locale-archive
': Operation not supported

Clearly, chcon(1) is incapable of copying the security context. In turn,
that's because sys-apps/coreutils hasn't been built with USE="selinux"
in effect. I was able to make the utility work by copying the instance
provided by Fedora into the chroot environment, along with the
"libselinux.so.1" library to which it links.

It is interesting to note that in a situation such as this, the files
unpacked from the tarball will end up carrying security labels that are
surplus to requirements. That is, the user may have no intention of
using SELinux in Gentoo but will end up with a large number of files
bearing a label of "unconfined_u:object_r:unlabeled_t:s0".

Anyway, address this issue by capturing the standard error of chcon(1)
and quietly disregarding errors where any of the captured lines are
found to end with ": Operation not permitted". The C locale is duly
coerced, ensuring that the error string cannot be translated to any
other language. As unpalatable a solution as it may be, the alternatives
that I am aware of would be worse still.

Reported-by: Dennis Clarke <dc <AT> genunix.com>
Fixes: 42eb5eaf744f5561e86458ba242f2514cfa80595
Closes: https://bugs.gentoo.org/962824
Bug: https://bugs.gentoo.org/962753
Signed-off-by: Kerin Millar <kfm <AT> plushkava.net>

 locale-gen | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/locale-gen b/locale-gen
index e360da3..45919fa 100644
--- a/locale-gen
+++ b/locale-gen
@@ -548,7 +548,7 @@ sub install_archive ($src_path, $dst_path, 
$may_reset_labels) {
 
        # If a prior archive exists, attempt to preserve its SELinux label.
        if ($has_seclabels && $has_archive) {
-               run('chcon', "--reference=$dst_path", '--', $interim_path);
+               copy_security_context($dst_path, $interim_path);
        }
 
        # Activate the new archive by atomically renaming it into place.
@@ -569,6 +569,18 @@ sub install_archive ($src_path, $dst_path, 
$may_reset_labels) {
        }
 }
 
+sub copy_security_context ($src_path, $dst_path) {
+       local @ENV{'SRC_PATH', 'DST_PATH'} = ($src_path, $dst_path);
+       my $stderr = qx{ LC_ALL=C chcon --reference="\$SRC_PATH" -- 
"\$DST_PATH" 2>&1 >/dev/null };
+       # Throw exceptions for any errors that are not a consequence of ENOTSUP.
+       if ($? != 0 && $stderr !~ m/: Operation not supported$/m) {
+               if (length $stderr) {
+                       warn $stderr;
+               }
+               throw_child_error('chcon');
+       }
+}
+
 sub fopen ($path, $mode = '<') {
        if (! open my $fh, $mode, $path) {
                die "$PROGRAM: Can't open '$path': $!\n";

Reply via email to