1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2016 Daniel Mack
8 #include <linux/libbpf.h>
12 #include "bpf-firewall.h"
13 #include "bpf-program.h"
14 #include "load-fragment.h"
18 #include "test-helper.h"
22 int main(int argc
, char *argv
[]) {
23 struct bpf_insn exit_insn
[] = {
24 BPF_MOV64_IMM(BPF_REG_0
, 1),
28 _cleanup_(rm_rf_physical_and_freep
) char *runtime_dir
= NULL
;
29 CGroupContext
*cc
= NULL
;
30 _cleanup_(bpf_program_unrefp
) BPFProgram
*p
= NULL
;
31 _cleanup_(manager_freep
) Manager
*m
= NULL
;
36 log_set_max_level(LOG_DEBUG
);
37 log_parse_environment();
40 r
= enter_cgroup_subroot();
41 if (r
== -ENOMEDIUM
) {
42 log_notice("cgroupfs not available, skipping tests");
43 return EXIT_TEST_SKIP
;
46 assert_se(set_unit_path(get_testdata_dir("")) >= 0);
47 assert_se(runtime_dir
= setup_fake_runtime_dir());
49 r
= bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB
, &p
);
52 r
= bpf_program_add_instructions(p
, exit_insn
, ELEMENTSOF(exit_insn
));
56 log_notice("Not running as root, skipping kernel related tests.");
57 return EXIT_TEST_SKIP
;
60 r
= bpf_firewall_supported();
61 if (r
== BPF_FIREWALL_UNSUPPORTED
) {
62 log_notice("BPF firewalling not supported, skipping");
63 return EXIT_TEST_SKIP
;
67 if (r
== BPF_FIREWALL_SUPPORTED_WITH_MULTI
)
68 log_notice("BPF firewalling with BPF_F_ALLOW_MULTI supported. Yay!");
70 log_notice("BPF firewalling (though without BPF_F_ALLOW_MULTI) supported. Good.");
72 r
= bpf_program_load_kernel(p
, log_buf
, ELEMENTSOF(log_buf
));
75 p
= bpf_program_unref(p
);
77 /* The simple tests suceeded. Now let's try full unit-based use-case. */
79 assert_se(manager_new(UNIT_FILE_USER
, true, &m
) >= 0);
80 assert_se(manager_startup(m
, NULL
, NULL
) >= 0);
82 assert_se(u
= unit_new(m
, sizeof(Service
)));
83 assert_se(unit_add_name(u
, "foo.service") == 0);
84 assert_se(cc
= unit_get_cgroup_context(u
));
87 cc
->ip_accounting
= true;
89 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);
90 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);
91 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);
92 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);
93 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);
94 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);
96 assert(cc
->ip_address_allow
);
97 assert(cc
->ip_address_allow
->items_next
);
98 assert(!cc
->ip_address_allow
->items_next
->items_next
);
100 /* The deny list is defined redundantly, let's ensure it got properly reduced */
101 assert(cc
->ip_address_deny
);
102 assert(cc
->ip_address_deny
->items_next
);
103 assert(!cc
->ip_address_deny
->items_next
->items_next
);
105 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);
106 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);
108 assert_se(SERVICE(u
)->exec_command
[SERVICE_EXEC_START
]);
109 assert_se(SERVICE(u
)->exec_command
[SERVICE_EXEC_START
]->command_next
);
110 assert_se(!SERVICE(u
)->exec_command
[SERVICE_EXEC_START
]->command_next
->command_next
);
112 SERVICE(u
)->type
= SERVICE_ONESHOT
;
113 u
->load_state
= UNIT_LOADED
;
115 unit_dump(u
, stdout
, NULL
);
117 r
= bpf_firewall_compile(u
);
118 if (IN_SET(r
, -ENOTTY
, -ENOSYS
, -EPERM
))
119 /* Kernel doesn't support the necessary bpf bits, or masked out via seccomp? */
120 return EXIT_TEST_SKIP
;
123 assert(u
->ip_bpf_ingress
);
124 assert(u
->ip_bpf_egress
);
126 r
= bpf_program_load_kernel(u
->ip_bpf_ingress
, log_buf
, ELEMENTSOF(log_buf
));
129 log_notice("-------");
130 log_notice("%s", log_buf
);
131 log_notice("-------");
135 r
= bpf_program_load_kernel(u
->ip_bpf_egress
, log_buf
, ELEMENTSOF(log_buf
));
138 log_notice("-------");
139 log_notice("%s", log_buf
);
140 log_notice("-------");
144 assert_se(unit_start(u
) >= 0);
146 while (!IN_SET(SERVICE(u
)->state
, SERVICE_DEAD
, SERVICE_FAILED
))
147 assert_se(sd_event_run(m
->event
, UINT64_MAX
) >= 0);
149 assert_se(SERVICE(u
)->exec_command
[SERVICE_EXEC_START
]->exec_status
.code
== CLD_EXITED
&&
150 SERVICE(u
)->exec_command
[SERVICE_EXEC_START
]->exec_status
.status
== EXIT_SUCCESS
);
152 assert_se(SERVICE(u
)->exec_command
[SERVICE_EXEC_START
]->command_next
->exec_status
.code
!= CLD_EXITED
||
153 SERVICE(u
)->exec_command
[SERVICE_EXEC_START
]->command_next
->exec_status
.status
!= EXIT_SUCCESS
);