diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2020-06-23 18:26:01 +0200 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2020-06-23 20:53:19 +0200 |
commit | db3b8d5d412bf905a77920f447d104dce09e00fb (patch) | |
tree | 6b393265f265fe5fccc55f87a13c466f52f40f1e /src | |
parent | c238a1f5f14fd2480b61823301bfe12b2896ce27 (diff) | |
download | systemd-db3b8d5d412bf905a77920f447d104dce09e00fb.tar.gz |
fuzz-udev-rules: rewrite to not require root privileges
Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=20142.
It turns out we don't need to do all this preparatory work if we want to parse
just one file.
Diffstat (limited to 'src')
-rw-r--r-- | src/fuzz/fuzz-udev-rules.c | 91 |
1 files changed, 8 insertions, 83 deletions
diff --git a/src/fuzz/fuzz-udev-rules.c b/src/fuzz/fuzz-udev-rules.c index a4a1adec3e..dd3c403ebb 100644 --- a/src/fuzz/fuzz-udev-rules.c +++ b/src/fuzz/fuzz-udev-rules.c @@ -1,106 +1,31 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -#include <errno.h> -#include <sched.h> -#include <sys/mount.h> -#include <unistd.h> +#include <stdio.h> #include "fd-util.h" #include "fs-util.h" #include "fuzz.h" -#include "log.h" -#include "mkdir.h" -#include "rm-rf.h" -#include "string-util.h" #include "tests.h" +#include "tmpfile-util.h" #include "udev-rules.h" -static struct fakefs { - const char *target; - bool ignore_mount_error; - bool is_mounted; -} fakefss[] = { - { "/sys", false, false }, - { "/dev", false, false }, - { "/run", false, false }, - { "/etc", false, false }, - { UDEVLIBEXECDIR "/rules.d", true, false }, -}; - -static int setup_mount_namespace(void) { - static thread_local bool is_namespaced = false; - - if (is_namespaced) - return 1; - - if (unshare(CLONE_NEWNS) < 0) - return log_error_errno(errno, "Failed to call unshare(): %m"); - - if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) - return log_error_errno(errno, "Failed to mount / as private: %m"); - - is_namespaced = true; - - return 1; -} - -static int setup_fake_filesystems(const char *runtime_dir) { - for (unsigned i = 0; i < ELEMENTSOF(fakefss); i++) { - if (mount(runtime_dir, fakefss[i].target, NULL, MS_BIND, NULL) < 0) { - log_full_errno(fakefss[i].ignore_mount_error ? LOG_DEBUG : LOG_ERR, errno, "Failed to mount %s: %m", fakefss[i].target); - if (!fakefss[i].ignore_mount_error) - return -errno; - } else - fakefss[i].is_mounted = true; - } - - return 0; -} - -static int cleanup_fake_filesystems(const char *runtime_dir) { - for (unsigned i = 0; i < ELEMENTSOF(fakefss); i++) { - if (!fakefss[i].is_mounted) - continue; - - if (umount(fakefss[i].target) < 0) { - log_full_errno(fakefss[i].ignore_mount_error ? LOG_DEBUG : LOG_ERR, errno, "Failed to umount %s: %m", fakefss[i].target); - if (!fakefss[i].ignore_mount_error) - return -errno; - } else - fakefss[i].is_mounted = false; - } - return 0; -} - int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { _cleanup_(udev_rules_freep) UdevRules *rules = NULL; - _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; - FILE *f = NULL; - - (void) setup_mount_namespace(); - - assert_se(runtime_dir = setup_fake_runtime_dir()); - - if (setup_fake_filesystems(runtime_dir) < 0) { -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return EXIT_TEST_SKIP; -#endif - } + _cleanup_fclose_ FILE *f = NULL; + _cleanup_(unlink_tempfilep) char filename[] = "/tmp/fuzz-udev-rules.XXXXXX"; if (!getenv("SYSTEMD_LOG_LEVEL")) { log_set_max_level_realm(LOG_REALM_UDEV, LOG_CRIT); log_set_max_level_realm(LOG_REALM_SYSTEMD, LOG_CRIT); } - assert_se(mkdir_p("/etc/udev/rules.d", 0755) >= 0); - f = fopen("/etc/udev/rules.d/fuzz.rules", "we"); - assert_se(f); + assert_se(fmkostemp_safe(filename, "r+", &f) == 0); if (size != 0) assert_se(fwrite(data, size, 1, f) == 1); - assert_se(fclose(f) == 0); + fflush(f); - assert_se(udev_rules_load(&rules, RESOLVE_NAME_EARLY) == 0); + assert_se(rules = udev_rules_new(RESOLVE_NAME_EARLY)); + assert_se(udev_rules_parse_file(rules, filename) == 0); - assert_se(cleanup_fake_filesystems(runtime_dir) >= 0); return 0; } |