]>
Commit | Line | Data |
---|---|---|
28b76fc8 JK |
1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
2 | ||
cd09a5f3 | 3 | #include "bpf-socket-bind.h" |
28b76fc8 JK |
4 | #include "load-fragment.h" |
5 | #include "manager.h" | |
6 | #include "process-util.h" | |
7 | #include "rlimit-util.h" | |
8 | #include "rm-rf.h" | |
9 | #include "service.h" | |
28b76fc8 JK |
10 | #include "strv.h" |
11 | #include "tests.h" | |
12 | #include "unit.h" | |
13 | #include "virt.h" | |
14 | ||
15 | static int find_netcat_executable(char **ret_path) { | |
de010b0b | 16 | char **candidates = STRV_MAKE("ncat", "nc", "netcat"); |
28b76fc8 JK |
17 | int r = 0; |
18 | ||
19 | STRV_FOREACH(c, candidates) { | |
20 | r = find_executable(*c, ret_path); | |
21 | if (r == 0) | |
22 | break; | |
23 | } | |
24 | ||
25 | return r; | |
26 | } | |
27 | ||
28 | static int test_socket_bind( | |
29 | Manager *m, | |
30 | const char *unit_name, | |
31 | const char *netcat_path, | |
32 | const char *port, | |
33 | char **allow_rules, | |
34 | char **deny_rules) { | |
35 | _cleanup_free_ char *exec_start = NULL; | |
36 | _cleanup_(unit_freep) Unit *u = NULL; | |
28b76fc8 | 37 | CGroupContext *cc = NULL; |
28b76fc8 JK |
38 | int cld_code, r; |
39 | ||
40 | assert_se(u = unit_new(m, sizeof(Service))); | |
41 | assert_se(unit_add_name(u, unit_name) == 0); | |
42 | assert_se(cc = unit_get_cgroup_context(u)); | |
43 | ||
44 | STRV_FOREACH(rule, allow_rules) { | |
45 | r = config_parse_cgroup_socket_bind( | |
46 | u->id, "filename", 1, "Service", 1, "SocketBindAllow", 0, | |
47 | *rule, &cc->socket_bind_allow, u); | |
48 | if (r < 0) | |
49 | return log_unit_error_errno(u, r, "Failed to parse SocketBindAllow: %m"); | |
50 | } | |
51 | ||
52 | fprintf(stderr, "SocketBindAllow:"); | |
53 | LIST_FOREACH(socket_bind_items, bi, cc->socket_bind_allow) | |
54 | cgroup_context_dump_socket_bind_item(bi, stderr); | |
55 | fputc('\n', stderr); | |
56 | ||
57 | STRV_FOREACH(rule, deny_rules) { | |
58 | r = config_parse_cgroup_socket_bind( | |
59 | u->id, "filename", 1, "Service", 1, "SocketBindDeny", 0, | |
60 | *rule, &cc->socket_bind_deny, u); | |
61 | if (r < 0) | |
62 | return log_unit_error_errno(u, r, "Failed to parse SocketBindDeny: %m"); | |
63 | } | |
64 | ||
65 | fprintf(stderr, "SocketBindDeny:"); | |
66 | LIST_FOREACH(socket_bind_items, bi, cc->socket_bind_deny) | |
67 | cgroup_context_dump_socket_bind_item(bi, stderr); | |
68 | fputc('\n', stderr); | |
69 | ||
70 | exec_start = strjoin("-timeout --preserve-status -sSIGTERM 1s ", netcat_path, " -l ", port, " -vv"); | |
71 | assert_se(exec_start != NULL); | |
72 | ||
73 | r = config_parse_exec(u->id, "filename", 1, "Service", 1, "ExecStart", | |
74 | SERVICE_EXEC_START, exec_start, SERVICE(u)->exec_command, u); | |
75 | if (r < 0) | |
76 | return log_error_errno(r, "Failed to parse ExecStart"); | |
77 | ||
78 | SERVICE(u)->type = SERVICE_ONESHOT; | |
79 | u->load_state = UNIT_LOADED; | |
80 | ||
81 | r = unit_start(u); | |
82 | if (r < 0) | |
83 | return log_error_errno(r, "Unit start failed %m"); | |
84 | ||
85 | while (!IN_SET(SERVICE(u)->state, SERVICE_DEAD, SERVICE_FAILED)) { | |
86 | r = sd_event_run(m->event, UINT64_MAX); | |
87 | if (r < 0) | |
88 | return log_error_errno(errno, "Event run failed %m"); | |
89 | } | |
90 | ||
91 | cld_code = SERVICE(u)->exec_command[SERVICE_EXEC_START]->exec_status.code; | |
92 | if (cld_code != CLD_EXITED) | |
93 | return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "ExecStart didn't exited, code='%s'", sigchld_code_to_string(cld_code)); | |
94 | ||
95 | if (SERVICE(u)->state != SERVICE_DEAD) | |
96 | return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Service is not dead"); | |
97 | ||
98 | return 0; | |
99 | } | |
100 | ||
101 | int main(int argc, char *argv[]) { | |
102 | _cleanup_free_ char *unit_dir = NULL, *netcat_path = NULL; | |
103 | _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; | |
104 | _cleanup_(manager_freep) Manager *m = NULL; | |
105 | struct rlimit rl; | |
106 | int r; | |
107 | ||
108 | test_setup_logging(LOG_DEBUG); | |
109 | ||
110 | if (detect_container() > 0) | |
111 | return log_tests_skipped("test-bpf fails inside LXC and Docker containers: https://github.com/systemd/systemd/issues/9666"); | |
112 | ||
113 | if (getuid() != 0) | |
114 | return log_tests_skipped("not running as root"); | |
115 | ||
116 | assert_se(getrlimit(RLIMIT_MEMLOCK, &rl) >= 0); | |
117 | rl.rlim_cur = rl.rlim_max = MAX(rl.rlim_max, CAN_MEMLOCK_SIZE); | |
118 | (void) setrlimit_closest(RLIMIT_MEMLOCK, &rl); | |
119 | ||
120 | if (!can_memlock()) | |
4a55ce8f | 121 | return log_tests_skipped("Can't use mlock()"); |
28b76fc8 | 122 | |
cd09a5f3 | 123 | r = bpf_socket_bind_supported(); |
28b76fc8 | 124 | if (r <= 0) |
4a55ce8f | 125 | return log_tests_skipped("socket-bind is not supported"); |
28b76fc8 JK |
126 | |
127 | if (find_netcat_executable(&netcat_path) != 0) | |
4a55ce8f | 128 | return log_tests_skipped("Can not find netcat executable"); |
28b76fc8 JK |
129 | |
130 | r = enter_cgroup_subroot(NULL); | |
131 | if (r == -ENOMEDIUM) | |
132 | return log_tests_skipped("cgroupfs not available"); | |
133 | ||
134 | assert_se(get_testdata_dir("units", &unit_dir) >= 0); | |
135 | assert_se(set_unit_path(unit_dir) >= 0); | |
136 | assert_se(runtime_dir = setup_fake_runtime_dir()); | |
137 | ||
138 | assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0); | |
2a7cf953 | 139 | assert_se(manager_startup(m, NULL, NULL, NULL) >= 0); |
28b76fc8 JK |
140 | |
141 | assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "2000", STRV_MAKE("2000"), STRV_MAKE("any")) >= 0); | |
f80a206a LP |
142 | assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "2000", STRV_MAKE("ipv6:2001-2002"), STRV_MAKE("any")) >= 0); |
143 | assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "6666", STRV_MAKE("ipv4:6666", "6667"), STRV_MAKE("any")) >= 0); | |
28b76fc8 JK |
144 | assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "6666", STRV_MAKE("6667", "6668", ""), STRV_MAKE("any")) >= 0); |
145 | assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "7777", STRV_MAKE_EMPTY, STRV_MAKE_EMPTY) >= 0); | |
146 | assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "8888", STRV_MAKE("any"), STRV_MAKE("any")) >= 0); | |
5587ce7f JK |
147 | assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "8888", STRV_MAKE("ipv6:tcp:8888-8889"), STRV_MAKE("any")) >= 0); |
148 | assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "10000", STRV_MAKE("ipv6:udp:9999-10000"), STRV_MAKE("any")) >= 0); | |
149 | assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "6666", STRV_MAKE("ipv4:tcp:6666"), STRV_MAKE("any")) >= 0); | |
150 | assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "6666", STRV_MAKE("ipv4:udp:6666"), STRV_MAKE("any")) >= 0); | |
151 | assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "6666", STRV_MAKE("tcp:6666"), STRV_MAKE("any")) >= 0); | |
28b76fc8 JK |
152 | |
153 | return 0; | |
154 | } |