From: Christian Göttsche <cgzones@xxxxxxxxxxxxxx> 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@xxxxxxxxxxxxxx> --- 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 --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; } -- 2.47.2