diff --git a/0003-libselinux-export-flush_class_cache-call-it-on-polic.patch b/0003-libselinux-export-flush_class_cache-call-it-on-polic.patch new file mode 100644 index 0000000..16b9859 --- /dev/null +++ b/0003-libselinux-export-flush_class_cache-call-it-on-polic.patch @@ -0,0 +1,124 @@ +From 48de56d96b15a6879f653d8dad57f6862a3cbaa0 Mon Sep 17 00:00:00 2001 +From: Stephen Smalley +Date: Tue, 21 Jan 2020 11:18:22 -0500 +Subject: [PATCH] libselinux: export flush_class_cache(), call it on policyload + +Rename flush_class_cache() to selinux_flush_class_cache(), export it +for direct use by userspace policy enforcers, and call it on all policy +load notifications rather than only when using selinux_check_access(). +This ensures that policy reloads that change a userspace class or +permission value will be reflected by subsequent string_to_security_class() +or string_to_av_perm() calls. + +Signed-off-by: Stephen Smalley +--- + libselinux/include/selinux/selinux.h | 3 +++ + libselinux/src/avc_internal.c | 2 ++ + libselinux/src/checkAccess.c | 13 ------------- + libselinux/src/selinux_internal.h | 3 +-- + libselinux/src/stringrep.c | 4 +++- + 5 files changed, 9 insertions(+), 16 deletions(-) + +diff --git a/libselinux/include/selinux/selinux.h b/libselinux/include/selinux/selinux.h +index fe46e681488d..7922d96b70c7 100644 +--- a/libselinux/include/selinux/selinux.h ++++ b/libselinux/include/selinux/selinux.h +@@ -418,6 +418,9 @@ extern int security_av_string(security_class_t tclass, + /* Display an access vector in a string representation. */ + extern void print_access_vector(security_class_t tclass, access_vector_t av); + ++/* Flush the SELinux class cache, e.g. upon a policy reload. */ ++extern void selinux_flush_class_cache(void); ++ + /* Set the function used by matchpathcon_init when displaying + errors about the file_contexts configuration. If not set, + then this defaults to fprintf(stderr, fmt, ...). */ +diff --git a/libselinux/src/avc_internal.c b/libselinux/src/avc_internal.c +index 49cecc96daee..568a3d928ac1 100644 +--- a/libselinux/src/avc_internal.c ++++ b/libselinux/src/avc_internal.c +@@ -23,6 +23,7 @@ + #include "callbacks.h" + #include "selinux_netlink.h" + #include "avc_internal.h" ++#include "selinux_internal.h" + + #ifndef NETLINK_SELINUX + #define NETLINK_SELINUX 7 +@@ -207,6 +208,7 @@ static int avc_netlink_process(void *buf) + avc_prefix, rc, errno); + return rc; + } ++ selinux_flush_class_cache(); + rc = selinux_netlink_policyload(msg->seqno); + if (rc < 0) + return rc; +diff --git a/libselinux/src/checkAccess.c b/libselinux/src/checkAccess.c +index 16bfcfb63f85..7227ffe51eac 100644 +--- a/libselinux/src/checkAccess.c ++++ b/libselinux/src/checkAccess.c +@@ -10,25 +10,12 @@ + static pthread_once_t once = PTHREAD_ONCE_INIT; + static int selinux_enabled; + +-static int avc_reset_callback(uint32_t event __attribute__((unused)), +- security_id_t ssid __attribute__((unused)), +- security_id_t tsid __attribute__((unused)), +- security_class_t tclass __attribute__((unused)), +- access_vector_t perms __attribute__((unused)), +- access_vector_t *out_retained __attribute__((unused))) +-{ +- flush_class_cache(); +- return 0; +-} +- + static void avc_init_once(void) + { + selinux_enabled = is_selinux_enabled(); + if (selinux_enabled == 1) { + if (avc_open(NULL, 0)) + return; +- avc_add_callback(avc_reset_callback, AVC_CALLBACK_RESET, +- 0, 0, 0, 0); + } + } + +diff --git a/libselinux/src/selinux_internal.h b/libselinux/src/selinux_internal.h +index 8b4bed2fd0d1..61b78aaa7c10 100644 +--- a/libselinux/src/selinux_internal.h ++++ b/libselinux/src/selinux_internal.h +@@ -107,8 +107,7 @@ hidden_proto(selinux_trans_to_raw_context); + hidden_proto(security_get_initial_context); + hidden_proto(security_get_initial_context_raw); + hidden_proto(selinux_reset_config); +- +-hidden void flush_class_cache(void); ++hidden_proto(selinux_flush_class_cache); + + extern int require_seusers hidden; + extern int selinux_page_size hidden; +diff --git a/libselinux/src/stringrep.c b/libselinux/src/stringrep.c +index 4db95398e138..29757b750878 100644 +--- a/libselinux/src/stringrep.c ++++ b/libselinux/src/stringrep.c +@@ -158,7 +158,7 @@ err1: + return NULL; + } + +-hidden void flush_class_cache(void) ++void selinux_flush_class_cache(void) + { + struct discover_class_node *cur = discover_class_cache, *prev = NULL; + size_t i; +@@ -180,6 +180,8 @@ hidden void flush_class_cache(void) + discover_class_cache = NULL; + } + ++hidden_def(selinux_flush_class_cache) ++ + security_class_t string_to_security_class(const char *s) + { + struct discover_class_node *node; +-- +2.25.1 + diff --git a/0004-libselinux-Eliminate-use-of-security_compute_user.patch b/0004-libselinux-Eliminate-use-of-security_compute_user.patch new file mode 100644 index 0000000..2f4c444 --- /dev/null +++ b/0004-libselinux-Eliminate-use-of-security_compute_user.patch @@ -0,0 +1,354 @@ +From 4039d67b1e3b235b5fdc90cd70c907711fe5cd22 Mon Sep 17 00:00:00 2001 +From: Petr Lautrbach +Date: Mon, 17 Feb 2020 21:47:35 +0100 +Subject: [PATCH] libselinux: Eliminate use of security_compute_user() + +get_ordered_context_list() code used to ask the kernel to compute the complete +set of reachable contexts using /sys/fs/selinux/user aka +security_compute_user(). This set can be so huge so that it doesn't fit into a +kernel page and security_compute_user() fails. Even if it doesn't fail, +get_ordered_context_list() throws away the vast majority of the returned +contexts because they don't match anything in +/etc/selinux/targeted/contexts/default_contexts or +/etc/selinux/targeted/contexts/users/ + +get_ordered_context_list() is rewritten to compute set of contexts based on +/etc/selinux/targeted/contexts/users/ and +/etc/selinux/targeted/contexts/default_contexts files and to return only valid +contexts, using security_check_context(), from this set. + +Fixes: https://github.com/SELinuxProject/selinux/issues/28 + +Signed-off-by: Petr Lautrbach +--- + libselinux/src/get_context_list.c | 212 +++++++++++++----------------- + 1 file changed, 93 insertions(+), 119 deletions(-) + +diff --git a/libselinux/src/get_context_list.c b/libselinux/src/get_context_list.c +index 689e46589f30..26d7b3b98e75 100644 +--- a/libselinux/src/get_context_list.c ++++ b/libselinux/src/get_context_list.c +@@ -2,6 +2,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -114,64 +115,41 @@ int get_default_context(const char *user, + return 0; + } + +-static int find_partialcon(char ** list, +- unsigned int nreach, char *part) ++static int is_in_reachable(char **reachable, const char *usercon_str) + { +- const char *conrole, *contype; +- char *partrole, *parttype, *ptr; +- context_t con; +- unsigned int i; ++ if (!reachable) ++ return 0; + +- partrole = part; +- ptr = part; +- while (*ptr && !isspace(*ptr) && *ptr != ':') +- ptr++; +- if (*ptr != ':') +- return -1; +- *ptr++ = 0; +- parttype = ptr; +- while (*ptr && !isspace(*ptr) && *ptr != ':') +- ptr++; +- *ptr = 0; +- +- for (i = 0; i < nreach; i++) { +- con = context_new(list[i]); +- if (!con) +- return -1; +- conrole = context_role_get(con); +- contype = context_type_get(con); +- if (!conrole || !contype) { +- context_free(con); +- return -1; +- } +- if (!strcmp(conrole, partrole) && !strcmp(contype, parttype)) { +- context_free(con); +- return i; ++ for (; *reachable != NULL; reachable++) { ++ if (strcmp(*reachable, usercon_str) == 0) { ++ return 1; + } +- context_free(con); + } +- +- return -1; ++ return 0; + } + +-static int get_context_order(FILE * fp, ++static int get_context_user(FILE * fp, + char * fromcon, +- char ** reachable, +- unsigned int nreach, +- unsigned int *ordering, unsigned int *nordered) ++ const char * user, ++ char ***reachable, ++ unsigned int *nreachable) + { + char *start, *end = NULL; + char *line = NULL; +- size_t line_len = 0; ++ size_t line_len = 0, usercon_len; ++ size_t user_len = strlen(user); + ssize_t len; + int found = 0; +- const char *fromrole, *fromtype; ++ const char *fromrole, *fromtype, *fromlevel; + char *linerole, *linetype; +- unsigned int i; ++ char **new_reachable = NULL; ++ char *usercon_str; + context_t con; ++ context_t usercon; ++ + int rc; + +- errno = -EINVAL; ++ errno = EINVAL; + + /* Extract the role and type of the fromcon for matching. + User identity and MLS range can be variable. */ +@@ -180,6 +158,7 @@ static int get_context_order(FILE * fp, + return -1; + fromrole = context_role_get(con); + fromtype = context_type_get(con); ++ fromlevel = context_range_get(con); + if (!fromrole || !fromtype) { + context_free(con); + return -1; +@@ -243,23 +222,75 @@ static int get_context_order(FILE * fp, + if (*end) + *end++ = 0; + +- /* Check for a match in the reachable list. */ +- rc = find_partialcon(reachable, nreach, start); +- if (rc < 0) { +- /* No match, skip it. */ ++ /* Check whether a new context is valid */ ++ if (SIZE_MAX - user_len < strlen(start) + 2) { ++ fprintf(stderr, "%s: one of partial contexts is too big\n", __FUNCTION__); ++ errno = EINVAL; ++ rc = -1; ++ goto out; ++ } ++ usercon_len = user_len + strlen(start) + 2; ++ usercon_str = malloc(usercon_len); ++ if (!usercon_str) { ++ rc = -1; ++ goto out; ++ } ++ ++ /* set range from fromcon in the new usercon */ ++ snprintf(usercon_str, usercon_len, "%s:%s", user, start); ++ usercon = context_new(usercon_str); ++ if (!usercon) { ++ if (errno != EINVAL) { ++ free(usercon_str); ++ rc = -1; ++ goto out; ++ } ++ fprintf(stderr, ++ "%s: can't create a context from %s, skipping\n", ++ __FUNCTION__, usercon_str); ++ free(usercon_str); + start = end; + continue; + } ++ free(usercon_str); ++ if (context_range_set(usercon, fromlevel) != 0) { ++ context_free(usercon); ++ rc = -1; ++ goto out; ++ } ++ usercon_str = context_str(usercon); ++ if (!usercon_str) { ++ context_free(usercon); ++ rc = -1; ++ goto out; ++ } + +- /* If a match is found and the entry is not already ordered +- (e.g. due to prior match in prior config file), then set +- the ordering for it. */ +- i = rc; +- if (ordering[i] == nreach) +- ordering[i] = (*nordered)++; ++ /* check whether usercon is already in reachable */ ++ if (is_in_reachable(*reachable, usercon_str)) { ++ context_free(usercon); ++ start = end; ++ continue; ++ } ++ if (security_check_context(usercon_str) == 0) { ++ new_reachable = realloc(*reachable, (*nreachable + 2) * sizeof(char *)); ++ if (!new_reachable) { ++ context_free(usercon); ++ rc = -1; ++ goto out; ++ } ++ *reachable = new_reachable; ++ new_reachable[*nreachable] = strdup(usercon_str); ++ if (new_reachable[*nreachable] == NULL) { ++ context_free(usercon); ++ rc = -1; ++ goto out; ++ } ++ new_reachable[*nreachable + 1] = 0; ++ *nreachable += 1; ++ } ++ context_free(usercon); + start = end; + } +- + rc = 0; + + out: +@@ -313,21 +344,6 @@ static int get_failsafe_context(const char *user, char ** newcon) + return 0; + } + +-struct context_order { +- char * con; +- unsigned int order; +-}; +- +-static int order_compare(const void *A, const void *B) +-{ +- const struct context_order *c1 = A, *c2 = B; +- if (c1->order < c2->order) +- return -1; +- else if (c1->order > c2->order) +- return 1; +- return strcmp(c1->con, c2->con); +-} +- + int get_ordered_context_list_with_level(const char *user, + const char *level, + char * fromcon, +@@ -395,11 +411,8 @@ int get_ordered_context_list(const char *user, + char *** list) + { + char **reachable = NULL; +- unsigned int *ordering = NULL; +- struct context_order *co = NULL; +- char **ptr; + int rc = 0; +- unsigned int nreach = 0, nordered = 0, freefrom = 0, i; ++ unsigned nreachable = 0, freefrom = 0; + FILE *fp; + char *fname = NULL; + size_t fname_len; +@@ -413,23 +426,6 @@ int get_ordered_context_list(const char *user, + freefrom = 1; + } + +- /* Determine the set of reachable contexts for the user. */ +- rc = security_compute_user(fromcon, user, &reachable); +- if (rc < 0) +- goto failsafe; +- nreach = 0; +- for (ptr = reachable; *ptr; ptr++) +- nreach++; +- if (!nreach) +- goto failsafe; +- +- /* Initialize ordering array. */ +- ordering = malloc(nreach * sizeof(unsigned int)); +- if (!ordering) +- goto failsafe; +- for (i = 0; i < nreach; i++) +- ordering[i] = nreach; +- + /* Determine the ordering to apply from the optional per-user config + and from the global config. */ + fname_len = strlen(user_contexts_path) + strlen(user) + 2; +@@ -440,8 +436,8 @@ int get_ordered_context_list(const char *user, + fp = fopen(fname, "re"); + if (fp) { + __fsetlocking(fp, FSETLOCKING_BYCALLER); +- rc = get_context_order(fp, fromcon, reachable, nreach, ordering, +- &nordered); ++ rc = get_context_user(fp, fromcon, user, &reachable, &nreachable); ++ + fclose(fp); + if (rc < 0 && errno != ENOENT) { + fprintf(stderr, +@@ -454,8 +450,7 @@ int get_ordered_context_list(const char *user, + fp = fopen(selinux_default_context_path(), "re"); + if (fp) { + __fsetlocking(fp, FSETLOCKING_BYCALLER); +- rc = get_context_order(fp, fromcon, reachable, nreach, ordering, +- &nordered); ++ rc = get_context_user(fp, fromcon, user, &reachable, &nreachable); + fclose(fp); + if (rc < 0 && errno != ENOENT) { + fprintf(stderr, +@@ -463,40 +458,19 @@ int get_ordered_context_list(const char *user, + __FUNCTION__, selinux_default_context_path()); + /* Fall through */ + } +- rc = 0; + } + +- if (!nordered) ++ if (!nreachable) + goto failsafe; + +- /* Apply the ordering. */ +- co = malloc(nreach * sizeof(struct context_order)); +- if (!co) +- goto failsafe; +- for (i = 0; i < nreach; i++) { +- co[i].con = reachable[i]; +- co[i].order = ordering[i]; +- } +- qsort(co, nreach, sizeof(struct context_order), order_compare); +- for (i = 0; i < nreach; i++) +- reachable[i] = co[i].con; +- free(co); +- +- /* Only report the ordered entries to the caller. */ +- if (nordered <= nreach) { +- for (i = nordered; i < nreach; i++) +- free(reachable[i]); +- reachable[nordered] = NULL; +- rc = nordered; +- } +- + out: +- if (rc > 0) ++ if (nreachable > 0) { + *list = reachable; ++ rc = nreachable; ++ } + else + freeconary(reachable); + +- free(ordering); + if (freefrom) + freecon(fromcon); + +@@ -519,7 +493,7 @@ int get_ordered_context_list(const char *user, + reachable = NULL; + goto out; + } +- rc = 1; /* one context in the list */ ++ nreachable = 1; /* one context in the list */ + goto out; + } + +-- +2.25.1 + diff --git a/0005-libselinux-deprecate-security_compute_user-update-ma.patch b/0005-libselinux-deprecate-security_compute_user-update-ma.patch new file mode 100644 index 0000000..85be8ff --- /dev/null +++ b/0005-libselinux-deprecate-security_compute_user-update-ma.patch @@ -0,0 +1,168 @@ +From 59444ff7e41642a66cc084b6aee175fa3c4c925f Mon Sep 17 00:00:00 2001 +From: Stephen Smalley +Date: Thu, 20 Feb 2020 10:40:19 -0500 +Subject: [PATCH] libselinux: deprecate security_compute_user(), update man + pages + +commit 1f89c4e7879fcf6da5d8d1b025dcc03371f30fc9 ("libselinux: Eliminate +use of security_compute_user()") eliminated the use of +security_compute_user() by get_ordered_context_list(). Deprecate +all use of security_compute_user() by updating the headers and man +pages and logging a warning message on any calls to it. Remove +the example utility that called the interface. While here, also +fix the documentation of correct usage of the user argument to these +interfaces. + +Fixes: https://github.com/SELinuxProject/selinux/issues/70 +Signed-off-by: Stephen Smalley +Acked-by: Petr Lautrbach +--- + libselinux/include/selinux/selinux.h | 8 +++- + .../man/man3/get_ordered_context_list.3 | 24 +++++++++--- + libselinux/man/man3/security_compute_av.3 | 5 ++- + libselinux/src/compute_user.c | 3 ++ + libselinux/utils/compute_user.c | 38 ------------------- + 5 files changed, 31 insertions(+), 47 deletions(-) + delete mode 100644 libselinux/utils/compute_user.c + +diff --git a/libselinux/include/selinux/selinux.h b/libselinux/include/selinux/selinux.h +index 7922d96b70c7..17d473208dc1 100644 +--- a/libselinux/include/selinux/selinux.h ++++ b/libselinux/include/selinux/selinux.h +@@ -246,8 +246,12 @@ extern int security_compute_member_raw(const char * scon, + security_class_t tclass, + char ** newcon); + +-/* Compute the set of reachable user contexts and set *con to refer to +- the NULL-terminated array of contexts. Caller must free via freeconary. */ ++/* ++ * Compute the set of reachable user contexts and set *con to refer to ++ * the NULL-terminated array of contexts. Caller must free via freeconary. ++ * These interfaces are deprecated. Use get_ordered_context_list() or ++ * one of its variant interfaces instead. ++ */ + extern int security_compute_user(const char * scon, + const char *username, + char *** con); +diff --git a/libselinux/man/man3/get_ordered_context_list.3 b/libselinux/man/man3/get_ordered_context_list.3 +index e084da406af1..3ed14a96879c 100644 +--- a/libselinux/man/man3/get_ordered_context_list.3 ++++ b/libselinux/man/man3/get_ordered_context_list.3 +@@ -26,14 +26,28 @@ get_ordered_context_list, get_ordered_context_list_with_level, get_default_conte + .BI "int get_default_type(const char *" role ", char **" type ); + . + .SH "DESCRIPTION" ++ ++This family of functions can be used to obtain either a prioritized list of ++all reachable security contexts for a given SELinux user or a single default ++(highest priority) context for a given SELinux user for use by login-like ++programs. These functions takes a SELinux user identity that must ++be defined in the SELinux policy as their input, not a Linux username. ++Most callers should typically first call ++.BR getseuserbyname(3) ++to look up the SELinux user identity and level for a given ++Linux username and then invoke one of ++.BR get_ordered_context_list_with_level () ++or ++.BR get_default_context_with_level () ++with the returned SELinux user and level as inputs. ++ + .BR get_ordered_context_list () +-invokes the +-.BR security_compute_user (3) +-function to obtain the list of contexts for the specified ++obtains the list of contexts for the specified ++SELinux + .I user +-that are reachable from the specified ++identity that are reachable from the specified + .I fromcon +-context. The function then orders the resulting list based on the global ++context based on the global + .I \%/etc/selinux/{SELINUXTYPE}/contexts/default_contexts + file and the per-user + .I \%/etc/selinux/{SELINUXTYPE}/contexts/users/ +diff --git a/libselinux/man/man3/security_compute_av.3 b/libselinux/man/man3/security_compute_av.3 +index cb1a9ba49f46..6fa3b7ee017a 100644 +--- a/libselinux/man/man3/security_compute_av.3 ++++ b/libselinux/man/man3/security_compute_av.3 +@@ -101,8 +101,9 @@ instance. + + .BR security_compute_user () + is used to determine the set of user contexts that can be reached from a +-source context. It is mainly used by +-.BR get_ordered_context_list (). ++source context. This function is deprecated; use ++.BR get_ordered_context_list (3) ++instead. + + .BR security_validatetrans () + is used to determine if a transition from scon to newcon using tcon as the object +diff --git a/libselinux/src/compute_user.c b/libselinux/src/compute_user.c +index 401fd107e363..40575ef5e986 100644 +--- a/libselinux/src/compute_user.c ++++ b/libselinux/src/compute_user.c +@@ -8,6 +8,7 @@ + #include "selinux_internal.h" + #include "policy.h" + #include ++#include "callbacks.h" + + int security_compute_user_raw(const char * scon, + const char *user, char *** con) +@@ -29,6 +30,8 @@ int security_compute_user_raw(const char * scon, + return -1; + } + ++ selinux_log(SELINUX_WARNING, "Direct use of security_compute_user() is deprecated, switch to get_ordered_context_list()\n"); ++ + snprintf(path, sizeof path, "%s/user", selinux_mnt); + fd = open(path, O_RDWR | O_CLOEXEC); + if (fd < 0) +diff --git a/libselinux/utils/compute_user.c b/libselinux/utils/compute_user.c +deleted file mode 100644 +index 86d00a6eff1c..000000000000 +--- a/libselinux/utils/compute_user.c ++++ /dev/null +@@ -1,38 +0,0 @@ +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-int main(int argc, char **argv) +-{ +- char **buf, **ptr; +- int ret; +- +- if (argc != 3) { +- fprintf(stderr, "usage: %s context user\n", argv[0]); +- exit(1); +- } +- +- ret = security_compute_user(argv[1], argv[2], &buf); +- if (ret < 0) { +- fprintf(stderr, "%s: security_compute_user(%s,%s) failed\n", +- argv[0], argv[1], argv[2]); +- exit(2); +- } +- +- if (!buf[0]) { +- printf("none\n"); +- exit(EXIT_SUCCESS); +- } +- +- for (ptr = buf; *ptr; ptr++) { +- printf("%s\n", *ptr); +- } +- freeconary(buf); +- exit(EXIT_SUCCESS); +-} +-- +2.25.1 + diff --git a/libselinux.spec b/libselinux.spec index 7d24ca5..117cdbd 100644 --- a/libselinux.spec +++ b/libselinux.spec @@ -4,7 +4,7 @@ Summary: SELinux library and simple utilities Name: libselinux Version: 3.0 -Release: 3%{?dist} +Release: 4%{?dist} License: Public Domain # https://github.com/SELinuxProject/selinux/wiki/Releases Source0: https://github.com/SELinuxProject/selinux/releases/download/20191204/libselinux-3.0.tar.gz @@ -18,6 +18,9 @@ Url: https://github.com/SELinuxProject/selinux/wiki # Patch list start Patch0001: 0001-Fix-selinux-man-page-to-refer-seinfo-and-sesearch-to.patch Patch0002: 0002-Verify-context-input-to-funtions-to-make-sure-the-co.patch +Patch0003: 0003-libselinux-export-flush_class_cache-call-it-on-polic.patch +Patch0004: 0004-libselinux-Eliminate-use-of-security_compute_user.patch +Patch0005: 0005-libselinux-deprecate-security_compute_user-update-ma.patch # Patch list end BuildRequires: gcc BuildRequires: ruby-devel ruby libsepol-static >= %{libsepolver} swig pcre2-devel xz-devel @@ -219,6 +222,9 @@ rm -f %{buildroot}%{_mandir}/man8/togglesebool* %{ruby_vendorarchdir}/selinux.so %changelog +* Thu Mar 5 2020 Petr Lautrbach - 3.0-4 +- Eliminate use of security_compute_user() + * Wed Jan 29 2020 Fedora Release Engineering - 3.0-3 - Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild