public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/libsemanage] rawhide: Optionally sort file_contexts.local by specificity
@ 2026-09-08 15:07 Petr Lautrbach
  0 siblings, 0 replies; only message in thread
From: Petr Lautrbach @ 2026-09-08 15:07 UTC (permalink / raw)
  To: git-commits

A new commit has been pushed.

Repo   : rpms/libsemanage
Branch : rawhide
Commit : aecb61672ec87c4a3ffb2ca1b2bd39d9fe519ff6
Author : Petr Lautrbach <lautrbach@redhat.com>
Date   : 2026-09-08T10:01:52+02:00
Stats  : +316/-7 in 4 file(s)
URL    : https://src.fedoraproject.org/rpms/libsemanage/c/aecb61672ec87c4a3ffb2ca1b2bd39d9fe519ff6?branch=rawhide

Log:
Optionally sort file_contexts.local by specificity

---
diff --git a/0001-libsemanage-optionally-sort-file_contexts.local-by-s.patch b/0001-libsemanage-optionally-sort-file_contexts.local-by-s.patch
new file mode 100644
index 0000000..44c66d6
--- /dev/null
+++ b/0001-libsemanage-optionally-sort-file_contexts.local-by-s.patch
@@ -0,0 +1,258 @@
+From 8941a47c788d974f284ad3ad03b16b0b53f6f37f Mon Sep 17 00:00:00 2001
+From: Stephen Smalley <stephen.smalley.work@gmail.com>
+Date: Thu, 3 Sep 2026 07:59:28 -0400
+Subject: [PATCH] libsemanage: optionally sort file_contexts.local by
+ specificity
+Content-type: text/plain
+
+The policy-supplied file_contexts is emitted by the CIL compiler in
+least-to-most-specific order (cil_post_filecon_compare()) so that the
+libselinux label_file backend, which returns last matching spec, picks
+the most specific match. file_contexts.local is written by libsemanage
+in the order the entriers were added with semanage fcontext -a, so a
+broad entry added after a narrow one overrides it, and callers cannot
+rely on "most specific wins" for local customizations.
+
+Add a semanage.conf sort-local-fcontexts boolean. When set to true,
+the copy of file_contexts.local installed to the policy directory is
+run through semanage_fc_sort(), which uses the same heuristics as
+cil_post_filecon_compare(), with equally-specific entries retaining
+their insertion order. The module store copy is left in insertion
+order, so semanage fcontext -l -C still shows entries as they were
+added.
+
+Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=678577
+Fixes: https://github.com/SELinuxProject/selinux/issues/40
+Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
+---
+ libsemanage/man/man5/semanage.conf.5 | 13 ++++++
+ libsemanage/src/conf-parse.y         | 15 +++++-
+ libsemanage/src/conf-scan.l          |  1 +
+ libsemanage/src/direct_api.c         | 19 ++++++--
+ libsemanage/src/semanage_conf.h      |  1 +
+ libsemanage/src/semanage_store.c     | 70 ++++++++++++++++++++++++++++
+ libsemanage/src/semanage_store.h     |  2 +
+ 7 files changed, 116 insertions(+), 5 deletions(-)
+
+diff --git a/libsemanage/man/man5/semanage.conf.5 b/libsemanage/man/man5/semanage.conf.5
+index 74f0d34fe17c..336e02d09692 100644
+--- a/libsemanage/man/man5/semanage.conf.5
++++ b/libsemanage/man/man5/semanage.conf.5
+@@ -131,6 +131,19 @@ It can be set to either "true" or "false" and by default it is set to "true".
+ When set to "true", duplicate type, type attribute, and role declarations will be allowed.
+ It can be set to either "true" or "false" and by default it is set to "true".
+ 
++.TP
++.B sort-local-fcontexts
++When set to "true", the installed
++.I file_contexts.local
++file is sorted from least to most specific using the same heuristic as the policy-supplied
++.IR file_contexts ,
++so the most specific local entry wins regardless of the order the entries were added with
++.BR "semanage fcontext \-a" .
++The module store copy (and thus
++.BR "semanage fcontext \-l \-C" )
++is unaffected.
++It can be set to either "true" or "false" and by default it is set to "false", preserving insertion-order matching.
++
+ .RE
+ .PP
+ For certain tasks the SELinux Management library resorts to running
+diff --git a/libsemanage/src/conf-parse.y b/libsemanage/src/conf-parse.y
+index dee17b2fbbbc..ba75a1ecfc8d 100644
+--- a/libsemanage/src/conf-parse.y
++++ b/libsemanage/src/conf-parse.y
+@@ -62,7 +62,7 @@ static int parse_errors;
+         char *s;
+ }
+ 
+-%token MODULE_STORE VERSION EXPAND_CHECK FILE_MODE SAVE_PREVIOUS SAVE_LINKED TARGET_PLATFORM COMPILER_DIR IGNORE_MODULE_CACHE STORE_ROOT OPTIMIZE_POLICY MULTIPLE_DECLS
++%token MODULE_STORE VERSION EXPAND_CHECK FILE_MODE SAVE_PREVIOUS SAVE_LINKED TARGET_PLATFORM COMPILER_DIR IGNORE_MODULE_CACHE STORE_ROOT OPTIMIZE_POLICY MULTIPLE_DECLS SORT_LOCAL_FCONTEXTS
+ %token LOAD_POLICY_START SETFILES_START SEFCONTEXT_COMPILE_START DISABLE_GENHOMEDIRCON HANDLE_UNKNOWN USEPASSWD IGNOREDIRS
+ %token BZIP_BLOCKSIZE BZIP_SMALL RELABEL_STORE REMOVE_HLL
+ %token VERIFY_MOD_START VERIFY_LINKED_START VERIFY_KERNEL_START BLOCK_END
+@@ -101,6 +101,7 @@ single_opt:     module_store
+ 	|	relabel_store
+ 	|	optimize_policy
+ 	|	multiple_decls
++        |       sort_local_fcontexts
+         ;
+ 
+ module_store:   MODULE_STORE '=' ARG {
+@@ -329,6 +330,17 @@ multiple_decls:  MULTIPLE_DECLS '=' ARG {
+ 	free($3);
+ }
+ 
++sort_local_fcontexts: SORT_LOCAL_FCONTEXTS '=' ARG {
++	if (strcasecmp($3, "false") == 0) {
++		current_conf->sort_local_fcontexts = false;
++	} else if (strcasecmp($3, "true") == 0) {
++		current_conf->sort_local_fcontexts = true;
++	} else {
++		yyerror("sort-local-fcontexts can only be 'true' or 'false'");
++	}
++	free($3);
++}
++
+ command_block:
+                 command_start external_opts BLOCK_END  {
+                         if (new_external->path == NULL) {
+@@ -425,6 +437,7 @@ static int semanage_conf_init(semanage_conf_t * conf)
+ 	conf->relabel_store = true;
+ 	conf->optimize_policy = true;
+ 	conf->multiple_decls = true;
++	conf->sort_local_fcontexts = false;
+ 
+ 	conf->save_previous = false;
+ 	conf->save_linked = false;
+diff --git a/libsemanage/src/conf-scan.l b/libsemanage/src/conf-scan.l
+index c592fb6387a1..8d1d56ac33f3 100644
+--- a/libsemanage/src/conf-scan.l
++++ b/libsemanage/src/conf-scan.l
+@@ -57,6 +57,7 @@ remove-hll	return REMOVE_HLL;
+ relabel_store	return RELABEL_STORE;
+ optimize-policy return OPTIMIZE_POLICY;
+ multiple-decls return MULTIPLE_DECLS;
++sort-local-fcontexts return SORT_LOCAL_FCONTEXTS;
+ "[load_policy]"   return LOAD_POLICY_START;
+ "[setfiles]"      return SETFILES_START;
+ "[sefcontext_compile]"      return SEFCONTEXT_COMPILE_START;
+diff --git a/libsemanage/src/direct_api.c b/libsemanage/src/direct_api.c
+index 9572dbf05982..37ea1cd23c98 100644
+--- a/libsemanage/src/direct_api.c
++++ b/libsemanage/src/direct_api.c
+@@ -1607,10 +1607,21 @@ static int semanage_direct_commit(semanage_handle_t *sh)
+ 		goto cleanup;
+ 	}
+ 
+-	retval = copy_file_if_exists(
+-		sh, semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_LOCAL),
+-		semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_LOCAL),
+-		sh->conf->file_mode);
++	if (sh->conf->sort_local_fcontexts) {
++		retval = semanage_sort_fc_file(
++			sh,
++			semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_LOCAL),
++			semanage_final_path(SEMANAGE_FINAL_TMP,
++					    SEMANAGE_FC_LOCAL),
++			sh->conf->file_mode);
++	} else {
++		retval = copy_file_if_exists(
++			sh,
++			semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_LOCAL),
++			semanage_final_path(SEMANAGE_FINAL_TMP,
++					    SEMANAGE_FC_LOCAL),
++			sh->conf->file_mode);
++	}
+ 	if (retval < 0) {
+ 		goto cleanup;
+ 	}
+diff --git a/libsemanage/src/semanage_conf.h b/libsemanage/src/semanage_conf.h
+index 5a24ea87026d..d8544dc908f5 100644
+--- a/libsemanage/src/semanage_conf.h
++++ b/libsemanage/src/semanage_conf.h
+@@ -51,6 +51,7 @@ typedef struct semanage_conf {
+ 	bool optimize_policy;
+ 	bool multiple_decls;
+ 	bool relabel_store;
++	bool sort_local_fcontexts;
+ 	char *ignoredirs; /* ";" separated of list for genhomedircon to ignore */
+ 	struct external_prog *load_policy;
+ 	struct external_prog *setfiles;
+diff --git a/libsemanage/src/semanage_store.c b/libsemanage/src/semanage_store.c
+index f14ebe97ecf6..d6f56a82795d 100644
+--- a/libsemanage/src/semanage_store.c
++++ b/libsemanage/src/semanage_store.c
+@@ -1604,6 +1604,76 @@ cleanup:
+ 	return retval;
+ }
+ 
++/*
++ * Read file-context specifications from @src, sort them from least
++ * to most specific using the same heuristic as the policy-supplied
++ * file_contexts (see semanage_fc_compare()), and write the result to
++ * @dst. Comments in @src are dropped; the auto-generated header is
++ * re-emitted. A missing @src is not an error.
++ */
++int semanage_sort_fc_file(semanage_handle_t *sh, const char *src,
++			  const char *dst, mode_t mode)
++{
++	const char *header = "# This file is auto-generated by libsemanage\n"
++			     "# Do not edit directly.\n\n";
++	struct file_contents contents = {};
++	char *sorted = NULL;
++	size_t sorted_len = 0;
++	int out = -1, retval = -1;
++	mode_t mask;
++
++	if (access(src, F_OK) != 0)
++		return (errno == ENOENT) ? 0 : -1;
++
++	if (map_compressed_file(sh, src, &contents) < 0) {
++		ERR(sh, "Could not read %s.", src);
++		return -1;
++	}
++
++	if (contents.len > 0 &&
++	    semanage_fc_sort(sh, contents.data, contents.len, &sorted,
++			     &sorted_len) < 0) {
++		ERR(sh, "Could not sort file contexts from %s.", src);
++		goto cleanup;
++	}
++
++	if (!mode)
++		mode = S_IRUSR | S_IWUSR;
++	mask = umask(0);
++	out = open(dst, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
++	umask(mask);
++	if (out < 0) {
++		ERR(sh, "Could not open %s for writing.", dst);
++		goto cleanup;
++	}
++	if (write_full(out, header, strlen(header)) < 0) {
++		ERR(sh, "Write to %s failed.", dst);
++		goto cleanup;
++	}
++
++	if (sorted && sorted_len > 1 &&
++	    write_full(out, sorted, sorted_len - 1) < 0) {
++		ERR(sh, "Write to %s failed.", dst);
++		goto cleanup;
++	}
++
++	if (close(out) < 0 && errno != EINTR) {
++		out = -1;
++		goto cleanup;
++	}
++	out = -1;
++
++	semanage_setfiles(sh, dst);
++	retval = 0;
++
++cleanup:
++	if (out >= 0)
++		close(out);
++	free(sorted);
++	unmap_compressed_file(&contents);
++	return retval;
++}
++
+ static int sefcontext_compile(semanage_handle_t *sh, const char *path)
+ {
+ 	int r;
+diff --git a/libsemanage/src/semanage_store.h b/libsemanage/src/semanage_store.h
+index 86ae093652f2..3480595127a9 100644
+--- a/libsemanage/src/semanage_store.h
++++ b/libsemanage/src/semanage_store.h
+@@ -156,6 +156,8 @@ int semanage_split_fc(semanage_handle_t *sh);
+ /* sort file context routines */
+ int semanage_fc_sort(semanage_handle_t *sh, const char *buf, size_t buf_len,
+ 		     char **sorted_buf, size_t *sorted_buf_len);
++int semanage_sort_fc_file(semanage_handle_t *sh, const char *src,
++			  const char *dst, mode_t mode);
+ 
+ /* sort netfilter context routines */
+ int semanage_nc_sort(semanage_handle_t *sh, const char *buf, size_t buf_len,
+-- 
+2.55.0
+

diff --git a/0002-libsemanage-genhomedircon-reject-users-with-a-relati.patch b/0002-libsemanage-genhomedircon-reject-users-with-a-relati.patch
new file mode 100644
index 0000000..87fa790
--- /dev/null
+++ b/0002-libsemanage-genhomedircon-reject-users-with-a-relati.patch
@@ -0,0 +1,46 @@
+From ed3001e29f66ce63ccdbd21420c1447522fe2f83 Mon Sep 17 00:00:00 2001
+From: Vit Mojzis <vmojzis@redhat.com>
+Date: Wed, 2 Sep 2026 13:38:29 +0200
+Subject: [PATCH] libsemanage/genhomedircon: reject users with a relative home
+ directory
+Content-type: text/plain
+
+If a user's home directory in the password database is empty or
+otherwise does not start with "/" (e.g. because of a broken NSS lookup
+or a malformed passwd entry), the HOME_DIR template ends up being turned
+into a regular expression such as "/.+", which matches any path on the
+filesystem. This causes genhomedircon to generate a file context that
+relabels far more of the filesystem than intended. Skip such users
+instead of using their home directory to build the regex.
+
+Signed-off-by: Vit Mojzis <vmojzis@redhat.com>
+Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com>
+---
+ libsemanage/src/genhomedircon.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/libsemanage/src/genhomedircon.c b/libsemanage/src/genhomedircon.c
+index ce7ea16722d8..e3f55f68b358 100644
+--- a/libsemanage/src/genhomedircon.c
++++ b/libsemanage/src/genhomedircon.c
+@@ -1110,6 +1110,17 @@ retry:
+ 		pwent->pw_dir[len] = '\0';
+ 	}
+ 
++	if (pwent->pw_dir[0] != '/') {
++		/* an empty (or otherwise relative) home directory would
++		 * turn the HOME_DIR template into a regex that matches
++		 * everything, e.g. "/.+", so refuse to use it */
++		WARN(s->h_semanage,
++		     "user %s has an invalid home directory \"%s\", ignoring",
++		     name, pwent->pw_dir);
++		retval = STATUS_SUCCESS;
++		goto cleanup;
++	}
++
+ 	if (strcmp(pwent->pw_dir, "/") == 0) {
+ 		/* don't relabel / genhomdircon checked to see if root
+ 		 * was the user and if so, set his home directory to
+-- 
+2.55.0
+

diff --git a/changelog b/changelog
index 01dd7b8..4a6735e 100644
--- a/changelog
+++ b/changelog
@@ -1,3 +1,12 @@
+* Tue Sep 08 2026 Petr Lautrbach <lautrbach@redhat.com> - 3.11-4
+- Optionally sort file_contexts.local by specificity
+
+* Wed Jul 22 2026 Python Maint <python-maint@redhat.com> - 3.11-3
+- Rebuilt for Python 3.15.0b4 ABI change
+
+* Thu Jul 16 2026 Fedora Release Engineering <releng@fedoraproject.org> - 3.11-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild
+
 * Wed Jul 01 2026 Petr Lautrbach <lautrbach@redhat.com> - 3.11-1
 - SELinux userspace 3.11 release
 

diff --git a/libsemanage.spec b/libsemanage.spec
index d08b381..ed7dfd4 100644
--- a/libsemanage.spec
+++ b/libsemanage.spec
@@ -4,7 +4,7 @@
 Summary: SELinux binary policy manipulation library
 Name: libsemanage
 Version: 3.11
-Release: 3%{?dist}
+Release: 4%{?dist}
 License: LGPL-2.1-or-later
 Source0: https://github.com/SELinuxProject/selinux/releases/download/%{version}/libsemanage-%{version}.tar.gz
 Source1: https://github.com/SELinuxProject/selinux/releases/download/%{version}/libsemanage-%{version}.tar.gz.asc
@@ -12,6 +12,8 @@ Source2: https://github.com/bachradsusi.gpg
 # git format-patch -N 3.11 -- libsemanage
 # i=1; for j in 00*patch; do printf "Patch%04d: %s\n" $i $j; i=$((i+1));done
 # Patch list start
+Patch0001: 0001-libsemanage-optionally-sort-file_contexts.local-by-s.patch
+Patch0002: 0002-libsemanage-genhomedircon-reject-users-with-a-relati.patch
 # Patch list end
 URL: https://github.com/SELinuxProject/selinux/wiki
 VCS: git:https://github.com/SELinuxProject/selinux.git
@@ -158,10 +160,4 @@ cp %{SOURCE3} ${RPM_BUILD_ROOT}%{_sysconfdir}/selinux/semanage.conf
 %{_libexecdir}/selinux/semanage_migrate_store
 
 %changelog
-* Wed Jul 22 2026 Python Maint <python-maint@redhat.com> - 3.11-3
-- Rebuilt for Python 3.15.0b4 ABI change
-
-* Thu Jul 16 2026 Fedora Release Engineering <releng@fedoraproject.org> - 3.11-2
-- Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild
-
 %autochangelog

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-09-08 15:07 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-08 15:07 [rpms/libsemanage] rawhide: Optionally sort file_contexts.local by specificity Petr Lautrbach

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox