]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/bpf-socket-bind.c
Merge pull request #22791 from keszybz/bootctl-invert-order
[thirdparty/systemd.git] / src / core / bpf-socket-bind.c
CommitLineData
948def4a 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
91ce91c7
JK
2
3#if BPF_FRAMEWORK
4#include <bpf/bpf.h>
5#endif
6
7#include "fd-util.h"
cd09a5f3 8#include "bpf-socket-bind.h"
91ce91c7
JK
9
10#if BPF_FRAMEWORK
11/* libbpf, clang, llvm and bpftool compile time dependencies are satisfied */
c5fd89ad 12#include "bpf-dlopen.h"
91ce91c7 13#include "bpf-link.h"
d40ce018 14#include "bpf/socket_bind/socket-bind-skel.h"
91ce91c7
JK
15#include "bpf/socket_bind/socket-bind-api.bpf.h"
16
17static struct socket_bind_bpf *socket_bind_bpf_free(struct socket_bind_bpf *obj) {
18 /* socket_bind_bpf__destroy handles object == NULL case */
19 (void) socket_bind_bpf__destroy(obj);
20
21 return NULL;
22}
23
24DEFINE_TRIVIAL_CLEANUP_FUNC(struct socket_bind_bpf *, socket_bind_bpf_free);
25
26static int update_rules_map(
0b051424
LP
27 int map_fd,
28 CGroupSocketBindItem *head) {
29
91ce91c7
JK
30 uint32_t i = 0;
31
32 assert(map_fd >= 0);
33
34 LIST_FOREACH(socket_bind_items, item, head) {
91ce91c7
JK
35 struct socket_bind_rule val = {
36 .address_family = (uint32_t) item->address_family,
560d7624 37 .protocol = item->ip_protocol,
91ce91c7
JK
38 .nr_ports = item->nr_ports,
39 .port_min = item->port_min,
40 };
41
0b051424
LP
42 uint32_t key = i++;
43
c5fd89ad 44 if (sym_bpf_map_update_elem(map_fd, &key, &val, BPF_ANY) != 0)
91ce91c7
JK
45 return -errno;
46 }
47
48 return 0;
49}
50
51static int prepare_socket_bind_bpf(
0b051424
LP
52 Unit *u,
53 CGroupSocketBindItem *allow,
54 CGroupSocketBindItem *deny,
55 struct socket_bind_bpf **ret_obj) {
56
57 _cleanup_(socket_bind_bpf_freep) struct socket_bind_bpf *obj = NULL;
58 size_t allow_count = 0, deny_count = 0;
91ce91c7 59 int allow_map_fd, deny_map_fd, r;
91ce91c7
JK
60
61 assert(ret_obj);
62
0b051424 63 LIST_FOREACH(socket_bind_items, item, allow)
91ce91c7
JK
64 allow_count++;
65
66 LIST_FOREACH(socket_bind_items, item, deny)
67 deny_count++;
68
69 if (allow_count > SOCKET_BIND_MAX_RULES)
1a9e33ae
ZJS
70 return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, SYNTHETIC_ERRNO(EINVAL),
71 "Maximum number of socket bind rules=%u is exceeded", SOCKET_BIND_MAX_RULES);
91ce91c7
JK
72
73 if (deny_count > SOCKET_BIND_MAX_RULES)
1a9e33ae
ZJS
74 return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, SYNTHETIC_ERRNO(EINVAL),
75 "Maximum number of socket bind rules=%u is exceeded", SOCKET_BIND_MAX_RULES);
91ce91c7
JK
76
77 obj = socket_bind_bpf__open();
78 if (!obj)
cc20479f 79 return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, errno, "Failed to open BPF object: %m");
91ce91c7 80
c5fd89ad 81 if (sym_bpf_map__resize(obj->maps.sd_bind_allow, MAX(allow_count, 1u)) != 0)
1a9e33ae
ZJS
82 return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, errno,
83 "Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj->maps.sd_bind_allow));
91ce91c7 84
c5fd89ad 85 if (sym_bpf_map__resize(obj->maps.sd_bind_deny, MAX(deny_count, 1u)) != 0)
1a9e33ae
ZJS
86 return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, errno,
87 "Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj->maps.sd_bind_deny));
91ce91c7
JK
88
89 if (socket_bind_bpf__load(obj) != 0)
1a9e33ae
ZJS
90 return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, errno,
91 "Failed to load BPF object: %m");
91ce91c7 92
c5fd89ad 93 allow_map_fd = sym_bpf_map__fd(obj->maps.sd_bind_allow);
91ce91c7
JK
94 assert(allow_map_fd >= 0);
95
96 r = update_rules_map(allow_map_fd, allow);
97 if (r < 0)
1a9e33ae
ZJS
98 return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, r,
99 "Failed to put socket bind allow rules into BPF map '%s'",
100 sym_bpf_map__name(obj->maps.sd_bind_allow));
91ce91c7 101
c5fd89ad 102 deny_map_fd = sym_bpf_map__fd(obj->maps.sd_bind_deny);
91ce91c7
JK
103 assert(deny_map_fd >= 0);
104
105 r = update_rules_map(deny_map_fd, deny);
106 if (r < 0)
1a9e33ae
ZJS
107 return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, r,
108 "Failed to put socket bind deny rules into BPF map '%s'",
109 sym_bpf_map__name(obj->maps.sd_bind_deny));
91ce91c7
JK
110
111 *ret_obj = TAKE_PTR(obj);
112 return 0;
113}
114
cd09a5f3 115int bpf_socket_bind_supported(void) {
91ce91c7 116 _cleanup_(socket_bind_bpf_freep) struct socket_bind_bpf *obj = NULL;
0b051424 117 int r;
91ce91c7 118
0b051424 119 r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER);
91ce91c7 120 if (r < 0)
0b051424 121 return log_debug_errno(r, "Can't determine whether the unified hierarchy is used: %m");
91ce91c7 122 if (r == 0) {
0b051424
LP
123 log_debug("Not running with unified cgroup hierarchy, BPF is not supported");
124 return false;
91ce91c7
JK
125 }
126
0b051424
LP
127 if (dlopen_bpf() < 0)
128 return false;
c5fd89ad
LB
129
130 if (!sym_bpf_probe_prog_type(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, /*ifindex=*/0)) {
0b051424
LP
131 log_debug("BPF program type cgroup_sock_addr is not supported");
132 return false;
91ce91c7
JK
133 }
134
135 r = prepare_socket_bind_bpf(/*unit=*/NULL, /*allow_rules=*/NULL, /*deny_rules=*/NULL, &obj);
136 if (r < 0) {
137 log_debug_errno(r, "BPF based socket_bind is not supported: %m");
0b051424 138 return false;
91ce91c7
JK
139 }
140
d63a3d35 141 return bpf_can_link_program(obj->progs.sd_bind4);
91ce91c7
JK
142}
143
cd09a5f3 144int bpf_socket_bind_add_initial_link_fd(Unit *u, int fd) {
3d027d4d
JK
145 int r;
146
147 assert(u);
148
149 if (!u->initial_socket_bind_link_fds) {
150 u->initial_socket_bind_link_fds = fdset_new();
151 if (!u->initial_socket_bind_link_fds)
152 return log_oom();
153 }
154
155 r = fdset_put(u->initial_socket_bind_link_fds, fd);
156 if (r < 0)
157 return log_unit_error_errno(u, r, "Failed to put socket-bind BPF link fd %d to initial fdset", fd);
158
159 return 0;
160}
161
162static int socket_bind_install_impl(Unit *u) {
91ce91c7
JK
163 _cleanup_(bpf_link_freep) struct bpf_link *ipv4 = NULL, *ipv6 = NULL;
164 _cleanup_(socket_bind_bpf_freep) struct socket_bind_bpf *obj = NULL;
165 _cleanup_free_ char *cgroup_path = NULL;
166 _cleanup_close_ int cgroup_fd = -1;
167 CGroupContext *cc;
168 int r;
169
0b051424
LP
170 assert(u);
171
91ce91c7
JK
172 cc = unit_get_cgroup_context(u);
173 if (!cc)
174 return 0;
175
176 r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, NULL, &cgroup_path);
177 if (r < 0)
178 return log_unit_error_errno(u, r, "Failed to get cgroup path: %m");
179
180 if (!cc->socket_bind_allow && !cc->socket_bind_deny)
181 return 0;
182
183 r = prepare_socket_bind_bpf(u, cc->socket_bind_allow, cc->socket_bind_deny, &obj);
184 if (r < 0)
185 return log_unit_error_errno(u, r, "Failed to load BPF object: %m");
186
187 cgroup_fd = open(cgroup_path, O_RDONLY | O_CLOEXEC, 0);
188 if (cgroup_fd < 0)
0b051424 189 return log_unit_error_errno(u, errno, "Failed to open cgroup=%s for reading: %m", cgroup_path);
91ce91c7 190
c5fd89ad
LB
191 ipv4 = sym_bpf_program__attach_cgroup(obj->progs.sd_bind4, cgroup_fd);
192 r = sym_libbpf_get_error(ipv4);
91ce91c7 193 if (r != 0)
0b051424
LP
194 return log_unit_error_errno(u, r, "Failed to link '%s' cgroup-bpf program: %m",
195 sym_bpf_program__name(obj->progs.sd_bind4));
91ce91c7 196
c5fd89ad
LB
197 ipv6 = sym_bpf_program__attach_cgroup(obj->progs.sd_bind6, cgroup_fd);
198 r = sym_libbpf_get_error(ipv6);
91ce91c7 199 if (r != 0)
0b051424
LP
200 return log_unit_error_errno(u, r, "Failed to link '%s' cgroup-bpf program: %m",
201 sym_bpf_program__name(obj->progs.sd_bind6));
91ce91c7
JK
202
203 u->ipv4_socket_bind_link = TAKE_PTR(ipv4);
204 u->ipv6_socket_bind_link = TAKE_PTR(ipv6);
205
206 return 0;
207}
3d027d4d 208
cd09a5f3 209int bpf_socket_bind_install(Unit *u) {
0b051424
LP
210 int r;
211
212 assert(u);
213
214 r = socket_bind_install_impl(u);
3d027d4d
JK
215 if (r == -ENOMEM)
216 return r;
217
218 fdset_close(u->initial_socket_bind_link_fds);
3d027d4d
JK
219 return r;
220}
221
cd09a5f3 222int bpf_serialize_socket_bind(Unit *u, FILE *f, FDSet *fds) {
3d027d4d
JK
223 int r;
224
225 assert(u);
226
d63a3d35 227 r = bpf_serialize_link(f, fds, "ipv4-socket-bind-bpf-link", u->ipv4_socket_bind_link);
3d027d4d
JK
228 if (r < 0)
229 return r;
230
d63a3d35 231 return bpf_serialize_link(f, fds, "ipv6-socket-bind-bpf-link", u->ipv6_socket_bind_link);
3d027d4d
JK
232}
233
91ce91c7 234#else /* ! BPF_FRAMEWORK */
cd09a5f3 235int bpf_socket_bind_supported(void) {
0b051424 236 return false;
91ce91c7
JK
237}
238
cd09a5f3 239int bpf_socket_bind_add_initial_link_fd(Unit *u, int fd) {
3d027d4d
JK
240 return 0;
241}
242
cd09a5f3 243int bpf_socket_bind_install(Unit *u) {
0b051424 244 return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to install socket bind: BPF framework is not supported");
91ce91c7
JK
245}
246
cd09a5f3 247int bpf_serialize_socket_bind(Unit *u, FILE *f, FDSet *fds) {
3d027d4d
JK
248 return 0;
249}
91ce91c7 250#endif