]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
db3a5930 DM |
2 | /*** |
3 | This file is part of systemd. | |
4 | ||
5 | Copyright 2016 Daniel Mack | |
6 | ||
7 | systemd is free software; you can redistribute it and/or modify it | |
8 | under the terms of the GNU Lesser General Public License as published by | |
9 | the Free Software Foundation; either version 2.1 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | systemd is distributed in the hope that it will be useful, but | |
13 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | Lesser General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU Lesser General Public License | |
18 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | |
19 | ***/ | |
20 | ||
21 | #include <linux/libbpf.h> | |
22 | #include <string.h> | |
23 | #include <unistd.h> | |
24 | ||
25 | #include "bpf-firewall.h" | |
26 | #include "bpf-program.h" | |
27 | #include "load-fragment.h" | |
28 | #include "manager.h" | |
29 | #include "rm-rf.h" | |
30 | #include "service.h" | |
31 | #include "test-helper.h" | |
32 | #include "tests.h" | |
33 | #include "unit.h" | |
34 | ||
35 | int main(int argc, char *argv[]) { | |
36 | struct bpf_insn exit_insn[] = { | |
37 | BPF_MOV64_IMM(BPF_REG_0, 1), | |
38 | BPF_EXIT_INSN() | |
39 | }; | |
40 | ||
41 | _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; | |
42 | CGroupContext *cc = NULL; | |
43 | _cleanup_(bpf_program_unrefp) BPFProgram *p = NULL; | |
44 | Manager *m = NULL; | |
45 | Unit *u; | |
46 | char log_buf[65535]; | |
47 | int r; | |
48 | ||
49 | log_set_max_level(LOG_DEBUG); | |
50 | log_parse_environment(); | |
51 | log_open(); | |
52 | ||
651d47d1 ZJS |
53 | r = enter_cgroup_subroot(); |
54 | if (r == -ENOMEDIUM) { | |
55 | log_notice("cgroupfs not available, skipping tests"); | |
56 | return EXIT_TEST_SKIP; | |
57 | } | |
58 | ||
db3a5930 DM |
59 | assert_se(set_unit_path(get_testdata_dir("")) >= 0); |
60 | assert_se(runtime_dir = setup_fake_runtime_dir()); | |
61 | ||
62 | r = bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB, &p); | |
63 | assert(r == 0); | |
64 | ||
65 | r = bpf_program_add_instructions(p, exit_insn, ELEMENTSOF(exit_insn)); | |
66 | assert(r == 0); | |
67 | ||
68 | if (getuid() != 0) { | |
69 | log_notice("Not running as root, skipping kernel related tests."); | |
70 | return EXIT_TEST_SKIP; | |
71 | } | |
72 | ||
73 | r = bpf_firewall_supported(); | |
74 | if (r == 0) { | |
75 | log_notice("BPF firewalling not supported, skipping"); | |
76 | return EXIT_TEST_SKIP; | |
77 | } | |
78 | assert_se(r > 0); | |
79 | ||
80 | r = bpf_program_load_kernel(p, log_buf, ELEMENTSOF(log_buf)); | |
81 | assert(r >= 0); | |
82 | ||
83 | p = bpf_program_unref(p); | |
84 | ||
85 | /* The simple tests suceeded. Now let's try full unit-based use-case. */ | |
86 | ||
87 | assert_se(manager_new(UNIT_FILE_USER, true, &m) >= 0); | |
88 | assert_se(manager_startup(m, NULL, NULL) >= 0); | |
89 | ||
90 | assert_se(u = unit_new(m, sizeof(Service))); | |
91 | assert_se(unit_add_name(u, "foo.service") == 0); | |
92 | assert_se(cc = unit_get_cgroup_context(u)); | |
93 | u->perpetual = true; | |
94 | ||
95 | cc->ip_accounting = true; | |
96 | ||
97 | assert_se(config_parse_ip_address_access(u->id, "filename", 1, "Service", 1, "IPAddressAllow", 0, "10.0.1.0/24", &cc->ip_address_allow, NULL) == 0); | |
98 | assert_se(config_parse_ip_address_access(u->id, "filename", 1, "Service", 1, "IPAddressAllow", 0, "127.0.0.2", &cc->ip_address_allow, NULL) == 0); | |
99 | assert_se(config_parse_ip_address_access(u->id, "filename", 1, "Service", 1, "IPAddressDeny", 0, "127.0.0.3", &cc->ip_address_deny, NULL) == 0); | |
100 | assert_se(config_parse_ip_address_access(u->id, "filename", 1, "Service", 1, "IPAddressDeny", 0, "10.0.3.2/24", &cc->ip_address_deny, NULL) == 0); | |
101 | assert_se(config_parse_ip_address_access(u->id, "filename", 1, "Service", 1, "IPAddressDeny", 0, "127.0.0.1/25", &cc->ip_address_deny, NULL) == 0); | |
102 | assert_se(config_parse_ip_address_access(u->id, "filename", 1, "Service", 1, "IPAddressDeny", 0, "127.0.0.4", &cc->ip_address_deny, NULL) == 0); | |
103 | ||
104 | assert(cc->ip_address_allow); | |
105 | assert(cc->ip_address_allow->items_next); | |
106 | assert(!cc->ip_address_allow->items_next->items_next); | |
107 | ||
108 | /* The deny list is defined redundantly, let's ensure it got properly reduced */ | |
109 | assert(cc->ip_address_deny); | |
110 | assert(cc->ip_address_deny->items_next); | |
111 | assert(!cc->ip_address_deny->items_next->items_next); | |
112 | ||
02ec6e04 DJL |
113 | assert_se(config_parse_exec(u->id, "filename", 1, "Service", 1, "ExecStart", SERVICE_EXEC_START, "/bin/ping -c 1 127.0.0.2 -W 5", SERVICE(u)->exec_command, u) == 0); |
114 | assert_se(config_parse_exec(u->id, "filename", 1, "Service", 1, "ExecStart", SERVICE_EXEC_START, "/bin/ping -c 1 127.0.0.3 -W 5", SERVICE(u)->exec_command, u) == 0); | |
db3a5930 DM |
115 | |
116 | assert_se(SERVICE(u)->exec_command[SERVICE_EXEC_START]); | |
117 | assert_se(SERVICE(u)->exec_command[SERVICE_EXEC_START]->command_next); | |
118 | assert_se(!SERVICE(u)->exec_command[SERVICE_EXEC_START]->command_next->command_next); | |
119 | ||
120 | SERVICE(u)->type = SERVICE_ONESHOT; | |
121 | u->load_state = UNIT_LOADED; | |
122 | ||
123 | unit_dump(u, stdout, NULL); | |
124 | ||
125 | r = bpf_firewall_compile(u); | |
126 | if (IN_SET(r, -ENOTTY, -ENOSYS, -EPERM )) { | |
127 | /* Kernel doesn't support the necessary bpf bits, or masked out via seccomp? */ | |
128 | manager_free(m); | |
129 | return EXIT_TEST_SKIP; | |
130 | } | |
131 | assert_se(r >= 0); | |
132 | ||
133 | assert(u->ip_bpf_ingress); | |
134 | assert(u->ip_bpf_egress); | |
135 | ||
136 | r = bpf_program_load_kernel(u->ip_bpf_ingress, log_buf, ELEMENTSOF(log_buf)); | |
137 | ||
138 | log_notice("log:"); | |
139 | log_notice("-------"); | |
140 | log_notice("%s", log_buf); | |
141 | log_notice("-------"); | |
142 | ||
143 | assert(r >= 0); | |
144 | ||
145 | r = bpf_program_load_kernel(u->ip_bpf_egress, log_buf, ELEMENTSOF(log_buf)); | |
146 | ||
147 | log_notice("log:"); | |
148 | log_notice("-------"); | |
149 | log_notice("%s", log_buf); | |
150 | log_notice("-------"); | |
151 | ||
152 | assert(r >= 0); | |
153 | ||
85e55d14 | 154 | assert_se(unit_start(u) >= 0); |
db3a5930 DM |
155 | |
156 | while (!IN_SET(SERVICE(u)->state, SERVICE_DEAD, SERVICE_FAILED)) | |
157 | assert_se(sd_event_run(m->event, UINT64_MAX) >= 0); | |
158 | ||
159 | assert_se(SERVICE(u)->exec_command[SERVICE_EXEC_START]->exec_status.code == CLD_EXITED && | |
160 | SERVICE(u)->exec_command[SERVICE_EXEC_START]->exec_status.status == EXIT_SUCCESS); | |
161 | ||
162 | assert_se(SERVICE(u)->exec_command[SERVICE_EXEC_START]->command_next->exec_status.code != CLD_EXITED || | |
163 | SERVICE(u)->exec_command[SERVICE_EXEC_START]->command_next->exec_status.status != EXIT_SUCCESS); | |
164 | ||
165 | manager_free(m); | |
166 | ||
167 | return 0; | |
168 | } |