From 990a13251ee74d5513ea3820c0663963bf6eb183 Mon Sep 17 00:00:00 2001 From: zgzxx Date: Tue, 13 Jun 2023 16:29:16 +0800 Subject: [PATCH] backport upstream patches (cherry picked from commit a7bf1057839c82d554d24c1220ddc1609098b96c) --- ...e-missing-directories-when-i-is-used.patch | 50 +++ ...port-libselinux-add-check-for-malloc.patch | 40 +++ ...selinux-bail-out-on-path-truncations.patch | 124 +++++++ ...rectly-hash-specfiles-larger-than-4G.patch | 77 +++++ ...v_current-value-when-using-getpidcon.patch | 322 ++++++++++++++++++ ...ilter-arguments-with-path-separators.patch | 63 ++++ ...y-leaks-on-the-audit2why-module-init.patch | 94 +++++ ...ux-fix-some-memory-issues-in-db_init.patch | 54 +++ ...nux-ignore-invalid-class-name-lookup.patch | 43 +++ ...ort-libselinux-limit-has-buffer-size.patch | 41 +++ ...e-fixed-sized-integer-for-hash-index.patch | 66 ++++ ...th-logic-to-avoid-uninitialized-read.patch | 88 +++++ libselinux.spec | 17 +- 13 files changed, 1078 insertions(+), 1 deletion(-) create mode 100644 backport-libselinux-Ignore-missing-directories-when-i-is-used.patch create mode 100644 backport-libselinux-add-check-for-malloc.patch create mode 100644 backport-libselinux-bail-out-on-path-truncations.patch create mode 100644 backport-libselinux-correctly-hash-specfiles-larger-than-4G.patch create mode 100644 backport-libselinux-do-not-return-the-cached-prev_current-value-when-using-getpidcon.patch create mode 100644 backport-libselinux-filter-arguments-with-path-separators.patch create mode 100644 backport-libselinux-fix-memory-leaks-on-the-audit2why-module-init.patch create mode 100644 backport-libselinux-fix-some-memory-issues-in-db_init.patch create mode 100644 backport-libselinux-ignore-invalid-class-name-lookup.patch create mode 100644 backport-libselinux-limit-has-buffer-size.patch create mode 100644 backport-libselinux-restore-use-fixed-sized-integer-for-hash-index.patch create mode 100644 backport-libselinux-simplify-policy-path-logic-to-avoid-uninitialized-read.patch diff --git a/backport-libselinux-Ignore-missing-directories-when-i-is-used.patch b/backport-libselinux-Ignore-missing-directories-when-i-is-used.patch new file mode 100644 index 0000000..5f44ac5 --- /dev/null +++ b/backport-libselinux-Ignore-missing-directories-when-i-is-used.patch @@ -0,0 +1,50 @@ +From 2f71384f233aa544cf0cf50be7e83c7762ad1c15 Mon Sep 17 00:00:00 2001 +From: Vit Mojzis +Date: Mon, 31 Oct 2022 17:46:17 +0100 +Subject: [PATCH] libselinux: Ignore missing directories when -i is used + +Currently "-i" only ignores a file whose parent directory exists. Start also +ignoring paths with missing components. + +Fixes: + # restorecon -i -v -R /var/log/missingdir/missingfile; echo $? + 255 + restorecon: SELinux: Could not get canonical path for /var/log/missingdir/missingfile restorecon: No such file or directory. + +Signed-off-by: Vit Mojzis +Acked-by: James Carter + +Reference:https://github.com/SELinuxProject/selinux/commit/2f71384f233aa544cf0cf50be7e83c7762ad1c15 +Confilct: modify state.flags. to flags. +--- + libselinux/src/selinux_restorecon.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/selinux_restorecon.c b/src/selinux_restorecon.c +index 2d24559f..6b5f6921 100644 +--- a/src/selinux_restorecon.c ++++ b/src/selinux_restorecon.c +@@ -1108,6 +1108,10 @@ static int selinux_restorecon_common(const char *pathname_orig, + pathname = realpath(pathname_orig, NULL); + if (!pathname) { + free(basename_cpy); ++ /* missing parent directory */ ++ if (flags.ignore_noent && errno == ENOENT) { ++ return 0; ++ } + goto realpatherr; + } + } else { +@@ -1121,6 +1125,9 @@ static int selinux_restorecon_common(const char *pathname_orig, + free(dirname_cpy); + if (!pathdnamer) { + free(basename_cpy); ++ if (flags.ignore_noent && errno == ENOENT) { ++ return 0; ++ } + goto realpatherr; + } + if (!strcmp(pathdnamer, "/")) +-- +2.27.0 + diff --git a/backport-libselinux-add-check-for-malloc.patch b/backport-libselinux-add-check-for-malloc.patch new file mode 100644 index 0000000..e076323 --- /dev/null +++ b/backport-libselinux-add-check-for-malloc.patch @@ -0,0 +1,40 @@ +From 4c47f92758df0ad266e8306bbec7b2798a4be3ea Mon Sep 17 00:00:00 2001 +From: Jie Lu +Date: Tue, 29 Nov 2022 20:00:20 +0800 +Subject: [PATCH] libselinux:add check for malloc + +Add return check for regex_data_create() to avoid NULL reference of regex_data + +(gdb) bt + #0 0x00007fbde5caec14 in pthread_mutex_init () from /usr/lib64/libc.so.6 + #1 0x00007fbde5e3a489 in regex_data_create () at regex.c:260 + #2 0x00007fbde5e3a4af in regex_prepare_data (regex=regex@entry=0x7fbde4613770, pattern_string=pattern_string@entry=0x563c6799a820 "^/home$", errordata=errordata@entry=0x7ffeb83fa950) at regex.c:76 + #3 0x00007fbde5e32fe6 in compile_regex (errbuf=0x0, spec=0x7fbde4613748) at label_file.h:407 + #4 lookup_all (key=0x563c679974e5 "/var/log/kadmind.log", type=, partial=partial@entry=false, match_count=match_count@entry=0x0, rec=, rec=) + at label_file.c:949 + #5 0x00007fbde5e33350 in lookup (rec=, key=, type=) at label_file.c:1092 + #6 0x00007fbde5e31878 in selabel_lookup_common (rec=0x563c67998cc0, translating=1, key=, type=) at label.c:167 + +Signed-off-by: Jie Lu +Acked-by: James Carter +--- + libselinux/src/regex.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/regex.c b/src/regex.c +index 73987d9f..149a7973 100644 +--- a/src/regex.c ++++ b/src/regex.c +@@ -257,6 +257,9 @@ struct regex_data *regex_data_create(void) + { + struct regex_data *regex_data = + (struct regex_data *)calloc(1, sizeof(struct regex_data)); ++ if (!regex_data) ++ return NULL; ++ + __pthread_mutex_init(®ex_data->match_mutex, NULL); + return regex_data; + } +-- +2.27.0 + diff --git a/backport-libselinux-bail-out-on-path-truncations.patch b/backport-libselinux-bail-out-on-path-truncations.patch new file mode 100644 index 0000000..4f701fe --- /dev/null +++ b/backport-libselinux-bail-out-on-path-truncations.patch @@ -0,0 +1,124 @@ +From d97c34efa5b95d8ec7c0445aa4f87eacf980bab6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Thu, 10 Nov 2022 19:23:42 +0100 +Subject: [PATCH] libselinux: bail out on path truncations +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Bail out if computed paths based on user input are being truncated, to +avoid wrong files to be opened. + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libselinux/src/booleans.c | 9 +++------ + libselinux/src/get_initial_context.c | 8 ++++++-- + libselinux/src/stringrep.c | 15 ++++++++++++--- + 3 files changed, 21 insertions(+), 11 deletions(-) + +diff --git a/src/booleans.c b/src/booleans.c +index ef1f64a0..dbcccd70 100644 +--- a/src/booleans.c ++++ b/src/booleans.c +@@ -7,7 +7,6 @@ + + #ifndef DISABLE_BOOL + +-#include + #include + #include + #include +@@ -147,7 +146,7 @@ out: + static int bool_open(const char *name, int flag) { + char *fname = NULL; + char *alt_name = NULL; +- int len; ++ size_t len; + int fd = -1; + int ret; + char *ptr; +@@ -164,9 +163,8 @@ static int bool_open(const char *name, int flag) { + return -1; + + ret = snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name); +- if (ret < 0) ++ if (ret < 0 || (size_t)ret >= len) + goto out; +- assert(ret < len); + + fd = open(fname, flag); + if (fd >= 0 || errno != ENOENT) +@@ -184,9 +182,8 @@ static int bool_open(const char *name, int flag) { + fname = ptr; + + ret = snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, alt_name); +- if (ret < 0) ++ if (ret < 0 || (size_t)ret >= len) + goto out; +- assert(ret < len); + + fd = open(fname, flag); + out: +diff --git a/src/get_initial_context.c b/src/get_initial_context.c +index 97ae3dcf..87c8adfa 100644 +--- a/src/get_initial_context.c ++++ b/src/get_initial_context.c +@@ -23,8 +23,12 @@ int security_get_initial_context_raw(const char * name, char ** con) + return -1; + } + +- snprintf(path, sizeof path, "%s%s%s", +- selinux_mnt, SELINUX_INITCON_DIR, name); ++ ret = snprintf(path, sizeof path, "%s%s%s", selinux_mnt, SELINUX_INITCON_DIR, name); ++ if (ret < 0 || (size_t)ret >= sizeof path) { ++ errno = EOVERFLOW; ++ return -1; ++ } ++ + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) + return -1; +diff --git a/src/stringrep.c b/src/stringrep.c +index 592410e5..d2237d1c 100644 +--- a/src/stringrep.c ++++ b/src/stringrep.c +@@ -82,7 +82,10 @@ static struct discover_class_node * discover_class(const char *s) + goto err2; + + /* load up class index */ +- snprintf(path, sizeof path, "%s/class/%s/index", selinux_mnt,s); ++ ret = snprintf(path, sizeof path, "%s/class/%s/index", selinux_mnt,s); ++ if (ret < 0 || (size_t)ret >= sizeof path) ++ goto err3; ++ + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) + goto err3; +@@ -97,7 +100,10 @@ static struct discover_class_node * discover_class(const char *s) + goto err3; + + /* load up permission indices */ +- snprintf(path, sizeof path, "%s/class/%s/perms",selinux_mnt,s); ++ ret = snprintf(path, sizeof path, "%s/class/%s/perms",selinux_mnt,s); ++ if (ret < 0 || (size_t)ret >= sizeof path) ++ goto err3; ++ + dir = opendir(path); + if (dir == NULL) + goto err3; +@@ -107,7 +113,10 @@ static struct discover_class_node * discover_class(const char *s) + unsigned int value; + struct stat m; + +- snprintf(path, sizeof path, "%s/class/%s/perms/%s", selinux_mnt,s,dentry->d_name); ++ ret = snprintf(path, sizeof path, "%s/class/%s/perms/%s", selinux_mnt,s,dentry->d_name); ++ if (ret < 0 || (size_t)ret >= sizeof path) ++ goto err4; ++ + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) + goto err4; +-- +2.27.0 + diff --git a/backport-libselinux-correctly-hash-specfiles-larger-than-4G.patch b/backport-libselinux-correctly-hash-specfiles-larger-than-4G.patch new file mode 100644 index 0000000..be7a024 --- /dev/null +++ b/backport-libselinux-correctly-hash-specfiles-larger-than-4G.patch @@ -0,0 +1,77 @@ +From e17619792fa1e342c7f0a819077129adff438cd1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Wed, 13 Apr 2022 17:56:33 +0200 +Subject: [PATCH] libselinux: correctly hash specfiles larger than 4G +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The internal Sha1Update() functions only handles buffers up to a size of +UINT32_MAX, due to its usage of the type uint32_t. This causes issues +when processing more than UINT32_MAX bytes, e.g. with a specfile larger +than 4G. 0aa974a4 ("libselinux: limit has buffer size") tried to +address this issue, but failed since the overflow check + + if (digest->hashbuf_size + buf_len < digest->hashbuf_size) { + +will be done in the widest common type, which is size_t, the type of +`buf_len`. + +Revert the type of `hashbuf_size` to size_t and instead process the data +in blocks of supported size. + +Acked-by: James Carter +Signed-off-by: Christian Göttsche +Reverts: 0aa974a4 ("libselinux: limit has buffer size") +--- + libselinux/src/label_internal.h | 2 +- + libselinux/src/label_support.c | 14 +++++++++++++- + 2 files changed, 14 insertions(+), 2 deletions(-) + +diff --git a/src/label_internal.h b/src/label_internal.h +index 82a762f7..782c6aa8 100644 +--- a/src/label_internal.h ++++ b/src/label_internal.h +@@ -57,7 +57,7 @@ int selabel_service_init(struct selabel_handle *rec, + struct selabel_digest { + unsigned char *digest; /* SHA1 digest of specfiles */ + unsigned char *hashbuf; /* buffer to hold specfiles */ +- uint32_t hashbuf_size; /* buffer size */ ++ size_t hashbuf_size; /* buffer size */ + size_t specfile_cnt; /* how many specfiles processed */ + char **specfile_list; /* and their names */ + }; +diff --git a/src/label_support.c b/src/label_support.c +index 94ed6e42..54fd49a5 100644 +--- a/src/label_support.c ++++ b/src/label_support.c +@@ -116,13 +116,25 @@ int read_spec_entries(char *line_buf, const char **errbuf, int num_args, ...) + void digest_gen_hash(struct selabel_digest *digest) + { + Sha1Context context; ++ size_t remaining_size; ++ const unsigned char *ptr; + + /* If SELABEL_OPT_DIGEST not set then just return */ + if (!digest) + return; + + Sha1Initialise(&context); +- Sha1Update(&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); ++ remaining_size -= UINT32_MAX; ++ ptr += UINT32_MAX; ++ } ++ Sha1Update(&context, ptr, remaining_size); ++ + Sha1Finalise(&context, (SHA1_HASH *)digest->digest); + free(digest->hashbuf); + digest->hashbuf = NULL; +-- +2.27.0 + diff --git a/backport-libselinux-do-not-return-the-cached-prev_current-value-when-using-getpidcon.patch b/backport-libselinux-do-not-return-the-cached-prev_current-value-when-using-getpidcon.patch new file mode 100644 index 0000000..51204ae --- /dev/null +++ b/backport-libselinux-do-not-return-the-cached-prev_current-value-when-using-getpidcon.patch @@ -0,0 +1,322 @@ +From c8ba7968b3abb1e17edd400bb795d5e452b57935 Mon Sep 17 00:00:00 2001 +From: Nicolas Iooss +Date: Sun, 29 May 2022 20:01:11 +0200 +Subject: [PATCH] libselinux: do not return the cached prev_current value when + using getpidcon() + +libselinux implements a cache mechanism for get*con() functions, such +that when a thread calls setcon(...) then getcon(...), the context is +directly returned. Unfortunately, getpidcon(pid, &context) uses the same +cached variable, so when a program uses setcon("something"), all later +calls to getpidcon(pid, ...) returns "something". This is a bug. + +Here is a program which illustrates this bug: + + #include + #include + + int main() { + char *context = ""; + if (getpidcon(1, &context) < 0) { + perror("getpidcon(1)"); + } + printf("getpidcon(1) = %s\n", context); + + if (getcon(&context) < 0) { + perror("getcon()"); + } + printf("getcon() = %s\n", context); + if (setcon(context) < 0) { + perror("setcon()"); + } + if (getpidcon(1, &context) < 0) { + perror("getpidcon(1)"); + } + printf("getpidcon(1) = %s\n", context); + + return 0; + } + +On an Arch Linux system using unconfined user, this program displays: + + getpidcon(1) = system_u:system_r:init_t + getcon() = unconfined_u:unconfined_r:unconfined_t + getpidcon(1) = unconfined_u:unconfined_r:unconfined_t + +With this commit, this program displays: + + getpidcon(1) = system_u:system_r:init_t + getcon() = unconfined_u:unconfined_r:unconfined_t + getpidcon(1) = system_u:system_r:init_t + +This bug was present in the first commit of +https://github.com/SELinuxProject/selinux git history. It was reported +in https://lore.kernel.org/selinux/20220121084012.GS7643@suse.com/ and a +patch to fix it was sent in +https://patchwork.kernel.org/project/selinux/patch/20220127130741.31940-1-jsegitz@suse.de/ +without a clear explanation. This patch added pid checks, which made +sense but were difficult to read. Instead, it is possible to change the +way the functions are called so that they directly know which cache +variable to use. + +Moreover, as the code is not clear at all (I spent too much time trying +to understand what the switch did and what the thread-local variable +contained), this commit also reworks libselinux/src/procattr.c to: +- not use hard-to-understand switch/case constructions on strings (they + are replaced by a new argument filled by macros) +- remove getpidattr_def macro (it was only used once, for pidcon, and + the code is clearer with one less macro) +- remove the pid parameter of setprocattrcon() and setprocattrcon_raw() + (it is always zero) + +Signed-off-by: Nicolas Iooss +Cc: Johannes Segitz +--- + libselinux/src/procattr.c | 147 +++++++++++++------------------------- + 1 file changed, 50 insertions(+), 97 deletions(-) + +diff --git a/src/procattr.c b/src/procattr.c +index 142fbf3a..6f4cfb82 100644 +--- a/src/procattr.c ++++ b/src/procattr.c +@@ -11,11 +11,14 @@ + + #define UNSET (char *) -1 + ++/* Cached values so that when a thread calls set*con() then gen*con(), the value ++ * which was set is directly returned. ++ */ + static __thread char *prev_current = UNSET; +-static __thread char * prev_exec = UNSET; +-static __thread char * prev_fscreate = UNSET; +-static __thread char * prev_keycreate = UNSET; +-static __thread char * prev_sockcreate = UNSET; ++static __thread char *prev_exec = UNSET; ++static __thread char *prev_fscreate = UNSET; ++static __thread char *prev_keycreate = UNSET; ++static __thread char *prev_sockcreate = UNSET; + + static pthread_once_t once = PTHREAD_ONCE_INIT; + static pthread_key_t destructor_key; +@@ -111,43 +114,18 @@ out: + return fd; + } + +-static int getprocattrcon_raw(char ** context, +- pid_t pid, const char *attr) ++static int getprocattrcon_raw(char **context, pid_t pid, const char *attr, ++ const char *prev_context) + { + char *buf; + size_t size; + int fd; + ssize_t ret; + int errno_hold; +- char * prev_context; + + __selinux_once(once, init_procattr); + init_thread_destructor(); + +- switch (attr[0]) { +- case 'c': +- prev_context = prev_current; +- break; +- case 'e': +- prev_context = prev_exec; +- break; +- case 'f': +- prev_context = prev_fscreate; +- break; +- case 'k': +- prev_context = prev_keycreate; +- break; +- case 's': +- prev_context = prev_sockcreate; +- break; +- case 'p': +- prev_context = NULL; +- break; +- default: +- errno = ENOENT; +- return -1; +- } +- + if (prev_context && prev_context != UNSET) { + *context = strdup(prev_context); + if (!(*context)) { +@@ -194,13 +172,13 @@ static int getprocattrcon_raw(char ** context, + return ret; + } + +-static int getprocattrcon(char ** context, +- pid_t pid, const char *attr) ++static int getprocattrcon(char **context, pid_t pid, const char *attr, ++ const char *prev_context) + { + int ret; + char * rcontext; + +- ret = getprocattrcon_raw(&rcontext, pid, attr); ++ ret = getprocattrcon_raw(&rcontext, pid, attr, prev_context); + + if (!ret) { + ret = selinux_raw_to_trans_context(rcontext, context); +@@ -210,45 +188,24 @@ static int getprocattrcon(char ** context, + return ret; + } + +-static int setprocattrcon_raw(const char * context, +- pid_t pid, const char *attr) ++static int setprocattrcon_raw(const char *context, const char *attr, ++ char **prev_context) + { + int fd; + ssize_t ret; + int errno_hold; +- char **prev_context, *context2 = NULL; ++ char *context2 = NULL; + + __selinux_once(once, init_procattr); + init_thread_destructor(); + +- switch (attr[0]) { +- case 'c': +- prev_context = &prev_current; +- break; +- case 'e': +- prev_context = &prev_exec; +- break; +- case 'f': +- prev_context = &prev_fscreate; +- break; +- case 'k': +- prev_context = &prev_keycreate; +- break; +- case 's': +- prev_context = &prev_sockcreate; +- break; +- default: +- errno = ENOENT; +- return -1; +- } +- + if (!context && !*prev_context) + return 0; + if (context && *prev_context && *prev_context != UNSET + && !strcmp(context, *prev_context)) + return 0; + +- fd = openattr(pid, attr, O_RDWR | O_CLOEXEC); ++ fd = openattr(0, attr, O_RDWR | O_CLOEXEC); + if (fd < 0) + return -1; + if (context) { +@@ -279,8 +236,8 @@ out: + } + } + +-static int setprocattrcon(const char * context, +- pid_t pid, const char *attr) ++static int setprocattrcon(const char *context, const char *attr, ++ char **prev_context) + { + int ret; + char * rcontext; +@@ -288,62 +245,58 @@ static int setprocattrcon(const char * context, + if (selinux_trans_to_raw_context(context, &rcontext)) + return -1; + +- ret = setprocattrcon_raw(rcontext, pid, attr); ++ ret = setprocattrcon_raw(rcontext, attr, prev_context); + + freecon(rcontext); + + return ret; + } + +-#define getselfattr_def(fn, attr) \ ++#define getselfattr_def(fn, attr, prev_context) \ + int get##fn##_raw(char **c) \ + { \ +- return getprocattrcon_raw(c, 0, #attr); \ ++ return getprocattrcon_raw(c, 0, attr, prev_context); \ + } \ + int get##fn(char **c) \ + { \ +- return getprocattrcon(c, 0, #attr); \ ++ return getprocattrcon(c, 0, attr, prev_context); \ + } + +-#define setselfattr_def(fn, attr) \ ++#define setselfattr_def(fn, attr, prev_context) \ + int set##fn##_raw(const char * c) \ + { \ +- return setprocattrcon_raw(c, 0, #attr); \ ++ return setprocattrcon_raw(c, attr, &prev_context); \ + } \ + int set##fn(const char * c) \ + { \ +- return setprocattrcon(c, 0, #attr); \ ++ return setprocattrcon(c, attr, &prev_context); \ + } + +-#define all_selfattr_def(fn, attr) \ +- getselfattr_def(fn, attr) \ +- setselfattr_def(fn, attr) ++#define all_selfattr_def(fn, attr, prev_context) \ ++ getselfattr_def(fn, attr, prev_context) \ ++ setselfattr_def(fn, attr, prev_context) + +-#define getpidattr_def(fn, attr) \ +- int get##fn##_raw(pid_t pid, char **c) \ +- { \ +- if (pid <= 0) { \ +- errno = EINVAL; \ +- return -1; \ +- } else { \ +- return getprocattrcon_raw(c, pid, #attr); \ +- } \ +- } \ +- int get##fn(pid_t pid, char **c) \ +- { \ +- if (pid <= 0) { \ +- errno = EINVAL; \ +- return -1; \ +- } else { \ +- return getprocattrcon(c, pid, #attr); \ +- } \ +- } ++all_selfattr_def(con, "current", prev_current) ++ getselfattr_def(prevcon, "prev", NULL) ++ all_selfattr_def(execcon, "exec", prev_exec) ++ all_selfattr_def(fscreatecon, "fscreate", prev_fscreate) ++ all_selfattr_def(sockcreatecon, "sockcreate", prev_sockcreate) ++ all_selfattr_def(keycreatecon, "keycreate", prev_keycreate) + +-all_selfattr_def(con, current) +- getpidattr_def(pidcon, current) +- getselfattr_def(prevcon, prev) +- all_selfattr_def(execcon, exec) +- all_selfattr_def(fscreatecon, fscreate) +- all_selfattr_def(sockcreatecon, sockcreate) +- all_selfattr_def(keycreatecon, keycreate) ++int getpidcon_raw(pid_t pid, char **c) ++{ ++ if (pid <= 0) { ++ errno = EINVAL; ++ return -1; ++ } ++ return getprocattrcon_raw(c, pid, "current", NULL); ++} + ++int getpidcon(pid_t pid, char **c) ++{ ++ if (pid <= 0) { ++ errno = EINVAL; ++ return -1; ++ } ++ return getprocattrcon(c, pid, "current", NULL); ++} +-- +2.27.0 + diff --git a/backport-libselinux-filter-arguments-with-path-separators.patch b/backport-libselinux-filter-arguments-with-path-separators.patch new file mode 100644 index 0000000..2ba40b2 --- /dev/null +++ b/backport-libselinux-filter-arguments-with-path-separators.patch @@ -0,0 +1,63 @@ +From d31280c26e066d68c3061fc24f5951829f641e81 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Mon, 14 Nov 2022 20:32:08 +0100 +Subject: [PATCH] libselinux: filter arguments with path separators +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Boolean names, taken by security_get_boolean_pending(3), +security_get_boolean_active(3) and security_set_boolean(3), as well as +user names, taken by security_get_initial_context(3), are used in path +constructions. Ensure they do not contain path separators to avoid +unwanted path traversal. + +Signed-off-by: Christian Göttsche +Acked-by: James Carter +--- + libselinux/src/booleans.c | 5 +++-- + libselinux/src/get_initial_context.c | 5 +++++ + 2 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/src/booleans.c b/src/booleans.c +index dbcccd70..e34b39ff 100644 +--- a/src/booleans.c ++++ b/src/booleans.c +@@ -131,7 +131,8 @@ char *selinux_boolean_sub(const char *name) + ptr++; + *ptr = '\0'; + +- sub = strdup(dst); ++ if (!strchr(dst, '/')) ++ sub = strdup(dst); + + break; + } +@@ -151,7 +152,7 @@ static int bool_open(const char *name, int flag) { + int ret; + char *ptr; + +- if (!name) { ++ if (!name || strchr(name, '/')) { + errno = EINVAL; + return -1; + } +diff --git a/src/get_initial_context.c b/src/get_initial_context.c +index 87c8adfa..0f25ba3f 100644 +--- a/src/get_initial_context.c ++++ b/src/get_initial_context.c +@@ -23,6 +23,11 @@ int security_get_initial_context_raw(const char * name, char ** con) + return -1; + } + ++ if (strchr(name, '/')) { ++ errno = EINVAL; ++ return -1; ++ } ++ + ret = snprintf(path, sizeof path, "%s%s%s", selinux_mnt, SELINUX_INITCON_DIR, name); + if (ret < 0 || (size_t)ret >= sizeof path) { + errno = EOVERFLOW; +-- +2.27.0 + diff --git a/backport-libselinux-fix-memory-leaks-on-the-audit2why-module-init.patch b/backport-libselinux-fix-memory-leaks-on-the-audit2why-module-init.patch new file mode 100644 index 0000000..6d0809a --- /dev/null +++ b/backport-libselinux-fix-memory-leaks-on-the-audit2why-module-init.patch @@ -0,0 +1,94 @@ +From 42f7f2fdcf1a38b6018933132ea6a35dc41bdeff Mon Sep 17 00:00:00 2001 +From: Jie Lu +Date: Tue, 15 Nov 2022 19:55:36 +0800 +Subject: [PATCH] libselinux: fix memory leaks on the audit2why module init + +Signed-off-by: Jie Lu +Acked-by: James Carter +--- + libselinux/src/audit2why.c | 32 +++++++++++++++++++++++--------- + 1 file changed, 23 insertions(+), 9 deletions(-) + +diff --git a/src/audit2why.c b/src/audit2why.c +index 44a9a341..ba1a66eb 100644 +--- a/src/audit2why.c ++++ b/src/audit2why.c +@@ -191,7 +191,7 @@ static PyObject *finish(PyObject *self __attribute__((unused)), PyObject *args) + + static int __policy_init(const char *init_path) + { +- FILE *fp; ++ FILE *fp = NULL; + const char *curpolicy; + char errormsg[PATH_MAX+1024+20]; + struct sepol_policy_file *pf = NULL; +@@ -235,18 +235,17 @@ static int __policy_init(const char *init_path) + snprintf(errormsg, sizeof(errormsg), + "policydb_init failed: %m\n"); + PyErr_SetString( PyExc_RuntimeError, errormsg); +- fclose(fp); +- return 1; ++ goto err; + } + sepol_policy_file_set_fp(pf, fp); + if (sepol_policydb_read(avc->policydb, pf)) { + snprintf(errormsg, sizeof(errormsg), + "invalid binary policy %s\n", curpolicy); + PyErr_SetString( PyExc_ValueError, errormsg); +- fclose(fp); +- return 1; ++ goto err; + } + fclose(fp); ++ fp = NULL; + sepol_set_policydb(&avc->policydb->p); + avc->handle = sepol_handle_create(); + /* Turn off messages */ +@@ -256,13 +255,13 @@ static int __policy_init(const char *init_path) + avc->policydb, &cnt); + if (rc < 0) { + PyErr_SetString( PyExc_RuntimeError, "unable to get bool count\n"); +- return 1; ++ goto err; + } + + boollist = calloc(cnt, sizeof(*boollist)); + if (!boollist) { + PyErr_SetString( PyExc_MemoryError, "Out of memory\n"); +- return 1; ++ goto err; + } + + sepol_bool_iterate(avc->handle, avc->policydb, +@@ -273,11 +272,26 @@ static int __policy_init(const char *init_path) + rc = sepol_sidtab_init(&sidtab); + if (rc < 0) { + PyErr_SetString( PyExc_RuntimeError, "unable to init sidtab\n"); +- free(boollist); +- return 1; ++ goto err; + } + sepol_set_sidtab(&sidtab); + return 0; ++ ++err: ++ if (boollist) ++ free(boollist); ++ if (avc){ ++ if (avc->handle) ++ sepol_handle_destroy(avc->handle); ++ if (avc->policydb) ++ sepol_policydb_free(avc->policydb); ++ free(avc); ++ } ++ if (pf) ++ sepol_policy_file_free(pf); ++ if (fp) ++ fclose(fp); ++ return 1; + } + + static PyObject *init(PyObject *self __attribute__((unused)), PyObject *args) { +-- +2.27.0 + diff --git a/backport-libselinux-fix-some-memory-issues-in-db_init.patch b/backport-libselinux-fix-some-memory-issues-in-db_init.patch new file mode 100644 index 0000000..a952525 --- /dev/null +++ b/backport-libselinux-fix-some-memory-issues-in-db_init.patch @@ -0,0 +1,54 @@ +From 001af27a6d32e5b3d1f7410f0007687d7e3c07f5 Mon Sep 17 00:00:00 2001 +From: Jie Lu +Date: Tue, 22 Nov 2022 13:21:10 +0800 +Subject: [PATCH] libselinux: fix some memory issues in db_init + +1. check the return of strdup to avoid a potential NULL reference. +2. make sure line_buf is freed. + +Signed-off-by: Jie Lu +Acked-by: James Carter +--- + libselinux/src/label_db.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/src/label_db.c b/src/label_db.c +index 94c05c6d..bd73201c 100644 +--- a/src/label_db.c ++++ b/src/label_db.c +@@ -293,6 +293,11 @@ db_init(const struct selinux_opt *opts, unsigned nopts, + return NULL; + } + rec->spec_file = strdup(path); ++ if (!rec->spec_file) { ++ free(catalog); ++ fclose(filp); ++ return NULL; ++ } + + /* + * Parse for each lines +@@ -322,18 +327,19 @@ db_init(const struct selinux_opt *opts, unsigned nopts, + if (process_line(path, line_buf, ++line_num, catalog) < 0) + goto out_error; + } +- free(line_buf); + + if (digest_add_specfile(rec->digest, filp, NULL, sb.st_size, path) < 0) + goto out_error; + + digest_gen_hash(rec->digest); + ++ free(line_buf); + fclose(filp); + + return catalog; + + out_error: ++ free(line_buf); + for (i = 0; i < catalog->nspec; i++) { + spec_t *spec = &catalog->specs[i]; + +-- +2.27.0 + diff --git a/backport-libselinux-ignore-invalid-class-name-lookup.patch b/backport-libselinux-ignore-invalid-class-name-lookup.patch new file mode 100644 index 0000000..749f97a --- /dev/null +++ b/backport-libselinux-ignore-invalid-class-name-lookup.patch @@ -0,0 +1,43 @@ +From f56a72ac9e86ddfbefedc41080f33fb06639f96b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Thi=C3=A9baud=20Weksteen?= +Date: Mon, 24 Oct 2022 20:13:54 +1100 +Subject: [PATCH] libselinux: ignore invalid class name lookup +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +selinux_check_access relies on string_to_security_class to resolve the +class index from its char* argument. There is no input validation done +on the string provided. It is possible to supply an argument containing +trailing backslashes (i.e., "sock_file//////") so that the paths built +in discover_class get truncated. The processing will then reference the +same permission file multiple time (e.g., perms/watch_reads will be +truncated to perms/watch). This will leak the memory allocated when +strdup'ing the permission name. The discover_class_cache will end up in +an invalid state (but not corrupted). + +Ensure that the class provided does not contain any path separator. + +Signed-off-by: Thiébaud Weksteen +Acked-by: James Carter +--- + libselinux/src/stringrep.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/stringrep.c b/src/stringrep.c +index 2fe69f43..592410e5 100644 +--- a/src/stringrep.c ++++ b/src/stringrep.c +@@ -63,6 +63,9 @@ static struct discover_class_node * discover_class(const char *s) + return NULL; + } + ++ if (strchr(s, '/') != NULL) ++ return NULL; ++ + /* allocate a node */ + node = malloc(sizeof(struct discover_class_node)); + if (node == NULL) +-- +2.27.0 + diff --git a/backport-libselinux-limit-has-buffer-size.patch b/backport-libselinux-limit-has-buffer-size.patch new file mode 100644 index 0000000..d2c77dc --- /dev/null +++ b/backport-libselinux-limit-has-buffer-size.patch @@ -0,0 +1,41 @@ +From 0aa974a439c60bd19e504d6a583cbae770de3701 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Fri, 8 Apr 2022 15:10:53 +0200 +Subject: [PATCH] libselinux: limit has buffer size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The `struct selabel_digest` member `hashbuf_size` is used to compute +hashes via `Sha1Update()`, which takes uint32_t as length parameter +type. Use that same type for `hashbuf_size` to avoid potential value +truncations, as the overflow check in `digest_add_specfile()` on +`hashbuf_size` is based on it. + + label_support.c: In function ‘digest_gen_hash’: + label_support.c:125:53: warning: conversion from ‘size_t’ {aka ‘long unsigned int’} to ‘uint32_t’ {aka ‘unsigned int’} may change value [-Wconversion] + 125 | Sha1Update(&context, digest->hashbuf, digest->hashbuf_size); + | ~~~~~~^~~~~~~~~~~~~~ + +Acked-by: James Carter +Signed-off-by: Christian Göttsche +--- + libselinux/src/label_internal.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/label_internal.h b/src/label_internal.h +index 782c6aa8..82a762f7 100644 +--- a/src/label_internal.h ++++ b/src/label_internal.h +@@ -57,7 +57,7 @@ int selabel_service_init(struct selabel_handle *rec, + struct selabel_digest { + unsigned char *digest; /* SHA1 digest of specfiles */ + unsigned char *hashbuf; /* buffer to hold specfiles */ +- size_t hashbuf_size; /* buffer size */ ++ uint32_t hashbuf_size; /* buffer size */ + size_t specfile_cnt; /* how many specfiles processed */ + char **specfile_list; /* and their names */ + }; +-- +2.27.0 + diff --git a/backport-libselinux-restore-use-fixed-sized-integer-for-hash-index.patch b/backport-libselinux-restore-use-fixed-sized-integer-for-hash-index.patch new file mode 100644 index 0000000..d37e830 --- /dev/null +++ b/backport-libselinux-restore-use-fixed-sized-integer-for-hash-index.patch @@ -0,0 +1,66 @@ +From 1609b9fdfddc1f6baa1b38b57018b16af9c5471a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Wed, 1 Feb 2023 11:55:10 +0100 +Subject: [PATCH] libselinux: restore: use fixed sized integer for hash index +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The hash mask is set to 2^16 - 1, which does not fit into a signed 16 +bit integer. Use uint32_t to be on the safe side. Also use size_t for +counting in debug function. + +Signed-off-by: Christian Göttsche +Acked-by: Jason Zaman + +Reference:https://github.com/SELinuxProject/selinux/commit/1609b9fdfddc1f6baa1b38b57018b16af9c5471a +Conflict:context adapt +--- + libselinux/src/selinux_restorecon.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/src/selinux_restorecon.c b/src/selinux_restorecon.c +index 40a759f0..7ef2d45d 100644 +--- a/src/selinux_restorecon.c ++++ b/src/selinux_restorecon.c +@@ -429,7 +429,8 @@ static int filespec_add(ino_t ino, const char *con, const char *file, + struct rest_flags *flags) + { + file_spec_t *prevfl, *fl; +- int h, ret; ++ uint32_t h; ++ int ret; + struct stat64 sb; + + if (!fl_head) { +@@ -524,7 +525,8 @@ unlock_1: + static void filespec_eval(void) + { + file_spec_t *fl; +- int h, used, nel, len, longest; ++ uint32_t h; ++ size_t used, nel, len, longest; + + if (!fl_head) + return; +@@ -544,7 +546,7 @@ static void filespec_eval(void) + } + + selinux_log(SELINUX_INFO, +- "filespec hash table stats: %d elements, %d/%d buckets used, longest chain length %d\n", ++ "filespec hash table stats: %zu elements, %zu/%zu buckets used, longest chain length %zu\n", + nel, used, HASH_BUCKETS, longest); + } + #else +@@ -559,7 +561,7 @@ static void filespec_eval(void) + static void filespec_destroy(void) + { + file_spec_t *fl, *tmp; +- int h; ++ uint32_t h; + + if (!fl_head) + return; +-- +2.27.0 + diff --git a/backport-libselinux-simplify-policy-path-logic-to-avoid-uninitialized-read.patch b/backport-libselinux-simplify-policy-path-logic-to-avoid-uninitialized-read.patch new file mode 100644 index 0000000..e7fd508 --- /dev/null +++ b/backport-libselinux-simplify-policy-path-logic-to-avoid-uninitialized-read.patch @@ -0,0 +1,88 @@ +From 31e3537624ad2d07271d4c02925ebc6cb942e0c6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Tue, 10 May 2022 20:20:36 +0200 +Subject: [PATCH] libselinux: simplify policy path logic to avoid uninitialized + read +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In case the function __policy_init() gets called with a NULL pointer, +the stack variable path remains uninitialized (except at its last +index). If parsing the binary policy fails in sepol_policydb_read() the +error branch would access those uninitialized memory. + +Signed-off-by: Christian Göttsche +--- + libselinux/src/audit2why.c | 34 +++++++++++++--------------------- + 1 file changed, 13 insertions(+), 21 deletions(-) + +diff --git a/src/audit2why.c b/src/audit2why.c +index ca38e13c..44a9a341 100644 +--- a/src/audit2why.c ++++ b/src/audit2why.c +@@ -192,25 +192,16 @@ static PyObject *finish(PyObject *self __attribute__((unused)), PyObject *args) + static int __policy_init(const char *init_path) + { + FILE *fp; +- char path[PATH_MAX]; ++ const char *curpolicy; + char errormsg[PATH_MAX+1024+20]; + struct sepol_policy_file *pf = NULL; + int rc; + unsigned int cnt; + +- path[PATH_MAX-1] = '\0'; + if (init_path) { +- strncpy(path, init_path, PATH_MAX-1); +- fp = fopen(path, "re"); +- if (!fp) { +- snprintf(errormsg, sizeof(errormsg), +- "unable to open %s: %m\n", +- path); +- PyErr_SetString( PyExc_ValueError, errormsg); +- return 1; +- } ++ curpolicy = init_path; + } else { +- const char *curpolicy = selinux_current_policy_path(); ++ curpolicy = selinux_current_policy_path(); + if (!curpolicy) { + /* SELinux disabled, must use -p option. */ + snprintf(errormsg, sizeof(errormsg), +@@ -218,14 +209,15 @@ static int __policy_init(const char *init_path) + PyErr_SetString( PyExc_ValueError, errormsg); + return 1; + } +- fp = fopen(curpolicy, "re"); +- if (!fp) { +- snprintf(errormsg, sizeof(errormsg), +- "unable to open %s: %m\n", +- curpolicy); +- PyErr_SetString( PyExc_ValueError, errormsg); +- return 1; +- } ++ } ++ ++ fp = fopen(curpolicy, "re"); ++ if (!fp) { ++ snprintf(errormsg, sizeof(errormsg), ++ "unable to open %s: %m\n", ++ curpolicy); ++ PyErr_SetString( PyExc_ValueError, errormsg); ++ return 1; + } + + avc = calloc(sizeof(struct avc_t), 1); +@@ -249,7 +241,7 @@ static int __policy_init(const char *init_path) + sepol_policy_file_set_fp(pf, fp); + if (sepol_policydb_read(avc->policydb, pf)) { + snprintf(errormsg, sizeof(errormsg), +- "invalid binary policy %s\n", path); ++ "invalid binary policy %s\n", curpolicy); + PyErr_SetString( PyExc_ValueError, errormsg); + fclose(fp); + return 1; +-- +2.27.0 + diff --git a/libselinux.spec b/libselinux.spec index 26f6aef..6d8164a 100644 --- a/libselinux.spec +++ b/libselinux.spec @@ -3,7 +3,7 @@ Name: libselinux Version: 3.3 -Release: 2 +Release: 3 License: Public Domain Summary: SELinux library and simple utilities Url: https://github.com/SELinuxProject/selinux/wiki @@ -14,6 +14,18 @@ Patch6001: backport-libselinux-free-memory-on-selabel_open-3-failure.patch Patch6002: backport-libselinux-restorecon-misc-tweaks.patch Patch6003: backport-libselinux-free-memory-in-error-branch.patch Patch6004: backport-libselinux-restorecon-avoid-printing-NULL-pointer.patch +Patch6005: backport-libselinux-limit-has-buffer-size.patch +Patch6006: backport-libselinux-correctly-hash-specfiles-larger-than-4G.patch +Patch6007: backport-libselinux-simplify-policy-path-logic-to-avoid-uninitialized-read.patch +Patch6008: backport-libselinux-do-not-return-the-cached-prev_current-value-when-using-getpidcon.patch +Patch6009: backport-libselinux-Ignore-missing-directories-when-i-is-used.patch +Patch6010: backport-libselinux-ignore-invalid-class-name-lookup.patch +Patch6011: backport-libselinux-fix-memory-leaks-on-the-audit2why-module-init.patch +Patch6012: backport-libselinux-bail-out-on-path-truncations.patch +Patch6013: backport-libselinux-filter-arguments-with-path-separators.patch +Patch6014: backport-libselinux-fix-some-memory-issues-in-db_init.patch +Patch6015: backport-libselinux-add-check-for-malloc.patch +Patch6016: backport-libselinux-restore-use-fixed-sized-integer-for-hash-index.patch Patch9000: do-malloc-trim-after-load-policy.patch @@ -134,6 +146,9 @@ mv %{buildroot}%{_sbindir}/getconlist %{buildroot}%{_sbindir}/selinuxconlist %{_mandir}/ru/man8/* %changelog +* Tue Jun 13 2023 zhangguangzhi - 3.3-3 +- backport upstream patches + * Sun Oct 9 2022 lujie - 3.3-2 - backport upstream patches -- Gitee