1 /* SPDX-License-Identifier: LGPL-2.1+ */
8 #include "bpf-socket-bind.h"
11 /* libbpf, clang, llvm and bpftool compile time dependencies are satisfied */
12 #include "bpf-dlopen.h"
14 #include "bpf/socket_bind/socket-bind.skel.h"
15 #include "bpf/socket_bind/socket-bind-api.bpf.h"
17 static 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
);
24 DEFINE_TRIVIAL_CLEANUP_FUNC(struct socket_bind_bpf
*, socket_bind_bpf_free
);
26 static int update_rules_map(
28 CGroupSocketBindItem
*head
) {
30 CGroupSocketBindItem
*item
;
35 LIST_FOREACH(socket_bind_items
, item
, head
) {
36 struct socket_bind_rule val
= {
37 .address_family
= (uint32_t) item
->address_family
,
38 .nr_ports
= item
->nr_ports
,
39 .port_min
= item
->port_min
,
44 if (sym_bpf_map_update_elem(map_fd
, &key
, &val
, BPF_ANY
) != 0)
51 static int prepare_socket_bind_bpf(
53 CGroupSocketBindItem
*allow
,
54 CGroupSocketBindItem
*deny
,
55 struct socket_bind_bpf
**ret_obj
) {
57 _cleanup_(socket_bind_bpf_freep
) struct socket_bind_bpf
*obj
= NULL
;
58 size_t allow_count
= 0, deny_count
= 0;
59 int allow_map_fd
, deny_map_fd
, r
;
60 CGroupSocketBindItem
*item
;
64 LIST_FOREACH(socket_bind_items
, item
, allow
)
67 LIST_FOREACH(socket_bind_items
, item
, deny
)
70 if (allow_count
> SOCKET_BIND_MAX_RULES
)
71 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_WARNING
, SYNTHETIC_ERRNO(EINVAL
),
72 "Maximum number of socket bind rules=%u is exceeded", SOCKET_BIND_MAX_RULES
);
74 if (deny_count
> SOCKET_BIND_MAX_RULES
)
75 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_WARNING
, SYNTHETIC_ERRNO(EINVAL
),
76 "Maximum number of socket bind rules=%u is exceeded", SOCKET_BIND_MAX_RULES
);
78 obj
= socket_bind_bpf__open();
80 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_DEBUG
, SYNTHETIC_ERRNO(ENOMEM
),
81 "Failed to open BPF object");
83 if (sym_bpf_map__resize(obj
->maps
.sd_bind_allow
, MAX(allow_count
, 1u)) != 0)
84 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_WARNING
, errno
,
85 "Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj
->maps
.sd_bind_allow
));
87 if (sym_bpf_map__resize(obj
->maps
.sd_bind_deny
, MAX(deny_count
, 1u)) != 0)
88 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_WARNING
, errno
,
89 "Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj
->maps
.sd_bind_deny
));
91 if (socket_bind_bpf__load(obj
) != 0)
92 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_DEBUG
, errno
,
93 "Failed to load BPF object: %m");
95 allow_map_fd
= sym_bpf_map__fd(obj
->maps
.sd_bind_allow
);
96 assert(allow_map_fd
>= 0);
98 r
= update_rules_map(allow_map_fd
, allow
);
100 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_WARNING
, r
,
101 "Failed to put socket bind allow rules into BPF map '%s'",
102 sym_bpf_map__name(obj
->maps
.sd_bind_allow
));
104 deny_map_fd
= sym_bpf_map__fd(obj
->maps
.sd_bind_deny
);
105 assert(deny_map_fd
>= 0);
107 r
= update_rules_map(deny_map_fd
, deny
);
109 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_WARNING
, r
,
110 "Failed to put socket bind deny rules into BPF map '%s'",
111 sym_bpf_map__name(obj
->maps
.sd_bind_deny
));
113 *ret_obj
= TAKE_PTR(obj
);
117 int bpf_socket_bind_supported(void) {
118 _cleanup_(socket_bind_bpf_freep
) struct socket_bind_bpf
*obj
= NULL
;
121 r
= cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER
);
123 return log_debug_errno(r
, "Can't determine whether the unified hierarchy is used: %m");
125 log_debug("Not running with unified cgroup hierarchy, BPF is not supported");
129 if (dlopen_bpf() < 0)
132 if (!sym_bpf_probe_prog_type(BPF_PROG_TYPE_CGROUP_SOCK_ADDR
, /*ifindex=*/0)) {
133 log_debug("BPF program type cgroup_sock_addr is not supported");
137 r
= prepare_socket_bind_bpf(/*unit=*/NULL
, /*allow_rules=*/NULL
, /*deny_rules=*/NULL
, &obj
);
139 log_debug_errno(r
, "BPF based socket_bind is not supported: %m");
143 return bpf_can_link_program(obj
->progs
.sd_bind4
);
146 int bpf_socket_bind_add_initial_link_fd(Unit
*u
, int fd
) {
151 if (!u
->initial_socket_bind_link_fds
) {
152 u
->initial_socket_bind_link_fds
= fdset_new();
153 if (!u
->initial_socket_bind_link_fds
)
157 r
= fdset_put(u
->initial_socket_bind_link_fds
, fd
);
159 return log_unit_error_errno(u
, r
, "Failed to put socket-bind BPF link fd %d to initial fdset", fd
);
164 static int socket_bind_install_impl(Unit
*u
) {
165 _cleanup_(bpf_link_freep
) struct bpf_link
*ipv4
= NULL
, *ipv6
= NULL
;
166 _cleanup_(socket_bind_bpf_freep
) struct socket_bind_bpf
*obj
= NULL
;
167 _cleanup_free_
char *cgroup_path
= NULL
;
168 _cleanup_close_
int cgroup_fd
= -1;
174 cc
= unit_get_cgroup_context(u
);
178 r
= cg_get_path(SYSTEMD_CGROUP_CONTROLLER
, u
->cgroup_path
, NULL
, &cgroup_path
);
180 return log_unit_error_errno(u
, r
, "Failed to get cgroup path: %m");
182 if (!cc
->socket_bind_allow
&& !cc
->socket_bind_deny
)
185 r
= prepare_socket_bind_bpf(u
, cc
->socket_bind_allow
, cc
->socket_bind_deny
, &obj
);
187 return log_unit_error_errno(u
, r
, "Failed to load BPF object: %m");
189 cgroup_fd
= open(cgroup_path
, O_RDONLY
| O_CLOEXEC
, 0);
191 return log_unit_error_errno(u
, errno
, "Failed to open cgroup=%s for reading: %m", cgroup_path
);
193 ipv4
= sym_bpf_program__attach_cgroup(obj
->progs
.sd_bind4
, cgroup_fd
);
194 r
= sym_libbpf_get_error(ipv4
);
196 return log_unit_error_errno(u
, r
, "Failed to link '%s' cgroup-bpf program: %m",
197 sym_bpf_program__name(obj
->progs
.sd_bind4
));
199 ipv6
= sym_bpf_program__attach_cgroup(obj
->progs
.sd_bind6
, cgroup_fd
);
200 r
= sym_libbpf_get_error(ipv6
);
202 return log_unit_error_errno(u
, r
, "Failed to link '%s' cgroup-bpf program: %m",
203 sym_bpf_program__name(obj
->progs
.sd_bind6
));
205 u
->ipv4_socket_bind_link
= TAKE_PTR(ipv4
);
206 u
->ipv6_socket_bind_link
= TAKE_PTR(ipv6
);
211 int bpf_socket_bind_install(Unit
*u
) {
216 r
= socket_bind_install_impl(u
);
220 fdset_close(u
->initial_socket_bind_link_fds
);
224 int bpf_serialize_socket_bind(Unit
*u
, FILE *f
, FDSet
*fds
) {
229 r
= bpf_serialize_link(f
, fds
, "ipv4-socket-bind-bpf-link", u
->ipv4_socket_bind_link
);
233 return bpf_serialize_link(f
, fds
, "ipv6-socket-bind-bpf-link", u
->ipv6_socket_bind_link
);
236 #else /* ! BPF_FRAMEWORK */
237 int bpf_socket_bind_supported(void) {
241 int bpf_socket_bind_add_initial_link_fd(Unit
*u
, int fd
) {
245 int bpf_socket_bind_install(Unit
*u
) {
246 return log_unit_debug_errno(u
, SYNTHETIC_ERRNO(EOPNOTSUPP
), "Failed to install socket bind: BPF framework is not supported");
249 int bpf_serialize_socket_bind(Unit
*u
, FILE *f
, FDSet
*fds
) {