From 1175f753dd821ae0973dfddfa4df53b6b4d5a551 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Sep 27 2022 14:47:00 +0000 Subject: import libselinux-3.4-3.el9 --- diff --git a/.gitignore b/.gitignore index f8649bc..609ac99 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/libselinux-3.3.tar.gz +SOURCES/libselinux-3.4.tar.gz diff --git a/.libselinux.metadata b/.libselinux.metadata index db6fb6a..5d9e33b 100644 --- a/.libselinux.metadata +++ b/.libselinux.metadata @@ -1 +1 @@ -70128f2395fc86b09c57db979972b4823b35e614 SOURCES/libselinux-3.3.tar.gz +1fff75ad31eca7979740af01279d868ca8cbd249 SOURCES/libselinux-3.4.tar.gz diff --git a/SOURCES/0001-Use-SHA-2-instead-of-SHA-1.patch b/SOURCES/0001-Use-SHA-2-instead-of-SHA-1.patch index ed63a8c..fcd15a6 100644 --- a/SOURCES/0001-Use-SHA-2-instead-of-SHA-1.patch +++ b/SOURCES/0001-Use-SHA-2-instead-of-SHA-1.patch @@ -1,7 +1,8 @@ -From ec1b147076345478636de763ce5d4e8daa69afd6 Mon Sep 17 00:00:00 2001 +From 04f73fee2892753b3e81923d2ac3d338acfdbc4c Mon Sep 17 00:00:00 2001 From: Petr Lautrbach Date: Fri, 30 Jul 2021 14:14:37 +0200 Subject: [PATCH] Use SHA-2 instead of SHA-1 +Content-type: text/plain The use of SHA-1 in RHEL9 is deprecated --- @@ -9,12 +10,12 @@ The use of SHA-1 in RHEL9 is deprecated libselinux/include/selinux/restorecon.h | 4 +- libselinux/man/man3/selabel_digest.3 | 4 +- libselinux/man/man3/selabel_open.3 | 2 +- - libselinux/man/man3/selinux_restorecon.3 | 16 +- + libselinux/man/man3/selinux_restorecon.3 | 18 +- .../man/man3/selinux_restorecon_xattr.3 | 2 +- libselinux/src/Makefile | 2 +- libselinux/src/label_file.c | 40 +-- libselinux/src/label_internal.h | 10 +- - libselinux/src/label_support.c | 8 +- + libselinux/src/label_support.c | 10 +- libselinux/src/selinux_restorecon.c | 24 +- libselinux/src/sha1.c | 220 ------------- libselinux/src/sha1.h | 85 ----- @@ -22,7 +23,7 @@ The use of SHA-1 in RHEL9 is deprecated libselinux/src/sha256.h | 89 ++++++ libselinux/utils/selabel_digest.c | 26 +- .../selabel_get_digests_all_partial_matches.c | 28 +- - 17 files changed, 469 insertions(+), 391 deletions(-) + 17 files changed, 471 insertions(+), 393 deletions(-) delete mode 100644 libselinux/src/sha1.c delete mode 100644 libselinux/src/sha1.h create mode 100644 libselinux/src/sha256.c @@ -50,10 +51,10 @@ index e8983606d93b..a35d84d63b0a 100644 * @num_specfiles: number of specfiles in the list. * diff --git a/libselinux/include/selinux/restorecon.h b/libselinux/include/selinux/restorecon.h -index 466de39aac72..ca8ce768587a 100644 +index b10fe684eff9..8df4744505b3 100644 --- a/libselinux/include/selinux/restorecon.h +++ b/libselinux/include/selinux/restorecon.h -@@ -27,8 +27,8 @@ extern int selinux_restorecon(const char *pathname, +@@ -41,8 +41,8 @@ extern int selinux_restorecon_parallel(const char *pathname, * restorecon_flags options */ /* @@ -83,7 +84,7 @@ index 56a008f00df0..5f7c42533d0e 100644 with the number of entries in .IR num_specfiles . diff --git a/libselinux/man/man3/selabel_open.3 b/libselinux/man/man3/selabel_open.3 -index 971ebc1acd41..2cf2eb8a1410 100644 +index 0e03e1be111e..14ab888d2e03 100644 --- a/libselinux/man/man3/selabel_open.3 +++ b/libselinux/man/man3/selabel_open.3 @@ -69,7 +69,7 @@ is used; a custom validation function can be provided via @@ -96,10 +97,10 @@ index 971ebc1acd41..2cf2eb8a1410 100644 .BR selabel_digest (3) . diff --git a/libselinux/man/man3/selinux_restorecon.3 b/libselinux/man/man3/selinux_restorecon.3 -index ad637406a30d..c4576fe79ff6 100644 +index 218aaf6d2ae5..5f6d4b386429 100644 --- a/libselinux/man/man3/selinux_restorecon.3 +++ b/libselinux/man/man3/selinux_restorecon.3 -@@ -28,7 +28,7 @@ If this is a directory and the +@@ -36,7 +36,7 @@ If this is a directory and the .B SELINUX_RESTORECON_RECURSE has been set (for descending through directories), then .BR selinux_restorecon () @@ -108,7 +109,7 @@ index ad637406a30d..c4576fe79ff6 100644 .BR selabel_get_digests_all_partial_matches (3) to an extended attribute of .IR security.sehash -@@ -47,7 +47,7 @@ will take place. +@@ -55,7 +55,7 @@ will take place. .br The .IR restorecon_flags @@ -117,7 +118,7 @@ index ad637406a30d..c4576fe79ff6 100644 .RS .B SELINUX_RESTORECON_SKIP_DIGEST .br -@@ -65,8 +65,8 @@ Do not check or update any extended attribute +@@ -73,8 +73,8 @@ Do not check or update any extended attribute entries. .sp .B SELINUX_RESTORECON_IGNORE_DIGEST @@ -128,7 +129,7 @@ index ad637406a30d..c4576fe79ff6 100644 .IR security.sehash extended attribute once relabeling has been completed successfully provided the .B SELINUX_RESTORECON_NOCHANGE -@@ -84,7 +84,7 @@ default specfile context. +@@ -95,7 +95,7 @@ default specfile context. .sp .B SELINUX_RESTORECON_RECURSE change file and directory labels recursively (descend directories) @@ -137,8 +138,14 @@ index ad637406a30d..c4576fe79ff6 100644 extended attribute as described in the .B NOTES section. -@@ -158,7 +158,7 @@ to treat conflicting specifications, such as where two hardlinks for the - same inode have different contexts, as errors. +@@ -179,12 +179,12 @@ for fetching the ignored (skipped) error count after + or + .BR selinux_restorecon_parallel (3) + completes with success. In case any errors were skipped during the file tree +-walk, the specfile entries SHA1 digest will not have been written to the ++walk, the specfile entries SHA256 digest will not have been written to the + .IR security.sehash + extended attribute. .RE .sp -The behavior regarding the checking and updating of the SHA1 digest described @@ -146,7 +153,7 @@ index ad637406a30d..c4576fe79ff6 100644 above is the default behavior. It is possible to change this by first calling .BR selabel_open (3) and not enabling the -@@ -200,7 +200,7 @@ To improve performance when relabeling file systems recursively (e.g. the +@@ -247,7 +247,7 @@ To improve performance when relabeling file systems recursively (e.g. the .B SELINUX_RESTORECON_RECURSE flag is set) .BR selinux_restorecon () @@ -155,7 +162,7 @@ index ad637406a30d..c4576fe79ff6 100644 .BR selabel_get_digests_all_partial_matches (3) to an extended attribute named .IR security.sehash -@@ -222,7 +222,7 @@ Should any of the specfile entries have changed, then when +@@ -269,7 +269,7 @@ Should any of the specfile entries have changed, then when .BR selinux_restorecon () is run again with the .B SELINUX_RESTORECON_RECURSE @@ -178,10 +185,10 @@ index c56326814b94..098c840fc59b 100644 .BR selabel_open (3) must be called specifying the required diff --git a/libselinux/src/Makefile b/libselinux/src/Makefile -index 52c40f018f51..674a5ed3a6f8 100644 +index 04bf4f240168..222c3fa2d7c3 100644 --- a/libselinux/src/Makefile +++ b/libselinux/src/Makefile -@@ -120,7 +120,7 @@ DISABLE_FLAGS+= -DNO_MEDIA_BACKEND -DNO_DB_BACKEND -DNO_X_BACKEND \ +@@ -119,7 +119,7 @@ DISABLE_FLAGS+= -DNO_MEDIA_BACKEND -DNO_DB_BACKEND -DNO_X_BACKEND \ -DBUILD_HOST SRCS= callbacks.c freecon.c label.c label_file.c \ label_backends_android.c regex.c label_support.c \ @@ -191,10 +198,10 @@ index 52c40f018f51..674a5ed3a6f8 100644 LABEL_BACKEND_ANDROID=y endif diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c -index 2e28d0474d73..c1306c9979e7 100644 +index 74ae9b9feb70..33d395e414f0 100644 --- a/libselinux/src/label_file.c +++ b/libselinux/src/label_file.c -@@ -1005,7 +1005,7 @@ static struct spec *lookup_common(struct selabel_handle *rec, +@@ -1010,7 +1010,7 @@ static struct spec *lookup_common(struct selabel_handle *rec, /* * Returns true if the digest of all partial matched contexts is the same as @@ -203,7 +210,7 @@ index 2e28d0474d73..c1306c9979e7 100644 * digest will always be returned. The caller must free any returned digests. */ static bool get_digests_all_partial_matches(struct selabel_handle *rec, -@@ -1014,39 +1014,39 @@ static bool get_digests_all_partial_matches(struct selabel_handle *rec, +@@ -1019,39 +1019,39 @@ static bool get_digests_all_partial_matches(struct selabel_handle *rec, uint8_t **xattr_digest, size_t *digest_len) { @@ -254,7 +261,7 @@ index 2e28d0474d73..c1306c9979e7 100644 return true; return false; -@@ -1066,22 +1066,22 @@ static bool hash_all_partial_matches(struct selabel_handle *rec, const char *key +@@ -1071,22 +1071,22 @@ static bool hash_all_partial_matches(struct selabel_handle *rec, const char *key return false; } @@ -327,31 +334,44 @@ index 782c6aa8cc0c..304e8d96490a 100644 }; diff --git a/libselinux/src/label_support.c b/libselinux/src/label_support.c -index 94ed6e4273cb..f53d73b609ab 100644 +index 54fd49a5b7b9..4003eb8dc7af 100644 --- a/libselinux/src/label_support.c +++ b/libselinux/src/label_support.c -@@ -115,15 +115,15 @@ int read_spec_entries(char *line_buf, const char **errbuf, int num_args, ...) +@@ -115,7 +115,7 @@ int read_spec_entries(char *line_buf, const char **errbuf, int num_args, ...) /* Once all the specfiles are in the hash_buf, generate the hash. */ void digest_gen_hash(struct selabel_digest *digest) { - Sha1Context context; + Sha256Context context; + size_t remaining_size; + const unsigned char *ptr; - /* If SELABEL_OPT_DIGEST not set then just return */ +@@ -123,19 +123,19 @@ void digest_gen_hash(struct selabel_digest *digest) if (!digest) return; - Sha1Initialise(&context); -- Sha1Update(&context, digest->hashbuf, digest->hashbuf_size); -- Sha1Finalise(&context, (SHA1_HASH *)digest->digest); + Sha256Initialise(&context); -+ Sha256Update(&context, digest->hashbuf, digest->hashbuf_size); + + /* Process in blocks of UINT32_MAX bytes */ + remaining_size = digest->hashbuf_size; + ptr = digest->hashbuf; + while (remaining_size > UINT32_MAX) { +- Sha1Update(&context, ptr, UINT32_MAX); ++ Sha256Update(&context, ptr, UINT32_MAX); + remaining_size -= UINT32_MAX; + ptr += UINT32_MAX; + } +- Sha1Update(&context, ptr, remaining_size); ++ Sha256Update(&context, ptr, remaining_size); + +- Sha1Finalise(&context, (SHA1_HASH *)digest->digest); + Sha256Finalise(&context, (SHA256_HASH *)digest->digest); free(digest->hashbuf); digest->hashbuf = NULL; return; diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c -index 04d956504952..100c77108a27 100644 +index 9dd6be817832..dc222b425c95 100644 --- a/libselinux/src/selinux_restorecon.c +++ b/libselinux/src/selinux_restorecon.c @@ -37,7 +37,7 @@ @@ -363,16 +383,16 @@ index 04d956504952..100c77108a27 100644 #define STAR_COUNT 1024 -@@ -293,7 +293,7 @@ static int exclude_non_seclabel_mounts(void) +@@ -305,7 +305,7 @@ static uint64_t exclude_non_seclabel_mounts(void) static int add_xattr_entry(const char *directory, bool delete_nonmatch, bool delete_all) { - char *sha1_buf = NULL; + char *sha256_buf = NULL; size_t i, digest_len = 0; - int rc, digest_result; - bool match; -@@ -316,15 +316,15 @@ static int add_xattr_entry(const char *directory, bool delete_nonmatch, + int rc; + enum digest_result digest_result; +@@ -329,15 +329,15 @@ static int add_xattr_entry(const char *directory, bool delete_nonmatch, } /* Convert entry to a hex encoded string. */ @@ -391,7 +411,7 @@ index 04d956504952..100c77108a27 100644 digest_result = match ? MATCH : NOMATCH; -@@ -344,7 +344,7 @@ static int add_xattr_entry(const char *directory, bool delete_nonmatch, +@@ -357,7 +357,7 @@ static int add_xattr_entry(const char *directory, bool delete_nonmatch, /* Now add entries to link list. */ new_entry = malloc(sizeof(struct dir_xattr)); if (!new_entry) { @@ -400,7 +420,7 @@ index 04d956504952..100c77108a27 100644 goto oom; } new_entry->next = NULL; -@@ -352,15 +352,15 @@ static int add_xattr_entry(const char *directory, bool delete_nonmatch, +@@ -365,15 +365,15 @@ static int add_xattr_entry(const char *directory, bool delete_nonmatch, new_entry->directory = strdup(directory); if (!new_entry->directory) { free(new_entry); @@ -419,7 +439,7 @@ index 04d956504952..100c77108a27 100644 goto oom; } -@@ -374,7 +374,7 @@ static int add_xattr_entry(const char *directory, bool delete_nonmatch, +@@ -387,7 +387,7 @@ static int add_xattr_entry(const char *directory, bool delete_nonmatch, dir_xattr_last = new_entry; } @@ -428,7 +448,7 @@ index 04d956504952..100c77108a27 100644 return 0; oom: -@@ -741,7 +741,7 @@ err: +@@ -781,7 +781,7 @@ err: struct dir_hash_node { char *path; @@ -437,7 +457,7 @@ index 04d956504952..100c77108a27 100644 struct dir_hash_node *next; }; /* -@@ -1091,7 +1091,7 @@ int selinux_restorecon(const char *pathname_orig, +@@ -1270,7 +1270,7 @@ static int selinux_restorecon_common(const char *pathname_orig, if (setxattr(current->path, RESTORECON_PARTIAL_MATCH_DIGEST, current->digest, @@ -1159,7 +1179,7 @@ index 000000000000..406ed869cd82 + SHA256_HASH* Digest // [in] + ); diff --git a/libselinux/utils/selabel_digest.c b/libselinux/utils/selabel_digest.c -index 49408a0ba8d8..67befadd23c5 100644 +index 6a8313a2c88d..a69331f1c6b5 100644 --- a/libselinux/utils/selabel_digest.c +++ b/libselinux/utils/selabel_digest.c @@ -15,8 +15,8 @@ static __attribute__ ((__noreturn__)) void usage(const char *progname) @@ -1240,7 +1260,7 @@ index 49408a0ba8d8..67befadd23c5 100644 selabel_close(hnd); return rc; diff --git a/libselinux/utils/selabel_get_digests_all_partial_matches.c b/libselinux/utils/selabel_get_digests_all_partial_matches.c -index e28833d2ce97..900f018c0091 100644 +index c4e0f836b260..80723f714264 100644 --- a/libselinux/utils/selabel_get_digests_all_partial_matches.c +++ b/libselinux/utils/selabel_get_digests_all_partial_matches.c @@ -18,8 +18,8 @@ static __attribute__ ((__noreturn__)) void usage(const char *progname) @@ -1263,7 +1283,7 @@ index e28833d2ce97..900f018c0091 100644 struct selabel_handle *hnd; struct selinux_opt selabel_option[] = { -@@ -105,27 +105,27 @@ int main(int argc, char **argv) +@@ -106,27 +106,27 @@ int main(int argc, char **argv) &xattr_digest, &digest_len); @@ -1297,7 +1317,7 @@ index e28833d2ce97..900f018c0091 100644 ftsent->fts_path); printf("as file_context entry is \"<>\"\n"); goto cleanup; -@@ -135,25 +135,25 @@ int main(int argc, char **argv) +@@ -136,25 +136,25 @@ int main(int argc, char **argv) ftsent->fts_path); for (i = 0; i < digest_len; i++) @@ -1329,5 +1349,5 @@ index e28833d2ce97..900f018c0091 100644 } default: -- -2.32.0 +2.36.1 diff --git a/SOURCES/0002-Revert-libselinux-restorecon-pin-file-to-avoid-TOCTO.patch b/SOURCES/0002-Revert-libselinux-restorecon-pin-file-to-avoid-TOCTO.patch new file mode 100644 index 0000000..f586640 --- /dev/null +++ b/SOURCES/0002-Revert-libselinux-restorecon-pin-file-to-avoid-TOCTO.patch @@ -0,0 +1,172 @@ +From f785c53174fd0ebad913e105382360f9d46205d8 Mon Sep 17 00:00:00 2001 +From: Petr Lautrbach +Date: Tue, 31 May 2022 13:37:12 +0200 +Subject: [PATCH] Revert "libselinux: restorecon: pin file to avoid TOCTOU + issues" +Content-type: text/plain + +This reverts commit 7e979b56fd2cee28f647376a7233d2ac2d12ca50. + +The reverted commit broke `setfiles` when it's run from a chroot +without /proc mounted, e.g. + + # chroot /mnt/sysimage + + chroot# setfiles -e /proc -e /sys /sys /etc/selinux/targeted/contexts/files/file_contexts / + [strace] + openat(AT_FDCWD, "/", O_RDONLY|O_EXCL|O_NOFOLLOW|O_PATH) = 3 + newfstatat(3, "", {st_mode=S_IFDIR|0555, st_size=4096, ...}, AT_EMPTY_PATH) = 0 + mmap(NULL, 2101248, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1697c91000 + fgetxattr(3, "security.selinux", 0x55be8881d3f0, 255) = -1 EBADF (Bad file descriptor) + fcntl(3, F_GETFL) = 0x220000 (flags O_RDONLY|O_NOFOLLOW|O_PATH) + getxattr("/proc/self/fd/3", "security.selinux", 0x55be8881d3f0, 255) = -1 ENOENT (No such file or directory) + [/strace] + setfiles: Could not set context for /: No such file or directory + +Signed-off-by: Petr Lautrbach +--- + libselinux/src/selinux_restorecon.c | 43 ++++++++++++----------------- + 1 file changed, 18 insertions(+), 25 deletions(-) + +diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c +index dc222b425c95..a50005353265 100644 +--- a/libselinux/src/selinux_restorecon.c ++++ b/libselinux/src/selinux_restorecon.c +@@ -623,13 +623,13 @@ out: + return rc; + } + +-static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool first) ++static int restorecon_sb(const char *pathname, const struct stat *sb, ++ struct rest_flags *flags, bool first) + { + char *newcon = NULL; + char *curcon = NULL; + char *newtypecon = NULL; +- int fd = -1, rc; +- struct stat stat_buf; ++ int rc; + bool updated = false; + const char *lookup_path = pathname; + float pc; +@@ -644,21 +644,13 @@ static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool fi + lookup_path += rootpathlen; + } + +- fd = open(pathname, O_PATH | O_NOFOLLOW | O_EXCL); +- if (fd < 0) +- goto err; +- +- rc = fstat(fd, &stat_buf); +- if (rc < 0) +- goto err; +- + if (rootpath != NULL && lookup_path[0] == '\0') + /* this is actually the root dir of the alt root. */ + rc = selabel_lookup_raw(fc_sehandle, &newcon, "/", +- stat_buf.st_mode); ++ sb->st_mode); + else + rc = selabel_lookup_raw(fc_sehandle, &newcon, lookup_path, +- stat_buf.st_mode); ++ sb->st_mode); + + if (rc < 0) { + if (errno == ENOENT) { +@@ -667,10 +659,10 @@ static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool fi + "Warning no default label for %s\n", + lookup_path); + +- goto out; /* no match, but not an error */ ++ return 0; /* no match, but not an error */ + } + +- goto err; ++ return -1; + } + + if (flags->progress) { +@@ -690,17 +682,19 @@ static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool fi + } + + if (flags->add_assoc) { +- rc = filespec_add(stat_buf.st_ino, newcon, pathname, flags); ++ rc = filespec_add(sb->st_ino, newcon, pathname, flags); + + if (rc < 0) { + selinux_log(SELINUX_ERROR, + "filespec_add error: %s\n", pathname); +- goto out1; ++ freecon(newcon); ++ return -1; + } + + if (rc > 0) { + /* Already an association and it took precedence. */ +- goto out; ++ freecon(newcon); ++ return 0; + } + } + +@@ -708,7 +702,7 @@ static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool fi + selinux_log(SELINUX_INFO, "%s matched by %s\n", + pathname, newcon); + +- if (fgetfilecon_raw(fd, &curcon) < 0) { ++ if (lgetfilecon_raw(pathname, &curcon) < 0) { + if (errno != ENODATA) + goto err; + +@@ -741,7 +735,7 @@ static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool fi + } + + if (!flags->nochange) { +- if (fsetfilecon(fd, newcon) < 0) ++ if (lsetfilecon(pathname, newcon) < 0) + goto err; + updated = true; + } +@@ -766,8 +760,6 @@ static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool fi + out: + rc = 0; + out1: +- if (fd >= 0) +- close(fd); + freecon(curcon); + freecon(newcon); + return rc; +@@ -865,6 +857,7 @@ static void *selinux_restorecon_thread(void *arg) + FTSENT *ftsent; + int error; + char ent_path[PATH_MAX]; ++ struct stat ent_st; + bool first = false; + + if (state->parallel) +@@ -962,11 +955,11 @@ loop_body: + /* fall through */ + default: + strcpy(ent_path, ftsent->fts_path); +- ++ ent_st = *ftsent->fts_statp; + if (state->parallel) + pthread_mutex_unlock(&state->mutex); + +- error = restorecon_sb(ent_path, &state->flags, ++ error = restorecon_sb(ent_path, &ent_st, &state->flags, + first); + + if (state->parallel) { +@@ -1162,7 +1155,7 @@ static int selinux_restorecon_common(const char *pathname_orig, + goto cleanup; + } + +- error = restorecon_sb(pathname, &state.flags, true); ++ error = restorecon_sb(pathname, &sb, &state.flags, true); + goto cleanup; + } + +-- +2.36.1 + diff --git a/SOURCES/0002-label_file-fix-a-data-race.patch b/SOURCES/0002-label_file-fix-a-data-race.patch deleted file mode 100644 index 0554c37..0000000 --- a/SOURCES/0002-label_file-fix-a-data-race.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 5844f389429f26a0a62a65561fa3006feaaf6f3b Mon Sep 17 00:00:00 2001 -From: Ondrej Mosnacek -Date: Tue, 26 Oct 2021 13:52:32 +0200 -Subject: [PATCH] label_file: fix a data race - -The 'matches' member of 'struct spec' may be written to by different -threads, so it needs to be accessed using the proper atomic constructs. -Since the actual count of matches doesn't matter and is not used, -convert this field to a bool and just atomically set/read it using GCC -__atomic builtins (which are already being used in another place). - -If the compiler lacks support for __atomic builtins (which seem to have -been introduced in GCC 4.1), just fail the compilation. I don't think -it's worth tryin to invent a workaround to support a 15 years old -compiler. - -Signed-off-by: Ondrej Mosnacek ---- - libselinux/src/label_file.c | 15 +++++++++++++-- - libselinux/src/label_file.h | 2 +- - 2 files changed, 14 insertions(+), 3 deletions(-) - -diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c -index c1306c9979e7..33d395e414f0 100644 ---- a/libselinux/src/label_file.c -+++ b/libselinux/src/label_file.c -@@ -951,7 +951,12 @@ static struct spec **lookup_all(struct selabel_handle *rec, - rc = regex_match(spec->regex, key, partial); - if (rc == REGEX_MATCH || (partial && rc == REGEX_MATCH_PARTIAL)) { - if (rc == REGEX_MATCH) { -- spec->matches++; -+#ifdef __ATOMIC_RELAXED -+ __atomic_store_n(&spec->any_matches, -+ true, __ATOMIC_RELAXED); -+#else -+#error "Please use a compiler that supports __atomic builtins" -+#endif - } - - if (strcmp(spec_arr[i].lr.ctx_raw, "<>") == 0) { -@@ -1249,9 +1254,15 @@ static void stats(struct selabel_handle *rec) - struct saved_data *data = (struct saved_data *)rec->data; - unsigned int i, nspec = data->nspec; - struct spec *spec_arr = data->spec_arr; -+ bool any_matches; - - for (i = 0; i < nspec; i++) { -- if (spec_arr[i].matches == 0) { -+#ifdef __ATOMIC_RELAXED -+ any_matches = __atomic_load_n(&spec_arr[i].any_matches, __ATOMIC_RELAXED); -+#else -+#error "Please use a compiler that supports __atomic builtins" -+#endif -+ if (!any_matches) { - if (spec_arr[i].type_str) { - COMPAT_LOG(SELINUX_WARNING, - "Warning! No matches for (%s, %s, %s)\n", -diff --git a/libselinux/src/label_file.h b/libselinux/src/label_file.h -index 343ffc705e43..b453e13f8075 100644 ---- a/libselinux/src/label_file.h -+++ b/libselinux/src/label_file.h -@@ -51,7 +51,7 @@ struct spec { - bool regex_compiled; /* bool to indicate if the regex is compiled */ - pthread_mutex_t regex_lock; /* lock for lazy compilation of regex */ - mode_t mode; /* mode format value */ -- int matches; /* number of matching pathnames */ -+ bool any_matches; /* did any pathname match? */ - int stem_id; /* indicates which stem-compression item */ - char hasMetaChars; /* regular expression has meta-chars */ - char from_mmap; /* this spec is from an mmap of the data */ --- -2.33.1 - diff --git a/SOURCES/0003-selinux_restorecon-simplify-fl_head-allocation-by-us.patch b/SOURCES/0003-selinux_restorecon-simplify-fl_head-allocation-by-us.patch deleted file mode 100644 index 01c6d25..0000000 --- a/SOURCES/0003-selinux_restorecon-simplify-fl_head-allocation-by-us.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 5dd3a11842c08a25a0f7ab798ce85710fe1e8f1f Mon Sep 17 00:00:00 2001 -From: Ondrej Mosnacek -Date: Tue, 26 Oct 2021 13:52:33 +0200 -Subject: [PATCH] selinux_restorecon: simplify fl_head allocation by using - calloc() - -Signed-off-by: Ondrej Mosnacek ---- - libselinux/src/selinux_restorecon.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c -index 100c77108a27..e29a2c390182 100644 ---- a/libselinux/src/selinux_restorecon.c -+++ b/libselinux/src/selinux_restorecon.c -@@ -425,10 +425,9 @@ static int filespec_add(ino_t ino, const char *con, const char *file, - struct stat64 sb; - - if (!fl_head) { -- fl_head = malloc(sizeof(file_spec_t) * HASH_BUCKETS); -+ fl_head = calloc(HASH_BUCKETS, sizeof(file_spec_t)); - if (!fl_head) - goto oom; -- memset(fl_head, 0, sizeof(file_spec_t) * HASH_BUCKETS); - } - - h = (ino + (ino >> HASH_BITS)) & HASH_MASK; --- -2.33.1 - diff --git a/SOURCES/0004-selinux_restorecon-protect-file_spec-list-with-a-mut.patch b/SOURCES/0004-selinux_restorecon-protect-file_spec-list-with-a-mut.patch deleted file mode 100644 index 1143f33..0000000 --- a/SOURCES/0004-selinux_restorecon-protect-file_spec-list-with-a-mut.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 4598a46c5ed12248a3a6e1dbe1b5a3dca52bacac Mon Sep 17 00:00:00 2001 -From: Ondrej Mosnacek -Date: Tue, 26 Oct 2021 13:52:34 +0200 -Subject: [PATCH] selinux_restorecon: protect file_spec list with a mutex - -Not very useful on its own, but will allow to implement a parallel -version of selinux_restorecon() in subsequent patches. - -Signed-off-by: Ondrej Mosnacek ---- - libselinux/src/selinux_restorecon.c | 16 ++++++++++++++-- - 1 file changed, 14 insertions(+), 2 deletions(-) - -diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c -index e29a2c390182..43acbace309d 100644 ---- a/libselinux/src/selinux_restorecon.c -+++ b/libselinux/src/selinux_restorecon.c -@@ -411,6 +411,7 @@ typedef struct file_spec { - } file_spec_t; - - static file_spec_t *fl_head; -+static pthread_mutex_t fl_mutex = PTHREAD_MUTEX_INITIALIZER; - - /* - * Try to add an association between an inode and a context. If there is a -@@ -424,6 +425,8 @@ static int filespec_add(ino_t ino, const char *con, const char *file, - int h, ret; - struct stat64 sb; - -+ __pthread_mutex_lock(&fl_mutex); -+ - if (!fl_head) { - fl_head = calloc(HASH_BUCKETS, sizeof(file_spec_t)); - if (!fl_head) -@@ -444,11 +447,11 @@ static int filespec_add(ino_t ino, const char *con, const char *file, - fl->con = strdup(con); - if (!fl->con) - goto oom; -- return 1; -+ goto unlock_1; - } - - if (strcmp(fl->con, con) == 0) -- return 1; -+ goto unlock_1; - - selinux_log(SELINUX_ERROR, - "conflicting specifications for %s and %s, using %s.\n", -@@ -457,6 +460,9 @@ static int filespec_add(ino_t ino, const char *con, const char *file, - fl->file = strdup(file); - if (!fl->file) - goto oom; -+ -+ __pthread_mutex_unlock(&fl_mutex); -+ - if (flags->conflicterror) { - selinux_log(SELINUX_ERROR, - "treating conflicting specifications as an error.\n"); -@@ -481,13 +487,19 @@ static int filespec_add(ino_t ino, const char *con, const char *file, - goto oom_freefl; - fl->next = prevfl->next; - prevfl->next = fl; -+ -+ __pthread_mutex_unlock(&fl_mutex); - return 0; - - oom_freefl: - free(fl); - oom: -+ __pthread_mutex_unlock(&fl_mutex); - selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__); - return -1; -+unlock_1: -+ __pthread_mutex_unlock(&fl_mutex); -+ return 1; - } - - /* --- -2.33.1 - diff --git a/SOURCES/0005-libselinux-make-selinux_log-thread-safe.patch b/SOURCES/0005-libselinux-make-selinux_log-thread-safe.patch deleted file mode 100644 index 078d5b4..0000000 --- a/SOURCES/0005-libselinux-make-selinux_log-thread-safe.patch +++ /dev/null @@ -1,88 +0,0 @@ -From c2e4cf5b21e8c775c669f3933d25a0946774ec0d Mon Sep 17 00:00:00 2001 -From: Ondrej Mosnacek -Date: Tue, 26 Oct 2021 13:52:35 +0200 -Subject: [PATCH] libselinux: make selinux_log() thread-safe - -Ensure that selinux_log() is thread-safe by guarding the call to the -underlying callback with a mutex. - -Signed-off-by: Ondrej Mosnacek ---- - libselinux/src/callbacks.c | 8 +++++--- - libselinux/src/callbacks.h | 13 ++++++++++++- - 2 files changed, 17 insertions(+), 4 deletions(-) - -diff --git a/libselinux/src/callbacks.c b/libselinux/src/callbacks.c -index c18ccc54754a..469c4055f4d7 100644 ---- a/libselinux/src/callbacks.c -+++ b/libselinux/src/callbacks.c -@@ -10,6 +10,8 @@ - #include - #include "callbacks.h" - -+pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER; -+ - /* default implementations */ - static int __attribute__ ((format(printf, 2, 3))) - default_selinux_log(int type __attribute__((unused)), const char *fmt, ...) -@@ -56,7 +58,7 @@ default_selinux_policyload(int seqno __attribute__((unused))) - - /* callback pointers */ - int __attribute__ ((format(printf, 2, 3))) --(*selinux_log)(int, const char *, ...) = -+(*selinux_log_direct)(int, const char *, ...) = - default_selinux_log; - - int -@@ -81,7 +83,7 @@ selinux_set_callback(int type, union selinux_callback cb) - { - switch (type) { - case SELINUX_CB_LOG: -- selinux_log = cb.func_log; -+ selinux_log_direct = cb.func_log; - break; - case SELINUX_CB_AUDIT: - selinux_audit = cb.func_audit; -@@ -106,7 +108,7 @@ selinux_get_callback(int type) - - switch (type) { - case SELINUX_CB_LOG: -- cb.func_log = selinux_log; -+ cb.func_log = selinux_log_direct; - break; - case SELINUX_CB_AUDIT: - cb.func_audit = selinux_audit; -diff --git a/libselinux/src/callbacks.h b/libselinux/src/callbacks.h -index 03d87f0cbdfe..f4dab15789f9 100644 ---- a/libselinux/src/callbacks.h -+++ b/libselinux/src/callbacks.h -@@ -10,9 +10,11 @@ - #include - #include - -+#include "selinux_internal.h" -+ - /* callback pointers */ - extern int __attribute__ ((format(printf, 2, 3))) --(*selinux_log) (int type, const char *, ...) ; -+(*selinux_log_direct) (int type, const char *, ...) ; - - extern int - (*selinux_audit) (void *, security_class_t, char *, size_t) ; -@@ -26,4 +28,13 @@ extern int - extern int - (*selinux_netlink_policyload) (int seqno) ; - -+/* Thread-safe selinux_log() function */ -+extern pthread_mutex_t log_mutex; -+ -+#define selinux_log(type, ...) do { \ -+ __pthread_mutex_lock(&log_mutex); \ -+ selinux_log_direct(type, __VA_ARGS__); \ -+ __pthread_mutex_unlock(&log_mutex); \ -+} while(0) -+ - #endif /* _SELINUX_CALLBACKS_H_ */ --- -2.33.1 - diff --git a/SOURCES/0006-libselinux-make-is_context_customizable-thread-safe.patch b/SOURCES/0006-libselinux-make-is_context_customizable-thread-safe.patch deleted file mode 100644 index 3dc8213..0000000 --- a/SOURCES/0006-libselinux-make-is_context_customizable-thread-safe.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 9a8db9356c07d16a9337df416a3261c0527afeb7 Mon Sep 17 00:00:00 2001 -From: Ondrej Mosnacek -Date: Tue, 26 Oct 2021 13:52:36 +0200 -Subject: [PATCH] libselinux: make is_context_customizable() thread-safe -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Use the __selinux_once() macro to ensure that threads don't race to -initialize the list of customizable types. - -Reported-by: Christian Göttsche -Signed-off-by: Ondrej Mosnacek -Tested-by: Christian Göttsche ---- - libselinux/src/is_customizable_type.c | 23 +++++++++++------------ - 1 file changed, 11 insertions(+), 12 deletions(-) - -diff --git a/libselinux/src/is_customizable_type.c b/libselinux/src/is_customizable_type.c -index 1b17860c3622..f83e1e83e944 100644 ---- a/libselinux/src/is_customizable_type.c -+++ b/libselinux/src/is_customizable_type.c -@@ -9,7 +9,10 @@ - #include "selinux_internal.h" - #include "context_internal.h" - --static int get_customizable_type_list(char *** retlist) -+static char **customizable_list = NULL; -+static pthread_once_t customizable_once = PTHREAD_ONCE_INIT; -+ -+static void customizable_init(void) - { - FILE *fp; - char *buf; -@@ -18,12 +21,12 @@ static int get_customizable_type_list(char *** retlist) - - fp = fopen(selinux_customizable_types_path(), "re"); - if (!fp) -- return -1; -+ return; - - buf = malloc(selinux_page_size); - if (!buf) { - fclose(fp); -- return -1; -+ return; - } - while (fgets_unlocked(buf, selinux_page_size, fp) && ctr < UINT_MAX) { - ctr++; -@@ -54,23 +57,19 @@ static int get_customizable_type_list(char *** retlist) - fclose(fp); - free(buf); - if (!list) -- return -1; -- *retlist = list; -- return 0; -+ return; -+ customizable_list = list; - } - --static char **customizable_list = NULL; -- - int is_context_customizable(const char * scontext) - { - int i; - const char *type; - context_t c; - -- if (!customizable_list) { -- if (get_customizable_type_list(&customizable_list) != 0) -- return -1; -- } -+ __selinux_once(customizable_once, customizable_init); -+ if (!customizable_list) -+ return -1; - - c = context_new(scontext); - if (!c) --- -2.33.1 - diff --git a/SOURCES/0007-selinux_restorecon-add-a-global-mutex-to-synchronize.patch b/SOURCES/0007-selinux_restorecon-add-a-global-mutex-to-synchronize.patch deleted file mode 100644 index a5affd5..0000000 --- a/SOURCES/0007-selinux_restorecon-add-a-global-mutex-to-synchronize.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 73310c9694724b3ef54bbf3a3193dbb0a68ecc3b Mon Sep 17 00:00:00 2001 -From: Ondrej Mosnacek -Date: Tue, 26 Oct 2021 13:52:37 +0200 -Subject: [PATCH] selinux_restorecon: add a global mutex to synchronize - progress output - -Another small incremental change to pave the way for a parallel -selinux_restorecon() function. - -Signed-off-by: Ondrej Mosnacek ---- - libselinux/src/selinux_restorecon.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c -index 43acbace309d..169dfe3ae232 100644 ---- a/libselinux/src/selinux_restorecon.c -+++ b/libselinux/src/selinux_restorecon.c -@@ -60,6 +60,7 @@ static int exclude_count = 0; - static struct edir *exclude_lst = NULL; - static uint64_t fc_count = 0; /* Number of files processed so far */ - static uint64_t efile_count; /* Estimated total number of files */ -+static pthread_mutex_t progress_mutex = PTHREAD_MUTEX_INITIALIZER; - - /* Store information on directories with xattr's. */ - static struct dir_xattr *dir_xattr_list; -@@ -647,6 +648,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, - } - - if (flags->progress) { -+ __pthread_mutex_lock(&progress_mutex); - fc_count++; - if (fc_count % STAR_COUNT == 0) { - if (flags->mass_relabel && efile_count > 0) { -@@ -658,6 +660,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, - } - fflush(stdout); - } -+ __pthread_mutex_unlock(&progress_mutex); - } - - if (flags->add_assoc) { --- -2.33.1 - diff --git a/SOURCES/0008-selinux_restorecon-introduce-selinux_restorecon_para.patch b/SOURCES/0008-selinux_restorecon-introduce-selinux_restorecon_para.patch deleted file mode 100644 index a16023e..0000000 --- a/SOURCES/0008-selinux_restorecon-introduce-selinux_restorecon_para.patch +++ /dev/null @@ -1,800 +0,0 @@ -From 847282ce385a4fc03092eb10422b1878590e9bdd Mon Sep 17 00:00:00 2001 -From: Ondrej Mosnacek -Date: Tue, 26 Oct 2021 13:52:38 +0200 -Subject: [PATCH] selinux_restorecon: introduce selinux_restorecon_parallel(3) - -Refactor selinux_restorecon(3) to allow for distributing the relabeling -to multiple threads and add a new function -selinux_restorecon_parallel(3), which allows specifying the number of -threads to use. The existing selinux_restorecon(3) function maintains -the same interface and maintains the same behavior (i.e. relabeling is -done on a single thread). - -The parallel implementation takes a simple approach of performing all -the directory tree traversal in a critical section and only letting the -relabeling of individual objects run in parallel. Thankfully, this -approach turns out to be efficient enough in practice, as shown by -restorecon benchmarks (detailed in a subsequent patch that switches -setfiles & restorecon to use selinux_restorecon_parallel(3)). - -Note that to be able to use the parallelism, the calling application/ -library must be explicitly linked to the libpthread library (statically -or dynamically). This is necessary to mantain the requirement that -libselinux shouldn't explicitly link with libpthread. (I don't know what -exactly was the reason behind this requirement as the commit logs are -fuzzy, but special care has been taken in the past to maintain it, so I -didn't want to break it...) - -Signed-off-by: Ondrej Mosnacek ---- - libselinux/include/selinux/restorecon.h | 14 + - libselinux/man/man3/selinux_restorecon.3 | 29 ++ - .../man/man3/selinux_restorecon_parallel.3 | 1 + - libselinux/src/libselinux.map | 5 + - libselinux/src/selinux_internal.h | 16 + - libselinux/src/selinux_restorecon.c | 436 ++++++++++++------ - libselinux/src/selinuxswig_python.i | 6 +- - libselinux/src/selinuxswig_python_exception.i | 8 + - 8 files changed, 368 insertions(+), 147 deletions(-) - create mode 100644 libselinux/man/man3/selinux_restorecon_parallel.3 - -diff --git a/libselinux/include/selinux/restorecon.h b/libselinux/include/selinux/restorecon.h -index ca8ce768587a..8f9a030cda98 100644 ---- a/libselinux/include/selinux/restorecon.h -+++ b/libselinux/include/selinux/restorecon.h -@@ -2,6 +2,7 @@ - #define _RESTORECON_H_ - - #include -+#include - #include - - #ifdef __cplusplus -@@ -23,6 +24,19 @@ extern "C" { - */ - extern int selinux_restorecon(const char *pathname, - unsigned int restorecon_flags); -+/** -+ * selinux_restorecon_parallel - Relabel files, optionally use more threads. -+ * @pathname: specifies file/directory to relabel. -+ * @restorecon_flags: specifies the actions to be performed when relabeling. -+ * @nthreads: specifies the number of threads to use (0 = use number of CPUs -+ * currently online) -+ * -+ * Same as selinux_restorecon(3), but allows to use multiple threads to do -+ * the work. -+ */ -+extern int selinux_restorecon_parallel(const char *pathname, -+ unsigned int restorecon_flags, -+ size_t nthreads); - /* - * restorecon_flags options - */ -diff --git a/libselinux/man/man3/selinux_restorecon.3 b/libselinux/man/man3/selinux_restorecon.3 -index c4576fe79ff6..500845917fb8 100644 ---- a/libselinux/man/man3/selinux_restorecon.3 -+++ b/libselinux/man/man3/selinux_restorecon.3 -@@ -11,6 +11,14 @@ selinux_restorecon \- restore file(s) default SELinux security contexts - .br - .BI "unsigned int " restorecon_flags ");" - .in -+.sp -+.BI "int selinux_restorecon_parallel(const char *" pathname , -+.in +\w'int selinux_restorecon_parallel('u -+.br -+.BI "unsigned int " restorecon_flags "," -+.br -+.BI "size_t " nthreads ");" -+.in - . - .SH "DESCRIPTION" - .BR selinux_restorecon () -@@ -187,6 +195,27 @@ unless the - .B SELINUX_RESTORECON_IGNORE_MOUNTS - flag has been set. - .RE -+.sp -+.BR selinux_restorecon_parallel() -+is similar to -+.BR selinux_restorecon (3), -+but accepts another parameter that allows to run relabeling over multiple -+threads: -+.sp -+.RS -+.IR nthreads -+specifies the number of threads to use during relabeling. When set to 1, -+the behavior is the same as calling -+.BR selinux_restorecon (3). -+When set to 0, the function will try to use as many threads as there are -+online CPU cores. When set to any other number, the function will try to use -+the given number of threads. -+.sp -+Note that to use the parallel relabeling capability, the calling process -+must be linked with the -+.B libpthread -+library (either at compile time or dynamically at run time). Otherwise the -+function will print a warning and fall back to the single threaded mode. - . - .SH "RETURN VALUE" - On success, zero is returned. On error, \-1 is returned and -diff --git a/libselinux/man/man3/selinux_restorecon_parallel.3 b/libselinux/man/man3/selinux_restorecon_parallel.3 -new file mode 100644 -index 000000000000..092d8412cc93 ---- /dev/null -+++ b/libselinux/man/man3/selinux_restorecon_parallel.3 -@@ -0,0 +1 @@ -+.so man3/selinux_restorecon.3 -diff --git a/libselinux/src/libselinux.map b/libselinux/src/libselinux.map -index 2a368e93f9fd..d138e951ef0d 100644 ---- a/libselinux/src/libselinux.map -+++ b/libselinux/src/libselinux.map -@@ -240,3 +240,8 @@ LIBSELINUX_1.0 { - local: - *; - }; -+ -+LIBSELINUX_3.3 { -+ global: -+ selinux_restorecon_parallel; -+} LIBSELINUX_1.0; -diff --git a/libselinux/src/selinux_internal.h b/libselinux/src/selinux_internal.h -index 27e9ac532c3f..297dcf26dee3 100644 ---- a/libselinux/src/selinux_internal.h -+++ b/libselinux/src/selinux_internal.h -@@ -69,6 +69,22 @@ extern int selinux_page_size ; - pthread_mutex_unlock(LOCK); \ - } while (0) - -+#pragma weak pthread_create -+#pragma weak pthread_join -+#pragma weak pthread_cond_init -+#pragma weak pthread_cond_signal -+#pragma weak pthread_cond_destroy -+#pragma weak pthread_cond_wait -+ -+/* check if all functions needed to do parallel operations are available */ -+#define __pthread_supported ( \ -+ pthread_create && \ -+ pthread_join && \ -+ pthread_cond_init && \ -+ pthread_cond_destroy && \ -+ pthread_cond_signal && \ -+ pthread_cond_wait \ -+) - - #define SELINUXDIR "/etc/selinux/" - #define SELINUXCONFIG SELINUXDIR "config" -diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c -index 169dfe3ae232..f7e84657d09d 100644 ---- a/libselinux/src/selinux_restorecon.c -+++ b/libselinux/src/selinux_restorecon.c -@@ -610,7 +610,7 @@ out: - } - - static int restorecon_sb(const char *pathname, const struct stat *sb, -- struct rest_flags *flags) -+ struct rest_flags *flags, bool first) - { - char *newcon = NULL; - char *curcon = NULL; -@@ -639,7 +639,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, - sb->st_mode); - - if (rc < 0) { -- if (errno == ENOENT && flags->warnonnomatch) -+ if (errno == ENOENT && flags->warnonnomatch && first) - selinux_log(SELINUX_INFO, - "Warning no default label for %s\n", - lookup_path); -@@ -814,66 +814,215 @@ oom: - goto free; - } - -+struct rest_state { -+ struct rest_flags flags; -+ dev_t dev_num; -+ struct statfs sfsb; -+ bool ignore_digest; -+ bool setrestorecondigest; -+ bool parallel; - --/* -- * Public API -- */ -+ FTS *fts; -+ FTSENT *ftsent_first; -+ struct dir_hash_node *head, *current; -+ bool abort; -+ int error; -+ int saved_errno; -+ pthread_mutex_t mutex; -+}; - --/* selinux_restorecon(3) - Main function that is responsible for labeling */ --int selinux_restorecon(const char *pathname_orig, -- unsigned int restorecon_flags) -+static void *selinux_restorecon_thread(void *arg) - { -- struct rest_flags flags; -+ struct rest_state *state = arg; -+ FTS *fts = state->fts; -+ FTSENT *ftsent; -+ int error; -+ char ent_path[PATH_MAX]; -+ struct stat ent_st; -+ bool first = false; -+ -+ if (state->parallel) -+ pthread_mutex_lock(&state->mutex); -+ -+ if (state->ftsent_first) { -+ ftsent = state->ftsent_first; -+ state->ftsent_first = NULL; -+ first = true; -+ goto loop_body; -+ } -+ -+ while (((void)(errno = 0), ftsent = fts_read(fts)) != NULL) { -+loop_body: -+ /* If the FTS_XDEV flag is set and the device is different */ -+ if (state->flags.set_xdev && -+ ftsent->fts_statp->st_dev != state->dev_num) -+ continue; -+ -+ switch (ftsent->fts_info) { -+ case FTS_DC: -+ selinux_log(SELINUX_ERROR, -+ "Directory cycle on %s.\n", -+ ftsent->fts_path); -+ errno = ELOOP; -+ state->error = -1; -+ state->abort = true; -+ goto finish; -+ case FTS_DP: -+ continue; -+ case FTS_DNR: -+ error = errno; -+ errno = ftsent->fts_errno; -+ selinux_log(SELINUX_ERROR, -+ "Could not read %s: %m.\n", -+ ftsent->fts_path); -+ errno = error; -+ fts_set(fts, ftsent, FTS_SKIP); -+ continue; -+ case FTS_NS: -+ error = errno; -+ errno = ftsent->fts_errno; -+ selinux_log(SELINUX_ERROR, -+ "Could not stat %s: %m.\n", -+ ftsent->fts_path); -+ errno = error; -+ fts_set(fts, ftsent, FTS_SKIP); -+ continue; -+ case FTS_ERR: -+ error = errno; -+ errno = ftsent->fts_errno; -+ selinux_log(SELINUX_ERROR, -+ "Error on %s: %m.\n", -+ ftsent->fts_path); -+ errno = error; -+ fts_set(fts, ftsent, FTS_SKIP); -+ continue; -+ case FTS_D: -+ if (state->sfsb.f_type == SYSFS_MAGIC && -+ !selabel_partial_match(fc_sehandle, -+ ftsent->fts_path)) { -+ fts_set(fts, ftsent, FTS_SKIP); -+ continue; -+ } -+ -+ if (check_excluded(ftsent->fts_path)) { -+ fts_set(fts, ftsent, FTS_SKIP); -+ continue; -+ } - -- flags.nochange = (restorecon_flags & -+ if (state->setrestorecondigest) { -+ struct dir_hash_node *new_node = NULL; -+ -+ if (check_context_match_for_dir(ftsent->fts_path, -+ &new_node, -+ state->error) && -+ !state->ignore_digest) { -+ selinux_log(SELINUX_INFO, -+ "Skipping restorecon on directory(%s)\n", -+ ftsent->fts_path); -+ fts_set(fts, ftsent, FTS_SKIP); -+ continue; -+ } -+ -+ if (new_node && !state->error) { -+ if (!state->current) { -+ state->current = new_node; -+ state->head = state->current; -+ } else { -+ state->current->next = new_node; -+ state->current = new_node; -+ } -+ } -+ } -+ /* fall through */ -+ default: -+ strcpy(ent_path, ftsent->fts_path); -+ ent_st = *ftsent->fts_statp; -+ if (state->parallel) -+ pthread_mutex_unlock(&state->mutex); -+ -+ error = restorecon_sb(ent_path, &ent_st, &state->flags, -+ first); -+ -+ if (state->parallel) { -+ pthread_mutex_lock(&state->mutex); -+ if (state->abort) -+ goto unlock; -+ } -+ -+ state->error |= error; -+ first = false; -+ if (error && state->flags.abort_on_error) { -+ state->abort = true; -+ goto finish; -+ } -+ break; -+ } -+ } -+ -+finish: -+ if (!state->saved_errno) -+ state->saved_errno = errno; -+unlock: -+ if (state->parallel) -+ pthread_mutex_unlock(&state->mutex); -+ return NULL; -+} -+ -+static int selinux_restorecon_common(const char *pathname_orig, -+ unsigned int restorecon_flags, -+ size_t nthreads) -+{ -+ struct rest_state state; -+ -+ state.flags.nochange = (restorecon_flags & - SELINUX_RESTORECON_NOCHANGE) ? true : false; -- flags.verbose = (restorecon_flags & -+ state.flags.verbose = (restorecon_flags & - SELINUX_RESTORECON_VERBOSE) ? true : false; -- flags.progress = (restorecon_flags & -+ state.flags.progress = (restorecon_flags & - SELINUX_RESTORECON_PROGRESS) ? true : false; -- flags.mass_relabel = (restorecon_flags & -+ state.flags.mass_relabel = (restorecon_flags & - SELINUX_RESTORECON_MASS_RELABEL) ? true : false; -- flags.recurse = (restorecon_flags & -+ state.flags.recurse = (restorecon_flags & - SELINUX_RESTORECON_RECURSE) ? true : false; -- flags.set_specctx = (restorecon_flags & -+ state.flags.set_specctx = (restorecon_flags & - SELINUX_RESTORECON_SET_SPECFILE_CTX) ? true : false; -- flags.userealpath = (restorecon_flags & -+ state.flags.userealpath = (restorecon_flags & - SELINUX_RESTORECON_REALPATH) ? true : false; -- flags.set_xdev = (restorecon_flags & -+ state.flags.set_xdev = (restorecon_flags & - SELINUX_RESTORECON_XDEV) ? true : false; -- flags.add_assoc = (restorecon_flags & -+ state.flags.add_assoc = (restorecon_flags & - SELINUX_RESTORECON_ADD_ASSOC) ? true : false; -- flags.abort_on_error = (restorecon_flags & -+ state.flags.abort_on_error = (restorecon_flags & - SELINUX_RESTORECON_ABORT_ON_ERROR) ? true : false; -- flags.syslog_changes = (restorecon_flags & -+ state.flags.syslog_changes = (restorecon_flags & - SELINUX_RESTORECON_SYSLOG_CHANGES) ? true : false; -- flags.log_matches = (restorecon_flags & -+ state.flags.log_matches = (restorecon_flags & - SELINUX_RESTORECON_LOG_MATCHES) ? true : false; -- flags.ignore_noent = (restorecon_flags & -+ state.flags.ignore_noent = (restorecon_flags & - SELINUX_RESTORECON_IGNORE_NOENTRY) ? true : false; -- flags.warnonnomatch = true; -- flags.conflicterror = (restorecon_flags & -+ state.flags.warnonnomatch = true; -+ state.flags.conflicterror = (restorecon_flags & - SELINUX_RESTORECON_CONFLICT_ERROR) ? true : false; - ignore_mounts = (restorecon_flags & - SELINUX_RESTORECON_IGNORE_MOUNTS) ? true : false; -- bool ignore_digest = (restorecon_flags & -+ state.ignore_digest = (restorecon_flags & - SELINUX_RESTORECON_IGNORE_DIGEST) ? true : false; -- bool setrestorecondigest = true; -+ state.setrestorecondigest = true; -+ -+ state.head = NULL; -+ state.current = NULL; -+ state.abort = false; -+ state.error = 0; -+ state.saved_errno = 0; - - struct stat sb; -- struct statfs sfsb; -- FTS *fts; -- FTSENT *ftsent; - char *pathname = NULL, *pathdnamer = NULL, *pathdname, *pathbname; - char *paths[2] = { NULL, NULL }; - int fts_flags, error, sverrno; -- dev_t dev_num = 0; - struct dir_hash_node *current = NULL; -- struct dir_hash_node *head = NULL; -- int errno_tmp; - -- if (flags.verbose && flags.progress) -- flags.verbose = false; -+ if (state.flags.verbose && state.flags.progress) -+ state.flags.verbose = false; - - __selinux_once(fc_once, restorecon_init); - -@@ -886,13 +1035,31 @@ int selinux_restorecon(const char *pathname_orig, - */ - if (selabel_no_digest || - (restorecon_flags & SELINUX_RESTORECON_SKIP_DIGEST)) -- setrestorecondigest = false; -+ state.setrestorecondigest = false; -+ -+ if (!__pthread_supported) { -+ if (nthreads != 1) { -+ nthreads = 1; -+ selinux_log(SELINUX_WARNING, -+ "Threading functionality not available, falling back to 1 thread."); -+ } -+ } else if (nthreads == 0) { -+ long nproc = sysconf(_SC_NPROCESSORS_ONLN); -+ -+ if (nproc > 0) { -+ nthreads = nproc; -+ } else { -+ nthreads = 1; -+ selinux_log(SELINUX_WARNING, -+ "Unable to detect CPU count, falling back to 1 thread."); -+ } -+ } - - /* - * Convert passed-in pathname to canonical pathname by resolving - * realpath of containing dir, then appending last component name. - */ -- if (flags.userealpath) { -+ if (state.flags.userealpath) { - char *basename_cpy = strdup(pathname_orig); - if (!basename_cpy) - goto realpatherr; -@@ -937,7 +1104,7 @@ int selinux_restorecon(const char *pathname_orig, - paths[0] = pathname; - - if (lstat(pathname, &sb) < 0) { -- if (flags.ignore_noent && errno == ENOENT) { -+ if (state.flags.ignore_noent && errno == ENOENT) { - free(pathdnamer); - free(pathname); - return 0; -@@ -952,21 +1119,21 @@ int selinux_restorecon(const char *pathname_orig, - - /* Skip digest if not a directory */ - if (!S_ISDIR(sb.st_mode)) -- setrestorecondigest = false; -+ state.setrestorecondigest = false; - -- if (!flags.recurse) { -+ if (!state.flags.recurse) { - if (check_excluded(pathname)) { - error = 0; - goto cleanup; - } - -- error = restorecon_sb(pathname, &sb, &flags); -+ error = restorecon_sb(pathname, &sb, &state.flags, true); - goto cleanup; - } - - /* Obtain fs type */ -- memset(&sfsb, 0, sizeof sfsb); -- if (!S_ISLNK(sb.st_mode) && statfs(pathname, &sfsb) < 0) { -+ memset(&state.sfsb, 0, sizeof(state.sfsb)); -+ if (!S_ISLNK(sb.st_mode) && statfs(pathname, &state.sfsb) < 0) { - selinux_log(SELINUX_ERROR, - "statfs(%s) failed: %m\n", - pathname); -@@ -975,21 +1142,21 @@ int selinux_restorecon(const char *pathname_orig, - } - - /* Skip digest on in-memory filesystems and /sys */ -- if (sfsb.f_type == RAMFS_MAGIC || sfsb.f_type == TMPFS_MAGIC || -- sfsb.f_type == SYSFS_MAGIC) -- setrestorecondigest = false; -+ if (state.sfsb.f_type == RAMFS_MAGIC || state.sfsb.f_type == TMPFS_MAGIC || -+ state.sfsb.f_type == SYSFS_MAGIC) -+ state.setrestorecondigest = false; - -- if (flags.set_xdev) -+ if (state.flags.set_xdev) - fts_flags = FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV; - else - fts_flags = FTS_PHYSICAL | FTS_NOCHDIR; - -- fts = fts_open(paths, fts_flags, NULL); -- if (!fts) -+ state.fts = fts_open(paths, fts_flags, NULL); -+ if (!state.fts) - goto fts_err; - -- ftsent = fts_read(fts); -- if (!ftsent) -+ state.ftsent_first = fts_read(state.fts); -+ if (!state.ftsent_first) - goto fts_err; - - /* -@@ -1001,106 +1168,66 @@ int selinux_restorecon(const char *pathname_orig, - * directories with a different device number when the FTS_XDEV flag - * is set (from http://marc.info/?l=selinux&m=124688830500777&w=2). - */ -- dev_num = ftsent->fts_statp->st_dev; -+ state.dev_num = state.ftsent_first->fts_statp->st_dev; - -- error = 0; -- do { -- /* If the FTS_XDEV flag is set and the device is different */ -- if (flags.set_xdev && ftsent->fts_statp->st_dev != dev_num) -- continue; -+ if (nthreads == 1) { -+ state.parallel = false; -+ selinux_restorecon_thread(&state); -+ } else { -+ size_t i; -+ pthread_t self = pthread_self(); -+ pthread_t *threads = NULL; - -- switch (ftsent->fts_info) { -- case FTS_DC: -- selinux_log(SELINUX_ERROR, -- "Directory cycle on %s.\n", -- ftsent->fts_path); -- errno = ELOOP; -- error = -1; -- goto out; -- case FTS_DP: -- continue; -- case FTS_DNR: -- errno_tmp = errno; -- errno = ftsent->fts_errno; -- selinux_log(SELINUX_ERROR, -- "Could not read %s: %m.\n", -- ftsent->fts_path); -- errno = errno_tmp; -- fts_set(fts, ftsent, FTS_SKIP); -- continue; -- case FTS_NS: -- errno_tmp = errno; -- errno = ftsent->fts_errno; -- selinux_log(SELINUX_ERROR, -- "Could not stat %s: %m.\n", -- ftsent->fts_path); -- errno = errno_tmp; -- fts_set(fts, ftsent, FTS_SKIP); -- continue; -- case FTS_ERR: -- errno_tmp = errno; -- errno = ftsent->fts_errno; -- selinux_log(SELINUX_ERROR, -- "Error on %s: %m.\n", -- ftsent->fts_path); -- errno = errno_tmp; -- fts_set(fts, ftsent, FTS_SKIP); -- continue; -- case FTS_D: -- if (sfsb.f_type == SYSFS_MAGIC && -- !selabel_partial_match(fc_sehandle, -- ftsent->fts_path)) { -- fts_set(fts, ftsent, FTS_SKIP); -- continue; -- } -+ pthread_mutex_init(&state.mutex, NULL); - -- if (check_excluded(ftsent->fts_path)) { -- fts_set(fts, ftsent, FTS_SKIP); -- continue; -+ threads = calloc(nthreads - 1, sizeof(*threads)); -+ if (!threads) -+ goto oom; -+ -+ state.parallel = true; -+ /* -+ * Start (nthreads - 1) threads - the main thread is going to -+ * take part, too. -+ */ -+ for (i = 0; i < nthreads - 1; i++) { -+ if (pthread_create(&threads[i], NULL, -+ selinux_restorecon_thread, &state)) { -+ /* -+ * If any thread fails to be created, just mark -+ * it as such and let the successfully created -+ * threads do the job. In the worst case the -+ * main thread will do everything, but that's -+ * still better than to give up. -+ */ -+ threads[i] = self; - } -+ } - -- if (setrestorecondigest) { -- struct dir_hash_node *new_node = NULL; -+ /* Let's join in on the fun! */ -+ selinux_restorecon_thread(&state); - -- if (check_context_match_for_dir(ftsent->fts_path, -- &new_node, -- error) && -- !ignore_digest) { -- selinux_log(SELINUX_INFO, -- "Skipping restorecon on directory(%s)\n", -- ftsent->fts_path); -- fts_set(fts, ftsent, FTS_SKIP); -- continue; -- } -- -- if (new_node && !error) { -- if (!current) { -- current = new_node; -- head = current; -- } else { -- current->next = new_node; -- current = current->next; -- } -- } -- } -- /* fall through */ -- default: -- error |= restorecon_sb(ftsent->fts_path, -- ftsent->fts_statp, &flags); -- if (flags.warnonnomatch) -- flags.warnonnomatch = false; -- if (error && flags.abort_on_error) -- goto out; -- break; -+ /* Now wait for all threads to finish. */ -+ for (i = 0; i < nthreads - 1; i++) { -+ /* Skip threads that failed to be created. */ -+ if (pthread_equal(threads[i], self)) -+ continue; -+ pthread_join(threads[i], NULL); - } -- } while ((ftsent = fts_read(fts)) != NULL); -+ free(threads); -+ -+ pthread_mutex_destroy(&state.mutex); -+ } -+ -+ error = state.error; -+ if (state.saved_errno) -+ goto out; - - /* - * Labeling successful. Write partial match digests for subdirectories. - * TODO: Write digest upon FTS_DP if no error occurs in its descents. - */ -- if (setrestorecondigest && !flags.nochange && !error) { -- current = head; -+ if (state.setrestorecondigest && !state.flags.nochange && !error) { -+ current = state.head; - while (current != NULL) { - if (setxattr(current->path, - RESTORECON_PARTIAL_MATCH_DIGEST, -@@ -1115,22 +1242,21 @@ int selinux_restorecon(const char *pathname_orig, - } - - out: -- if (flags.progress && flags.mass_relabel) -+ if (state.flags.progress && state.flags.mass_relabel) - fprintf(stdout, "\r%s 100.0%%\n", pathname); - -- sverrno = errno; -- (void) fts_close(fts); -- errno = sverrno; -+ (void) fts_close(state.fts); -+ errno = state.saved_errno; - cleanup: -- if (flags.add_assoc) { -- if (flags.verbose) -+ if (state.flags.add_assoc) { -+ if (state.flags.verbose) - filespec_eval(); - filespec_destroy(); - } - free(pathdnamer); - free(pathname); - -- current = head; -+ current = state.head; - while (current != NULL) { - struct dir_hash_node *next = current->next; - -@@ -1164,6 +1290,26 @@ fts_err: - goto cleanup; - } - -+ -+/* -+ * Public API -+ */ -+ -+/* selinux_restorecon(3) - Main function that is responsible for labeling */ -+int selinux_restorecon(const char *pathname_orig, -+ unsigned int restorecon_flags) -+{ -+ return selinux_restorecon_common(pathname_orig, restorecon_flags, 1); -+} -+ -+/* selinux_restorecon_parallel(3) - Parallel version of selinux_restorecon(3) */ -+int selinux_restorecon_parallel(const char *pathname_orig, -+ unsigned int restorecon_flags, -+ size_t nthreads) -+{ -+ return selinux_restorecon_common(pathname_orig, restorecon_flags, nthreads); -+} -+ - /* selinux_restorecon_set_sehandle(3) is called to set the global fc handle */ - void selinux_restorecon_set_sehandle(struct selabel_handle *hndl) - { -diff --git a/libselinux/src/selinuxswig_python.i b/libselinux/src/selinuxswig_python.i -index 4c73bf92df96..17e03b9e36a5 100644 ---- a/libselinux/src/selinuxswig_python.i -+++ b/libselinux/src/selinuxswig_python.i -@@ -20,7 +20,7 @@ DISABLED = -1 - PERMISSIVE = 0 - ENFORCING = 1 - --def restorecon(path, recursive=False, verbose=False, force=False): -+def restorecon(path, recursive=False, verbose=False, force=False, nthreads=1): - """ Restore SELinux context on a given path - - Arguments: -@@ -32,6 +32,8 @@ def restorecon(path, recursive=False, verbose=False, force=False): - force -- Force reset of context to match file_context for customizable files, - and the default file context, changing the user, role, range portion as well - as the type (default False) -+ nthreads -- The number of threads to use during relabeling, or 0 to use as many -+ threads as there are online CPU cores (default 1) - """ - - restorecon_flags = SELINUX_RESTORECON_IGNORE_DIGEST | SELINUX_RESTORECON_REALPATH -@@ -41,7 +43,7 @@ def restorecon(path, recursive=False, verbose=False, force=False): - restorecon_flags |= SELINUX_RESTORECON_VERBOSE - if force: - restorecon_flags |= SELINUX_RESTORECON_SET_SPECFILE_CTX -- selinux_restorecon(os.path.expanduser(path), restorecon_flags) -+ selinux_restorecon_parallel(os.path.expanduser(path), restorecon_flags, nthreads) - - def chcon(path, context, recursive=False): - """ Set the SELinux context on a given path """ -diff --git a/libselinux/src/selinuxswig_python_exception.i b/libselinux/src/selinuxswig_python_exception.i -index 237ea69ad5f5..a02f4923a1e7 100644 ---- a/libselinux/src/selinuxswig_python_exception.i -+++ b/libselinux/src/selinuxswig_python_exception.i -@@ -1183,6 +1183,14 @@ - } - } - -+%exception selinux_restorecon_parallel { -+ $action -+ if (result < 0) { -+ PyErr_SetFromErrno(PyExc_OSError); -+ SWIG_fail; -+ } -+} -+ - %exception selinux_restorecon_set_alt_rootpath { - $action - if (result < 0) { --- -2.33.1 - diff --git a/SOURCES/0009-libselinux-Fix-selinux_restorecon_parallel-symbol-ve.patch b/SOURCES/0009-libselinux-Fix-selinux_restorecon_parallel-symbol-ve.patch deleted file mode 100644 index a8ce120..0000000 --- a/SOURCES/0009-libselinux-Fix-selinux_restorecon_parallel-symbol-ve.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 9456297275987dedefe2e8ad508360be9d9f9e7f Mon Sep 17 00:00:00 2001 -From: Petr Lautrbach -Date: Tue, 23 Nov 2021 11:31:08 +0100 -Subject: [PATCH] libselinux: Fix selinux_restorecon_parallel symbol version - -selinux_restorecon_parallel was originally proposed before 3.3, but it -was merged after release so it will be introduced in version 3.4. - -Signed-off-by: Petr Lautrbach ---- - libselinux/src/libselinux.map | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/libselinux/src/libselinux.map b/libselinux/src/libselinux.map -index d138e951ef0d..4acf1caacb55 100644 ---- a/libselinux/src/libselinux.map -+++ b/libselinux/src/libselinux.map -@@ -241,7 +241,7 @@ LIBSELINUX_1.0 { - *; - }; - --LIBSELINUX_3.3 { -+LIBSELINUX_3.4 { - global: - selinux_restorecon_parallel; - } LIBSELINUX_1.0; --- -2.33.1 - diff --git a/SPECS/libselinux.spec b/SPECS/libselinux.spec index 0b26d37..026015f 100644 --- a/SPECS/libselinux.spec +++ b/SPECS/libselinux.spec @@ -1,30 +1,23 @@ %define ruby_inc %(pkg-config --cflags ruby) -%define libsepolver 3.3-1 +%define libsepolver 3.4-1 Summary: SELinux library and simple utilities Name: libselinux -Version: 3.3 -Release: 2%{?dist} +Version: 3.4 +Release: 3%{?dist} License: Public Domain # https://github.com/SELinuxProject/selinux/wiki/Releases -Source0: https://github.com/SELinuxProject/selinux/releases/download/3.3/libselinux-3.3.tar.gz +Source0: https://github.com/SELinuxProject/selinux/releases/download/3.4/libselinux-3.4.tar.gz Source1: selinuxconlist.8 Source2: selinuxdefcon.8 Url: https://github.com/SELinuxProject/selinux/wiki # $ git clone https://github.com/fedora-selinux/selinux.git # $ cd selinux -# $ git format-patch -N 3.3 -- libselinux +# $ git format-patch -N 3.4 -- libselinux # $ i=1; for j in 00*patch; do printf "Patch%04d: %s\n" $i $j; i=$((i+1));done # Patch list start Patch0001: 0001-Use-SHA-2-instead-of-SHA-1.patch -Patch0002: 0002-label_file-fix-a-data-race.patch -Patch0003: 0003-selinux_restorecon-simplify-fl_head-allocation-by-us.patch -Patch0004: 0004-selinux_restorecon-protect-file_spec-list-with-a-mut.patch -Patch0005: 0005-libselinux-make-selinux_log-thread-safe.patch -Patch0006: 0006-libselinux-make-is_context_customizable-thread-safe.patch -Patch0007: 0007-selinux_restorecon-add-a-global-mutex-to-synchronize.patch -Patch0008: 0008-selinux_restorecon-introduce-selinux_restorecon_para.patch -Patch0009: 0009-libselinux-Fix-selinux_restorecon_parallel-symbol-ve.patch +Patch0002: 0002-Revert-libselinux-restorecon-pin-file-to-avoid-TOCTO.patch # Patch list end BuildRequires: gcc make BuildRequires: ruby-devel ruby libsepol-static >= %{libsepolver} swig pcre2-devel xz-devel @@ -221,6 +214,15 @@ rm -f %{buildroot}%{_mandir}/man8/togglesebool* %{ruby_vendorarchdir}/selinux.so %changelog +* Mon Jul 18 2022 Petr Lautrbach - 3.4-3 +- Drop SHA-1 from selinux_restorecon.3 + +* Tue May 31 2022 Petr Lautrbach - 3.4-2 +- Revert "libselinux: restorecon: pin file to avoid TOCTOU issues" + +* Thu May 19 2022 Petr Lautrbach - 3.4-1 +- SELinux userspace 3.4 release + * Mon Nov 29 2021 Petr Lautrbach - 3.3-2 - Introduce selinux_restorecon_parallel(3)