diff mbox series

[1/2] libselinux: introduce context_to_str(3)

Message ID 20250226094409.41452-2-cgoettsche@seltendoof.de (mailing list archive)
State New
Delegated to: Petr Lautrbach
Headers show
Series [1/2] libselinux: introduce context_to_str(3) | expand

Commit Message

Christian Göttsche Feb. 26, 2025, 9:44 a.m. UTC
From: Christian Göttsche <cgzones@googlemail.com>

Currently context_t offers the function context_str(3) to get the
formatted security context of the internal representation. The return
value is a pointer to an internally, on call allocated, stored cache.
This can lead to invalidation issues and if the caller wants to store
the result duplicate allocations.

Introduce context_to_str(3) not using any internal cache and moving
ownership of the string to the client.

Use in appropriate places.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
 libselinux/include/selinux/context.h |  8 ++++++++
 libselinux/src/context.c             | 30 ++++++++++++++++++++++++++++
 libselinux/src/get_context_list.c    | 15 +++++++-------
 libselinux/src/libselinux.map        |  5 +++++
 libselinux/src/selinux_restorecon.c  |  2 +-
 libselinux/src/setexecfilecon.c      |  2 +-
 6 files changed, 52 insertions(+), 10 deletions(-)
diff mbox series

Patch

diff --git a/libselinux/include/selinux/context.h b/libselinux/include/selinux/context.h
index 59d9bb69..1b62fc72 100644
--- a/libselinux/include/selinux/context.h
+++ b/libselinux/include/selinux/context.h
@@ -27,6 +27,14 @@  extern "C" {
 
 	extern const char *context_str(context_t con);
 
+/*
+ * Return the string value of the context_t.
+ * Similar to context_str(3), but the client owns the string
+ * and needs to free it via free(3).
+ */
+
+	extern char *context_to_str(context_t con);
+
 /* Free the storage used by a context */
 	extern void context_free(context_t con);
 
diff --git a/libselinux/src/context.c b/libselinux/src/context.c
index 33c48ef3..2891e5a0 100644
--- a/libselinux/src/context.c
+++ b/libselinux/src/context.c
@@ -141,6 +141,36 @@  const char *context_str(context_t context)
 }
 
 
+/*
+ * Return a new string value of the context.
+ */
+char *context_to_str(context_t context)
+{
+	const context_private_t *n = context->ptr;
+	char *buf;
+	size_t total = 0;
+
+	for (int i = 0; i < 4; i++) {
+		if (n->component[i]) {
+			total += strlen(n->component[i]) + 1;
+		}
+	}
+	buf = malloc(total);
+	if (buf != NULL) {
+		char *cp = buf;
+
+		cp = stpcpy(cp, n->component[0]);
+		for (int i = 1; i < 4; i++) {
+			if (n->component[i]) {
+				*cp++ = ':';
+				cp = stpcpy(cp, n->component[i]);
+			}
+		}
+	}
+	return buf;
+}
+
+
 /* Returns nonzero iff failed */
 static int set_comp(context_private_t * n, int idx, const char *str)
 {
diff --git a/libselinux/src/get_context_list.c b/libselinux/src/get_context_list.c
index 8d5ee6fb..0f3bdc5c 100644
--- a/libselinux/src/get_context_list.c
+++ b/libselinux/src/get_context_list.c
@@ -145,7 +145,7 @@  static int get_context_user(FILE * fp,
 	char *linerole, *linetype;
 	char **new_reachable = NULL;
 	char *usercon_str;
-	const char *usercon_str2;
+	char *usercon_str2;
 	context_t usercon;
 
 	int rc;
@@ -255,7 +255,7 @@  static int get_context_user(FILE * fp,
 			rc = -1;
 			goto out;
 		}
-		usercon_str2 = context_str(usercon);
+		usercon_str2 = context_to_str(usercon);
 		if (!usercon_str2) {
 			context_free(usercon);
 			rc = -1;
@@ -264,6 +264,7 @@  static int get_context_user(FILE * fp,
 
 		/* check whether usercon is already in reachable */
 		if (is_in_reachable(*reachable, usercon_str2)) {
+			free(usercon_str2);
 			context_free(usercon);
 			start = end;
 			continue;
@@ -271,20 +272,18 @@  static int get_context_user(FILE * fp,
 		if (security_check_context(usercon_str2) == 0) {
 			new_reachable = reallocarray(*reachable, *nreachable + 2, sizeof(char *));
 			if (!new_reachable) {
+				free(usercon_str2);
 				context_free(usercon);
 				rc = -1;
 				goto out;
 			}
 			*reachable = new_reachable;
-			new_reachable[*nreachable] = strdup(usercon_str2);
-			if (new_reachable[*nreachable] == NULL) {
-				context_free(usercon);
-				rc = -1;
-				goto out;
-			}
+			new_reachable[*nreachable] = usercon_str2;
+			usercon_str2 = NULL;
 			new_reachable[*nreachable + 1] = 0;
 			*nreachable += 1;
 		}
+		free(usercon_str2);
 		context_free(usercon);
 		start = end;
 	}
diff --git a/libselinux/src/libselinux.map b/libselinux/src/libselinux.map
index 02f5b761..ab002f01 100644
--- a/libselinux/src/libselinux.map
+++ b/libselinux/src/libselinux.map
@@ -257,3 +257,8 @@  LIBSELINUX_3.8 {
   global:
     matchpathcon_filespec_add64;
 } LIBSELINUX_3.5;
+
+LIBSELINUX_3.9 {
+  global:
+    context_to_str;
+} LIBSELINUX_3.8;
diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c
index ab1c5216..f5023492 100644
--- a/libselinux/src/selinux_restorecon.c
+++ b/libselinux/src/selinux_restorecon.c
@@ -611,7 +611,7 @@  static int compare_types(const char *curcon, const char *newcon, char **newtypec
 		rc |= context_role_set(conb, context_role_get(cona));
 		rc |= context_range_set(conb, context_range_get(cona));
 		if (!rc) {
-			*newtypecon = strdup(context_str(conb));
+			*newtypecon = context_to_str(conb);
 			if (!*newtypecon) {
 				rc = -1;
 				goto err;
diff --git a/libselinux/src/setexecfilecon.c b/libselinux/src/setexecfilecon.c
index 4b31e775..15346621 100644
--- a/libselinux/src/setexecfilecon.c
+++ b/libselinux/src/setexecfilecon.c
@@ -34,7 +34,7 @@  int setexecfilecon(const char *filename, const char *fallback_type)
 		if (context_type_set(con, fallback_type))
 			goto out;
 		freecon(newcon);
-		newcon = strdup(context_str(con));
+		newcon = context_to_str(con);
 		if (!newcon)
 			goto out;
 	}