]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
db3a5930 | 2 | /*** |
96b2fb93 | 3 | Copyright © 2016 Daniel Mack |
db3a5930 DM |
4 | ***/ |
5 | ||
6 | #include <linux/libbpf.h> | |
7 | #include <string.h> | |
8 | #include <unistd.h> | |
9 | ||
10 | #include "bpf-firewall.h" | |
11 | #include "bpf-program.h" | |
12 | #include "load-fragment.h" | |
13 | #include "manager.h" | |
14 | #include "rm-rf.h" | |
15 | #include "service.h" | |
16 | #include "test-helper.h" | |
17 | #include "tests.h" | |
18 | #include "unit.h" | |
19 | ||
20 | int main(int argc, char *argv[]) { | |
21 | struct bpf_insn exit_insn[] = { | |
22 | BPF_MOV64_IMM(BPF_REG_0, 1), | |
23 | BPF_EXIT_INSN() | |
24 | }; | |
25 | ||
26 | _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; | |
27 | CGroupContext *cc = NULL; | |
28 | _cleanup_(bpf_program_unrefp) BPFProgram *p = NULL; | |
c70cac54 | 29 | _cleanup_(manager_freep) Manager *m = NULL; |
db3a5930 DM |
30 | Unit *u; |
31 | char log_buf[65535]; | |
32 | int r; | |
33 | ||
34 | log_set_max_level(LOG_DEBUG); | |
35 | log_parse_environment(); | |
36 | log_open(); | |
37 | ||
651d47d1 ZJS |
38 | r = enter_cgroup_subroot(); |
39 | if (r == -ENOMEDIUM) { | |
40 | log_notice("cgroupfs not available, skipping tests"); | |
41 | return EXIT_TEST_SKIP; | |
42 | } | |
43 | ||
db3a5930 DM |
44 | assert_se(set_unit_path(get_testdata_dir("")) >= 0); |
45 | assert_se(runtime_dir = setup_fake_runtime_dir()); | |
46 | ||
47 | r = bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB, &p); | |
48 | assert(r == 0); | |
49 | ||
50 | r = bpf_program_add_instructions(p, exit_insn, ELEMENTSOF(exit_insn)); | |
51 | assert(r == 0); | |
52 | ||
53 | if (getuid() != 0) { | |
54 | log_notice("Not running as root, skipping kernel related tests."); | |
55 | return EXIT_TEST_SKIP; | |
56 | } | |
57 | ||
58 | r = bpf_firewall_supported(); | |
2ae7ee58 | 59 | if (r == BPF_FIREWALL_UNSUPPORTED) { |
db3a5930 DM |
60 | log_notice("BPF firewalling not supported, skipping"); |
61 | return EXIT_TEST_SKIP; | |
62 | } | |
63 | assert_se(r > 0); | |
64 | ||
2ae7ee58 LP |
65 | if (r == BPF_FIREWALL_SUPPORTED_WITH_MULTI) |
66 | log_notice("BPF firewalling with BPF_F_ALLOW_MULTI supported. Yay!"); | |
67 | else | |
68 | log_notice("BPF firewalling (though without BPF_F_ALLOW_MULTI) supported. Good."); | |
69 | ||
db3a5930 DM |
70 | r = bpf_program_load_kernel(p, log_buf, ELEMENTSOF(log_buf)); |
71 | assert(r >= 0); | |
72 | ||
73 | p = bpf_program_unref(p); | |
74 | ||
75 | /* The simple tests suceeded. Now let's try full unit-based use-case. */ | |
76 | ||
77 | assert_se(manager_new(UNIT_FILE_USER, true, &m) >= 0); | |
78 | assert_se(manager_startup(m, NULL, NULL) >= 0); | |
79 | ||
80 | assert_se(u = unit_new(m, sizeof(Service))); | |
81 | assert_se(unit_add_name(u, "foo.service") == 0); | |
82 | assert_se(cc = unit_get_cgroup_context(u)); | |
83 | u->perpetual = true; | |
84 | ||
85 | cc->ip_accounting = true; | |
86 | ||
87 | 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); | |
88 | 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); | |
89 | 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); | |
90 | 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); | |
91 | 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); | |
92 | 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); | |
93 | ||
94 | assert(cc->ip_address_allow); | |
95 | assert(cc->ip_address_allow->items_next); | |
96 | assert(!cc->ip_address_allow->items_next->items_next); | |
97 | ||
98 | /* The deny list is defined redundantly, let's ensure it got properly reduced */ | |
99 | assert(cc->ip_address_deny); | |
100 | assert(cc->ip_address_deny->items_next); | |
101 | assert(!cc->ip_address_deny->items_next->items_next); | |
102 | ||
02ec6e04 DJL |
103 | 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); |
104 | 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 |
105 | |
106 | assert_se(SERVICE(u)->exec_command[SERVICE_EXEC_START]); | |
107 | assert_se(SERVICE(u)->exec_command[SERVICE_EXEC_START]->command_next); | |
108 | assert_se(!SERVICE(u)->exec_command[SERVICE_EXEC_START]->command_next->command_next); | |
109 | ||
110 | SERVICE(u)->type = SERVICE_ONESHOT; | |
111 | u->load_state = UNIT_LOADED; | |
112 | ||
113 | unit_dump(u, stdout, NULL); | |
114 | ||
115 | r = bpf_firewall_compile(u); | |
c70cac54 | 116 | if (IN_SET(r, -ENOTTY, -ENOSYS, -EPERM )) |
db3a5930 | 117 | /* Kernel doesn't support the necessary bpf bits, or masked out via seccomp? */ |
db3a5930 | 118 | return EXIT_TEST_SKIP; |
db3a5930 DM |
119 | assert_se(r >= 0); |
120 | ||
121 | assert(u->ip_bpf_ingress); | |
122 | assert(u->ip_bpf_egress); | |
123 | ||
124 | r = bpf_program_load_kernel(u->ip_bpf_ingress, log_buf, ELEMENTSOF(log_buf)); | |
125 | ||
126 | log_notice("log:"); | |
127 | log_notice("-------"); | |
128 | log_notice("%s", log_buf); | |
129 | log_notice("-------"); | |
130 | ||
131 | assert(r >= 0); | |
132 | ||
133 | r = bpf_program_load_kernel(u->ip_bpf_egress, log_buf, ELEMENTSOF(log_buf)); | |
134 | ||
135 | log_notice("log:"); | |
136 | log_notice("-------"); | |
137 | log_notice("%s", log_buf); | |
138 | log_notice("-------"); | |
139 | ||
140 | assert(r >= 0); | |
141 | ||
85e55d14 | 142 | assert_se(unit_start(u) >= 0); |
db3a5930 DM |
143 | |
144 | while (!IN_SET(SERVICE(u)->state, SERVICE_DEAD, SERVICE_FAILED)) | |
145 | assert_se(sd_event_run(m->event, UINT64_MAX) >= 0); | |
146 | ||
147 | assert_se(SERVICE(u)->exec_command[SERVICE_EXEC_START]->exec_status.code == CLD_EXITED && | |
148 | SERVICE(u)->exec_command[SERVICE_EXEC_START]->exec_status.status == EXIT_SUCCESS); | |
149 | ||
150 | assert_se(SERVICE(u)->exec_command[SERVICE_EXEC_START]->command_next->exec_status.code != CLD_EXITED || | |
151 | SERVICE(u)->exec_command[SERVICE_EXEC_START]->command_next->exec_status.status != EXIT_SUCCESS); | |
152 | ||
db3a5930 DM |
153 | return 0; |
154 | } |