]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/fuzz/fuzz-udev-rules.c
udev: modernize udev-rules.c
[thirdparty/systemd.git] / src / fuzz / fuzz-udev-rules.c
CommitLineData
2e646cbe
EV
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"
25de7aa7 17#include "udev-rules.h"
2e646cbe 18
fa6e5861 19static struct fakefs {
2e646cbe
EV
20 const char *target;
21 bool ignore_mount_error;
fa6e5861 22 bool is_mounted;
2e646cbe 23} fakefss[] = {
fa6e5861
EV
24 { "/sys", false, false },
25 { "/dev", false, false },
26 { "/run", false, false },
27 { "/etc", false, false },
28 { UDEVLIBEXECDIR "/rules.d", true, false },
2e646cbe
EV
29};
30
31static int setup_mount_namespace(void) {
32 static thread_local bool is_namespaced = false;
33
34 if (is_namespaced)
35 return 1;
36
37 if (unshare(CLONE_NEWNS) < 0)
38 return log_error_errno(errno, "Failed to call unshare(): %m");
39
40 if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
41 return log_error_errno(errno, "Failed to mount / as private: %m");
42
43 is_namespaced = true;
44
45 return 1;
46}
47
48static int setup_fake_filesystems(const char *runtime_dir) {
fa6e5861 49 for (unsigned i = 0; i < ELEMENTSOF(fakefss); i++) {
2e646cbe
EV
50 if (mount(runtime_dir, fakefss[i].target, NULL, MS_BIND, NULL) < 0) {
51 log_full_errno(fakefss[i].ignore_mount_error ? LOG_DEBUG : LOG_ERR, errno, "Failed to mount %s: %m", fakefss[i].target);
52 if (!fakefss[i].ignore_mount_error)
53 return -errno;
fa6e5861
EV
54 } else
55 fakefss[i].is_mounted = true;
56 }
2e646cbe
EV
57
58 return 0;
59}
60
61static int cleanup_fake_filesystems(const char *runtime_dir) {
fa6e5861
EV
62 for (unsigned i = 0; i < ELEMENTSOF(fakefss); i++) {
63 if (!fakefss[i].is_mounted)
64 continue;
65
2e646cbe
EV
66 if (umount(fakefss[i].target) < 0) {
67 log_full_errno(fakefss[i].ignore_mount_error ? LOG_DEBUG : LOG_ERR, errno, "Failed to umount %s: %m", fakefss[i].target);
68 if (!fakefss[i].ignore_mount_error)
69 return -errno;
fa6e5861
EV
70 } else
71 fakefss[i].is_mounted = false;
72 }
2e646cbe
EV
73 return 0;
74}
75
76int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
9a07157d 77 _cleanup_(udev_rules_freep) UdevRules *rules = NULL;
2e646cbe
EV
78 _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
79 FILE *f = NULL;
80
8e96f161
EV
81 (void) setup_mount_namespace();
82
83 assert_se(runtime_dir = setup_fake_runtime_dir());
84
85 if (setup_fake_filesystems(runtime_dir) < 0) {
86#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
87 return EXIT_TEST_SKIP;
8e96f161
EV
88#endif
89 }
90
2e646cbe
EV
91 if (!getenv("SYSTEMD_LOG_LEVEL")) {
92 log_set_max_level_realm(LOG_REALM_UDEV, LOG_CRIT);
93 log_set_max_level_realm(LOG_REALM_SYSTEMD, LOG_CRIT);
94 }
95
2e646cbe
EV
96 assert_se(mkdir_p("/etc/udev/rules.d", 0755) >= 0);
97 f = fopen("/etc/udev/rules.d/fuzz.rules", "we");
98 assert_se(f);
99 if (size != 0)
100 assert_se(fwrite(data, size, 1, f) == 1);
101 assert_se(fclose(f) == 0);
2e646cbe 102
1d791281 103 assert_se(udev_rules_new(&rules, RESOLVE_NAME_EARLY) == 0);
2e646cbe 104
1d791281 105 assert_se(cleanup_fake_filesystems(runtime_dir) >= 0);
2e646cbe
EV
106 return 0;
107}