1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include <linux/bpf_insn.h>
8 #include "bpf-firewall.h"
9 #include "bpf-program.h"
10 #include "load-fragment.h"
14 #include "test-helper.h"
18 /* We use the same limit here that PID 1 bumps RLIMIT_MEMLOCK to if it can */
19 #define CAN_MEMLOCK_SIZE (64U*1024U*1024U)
21 static bool can_memlock(void) {
25 /* Let's see if we can mlock() a larger blob of memory. BPF programs are charged against
26 * RLIMIT_MEMLOCK, hence let's first make sure we can lock memory at all, and skip the test if we
27 * cannot. Why not check RLIMIT_MEMLOCK explicitly? Because in container environments the
28 * RLIMIT_MEMLOCK value we see might not match the RLIMIT_MEMLOCK value actually in effect. */
30 p
= mmap(NULL
, CAN_MEMLOCK_SIZE
, PROT_READ
|PROT_WRITE
, MAP_ANONYMOUS
|MAP_SHARED
, -1, 0);
34 b
= mlock(p
, CAN_MEMLOCK_SIZE
) >= 0;
36 assert_se(munlock(p
, CAN_MEMLOCK_SIZE
) >= 0);
38 assert_se(munmap(p
, CAN_MEMLOCK_SIZE
) >= 0);
42 int main(int argc
, char *argv
[]) {
43 struct bpf_insn exit_insn
[] = {
44 BPF_MOV64_IMM(BPF_REG_0
, 1),
48 _cleanup_(rm_rf_physical_and_freep
) char *runtime_dir
= NULL
;
49 CGroupContext
*cc
= NULL
;
50 _cleanup_(bpf_program_unrefp
) BPFProgram
*p
= NULL
;
51 _cleanup_(manager_freep
) Manager
*m
= NULL
;
57 test_setup_logging(LOG_DEBUG
);
59 if (is_run_on_travis_ci())
60 return log_tests_skipped("test-bpf fails on Travis CI: https://github.com/systemd/systemd/issues/9666");
62 assert_se(getrlimit(RLIMIT_MEMLOCK
, &rl
) >= 0);
63 rl
.rlim_cur
= rl
.rlim_max
= MAX3(rl
.rlim_cur
, rl
.rlim_max
, CAN_MEMLOCK_SIZE
);
64 (void) setrlimit(RLIMIT_MEMLOCK
, &rl
);
67 return log_tests_skipped("Can't use mlock(), skipping.");
69 r
= enter_cgroup_subroot();
71 return log_tests_skipped("cgroupfs not available");
73 assert_se(set_unit_path(get_testdata_dir()) >= 0);
74 assert_se(runtime_dir
= setup_fake_runtime_dir());
76 r
= bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB
, &p
);
79 r
= bpf_program_add_instructions(p
, exit_insn
, ELEMENTSOF(exit_insn
));
83 return log_tests_skipped("not running as root");
85 r
= bpf_firewall_supported();
86 if (r
== BPF_FIREWALL_UNSUPPORTED
)
87 return log_tests_skipped("BPF firewalling not supported");
90 if (r
== BPF_FIREWALL_SUPPORTED_WITH_MULTI
)
91 log_notice("BPF firewalling with BPF_F_ALLOW_MULTI supported. Yay!");
93 log_notice("BPF firewalling (though without BPF_F_ALLOW_MULTI) supported. Good.");
95 r
= bpf_program_load_kernel(p
, log_buf
, ELEMENTSOF(log_buf
));
98 p
= bpf_program_unref(p
);
100 /* The simple tests succeeded. Now let's try full unit-based use-case. */
102 assert_se(manager_new(UNIT_FILE_USER
, MANAGER_TEST_RUN_BASIC
, &m
) >= 0);
103 assert_se(manager_startup(m
, NULL
, NULL
) >= 0);
105 assert_se(u
= unit_new(m
, sizeof(Service
)));
106 assert_se(unit_add_name(u
, "foo.service") == 0);
107 assert_se(cc
= unit_get_cgroup_context(u
));
110 cc
->ip_accounting
= true;
112 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);
113 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);
114 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);
115 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);
116 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);
117 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);
119 assert(cc
->ip_address_allow
);
120 assert(cc
->ip_address_allow
->items_next
);
121 assert(!cc
->ip_address_allow
->items_next
->items_next
);
123 /* The deny list is defined redundantly, let's ensure it got properly reduced */
124 assert(cc
->ip_address_deny
);
125 assert(cc
->ip_address_deny
->items_next
);
126 assert(!cc
->ip_address_deny
->items_next
->items_next
);
128 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);
129 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);
131 assert_se(SERVICE(u
)->exec_command
[SERVICE_EXEC_START
]);
132 assert_se(SERVICE(u
)->exec_command
[SERVICE_EXEC_START
]->command_next
);
133 assert_se(!SERVICE(u
)->exec_command
[SERVICE_EXEC_START
]->command_next
->command_next
);
135 SERVICE(u
)->type
= SERVICE_ONESHOT
;
136 u
->load_state
= UNIT_LOADED
;
138 unit_dump(u
, stdout
, NULL
);
140 r
= bpf_firewall_compile(u
);
141 if (IN_SET(r
, -ENOTTY
, -ENOSYS
, -EPERM
))
142 return log_tests_skipped("Kernel doesn't support the necessary bpf bits (masked out via seccomp?)");
145 assert(u
->ip_bpf_ingress
);
146 assert(u
->ip_bpf_egress
);
148 r
= bpf_program_load_kernel(u
->ip_bpf_ingress
, log_buf
, ELEMENTSOF(log_buf
));
151 log_notice("-------");
152 log_notice("%s", log_buf
);
153 log_notice("-------");
157 r
= bpf_program_load_kernel(u
->ip_bpf_egress
, log_buf
, ELEMENTSOF(log_buf
));
160 log_notice("-------");
161 log_notice("%s", log_buf
);
162 log_notice("-------");
166 assert_se(unit_start(u
) >= 0);
168 while (!IN_SET(SERVICE(u
)->state
, SERVICE_DEAD
, SERVICE_FAILED
))
169 assert_se(sd_event_run(m
->event
, UINT64_MAX
) >= 0);
171 assert_se(SERVICE(u
)->exec_command
[SERVICE_EXEC_START
]->exec_status
.code
== CLD_EXITED
&&
172 SERVICE(u
)->exec_command
[SERVICE_EXEC_START
]->exec_status
.status
== EXIT_SUCCESS
);
174 assert_se(SERVICE(u
)->exec_command
[SERVICE_EXEC_START
]->command_next
->exec_status
.code
!= CLD_EXITED
||
175 SERVICE(u
)->exec_command
[SERVICE_EXEC_START
]->command_next
->exec_status
.status
!= EXIT_SUCCESS
);