This reverts commit 8997f54322f5648721ce42f723432a023219f02b. Needed to revert commit 92306daf5219e73f6e8bc9fc7699399457999bcd "libselinux: rework selabel_file(5) database", which broke Android file_context matching. Signed-off-by: James Carter <jwcart2@xxxxxxxxx> --- libselinux/fuzz/input | 0 .../fuzz/selabel_file_compiled-fuzzer.c | 281 ------------------ libselinux/fuzz/selabel_file_text-fuzzer.c | 225 -------------- libselinux/src/label_file.c | 38 +-- libselinux/src/label_file.h | 17 -- scripts/oss-fuzz.sh | 25 -- 6 files changed, 20 insertions(+), 566 deletions(-) delete mode 100644 libselinux/fuzz/input delete mode 100644 libselinux/fuzz/selabel_file_compiled-fuzzer.c delete mode 100644 libselinux/fuzz/selabel_file_text-fuzzer.c diff --git a/libselinux/fuzz/input b/libselinux/fuzz/input deleted file mode 100644 index e69de29b..00000000 diff --git a/libselinux/fuzz/selabel_file_compiled-fuzzer.c b/libselinux/fuzz/selabel_file_compiled-fuzzer.c deleted file mode 100644 index cf0710ad..00000000 --- a/libselinux/fuzz/selabel_file_compiled-fuzzer.c +++ /dev/null @@ -1,281 +0,0 @@ -#include <errno.h> -#include <stdint.h> -#include <stdio.h> -#include <sys/mman.h> -#include <unistd.h> - -#include <selinux/label.h> - -#include "../src/label_file.h" - -extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); - -#define MEMFD_FILE_NAME "file_contexts" -#define CTRL_PARTIAL (1U << 0) -#define CTRL_FIND_ALL (1U << 1) -#define CTRL_MODE (1U << 2) - - -__attribute__ ((format(printf, 2, 3))) -static int null_log(int type __attribute__((unused)), const char *fmt __attribute__((unused)), ...) -{ - return 0; -} - -static int validate_context(char **ctxp) -{ - assert(strcmp(*ctxp, "<<none>>") != 0); - - if (*ctxp[0] == '\0') { - errno = EINVAL; - return -1; - } - - return 0; -} - -static int write_full(int fd, const void *data, size_t size) -{ - ssize_t rc; - const unsigned char *p = data; - - while (size > 0) { - rc = write(fd, p, size); - if (rc == -1) { - if (errno == EINTR) - continue; - - return -1; - } - - p += rc; - size -= rc; - } - - return 0; -} - -static FILE* convert_data(const uint8_t *data, size_t size) -{ - FILE* stream; - int fd, rc; - - fd = memfd_create(MEMFD_FILE_NAME, MFD_CLOEXEC); - if (fd == -1) - return NULL; - - rc = write_full(fd, data, size); - if (rc == -1) { - close(fd); - return NULL; - } - - stream = fdopen(fd, "r"); - if (!stream) { - close(fd); - return NULL; - } - - rc = fseek(stream, 0L, SEEK_SET); - if (rc == -1) { - fclose(stream); - return NULL; - } - - return stream; -} - -int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) -{ - struct selabel_handle rec; - struct saved_data sdata = {}; - struct spec_node *root = NULL; - FILE* fp = NULL; - struct lookup_result *result = NULL; - uint8_t control; - uint8_t *fcontext_data1 = NULL, *fcontext_data2 = NULL, *fcontext_data3 = NULL; - char *key = NULL; - size_t fcontext_data1_len, fcontext_data2_len, fcontext_data3_len, key_len; - bool partial, find_all; - mode_t mode; - int rc; - - /* - * Treat first byte as control byte, whether to use partial mode, find all matches or mode to lookup - */ - if (size == 0) - return 0; - - control = data[0]; - data++; - size--; - - if (control & ~(CTRL_PARTIAL | CTRL_FIND_ALL | CTRL_MODE)) - return 0; - - partial = control & CTRL_PARTIAL; - find_all = control & CTRL_FIND_ALL; - /* S_IFSOCK has the highest integer value */ - mode = (control & CTRL_MODE) ? S_IFSOCK : 0; - - - /* - * Split the fuzzer input into up to four pieces: one to three compiled fcontext - * definitions (to mimic file_contexts, file_contexts.homedirs and file_contexts.local, - * and the lookup key - */ - const unsigned char separator[4] = { 0xde, 0xad, 0xbe, 0xef }; - const uint8_t *sep = memmem(data, size, separator, 4); - if (!sep || sep == data) - return 0; - - fcontext_data1_len = sep - data; - fcontext_data1 = malloc(fcontext_data1_len); - if (!fcontext_data1) - goto cleanup; - - memcpy(fcontext_data1, data, fcontext_data1_len); - data += fcontext_data1_len + 4; - size -= fcontext_data1_len + 4; - - sep = memmem(data, size, separator, 4); - if (sep) { - fcontext_data2_len = sep - data; - fcontext_data2 = malloc(fcontext_data2_len); - if (!fcontext_data2) - goto cleanup; - - memcpy(fcontext_data2, data, fcontext_data2_len); - data += fcontext_data2_len + 4; - size -= fcontext_data2_len + 4; - } - - sep = memmem(data, size, separator, 4); - if (sep) { - fcontext_data3_len = sep - data; - fcontext_data3 = malloc(fcontext_data3_len); - if (!fcontext_data3) - goto cleanup; - - memcpy(fcontext_data3, data, fcontext_data3_len); - data += fcontext_data3_len + 4; - size -= fcontext_data3_len + 4; - } - - key_len = size; - key = malloc(key_len + 1); - if (!key) - goto cleanup; - - memcpy(key, data, key_len); - key[key_len] = '\0'; - - - /* - * Mock selabel handle - */ - rec = (struct selabel_handle) { - .backend = SELABEL_CTX_FILE, - .validating = 1, - .data = &sdata, - }; - - selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) { .func_log = &null_log }); - /* validate to pre-compile regular expressions */ - selinux_set_callback(SELINUX_CB_VALIDATE, (union selinux_callback) { .func_validate = &validate_context }); - - root = calloc(1, sizeof(*root)); - if (!root) - goto cleanup; - - sdata.root = root; - - fp = convert_data(fcontext_data1, fcontext_data1_len); - if (!fp) - goto cleanup; - - errno = 0; - rc = load_mmap(fp, fcontext_data1_len, &rec, MEMFD_FILE_NAME); - if (rc) { - assert(errno != 0); - goto cleanup; - } - - fclose(fp); - - fp = convert_data(fcontext_data2, fcontext_data2_len); - if (!fp) - goto cleanup; - - errno = 0; - rc = load_mmap(fp, fcontext_data2_len, &rec, MEMFD_FILE_NAME); - if (rc) { - assert(errno != 0); - goto cleanup; - } - - fclose(fp); - - fp = convert_data(fcontext_data3, fcontext_data3_len); - if (!fp) - goto cleanup; - - errno = 0; - rc = load_mmap(fp, fcontext_data3_len, &rec, MEMFD_FILE_NAME); - if (rc) { - assert(errno != 0); - goto cleanup; - } - - sort_specs(&sdata); - - assert(cmp(&rec, &rec) == SELABEL_EQUAL); - - errno = 0; - result = lookup_all(&rec, key, mode, partial, find_all); - - if (!result) - assert(errno != 0); - - for (const struct lookup_result *res = result; res; res = res->next) { - assert(res->regex_str); - assert(res->regex_str[0] != '\0'); - assert(res->lr->ctx_raw); - assert(res->lr->ctx_raw[0] != '\0'); - assert(strcmp(res->lr->ctx_raw, "<<none>>") != 0); - assert(!res->lr->ctx_trans); - assert(res->lr->validated); - assert(res->prefix_len <= strlen(res->regex_str)); - } - - -cleanup: - free_lookup_result(result); - if (fp) - fclose(fp); - if (sdata.root) { - free_spec_node(sdata.root); - free(sdata.root); - } - - { - struct mmap_area *area, *last_area; - - area = sdata.mmap_areas; - while (area) { - rc = munmap(area->addr, area->len); - assert(rc == 0); - last_area = area; - area = area->next; - free(last_area); - } - } - - free(key); - free(fcontext_data3); - free(fcontext_data2); - free(fcontext_data1); - - /* Non-zero return values are reserved for future use. */ - return 0; -} diff --git a/libselinux/fuzz/selabel_file_text-fuzzer.c b/libselinux/fuzz/selabel_file_text-fuzzer.c deleted file mode 100644 index 5d851de1..00000000 --- a/libselinux/fuzz/selabel_file_text-fuzzer.c +++ /dev/null @@ -1,225 +0,0 @@ -#include <errno.h> -#include <stdint.h> -#include <stdio.h> -#include <sys/mman.h> -#include <unistd.h> - -#include <selinux/label.h> - -#include "../src/label_file.h" - -extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); - -#define MEMFD_FILE_NAME "file_contexts" -#define CTRL_PARTIAL (1U << 0) -#define CTRL_FIND_ALL (1U << 1) -#define CTRL_MODE (1U << 2) - - -__attribute__ ((format(printf, 2, 3))) -static int null_log(int type __attribute__((unused)), const char *fmt __attribute__((unused)), ...) -{ - return 0; -} - -static int validate_context(char **ctxp) -{ - assert(strcmp(*ctxp, "<<none>>") != 0); - - if (*ctxp[0] == '\0') { - errno = EINVAL; - return -1; - } - - return 0; -} - -static int write_full(int fd, const void *data, size_t size) -{ - ssize_t rc; - const unsigned char *p = data; - - while (size > 0) { - rc = write(fd, p, size); - if (rc == -1) { - if (errno == EINTR) - continue; - - return -1; - } - - p += rc; - size -= rc; - } - - return 0; -} - -static FILE* convert_data(const uint8_t *data, size_t size) -{ - FILE* stream; - int fd, rc; - - fd = memfd_create(MEMFD_FILE_NAME, MFD_CLOEXEC); - if (fd == -1) - return NULL; - - rc = write_full(fd, data, size); - if (rc == -1) { - close(fd); - return NULL; - } - - stream = fdopen(fd, "r"); - if (!stream) { - close(fd); - return NULL; - } - - rc = fseek(stream, 0L, SEEK_SET); - if (rc == -1) { - fclose(stream); - return NULL; - } - - return stream; -} - -int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) -{ - struct selabel_handle rec; - struct saved_data sdata = {}; - struct spec_node *root = NULL; - FILE* fp = NULL; - struct lookup_result *result = NULL; - uint8_t control; - uint8_t *fcontext_data = NULL; - char *key = NULL; - size_t fcontext_data_len, key_len; - bool partial, find_all; - mode_t mode; - int rc; - - /* - * Treat first byte as control byte, whether to use partial mode, find all matches or mode to lookup - */ - if (size == 0) - return 0; - - control = data[0]; - data++; - size--; - - if (control & ~(CTRL_PARTIAL | CTRL_FIND_ALL | CTRL_MODE)) - return 0; - - partial = control & CTRL_PARTIAL; - find_all = control & CTRL_FIND_ALL; - /* S_IFSOCK has the highest integer value */ - mode = (control & CTRL_MODE) ? S_IFSOCK : 0; - - - /* - * Split the fuzzer input into two pieces: the textual fcontext definition and the lookup key - */ - const unsigned char separator[4] = { 0xde, 0xad, 0xbe, 0xef }; - const uint8_t *sep = memmem(data, size, separator, 4); - if (!sep || sep == data) - return 0; - - fcontext_data_len = sep - data; - fcontext_data = malloc(fcontext_data_len); - if (!fcontext_data) - goto cleanup; - - memcpy(fcontext_data, data, fcontext_data_len); - - key_len = size - fcontext_data_len - 4; - key = malloc(key_len + 1); - if (!key) - goto cleanup; - - memcpy(key, sep + 4, key_len); - key[key_len] = '\0'; - - - /* - * Mock selabel handle - */ - rec = (struct selabel_handle) { - .backend = SELABEL_CTX_FILE, - .validating = 1, - .data = &sdata, - }; - - selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) { .func_log = &null_log }); - /* validate to pre-compile regular expressions */ - selinux_set_callback(SELINUX_CB_VALIDATE, (union selinux_callback) { .func_validate = &validate_context }); - - root = calloc(1, sizeof(*root)); - if (!root) - goto cleanup; - - sdata.root = root; - - fp = convert_data(fcontext_data, fcontext_data_len); - if (!fp) - goto cleanup; - - errno = 0; - rc = process_text_file(fp, /*prefix=*/ NULL, &rec, MEMFD_FILE_NAME); - if (rc) { - assert(errno != 0); - goto cleanup; - } - - sort_specs(&sdata); - - assert(cmp(&rec, &rec) == SELABEL_EQUAL); - - errno = 0; - result = lookup_all(&rec, key, mode, partial, find_all); - - if (!result) - assert(errno != 0); - - for (const struct lookup_result *res = result; res; res = res->next) { - assert(res->regex_str); - assert(res->regex_str[0] != '\0'); - assert(res->lr->ctx_raw); - assert(res->lr->ctx_raw[0] != '\0'); - assert(strcmp(res->lr->ctx_raw, "<<none>>") != 0); - assert(!res->lr->ctx_trans); - assert(res->lr->validated); - assert(res->prefix_len <= strlen(res->regex_str)); - } - - -cleanup: - free_lookup_result(result); - if (fp) - fclose(fp); - if (sdata.root) { - free_spec_node(sdata.root); - free(sdata.root); - } - - { - struct mmap_area *area, *last_area; - - area = sdata.mmap_areas; - while (area) { - rc = munmap(area->addr, area->len); - assert(rc == 0); - last_area = area; - area = area->next; - free(last_area); - } - } - - free(key); - free(fcontext_data); - - /* Non-zero return values are reserved for future use. */ - return 0; -} diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c index 189a5ed2..d9ee4063 100644 --- a/libselinux/src/label_file.c +++ b/libselinux/src/label_file.c @@ -27,13 +27,6 @@ #include "label_file.h" -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -# define FUZZ_EXTERN -#else -# define FUZZ_EXTERN static -#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ - - /* * Warn about duplicate specifications. */ @@ -121,8 +114,8 @@ static int nodups_spec_node(const struct spec_node *node, const char *path) return rc; } -FUZZ_EXTERN int process_text_file(FILE *fp, const char *prefix, - struct selabel_handle *rec, const char *path) +static int process_text_file(FILE *fp, const char *prefix, + struct selabel_handle *rec, const char *path) { int rc; size_t line_len; @@ -727,8 +720,8 @@ static int load_mmap_spec_node(struct mmap_area *mmap_area, const char *path, bo return 0; } -FUZZ_EXTERN int load_mmap(FILE *fp, const size_t len, struct selabel_handle *rec, - const char *path) +static int load_mmap(FILE *fp, const size_t len, struct selabel_handle *rec, + const char *path) { struct saved_data *data = rec->data; struct spec_node *root = NULL; @@ -1456,7 +1449,16 @@ static uint32_t search_literal_spec(const struct literal_spec *array, uint32_t s return (uint32_t)-1; } -FUZZ_EXTERN void free_lookup_result(struct lookup_result *result) +struct lookup_result { + const char *regex_str; + struct selabel_lookup_rec *lr; + uint16_t prefix_len; + uint8_t file_kind; + bool has_meta_chars; + struct lookup_result *next; +}; + +static void free_lookup_result(struct lookup_result *result) { struct lookup_result *tmp; @@ -1688,11 +1690,11 @@ static uint8_t mode_to_file_kind(int type) { // Finds all the matches of |key| in the given context. Returns the result in // the allocated array and updates the match count. If match_count is NULL, // stops early once the 1st match is found. -FUZZ_EXTERN struct lookup_result *lookup_all(struct selabel_handle *rec, - const char *key, - int type, - bool partial, - bool find_all) +static struct lookup_result *lookup_all(struct selabel_handle *rec, + const char *key, + int type, + bool partial, + bool find_all) { struct saved_data *data = (struct saved_data *)rec->data; struct lookup_result *result = NULL; @@ -2281,7 +2283,7 @@ static enum selabel_cmp_result spec_node_cmp(const struct spec_node *node1, cons return result; } -FUZZ_EXTERN enum selabel_cmp_result cmp(const struct selabel_handle *h1, const struct selabel_handle *h2) +static enum selabel_cmp_result cmp(const struct selabel_handle *h1, const struct selabel_handle *h2) { const struct saved_data *data1, *data2; diff --git a/libselinux/src/label_file.h b/libselinux/src/label_file.h index 529a1bd2..2dc772eb 100644 --- a/libselinux/src/label_file.h +++ b/libselinux/src/label_file.h @@ -50,23 +50,6 @@ #define LABEL_FILE_KIND_LNK 6 #define LABEL_FILE_KIND_REG 7 -/* Only exported for fuzzing */ -struct lookup_result { - const char *regex_str; - struct selabel_lookup_rec *lr; - uint16_t prefix_len; - uint8_t file_kind; - bool has_meta_chars; - struct lookup_result *next; -}; -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -extern int load_mmap(FILE *fp, const size_t len, struct selabel_handle *rec, const char *path); -extern int process_text_file(FILE *fp, const char *prefix, struct selabel_handle *rec, const char *path); -extern void free_lookup_result(struct lookup_result *result); -extern struct lookup_result *lookup_all(struct selabel_handle *rec, const char *key, int type, bool partial, bool find_all); -extern enum selabel_cmp_result cmp(const struct selabel_handle *h1, const struct selabel_handle *h2); -#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ - struct selabel_sub { char *src; unsigned int slen; diff --git a/scripts/oss-fuzz.sh b/scripts/oss-fuzz.sh index 9376b6e4..069f130a 100755 --- a/scripts/oss-fuzz.sh +++ b/scripts/oss-fuzz.sh @@ -44,13 +44,10 @@ export LIB_FUZZING_ENGINE=${LIB_FUZZING_ENGINE:--fsanitize=fuzzer} rm -rf "$DESTDIR" make -C libsepol clean -make -C libselinux clean # LIBSO and LIBMAP shouldn't be expanded here because their values are unknown until Makefile # has been read by make # shellcheck disable=SC2016 make -C libsepol V=1 LD_SONAME_FLAGS='-soname,$(LIBSO),--version-script=$(LIBMAP)' -j"$(nproc)" install -# shellcheck disable=SC2016 -make -C libselinux V=1 LD_SONAME_FLAGS='-soname,$(LIBSO),--version-script=libselinux.map' -j"$(nproc)" install ## secilc fuzzer ## @@ -87,25 +84,3 @@ $CXX $CXXFLAGS $LIB_FUZZING_ENGINE checkpolicy-fuzzer.o checkpolicy/*.o "$DESTDI zip -j "$OUT/checkpolicy-fuzzer_seed_corpus.zip" checkpolicy/fuzz/min_pol.mls.conf cp checkpolicy/fuzz/checkpolicy-fuzzer.dict "$OUT/" - -## selabel-file text fcontext based fuzzer ## - -# CFLAGS, CXXFLAGS and LIB_FUZZING_ENGINE have to be split to be accepted by -# the compiler/linker so they shouldn't be quoted -# shellcheck disable=SC2086 -$CC $CFLAGS -DUSE_PCRE2 -DPCRE2_CODE_UNIT_WIDTH=8 -c -o selabel_file_text-fuzzer.o libselinux/fuzz/selabel_file_text-fuzzer.c -# shellcheck disable=SC2086 -$CXX $CXXFLAGS $LIB_FUZZING_ENGINE selabel_file_text-fuzzer.o "$DESTDIR/usr/lib/libselinux.a" -lpcre2-8 -o "$OUT/selabel_file_text-fuzzer" - -zip -j "$OUT/selabel_file_text-fuzzer_seed_corpus.zip" libselinux/fuzz/input - -## selabel-file compiled fcontext based fuzzer ## - -# CFLAGS, CXXFLAGS and LIB_FUZZING_ENGINE have to be split to be accepted by -# the compiler/linker so they shouldn't be quoted -# shellcheck disable=SC2086 -$CC $CFLAGS -DUSE_PCRE2 -DPCRE2_CODE_UNIT_WIDTH=8 -c -o selabel_file_compiled-fuzzer.o libselinux/fuzz/selabel_file_compiled-fuzzer.c -# shellcheck disable=SC2086 -$CXX $CXXFLAGS $LIB_FUZZING_ENGINE selabel_file_compiled-fuzzer.o "$DESTDIR/usr/lib/libselinux.a" -lpcre2-8 -o "$OUT/selabel_file_compiled-fuzzer" - -zip -j "$OUT/selabel_file_compiled-fuzzer_seed_corpus.zip" libselinux/fuzz/input -- 2.47.1