selinux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Rahul Sandhu <nvraxn@gmail.com>
To: stephen.smalley.work@gmail.com
Cc: nvraxn@gmail.com, selinux@vger.kernel.org
Subject: [PATCH v2] libsemanage: semanage_store: recursively create SEMANAGE_ROOT
Date: Mon, 20 Oct 2025 18:40:27 +0100	[thread overview]
Message-ID: <20251020174027.11343-1-nvraxn@gmail.com> (raw)
In-Reply-To: <CAEjxPJ7VktYWYreg4PMUSTeoxRvBBoD0HVb1bsXdsach+j7PyA@mail.gmail.com>

In package build/install environments, when semodule(8) is passed the
`--path` option, it is expected that it creates the entire directory
tree for the policy root.

Some package managers warn or error if permissions do not align between
the tree on the existing system and the build environment about to be
merged. To make sure this is a non-issue, create the tree of the policy
root with 0755 permissions (in line with standards for `/var/lib`) and
then chmod the final path to the more restrictive 0700 permissions. As
the contents being placed in the policy root are security sensitive,
error instead of warning if we fail to chown the policy root to 0700.

Signed-off-by: Rahul Sandhu <nvraxn@gmail.com>
---
 libsemanage/src/semanage_store.c | 59 ++++++++++++++++++++++++++++----
 1 file changed, 53 insertions(+), 6 deletions(-)

v2: fix-up buffer length check, use memcpy instead of strncpy: we check
    the size already.

diff --git a/libsemanage/src/semanage_store.c b/libsemanage/src/semanage_store.c
index 1731c5e8..e3048c08 100644
--- a/libsemanage/src/semanage_store.c
+++ b/libsemanage/src/semanage_store.c
@@ -491,6 +491,45 @@ char *semanage_conf_path(void)
 	return semanage_conf;
 }
 
+/* Recursively create a directory from a path string.
+ * Returns 0 on success, -errno on failure.
+ */
+static int mkdir_recursive(const char *path, mode_t mode)
+{
+	if (!path || !*path) {
+		return -EINVAL;
+	}
+
+	char path_buffer[PATH_MAX] = {0};
+	size_t len = strlen(path);
+	/* + 1 for nullterm.  */
+	if (len + 1 > sizeof(path_buffer)) {
+		return -ENAMETOOLONG;
+	}
+
+	/* + 1 for nullterm.  */
+	memcpy(path_buffer, path, len + 1);
+
+	/* trim possible trailing slashes, except if '/' is the entire path.  */
+	while (len > 1 && path_buffer[len - 1] == '/') {
+		path_buffer[--len] = '\0';
+	}
+
+	for (char *pos = path_buffer + 1, *slash; (slash = strchr(pos, '/')); pos = slash + 1) {
+		*slash = '\0';
+		if (mkdir(path_buffer, mode) != 0 && errno != EEXIST) {
+			return -errno;
+		}
+		*slash = '/';
+	}
+
+	if (mkdir(path_buffer, mode) != 0 && errno != EEXIST) {
+		return -errno;
+	}
+
+	return 0;
+}
+
 /**************** functions that create module store ***************/
 
 /* Check that the semanage store exists.  If 'create' is non-zero then
@@ -506,14 +545,20 @@ int semanage_create_store(semanage_handle_t * sh, int create)
 
 	if (stat(path, &sb) == -1) {
 		if (errno == ENOENT && create) {
-			mask = umask(0077);
-			if (mkdir(path, S_IRWXU) == -1) {
-				umask(mask);
-				ERR(sh, "Could not create module store at %s.",
-				    path);
+			/* First we create directories recursively with standard permissions so that
+			   we don't screw up ownership of toplevel dirs such as `/var` in pkgmgr
+			   environments.  */
+			const int r = mkdir_recursive(path, (mode_t)0755);
+			if (r != 0) {
+				ERR(sh, "Could not create module store at %s: %s.", path, strerror(-r));
+				return -2;
+			}
+			/* Now that we've created the directory tree, we set the permissions of the
+			   target path to 0700. */
+			if (chmod(path, (mode_t)0700) != 0) {
+				ERR(sh, "Failed to chown module store at %s: %s.", path, strerror(errno));
 				return -2;
 			}
-			umask(mask);
 		} else {
 			if (create)
 				ERR(sh,
@@ -529,6 +574,8 @@ int semanage_create_store(semanage_handle_t * sh, int create)
 			return -1;
 		}
 	}
+	/* We no longer need to use mkdir_recursive at this point: the toplevel
+	   directory hierarchy has been created by now.  */
 	path = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_TOPLEVEL);
 	if (stat(path, &sb) == -1) {
 		if (errno == ENOENT && create) {
-- 
2.51.0


  reply	other threads:[~2025-10-20 17:42 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-10-18  5:19 [PATCH] libsemanage: semanage_store: recursively create SEMANAGE_ROOT Rahul Sandhu
2025-10-20 13:15 ` Stephen Smalley
2025-10-20 13:48   ` Rahul Sandhu
2025-10-20 16:27     ` Stephen Smalley
2025-10-20 17:19       ` Stephen Smalley
2025-10-20 17:40         ` Rahul Sandhu [this message]
2025-10-21 12:59           ` [PATCH v2] " Stephen Smalley
2025-10-22 15:38             ` Stephen Smalley

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20251020174027.11343-1-nvraxn@gmail.com \
    --to=nvraxn@gmail.com \
    --cc=selinux@vger.kernel.org \
    --cc=stephen.smalley.work@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).