Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libselinux for openSUSE:Factory checked in at 2025-07-20 15:27:50 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libselinux (Old) and /work/SRC/openSUSE:Factory/.libselinux.new.8875 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libselinux" Sun Jul 20 15:27:50 2025 rev:85 rq:1294367 version:3.9 Changes: -------- --- /work/SRC/openSUSE:Factory/libselinux/libselinux-bindings.changes 2025-03-11 20:44:50.481000235 +0100 +++ /work/SRC/openSUSE:Factory/.libselinux.new.8875/libselinux-bindings.changes 2025-07-20 15:27:55.593225390 +0200 @@ -1,0 +2,8 @@ +Thu Jul 17 15:42:25 UTC 2025 - Johannes Segitz <jseg...@suse.com> + +- Update to version 3.9 + * Fix local literal fcontext definitions priority + * Fix order for path substitutions + * Limit fcontext regex path length + +------------------------------------------------------------------- libselinux.changes: same change Old: ---- libselinux-3.8.1.tar.gz libselinux-3.8.1.tar.gz.asc New: ---- libselinux-3.9.tar.gz libselinux-3.9.tar.gz.asc ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libselinux-bindings.spec ++++++ --- /var/tmp/diff_new_pack.BWgzw2/_old 2025-07-20 15:27:57.985324378 +0200 +++ /var/tmp/diff_new_pack.BWgzw2/_new 2025-07-20 15:27:57.997324875 +0200 @@ -18,10 +18,10 @@ %{?sle15allpythons} %define python_subpackage_only 1 -%define libsepol_ver 3.8.1 +%define libsepol_ver 3.9 %define upname libselinux Name: libselinux-bindings -Version: 3.8.1 +Version: 3.9 Release: 0 Summary: SELinux runtime library and utilities License: SUSE-Public-Domain ++++++ libselinux.spec ++++++ --- /var/tmp/diff_new_pack.BWgzw2/_old 2025-07-20 15:27:58.153331330 +0200 +++ /var/tmp/diff_new_pack.BWgzw2/_new 2025-07-20 15:27:58.157331496 +0200 @@ -16,9 +16,9 @@ # -%define libsepol_ver 3.8.1 +%define libsepol_ver 3.9 Name: libselinux -Version: 3.8.1 +Version: 3.9 Release: 0 Summary: SELinux runtime library and utilities License: SUSE-Public-Domain ++++++ libselinux-3.8.1.tar.gz -> libselinux-3.9.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/VERSION new/libselinux-3.9/VERSION --- old/libselinux-3.8.1/VERSION 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/VERSION 2025-07-16 12:55:13.000000000 +0200 @@ -1 +1 @@ -3.8.1 +3.9 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/include/selinux/context.h new/libselinux-3.9/include/selinux/context.h --- old/libselinux-3.8.1/include/selinux/context.h 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/include/selinux/context.h 2025-07-16 12:55:13.000000000 +0200 @@ -27,6 +27,14 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/include/selinux/restorecon.h new/libselinux-3.9/include/selinux/restorecon.h --- old/libselinux-3.8.1/include/selinux/restorecon.h 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/include/selinux/restorecon.h 2025-07-16 12:55:13.000000000 +0200 @@ -128,6 +128,12 @@ */ #define SELINUX_RESTORECON_COUNT_ERRORS 0x20000 +/* + * In addition to the type component also change the user and + * role component of security contexts. + */ +#define SELINUX_RESTORECON_SET_USER_ROLE 0x40000 + /** * selinux_restorecon_set_sehandle - Set the global fc handle. * @hndl: specifies handle to set as the global fc handle. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/include/selinux/selinux.h new/libselinux-3.9/include/selinux/selinux.h --- old/libselinux-3.8.1/include/selinux/selinux.h 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/include/selinux/selinux.h 2025-07-16 12:55:13.000000000 +0200 @@ -537,7 +537,7 @@ with the same inode (e.g. due to multiple hard links). If so, then use the latter of the two specifications based on their order in the file contexts configuration. Return the used specification index. */ -#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && __BITS_PER_LONG < 64 +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(__INO64_T_TYPE) && !defined(__INO_T_MATCHES_INO64_T) #define matchpathcon_filespec_add matchpathcon_filespec_add64 #endif extern int matchpathcon_filespec_add(ino_t ino, int specind, const char *file); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/man/man3/security_compute_av.3 new/libselinux-3.9/man/man3/security_compute_av.3 --- old/libselinux-3.8.1/man/man3/security_compute_av.3 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/man/man3/security_compute_av.3 2025-07-16 12:55:13.000000000 +0200 @@ -181,6 +181,11 @@ .SH "RETURN VALUE" Returns zero on success or \-1 on error. . +.SH "CAVEATS" +.sp +These functions are not thread-safe, you have to protect them from +concurrent calls using exclusive locks when multiple threads are executing. +. .SH "SEE ALSO" .BR string_to_security_class (3), .BR string_to_av_perm (3), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/man/man3/selinux_status_open.3 new/libselinux-3.9/man/man3/selinux_status_open.3 --- old/libselinux-3.8.1/man/man3/selinux_status_open.3 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/man/man3/selinux_status_open.3 2025-07-16 12:55:13.000000000 +0200 @@ -82,10 +82,6 @@ .BR selinux_status_deny_unknown () returns 0 if SELinux treats policy queries on undefined object classes or permissions as being allowed, 1 if such queries are denied, or \-1 on error. -.sp -Also note that these interfaces are not thread-safe, so you have to protect -them from concurrent calls using exclusive locks when multiple threads are -performing. . .SH "RETURN VALUE" .BR selinux_status_open () @@ -96,6 +92,11 @@ Any other functions with a return value shall return its characteristic value as described above, or \-1 on errors. . +.SH "CAVEATS" +.sp +These functions are not thread-safe, you have to protect them from +concurrent calls using exclusive locks when multiple threads are executing. +. .SH "SEE ALSO" .ad l .nh diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/src/Makefile new/libselinux-3.9/src/Makefile --- old/libselinux-3.8.1/src/Makefile 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/src/Makefile 2025-07-16 12:55:13.000000000 +0200 @@ -147,7 +147,10 @@ SWIGRUBY = swig -Wall -ruby -o $(SWIGRUBYCOUT) -outdir ./ $(DISABLE_FLAGS) -all: $(LIBA) $(LIBSO) $(LIBPC) +all: $(LIBA) $(LIBPC) +ifneq ($(DISABLE_SHARED),y) +all: $(LIBSO) +endif pywrap: all selinuxswig_python_exception.i CFLAGS="$(CPPFLAGS) $(CFLAGS) $(SWIG_CFLAGS)" $(PYTHON) setup.py build_ext @@ -186,11 +189,13 @@ install: all test -d $(DESTDIR)$(LIBDIR) || install -m 755 -d $(DESTDIR)$(LIBDIR) install -m 644 $(LIBA) $(DESTDIR)$(LIBDIR) - test -d $(DESTDIR)$(SHLIBDIR) || install -m 755 -d $(DESTDIR)$(SHLIBDIR) - install -m 755 $(LIBSO) $(DESTDIR)$(SHLIBDIR) test -d $(DESTDIR)$(LIBDIR)/pkgconfig || install -m 755 -d $(DESTDIR)$(LIBDIR)/pkgconfig install -m 644 $(LIBPC) $(DESTDIR)$(LIBDIR)/pkgconfig +ifneq ($(DISABLE_SHARED),y) + test -d $(DESTDIR)$(SHLIBDIR) || install -m 755 -d $(DESTDIR)$(SHLIBDIR) + install -m 755 $(LIBSO) $(DESTDIR)$(SHLIBDIR) ln -sf --relative $(DESTDIR)$(SHLIBDIR)/$(LIBSO) $(DESTDIR)$(LIBDIR)/$(TARGET) +endif install-pywrap: pywrap CFLAGS="$(CPPFLAGS) $(CFLAGS) $(SWIG_CFLAGS)" $(PYTHON) -m pip install --prefix=$(PREFIX) `test -n "$(DESTDIR)" && echo --root $(DESTDIR) --ignore-installed --no-deps` $(PYTHON_SETUP_ARGS) . diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/src/compute_create.c new/libselinux-3.9/src/compute_create.c --- old/libselinux-3.8.1/src/compute_create.c 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/src/compute_create.c 2025-07-16 12:55:13.000000000 +0200 @@ -33,7 +33,7 @@ return -1; buffer[offset++] = '+'; } else { - static const char *table = "0123456789ABCDEF"; + static const char *const table = "0123456789ABCDEF"; int l = (code & 0x0f); int h = (code & 0xf0) >> 4; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/src/context.c new/libselinux-3.9/src/context.c --- old/libselinux-3.8.1/src/context.c 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/src/context.c 2025-07-16 12:55:13.000000000 +0200 @@ -141,6 +141,36 @@ } +/* + * 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/src/get_context_list.c new/libselinux-3.9/src/get_context_list.c --- old/libselinux-3.8.1/src/get_context_list.c 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/src/get_context_list.c 2025-07-16 12:55:13.000000000 +0200 @@ -145,7 +145,7 @@ 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 @@ 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 @@ /* 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 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/src/label_backends_android.c new/libselinux-3.9/src/label_backends_android.c --- old/libselinux-3.8.1/src/label_backends_android.c 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/src/label_backends_android.c 2025-07-16 12:55:13.000000000 +0200 @@ -58,10 +58,10 @@ for (jj = ii + 1; jj < data->nspec; jj++) { if (!strcmp(spec_arr[jj].property_key, curr_spec->property_key)) { - rc = -1; - errno = EINVAL; if (strcmp(spec_arr[jj].lr.ctx_raw, curr_spec->lr.ctx_raw)) { + rc = -1; + errno = EINVAL; selinux_log (SELINUX_ERROR, "%s: Multiple different specifications for %s (%s and %s).\n", @@ -70,7 +70,7 @@ curr_spec->lr.ctx_raw); } else { selinux_log - (SELINUX_ERROR, + (SELINUX_WARNING, "%s: Multiple same specifications for %s.\n", path, curr_spec->property_key); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/src/label_file.c new/libselinux-3.9/src/label_file.c --- old/libselinux-3.8.1/src/label_file.c 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/src/label_file.c 2025-07-16 12:55:13.000000000 +0200 @@ -480,7 +480,7 @@ return 0; } -static int load_mmap_literal_spec(struct mmap_area *mmap_area, bool validating, +static int load_mmap_literal_spec(struct mmap_area *mmap_area, bool validating, uint8_t inputno, struct literal_spec *lspec, const struct context_array *ctx_array) { uint32_t data_u32, ctx_id; @@ -489,6 +489,7 @@ int rc; lspec->from_mmap = true; + lspec->inputno = inputno; /* @@ -674,12 +675,22 @@ } static int load_mmap_spec_node(struct mmap_area *mmap_area, const char *path, bool validating, bool do_load_precompregex, - struct spec_node *node, bool is_root, uint8_t inputno, const struct context_array *ctx_array) + struct spec_node *node, const unsigned depth, uint8_t inputno, const struct context_array *ctx_array) { uint32_t data_u32, lspec_num, rspec_num, children_num; uint16_t data_u16, stem_len; + const bool is_root = (depth == 0); int rc; + /* + * Guard against deep recursion by malicious pre-compiled fcontext + * definitions. The limit of 32 is chosen intuitively and should + * suffice for any real world scenario. See the macro + * SPEC_NODE_MAX_DEPTH for the current value used for tree building. + */ + if (depth >= 32) + return -1; + node->from_mmap = true; @@ -732,7 +743,7 @@ node->literal_specs_alloc = lspec_num; for (uint32_t i = 0; i < lspec_num; i++) { - rc = load_mmap_literal_spec(mmap_area, validating, &node->literal_specs[i], ctx_array); + rc = load_mmap_literal_spec(mmap_area, validating, inputno, &node->literal_specs[i], ctx_array); if (rc) return -1; } @@ -794,7 +805,7 @@ node->children_alloc = children_num; for (uint32_t i = 0; i < children_num; i++) { - rc = load_mmap_spec_node(mmap_area, path, validating, do_load_precompregex, &node->children[i], false, inputno, ctx_array); + rc = load_mmap_spec_node(mmap_area, path, validating, do_load_precompregex, &node->children[i], depth + 1, inputno, ctx_array); if (rc) return -1; @@ -969,7 +980,7 @@ rc = load_mmap_spec_node(mmap_area, path, rec->validating, reg_version_matches && reg_arch_matches, - root, true, + root, 0, inputno, &ctx_array); if (rc) @@ -1339,6 +1350,15 @@ if (digest_add_specfile(digest, cfg, NULL, sb.st_size, path) < 0) goto err; + /* LIFO order for backward compatibility */ + for (uint32_t i = 0; i < tmp_num/2; i++) { + struct selabel_sub swap; + + swap = tmp[i]; + tmp[i] = tmp[tmp_num - i - 1]; + tmp[tmp_num - i - 1] = swap; + } + *out_subs = tmp; *out_num = tmp_num; *out_alloc = tmp_alloc; @@ -1662,7 +1682,7 @@ for (uint32_t i = n->regex_specs_num; i > 0; i--) { /* search in reverse order */ struct regex_spec *rspec = &n->regex_specs[i - 1]; - const char *errbuf = NULL; + char errbuf[256]; int rc; if (child_regex_match && @@ -1673,7 +1693,7 @@ if (file_kind != LABEL_FILE_KIND_ALL && rspec->file_kind != LABEL_FILE_KIND_ALL && file_kind != rspec->file_kind) continue; - if (compile_regex(rspec, &errbuf) < 0) { + if (compile_regex(rspec, errbuf, sizeof(errbuf)) < 0) { COMPAT_LOG(SELINUX_ERROR, "Failed to compile regular expression '%s': %s\n", rspec->regex_str, errbuf); goto fail; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/src/label_file.h new/libselinux-3.9/src/label_file.h --- old/libselinux-3.8.1/src/label_file.h 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/src/label_file.h 2025-07-16 12:55:13.000000000 +0200 @@ -96,6 +96,7 @@ char *regex_str; /* original regular expression string for diagnostics */ char *literal_match; /* simplified string from regular expression */ uint16_t prefix_len; /* length of fixed path prefix, i.e. length of the literal match */ + uint8_t inputno; /* Input number of source file */ uint8_t file_kind; /* file type */ bool any_matches; /* whether any pathname match */ bool from_mmap; /* whether this spec is from an mmap of the data */ @@ -367,8 +368,9 @@ if (ret) return ret; - /* Order wildcard mode (0) last */ - return (l1->file_kind < l2->file_kind) - (l1->file_kind > l2->file_kind); + /* Order by input number (higher number means added later, means higher priority) */ + ret = spaceship_cmp(l1->inputno, l2->inputno); + return -ret; } static inline int compare_spec_node(const void *p1, const void *p2) @@ -388,16 +390,22 @@ sort_spec_node(data->root, NULL); } -static inline int compile_regex(struct regex_spec *spec, const char **errbuf) +static int compile_regex(struct regex_spec *spec, char *errbuf, size_t errbuf_size) { const char *reg_buf; char *anchored_regex, *cp; struct regex_error_data error_data; - static char regex_error_format_buffer[256]; size_t len; int rc; bool regex_compiled; + if (!errbuf || errbuf_size == 0) { + errno = EINVAL; + return -1; + } + + *errbuf = '\0'; + /* We really want pthread_once() here, but since its * init_routine does not take a parameter, it's not possible * to use, so we generate the same effect with atomics and a @@ -433,11 +441,18 @@ reg_buf = spec->regex_str; /* Anchor the regular expression. */ len = strlen(reg_buf); + /* Use a sufficient large upper bound for regular expression lengths + * to limit the compilation time on malformed inputs. */ + if (len >= 4096) { + __pthread_mutex_unlock(&spec->regex_lock); + snprintf(errbuf, errbuf_size, "regex of length %zu too long", len); + errno = EINVAL; + return -1; + } cp = anchored_regex = malloc(len + 3); if (!anchored_regex) { - if (errbuf) - *errbuf = "out of memory"; __pthread_mutex_unlock(&spec->regex_lock); + snprintf(errbuf, errbuf_size, "out of memory"); return -1; } @@ -452,12 +467,7 @@ rc = regex_prepare_data(&spec->regex, anchored_regex, &error_data); free(anchored_regex); if (rc < 0) { - if (errbuf) { - regex_format_error(&error_data, - regex_error_format_buffer, - sizeof(regex_error_format_buffer)); - *errbuf = ®ex_error_format_buffer[0]; - } + regex_format_error(&error_data, errbuf, errbuf_size); __pthread_mutex_unlock(&spec->regex_lock); errno = EINVAL; return -1; @@ -624,9 +634,9 @@ data->num_specs++; if (rec->validating) { - const char *errbuf = NULL; + char errbuf[256]; - if (compile_regex(&node->regex_specs[id], &errbuf)) { + if (compile_regex(&node->regex_specs[id], errbuf, sizeof(errbuf))) { COMPAT_LOG(SELINUX_ERROR, "%s: line %u has invalid regex %s: %s\n", path, lineno, regex, errbuf); @@ -746,6 +756,7 @@ .regex_str = regex, .prefix_len = prefix_len, .literal_match = literal_regex, + .inputno = inputno, .file_kind = file_kind, .any_matches = false, .lr.ctx_raw = context, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/src/libselinux.map new/libselinux-3.9/src/libselinux.map --- old/libselinux-3.8.1/src/libselinux.map 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/src/libselinux.map 2025-07-16 12:55:13.000000000 +0200 @@ -257,3 +257,8 @@ global: matchpathcon_filespec_add64; } LIBSELINUX_3.5; + +LIBSELINUX_3.9 { + global: + context_to_str; +} LIBSELINUX_3.8; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/src/libselinux.pc.in new/libselinux-3.9/src/libselinux.pc.in --- old/libselinux-3.8.1/src/libselinux.pc.in 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/src/libselinux.pc.in 2025-07-16 12:55:13.000000000 +0200 @@ -6,7 +6,7 @@ Name: libselinux Description: SELinux utility library Version: @VERSION@ -URL: http://userspace.selinuxproject.org/ +URL: https://github.com/selinuxproject/selinux/wiki/Releases Requires.private: libsepol @PCRE_MODULE@ Libs: -L${libdir} -lselinux Cflags: -I${includedir} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/src/matchpathcon.c new/libselinux-3.9/src/matchpathcon.c --- old/libselinux-3.8.1/src/matchpathcon.c 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/src/matchpathcon.c 2025-07-16 12:55:13.000000000 +0200 @@ -261,7 +261,7 @@ return -1; } -#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && __BITS_PER_LONG < 64 +#if (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64) && defined(__INO64_T_TYPE) && !defined(__INO_T_MATCHES_INO64_T) /* alias defined in the public header but we undefine it here */ #undef matchpathcon_filespec_add @@ -280,9 +280,13 @@ { return matchpathcon_filespec_add64(ino, specind, file); } +#elif (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64) || defined(__INO_T_MATCHES_INO64_T) + +static_assert(sizeof(uint64_t) == sizeof(ino_t), "inode size mismatch"); + #else -static_assert(sizeof(unsigned long) == sizeof(ino_t), "inode size mismatch"); +static_assert(sizeof(uint32_t) == sizeof(ino_t), "inode size mismatch"); #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/src/regex.c new/libselinux-3.9/src/regex.c --- old/libselinux-3.8.1/src/regex.c 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/src/regex.c 2025-07-16 12:55:13.000000000 +0200 @@ -30,32 +30,38 @@ #endif #ifdef USE_PCRE2 -char const *regex_arch_string(void) +static pthread_once_t once = PTHREAD_ONCE_INIT; +static char arch_string_buffer[32]; + +static void regex_arch_string_init(void) { - static char arch_string_buffer[32]; - static char const *arch_string = ""; - char const *endianness = NULL; + char const *endianness; int rc; - if (arch_string[0] == '\0') { - if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) - endianness = "el"; - else if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) - endianness = "eb"; - - if (!endianness) - return NULL; - - rc = snprintf(arch_string_buffer, sizeof(arch_string_buffer), - "%zu-%zu-%s", sizeof(void *), - sizeof(REGEX_ARCH_SIZE_T), - endianness); - if (rc < 0) - abort(); + if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + endianness = "el"; + else if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + endianness = "eb"; + else { + arch_string_buffer[0] = '\0'; + return; + } - arch_string = &arch_string_buffer[0]; + rc = snprintf(arch_string_buffer, sizeof(arch_string_buffer), + "%zu-%zu-%s", sizeof(void *), + sizeof(REGEX_ARCH_SIZE_T), + endianness); + if (rc < 0 || (size_t)rc >= sizeof(arch_string_buffer)) { + arch_string_buffer[0] = '\0'; + return; } - return arch_string; +} + +const char *regex_arch_string(void) +{ + __selinux_once(once, regex_arch_string_init); + + return arch_string_buffer[0] != '\0' ? arch_string_buffer : NULL; } struct regex_data { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/src/selinux_config.c new/libselinux-3.9/src/selinux_config.c --- old/libselinux-3.8.1/src/selinux_config.c 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/src/selinux_config.c 2025-07-16 12:55:13.000000000 +0200 @@ -153,7 +153,6 @@ } static char *selinux_policyroot = NULL; -static const char *selinux_rootpath = SELINUXDIR; static void init_selinux_config(void) { @@ -312,7 +311,7 @@ const char *selinux_path(void) { - return selinux_rootpath; + return SELINUXDIR; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/src/selinux_internal.h new/libselinux-3.9/src/selinux_internal.h --- old/libselinux-3.8.1/src/selinux_internal.h 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/src/selinux_internal.h 2025-07-16 12:55:13.000000000 +0200 @@ -150,4 +150,6 @@ # define unlikely(x) (x) #endif /* __GNUC__ */ +#define spaceship_cmp(a, b) (((a) > (b)) - ((a) < (b))) + #endif /* SELINUX_INTERNAL_H_ */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/src/selinux_restorecon.c new/libselinux-3.9/src/selinux_restorecon.c --- old/libselinux-3.8.1/src/selinux_restorecon.c 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/src/selinux_restorecon.c 2025-07-16 12:55:13.000000000 +0200 @@ -76,6 +76,7 @@ bool progress; bool mass_relabel; bool set_specctx; + bool set_user_role; bool add_assoc; bool recurse; bool userealpath; @@ -585,43 +586,65 @@ /* * Called if SELINUX_RESTORECON_SET_SPECFILE_CTX is not set to check if * the type components differ, updating newtypecon if so. + * Also update user and role components if + * SELINUX_RESTORECON_SET_USER_ROLE is set. */ -static int compare_types(const char *curcon, const char *newcon, char **newtypecon) +static int compare_portions(const char *curcon, const char *newcon, + bool set_user_role, char **newtypecon) { - int types_differ = 0; - context_t cona; - context_t conb; + context_t curctx; + context_t newctx; + bool update = false; int rc = 0; - cona = context_new(curcon); - if (!cona) { + curctx = context_new(curcon); + if (!curctx) { rc = -1; goto out; } - conb = context_new(newcon); - if (!conb) { - context_free(cona); + newctx = context_new(newcon); + if (!newctx) { + context_free(curctx); rc = -1; goto out; } - types_differ = strcmp(context_type_get(cona), context_type_get(conb)); - if (types_differ) { - rc |= context_user_set(conb, context_user_get(cona)); - 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)); - if (!*newtypecon) { - rc = -1; + if (strcmp(context_type_get(curctx), context_type_get(newctx)) != 0) { + update = true; + rc = context_type_set(curctx, context_type_get(newctx)); + if (rc) + goto err; + } + + if (set_user_role) { + if (strcmp(context_user_get(curctx), context_user_get(newctx)) != 0) { + update = true; + rc = context_user_set(curctx, context_user_get(newctx)); + if (rc) + goto err; + } + + if (strcmp(context_role_get(curctx), context_role_get(newctx)) != 0) { + update = true; + rc = context_role_set(curctx, context_role_get(newctx)); + if (rc) goto err; - } } } + if (update) { + *newtypecon = context_to_str(curctx); + if (!*newtypecon) { + rc = -1; + goto err; + } + } else { + *newtypecon = NULL; + } + err: - context_free(cona); - context_free(conb); + context_free(curctx); + context_free(newctx); out: return rc; } @@ -631,7 +654,6 @@ { char *newcon = NULL; char *curcon = NULL; - char *newtypecon = NULL; int rc; const char *lookup_path = pathname; @@ -724,8 +746,13 @@ } if (!flags->set_specctx && curcon) { - /* If types different then update newcon. */ - rc = compare_types(curcon, newcon, &newtypecon); + char *newtypecon; + + /* If types are different then update newcon. + * Also update if SELINUX_RESTORECON_SET_USER_ROLE + * is set and user or role differs. + */ + rc = compare_portions(curcon, newcon, flags->set_user_role, &newtypecon); if (rc) goto err; @@ -1025,6 +1052,8 @@ SELINUX_RESTORECON_RECURSE) ? true : false; state.flags.set_specctx = (restorecon_flags & SELINUX_RESTORECON_SET_SPECFILE_CTX) ? true : false; + state.flags.set_user_role = (restorecon_flags & + SELINUX_RESTORECON_SET_USER_ROLE) ? true : false; state.flags.userealpath = (restorecon_flags & SELINUX_RESTORECON_REALPATH) ? true : false; state.flags.set_xdev = (restorecon_flags & diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/src/setexecfilecon.c new/libselinux-3.9/src/setexecfilecon.c --- old/libselinux-3.8.1/src/setexecfilecon.c 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/src/setexecfilecon.c 2025-07-16 12:55:13.000000000 +0200 @@ -34,7 +34,7 @@ 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; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/src/setup.py new/libselinux-3.9/src/setup.py --- old/libselinux-3.8.1/src/setup.py 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/src/setup.py 2025-07-16 12:55:13.000000000 +0200 @@ -4,7 +4,7 @@ setup( name="selinux", - version="3.8.1", + version="3.9", description="SELinux python 3 bindings", author="SELinux Project", author_email="seli...@vger.kernel.org", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libselinux-3.8.1/utils/Makefile new/libselinux-3.9/utils/Makefile --- old/libselinux-3.8.1/utils/Makefile 2025-03-05 19:59:06.000000000 +0100 +++ new/libselinux-3.9/utils/Makefile 2025-07-16 12:55:13.000000000 +0200 @@ -53,7 +53,13 @@ TARGETS=$(patsubst %.c,%,$(sort $(wildcard *.c))) endif -sefcontext_compile: LDLIBS += ../src/libselinux.a $(PCRE_LDLIBS) -lsepol +sefcontext_compile: LDLIBS += ../src/libselinux.a -lsepol + +PCRE_USERS = matchpathcon sefcontext_compile selabel_compare \ + selabel_digest selabel_get_digests_all_partial_matches \ + selabel_lookup selabel_lookup_best_match \ + selabel_partial_match +$(PCRE_USERS): LDLIBS += $(PCRE_LDLIBS) all: $(TARGETS)