Merge pull request #8423 from keszybz/unit-file-fuzzer

Unit file fuzzer
This commit is contained in:
Evgeny Vereshchagin
2018-03-12 23:08:32 +03:00
committed by GitHub
36 changed files with 1418 additions and 109 deletions
+2 -1
View File
@@ -254,7 +254,8 @@ int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run
Unit *units[strv_length(filenames)];
int i, count = 0;
const uint8_t flags = MANAGER_TEST_RUN_ENV_GENERATORS |
const uint8_t flags = MANAGER_TEST_RUN_BASIC |
MANAGER_TEST_RUN_ENV_GENERATORS |
run_generators * MANAGER_TEST_RUN_GENERATORS;
if (strv_isempty(filenames))
+48 -49
View File
@@ -667,7 +667,7 @@ static int manager_setup_sigchld_event_source(Manager *m) {
}
int manager_new(UnitFileScope scope, unsigned test_run_flags, Manager **_m) {
Manager *m;
_cleanup_(manager_freep) Manager *m = NULL;
int r;
assert(_m);
@@ -729,62 +729,66 @@ int manager_new(UnitFileScope scope, unsigned test_run_flags, Manager **_m) {
r = manager_default_environment(m);
if (r < 0)
goto fail;
return r;
r = hashmap_ensure_allocated(&m->units, &string_hash_ops);
if (r < 0)
goto fail;
return r;
r = hashmap_ensure_allocated(&m->jobs, NULL);
if (r < 0)
goto fail;
return r;
r = hashmap_ensure_allocated(&m->cgroup_unit, &path_hash_ops);
if (r < 0)
goto fail;
return r;
r = hashmap_ensure_allocated(&m->watch_bus, &string_hash_ops);
if (r < 0)
goto fail;
r = sd_event_default(&m->event);
if (r < 0)
goto fail;
r = manager_setup_run_queue(m);
if (r < 0)
goto fail;
r = manager_setup_signals(m);
if (r < 0)
goto fail;
r = manager_setup_cgroup(m);
if (r < 0)
goto fail;
r = manager_setup_time_change(m);
if (r < 0)
goto fail;
r = manager_setup_sigchld_event_source(m);
if (r < 0)
goto fail;
m->udev = udev_new();
if (!m->udev) {
r = -ENOMEM;
goto fail;
}
return r;
r = manager_setup_prefix(m);
if (r < 0)
goto fail;
return r;
m->udev = udev_new();
if (!m->udev)
return -ENOMEM;
r = sd_event_default(&m->event);
if (r < 0)
return r;
r = manager_setup_run_queue(m);
if (r < 0)
return r;
if (test_run_flags == MANAGER_TEST_RUN_MINIMAL) {
m->cgroup_root = strdup("");
if (!m->cgroup_root)
return -ENOMEM;
} else {
r = manager_setup_signals(m);
if (r < 0)
return r;
r = manager_setup_cgroup(m);
if (r < 0)
return r;
r = manager_setup_time_change(m);
if (r < 0)
return r;
r = manager_setup_sigchld_event_source(m);
if (r < 0)
return r;
}
if (MANAGER_IS_SYSTEM(m) && test_run_flags == 0) {
r = mkdir_label("/run/systemd/units", 0755);
if (r < 0 && r != -EEXIST)
goto fail;
return r;
}
m->taint_usr =
@@ -795,11 +799,8 @@ int manager_new(UnitFileScope scope, unsigned test_run_flags, Manager **_m) {
* since they might have gotten serialized across the reexec. */
*_m = m;
m = NULL;
return 0;
fail:
manager_free(m);
return r;
}
static int manager_setup_notify(Manager *m) {
@@ -1701,6 +1702,7 @@ int manager_load_unit_prepare(
sd_bus_error *e,
Unit **_ret) {
_cleanup_(unit_freep) Unit *cleanup_ret = NULL;
Unit *ret;
UnitType t;
int r;
@@ -1733,29 +1735,26 @@ int manager_load_unit_prepare(
return 1;
}
ret = unit_new(m, unit_vtable[t]->object_size);
ret = cleanup_ret = unit_new(m, unit_vtable[t]->object_size);
if (!ret)
return -ENOMEM;
if (path) {
ret->fragment_path = strdup(path);
if (!ret->fragment_path) {
unit_free(ret);
if (!ret->fragment_path)
return -ENOMEM;
}
}
r = unit_add_name(ret, name);
if (r < 0) {
unit_free(ret);
if (r < 0)
return r;
}
unit_add_to_load_queue(ret);
unit_add_to_dbus_queue(ret);
unit_add_to_gc_queue(ret);
*_ret = ret;
cleanup_ret = NULL;
return 0;
}
+6 -4
View File
@@ -96,10 +96,11 @@ typedef enum ManagerTimestamp {
enum {
/* 0 = run normally */
MANAGER_TEST_RUN_MINIMAL = 1, /* run test w/o generators */
MANAGER_TEST_RUN_ENV_GENERATORS = 2, /* also run env generators */
MANAGER_TEST_RUN_GENERATORS = 4, /* also run unit generators */
MANAGER_TEST_FULL = MANAGER_TEST_RUN_ENV_GENERATORS | MANAGER_TEST_RUN_GENERATORS,
MANAGER_TEST_RUN_MINIMAL = 1 << 1, /* create basic data structures */
MANAGER_TEST_RUN_BASIC = 1 << 2, /* interact with the environment */
MANAGER_TEST_RUN_ENV_GENERATORS = 1 << 3, /* also run env generators */
MANAGER_TEST_RUN_GENERATORS = 1 << 4, /* also run unit generators */
MANAGER_TEST_FULL = MANAGER_TEST_RUN_BASIC | MANAGER_TEST_RUN_ENV_GENERATORS | MANAGER_TEST_RUN_GENERATORS,
};
assert_cc((MANAGER_TEST_FULL & UINT8_MAX) == MANAGER_TEST_FULL);
@@ -379,6 +380,7 @@ struct Manager {
int manager_new(UnitFileScope scope, unsigned test_run_flags, Manager **m);
Manager* manager_free(Manager *m);
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
void manager_enumerate(Manager *m);
int manager_startup(Manager *m, FILE *serialization, FDSet *fds);
+3 -4
View File
@@ -128,7 +128,7 @@ Unit *unit_new(Manager *m, size_t size) {
}
int unit_new_for_name(Manager *m, size_t size, const char *name, Unit **ret) {
Unit *u;
_cleanup_(unit_freep) Unit *u = NULL;
int r;
u = unit_new(m, size);
@@ -136,12 +136,11 @@ int unit_new_for_name(Manager *m, size_t size, const char *name, Unit **ret) {
return -ENOMEM;
r = unit_add_name(u, name);
if (r < 0) {
unit_free(u);
if (r < 0)
return r;
}
*ret = u;
u = NULL;
return r;
}
+1
View File
@@ -610,6 +610,7 @@ DEFINE_CAST(SCOPE, Scope);
Unit *unit_new(Manager *m, size_t size);
void unit_free(Unit *u);
DEFINE_TRIVIAL_CLEANUP_FUNC(Unit *, unit_free);
int unit_new_for_name(Manager *m, size_t size, const char *name, Unit **ret);
int unit_add_name(Unit *u, const char *name);
+4
View File
@@ -33,6 +33,9 @@ int main(int argc, char **argv) {
char *name;
log_set_max_level(LOG_DEBUG);
log_parse_environment();
log_open();
for (i = 1; i < argc; i++) {
_cleanup_free_ char *buf = NULL;
@@ -47,5 +50,6 @@ int main(int argc, char **argv) {
(void) LLVMFuzzerTestOneInput((uint8_t*)buf, size);
printf("ok\n");
}
return EXIT_SUCCESS;
}
+59
View File
@@ -0,0 +1,59 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "conf-parser.h"
#include "fd-util.h"
#include "fileio.h"
#include "fuzz.h"
#include "install.h"
#include "load-fragment.h"
#include "string-util.h"
#include "unit.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
_cleanup_free_ char *out = NULL; /* out should be freed after g */
size_t out_size;
_cleanup_fclose_ FILE *f = NULL, *g = NULL;
_cleanup_free_ char *p = NULL;
UnitType t;
_cleanup_(manager_freep) Manager *m = NULL;
Unit *u;
const char *name;
if (size == 0)
return 0;
f = fmemopen((char*) data, size, "re");
assert_se(f);
if (read_line(f, LINE_MAX, &p) < 0)
return 0;
t = unit_type_from_string(p);
if (t < 0)
return 0;
if (!unit_vtable[t]->load)
return 0;
/* We don't want to fill the logs with messages about parse errors.
* Disable most logging if not running standalone */
if (!getenv("SYSTEMD_LOG_LEVEL"))
log_set_max_level(LOG_CRIT);
assert_se(manager_new(UNIT_FILE_SYSTEM, MANAGER_TEST_RUN_MINIMAL, &m) >= 0);
name = strjoina("a.", unit_type_to_string(t));
assert_se(unit_new_for_name(m, unit_vtable[t]->object_size, name, &u) >= 0);
(void) config_parse(name, name, f,
UNIT_VTABLE(u)->sections,
config_item_perf_lookup, load_fragment_gperf_lookup,
CONFIG_PARSE_ALLOW_INCLUDE, u);
g = open_memstream(&out, &out_size);
assert_se(g);
unit_dump(u, g, "");
return 0;
}
+8 -3
View File
@@ -22,9 +22,14 @@ fuzzers += [
[libgcrypt,
libgpg_error,
libm]],
[['src/fuzz/fuzz-dhcp-server.c',
],
[['src/fuzz/fuzz-dhcp-server.c'],
[libsystemd_network,
libshared],
[]]
[]],
[['src/fuzz/fuzz-unit-file.c'],
[libcore,
libshared],
[libmount]],
]
+2
View File
@@ -108,6 +108,7 @@ static int bus_error_name_to_errno(const char *name) {
}
m = __start_BUS_ERROR_MAP;
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
while (m < __stop_BUS_ERROR_MAP) {
/* For magic ELF error maps, the end marker might
* appear in the middle of things, since multiple maps
@@ -125,6 +126,7 @@ static int bus_error_name_to_errno(const char *name) {
m++;
}
#endif
return EIO;
}
+1 -2
View File
@@ -85,8 +85,7 @@ _public_ void udev_set_userdata(struct udev *udev, void *userdata) {
/**
* udev_new:
*
* Create udev library context. This reads the udev configuration
* file, and fills in the default values.
* Create udev library context. This only allocates the basic data structure.
*
* The initial refcount is 1, and needs to be decremented to
* release the resources of the udev library context.
+2 -6
View File
@@ -41,7 +41,7 @@ int main(int argc, char *argv[]) {
_cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
CGroupContext *cc = NULL;
_cleanup_(bpf_program_unrefp) BPFProgram *p = NULL;
Manager *m = NULL;
_cleanup_(manager_freep) Manager *m = NULL;
Unit *u;
char log_buf[65535];
int r;
@@ -128,11 +128,9 @@ int main(int argc, char *argv[]) {
unit_dump(u, stdout, NULL);
r = bpf_firewall_compile(u);
if (IN_SET(r, -ENOTTY, -ENOSYS, -EPERM )) {
if (IN_SET(r, -ENOTTY, -ENOSYS, -EPERM ))
/* Kernel doesn't support the necessary bpf bits, or masked out via seccomp? */
manager_free(m);
return EXIT_TEST_SKIP;
}
assert_se(r >= 0);
assert(u->ip_bpf_ingress);
@@ -167,7 +165,5 @@ int main(int argc, char *argv[]) {
assert_se(SERVICE(u)->exec_command[SERVICE_EXEC_START]->command_next->exec_status.code != CLD_EXITED ||
SERVICE(u)->exec_command[SERVICE_EXEC_START]->command_next->exec_status.status != EXIT_SUCCESS);
manager_free(m);
return 0;
}
+2 -4
View File
@@ -30,7 +30,7 @@
static int test_cgroup_mask(void) {
_cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
Manager *m = NULL;
_cleanup_(manager_freep) Manager *m = NULL;
Unit *son, *daughter, *parent, *root, *grandchild, *parent_deep;
FILE *serial = NULL;
FDSet *fdset = NULL;
@@ -45,7 +45,7 @@ static int test_cgroup_mask(void) {
/* Prepare the manager. */
assert_se(set_unit_path(get_testdata_dir("")) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m);
if (IN_SET(r, -EPERM, -EACCES)) {
puts("manager_new: Permission denied. Skipping test.");
return EXIT_TEST_SKIP;
@@ -114,8 +114,6 @@ static int test_cgroup_mask(void) {
assert_se(unit_get_target_mask(parent) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported));
assert_se(unit_get_target_mask(root) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported));
manager_free(m);
return 0;
}
+2 -4
View File
@@ -31,7 +31,7 @@
int main(int argc, char *argv[]) {
_cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
Manager *m = NULL;
_cleanup_(manager_freep) Manager *m = NULL;
Unit *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *g = NULL, *h = NULL;
FILE *serial = NULL;
FDSet *fdset = NULL;
@@ -47,7 +47,7 @@ int main(int argc, char *argv[]) {
/* prepare the test */
assert_se(set_unit_path(get_testdata_dir("")) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m);
if (MANAGER_SKIP_TEST(r)) {
log_notice_errno(r, "Skipping test: manager_new: %m");
return EXIT_TEST_SKIP;
@@ -143,7 +143,5 @@ int main(int argc, char *argv[]) {
assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], c));
assert_se(!hashmap_get(c->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a));
manager_free(m);
return 0;
}
+2 -4
View File
@@ -623,12 +623,12 @@ static void test_exec_standardinput(Manager *m) {
static int run_tests(UnitFileScope scope, const test_function_t *tests) {
const test_function_t *test = NULL;
Manager *m = NULL;
_cleanup_(manager_freep) Manager *m = NULL;
int r;
assert_se(tests);
r = manager_new(scope, MANAGER_TEST_RUN_MINIMAL, &m);
r = manager_new(scope, MANAGER_TEST_RUN_BASIC, &m);
if (MANAGER_SKIP_TEST(r)) {
log_notice_errno(r, "Skipping test: manager_new: %m");
return EXIT_TEST_SKIP;
@@ -639,8 +639,6 @@ static int run_tests(UnitFileScope scope, const test_function_t *tests) {
for (test = tests; test && *test; test++)
(*test)(m);
manager_free(m);
return 0;
}
+1 -1
View File
@@ -52,7 +52,7 @@ static int setup_test(Manager **m) {
return -EXIT_TEST_SKIP;
}
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &tmp);
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &tmp);
if (MANAGER_SKIP_TEST(r)) {
log_notice_errno(r, "Skipping test: manager_new: %m");
return -EXIT_TEST_SKIP;
+2 -4
View File
@@ -28,7 +28,7 @@
int main(int argc, char *argv[]) {
_cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
Manager *m = NULL;
_cleanup_(manager_freep) Manager *m = NULL;
Unit *idle_ok, *idle_bad, *rr_ok, *rr_bad, *rr_sched;
Service *ser;
FILE *serial = NULL;
@@ -44,7 +44,7 @@ int main(int argc, char *argv[]) {
/* prepare the test */
assert_se(set_unit_path(get_testdata_dir("")) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m);
if (MANAGER_SKIP_TEST(r)) {
log_notice_errno(r, "Skipping test: manager_new: %m");
return EXIT_TEST_SKIP;
@@ -98,7 +98,5 @@ int main(int argc, char *argv[]) {
assert_se(ser->exec_context.cpu_sched_policy == SCHED_RR);
assert_se(ser->exec_context.cpu_sched_priority == 99);
manager_free(m);
return EXIT_SUCCESS;
}
+4 -10
View File
@@ -113,8 +113,8 @@ static void test_config_parse_exec(void) {
ExecCommand *c = NULL, *c1;
const char *ccc;
Manager *m = NULL;
Unit *u = NULL;
_cleanup_(manager_freep) Manager *m = NULL;
_cleanup_(unit_freep) Unit *u = NULL;
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
if (MANAGER_SKIP_TEST(r)) {
@@ -441,9 +441,6 @@ static void test_config_parse_exec(void) {
assert_se(c == NULL);
exec_command_free_list(c);
unit_free(u);
manager_free(m);
}
static void test_config_parse_log_extra_fields(void) {
@@ -461,8 +458,8 @@ static void test_config_parse_log_extra_fields(void) {
int r;
Manager *m = NULL;
Unit *u = NULL;
_cleanup_(manager_freep) Manager *m = NULL;
_cleanup_(unit_freep) Unit *u = NULL;
ExecContext c = {};
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
@@ -507,9 +504,6 @@ static void test_config_parse_log_extra_fields(void) {
exec_context_free_log_extra_fields(&c);
unit_free(u);
manager_free(m);
log_info("/* %s – bye */", __func__);
}
+2 -5
View File
@@ -199,12 +199,11 @@ static void test_unit_name_mangle(void) {
}
static int test_unit_printf(void) {
Manager *m = NULL;
_cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *uid = NULL, *user = NULL, *shell = NULL, *home = NULL;
_cleanup_(manager_freep) Manager *m = NULL;
Unit *u, *u2;
int r;
_cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *uid = NULL, *user = NULL, *shell = NULL, *home = NULL;
assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid);
assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid);
assert_se(host = gethostname_malloc());
@@ -276,8 +275,6 @@ static int test_unit_printf(void) {
expect(u2, "%b", bid);
expect(u2, "%H", host);
expect(u2, "%t", "/run/user/*");
manager_free(m);
#undef expect
return 0;
+1 -3
View File
@@ -8,8 +8,8 @@
int main(int argc, char *argv[]) {
_cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
_cleanup_(manager_freep) Manager *m = NULL;
Unit *a, *b, *c, *u;
Manager *m;
int r;
log_set_max_level(LOG_DEBUG);
@@ -90,7 +90,5 @@ int main(int argc, char *argv[]) {
unit_unwatch_pid(c, 4711);
assert_se(manager_get_unit_by_pid(m, 4711) == NULL);
manager_free(m);
return 0;
}