Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <errno.h>
4 : : #include <sched.h>
5 : : #include <sys/mount.h>
6 : : #include <unistd.h>
7 : :
8 : : #include "fd-util.h"
9 : : #include "fs-util.h"
10 : : #include "fuzz.h"
11 : : #include "log.h"
12 : : #include "mkdir.h"
13 : : #include "missing.h"
14 : : #include "rm-rf.h"
15 : : #include "string-util.h"
16 : : #include "tests.h"
17 : : #include "udev-rules.h"
18 : :
19 : : static struct fakefs {
20 : : const char *target;
21 : : bool ignore_mount_error;
22 : : bool is_mounted;
23 : : } fakefss[] = {
24 : : { "/sys", false, false },
25 : : { "/dev", false, false },
26 : : { "/run", false, false },
27 : : { "/etc", false, false },
28 : : { UDEVLIBEXECDIR "/rules.d", true, false },
29 : : };
30 : :
31 : 0 : static int setup_mount_namespace(void) {
32 : : static thread_local bool is_namespaced = false;
33 : :
34 [ # # ]: 0 : if (is_namespaced)
35 : 0 : return 1;
36 : :
37 [ # # ]: 0 : if (unshare(CLONE_NEWNS) < 0)
38 [ # # ]: 0 : return log_error_errno(errno, "Failed to call unshare(): %m");
39 : :
40 [ # # ]: 0 : if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
41 [ # # ]: 0 : return log_error_errno(errno, "Failed to mount / as private: %m");
42 : :
43 : 0 : is_namespaced = true;
44 : :
45 : 0 : return 1;
46 : : }
47 : :
48 : 0 : static int setup_fake_filesystems(const char *runtime_dir) {
49 [ # # ]: 0 : for (unsigned i = 0; i < ELEMENTSOF(fakefss); i++) {
50 [ # # ]: 0 : if (mount(runtime_dir, fakefss[i].target, NULL, MS_BIND, NULL) < 0) {
51 [ # # # # ]: 0 : log_full_errno(fakefss[i].ignore_mount_error ? LOG_DEBUG : LOG_ERR, errno, "Failed to mount %s: %m", fakefss[i].target);
52 [ # # ]: 0 : if (!fakefss[i].ignore_mount_error)
53 : 0 : return -errno;
54 : : } else
55 : 0 : fakefss[i].is_mounted = true;
56 : : }
57 : :
58 : 0 : return 0;
59 : : }
60 : :
61 : 0 : static int cleanup_fake_filesystems(const char *runtime_dir) {
62 [ # # ]: 0 : for (unsigned i = 0; i < ELEMENTSOF(fakefss); i++) {
63 [ # # ]: 0 : if (!fakefss[i].is_mounted)
64 : 0 : continue;
65 : :
66 [ # # ]: 0 : if (umount(fakefss[i].target) < 0) {
67 [ # # # # ]: 0 : log_full_errno(fakefss[i].ignore_mount_error ? LOG_DEBUG : LOG_ERR, errno, "Failed to umount %s: %m", fakefss[i].target);
68 [ # # ]: 0 : if (!fakefss[i].ignore_mount_error)
69 : 0 : return -errno;
70 : : } else
71 : 0 : fakefss[i].is_mounted = false;
72 : : }
73 : 0 : return 0;
74 : : }
75 : :
76 : 0 : int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
77 : 0 : _cleanup_(udev_rules_freep) UdevRules *rules = NULL;
78 : 0 : _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
79 : 0 : FILE *f = NULL;
80 : :
81 : 0 : (void) setup_mount_namespace();
82 : :
83 [ # # ]: 0 : assert_se(runtime_dir = setup_fake_runtime_dir());
84 : :
85 [ # # ]: 0 : if (setup_fake_filesystems(runtime_dir) < 0) {
86 : : #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
87 : 0 : return EXIT_TEST_SKIP;
88 : : #endif
89 : : }
90 : :
91 [ # # ]: 0 : if (!getenv("SYSTEMD_LOG_LEVEL")) {
92 : 0 : log_set_max_level_realm(LOG_REALM_UDEV, LOG_CRIT);
93 : 0 : log_set_max_level_realm(LOG_REALM_SYSTEMD, LOG_CRIT);
94 : : }
95 : :
96 [ # # ]: 0 : assert_se(mkdir_p("/etc/udev/rules.d", 0755) >= 0);
97 : 0 : f = fopen("/etc/udev/rules.d/fuzz.rules", "we");
98 [ # # ]: 0 : assert_se(f);
99 [ # # ]: 0 : if (size != 0)
100 [ # # ]: 0 : assert_se(fwrite(data, size, 1, f) == 1);
101 [ # # ]: 0 : assert_se(fclose(f) == 0);
102 : :
103 [ # # ]: 0 : assert_se(udev_rules_new(&rules, RESOLVE_NAME_EARLY) == 0);
104 : :
105 [ # # ]: 0 : assert_se(cleanup_fake_filesystems(runtime_dir) >= 0);
106 : 0 : return 0;
107 : : }
|