summaryrefslogtreecommitdiff
path: root/src/fuzz
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2020-06-23 18:26:01 +0200
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2020-06-23 20:53:19 +0200
commitdb3b8d5d412bf905a77920f447d104dce09e00fb (patch)
tree6b393265f265fe5fccc55f87a13c466f52f40f1e /src/fuzz
parentc238a1f5f14fd2480b61823301bfe12b2896ce27 (diff)
downloadsystemd-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/fuzz')
-rw-r--r--src/fuzz/fuzz-udev-rules.c91
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;
}