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 .protocol
= item
->ip_protocol
,
39 .nr_ports
= item
->nr_ports
,
40 .port_min
= item
->port_min
,
45 if (sym_bpf_map_update_elem(map_fd
, &key
, &val
, BPF_ANY
) != 0)
52 static int prepare_socket_bind_bpf(
54 CGroupSocketBindItem
*allow
,
55 CGroupSocketBindItem
*deny
,
56 struct socket_bind_bpf
**ret_obj
) {
58 _cleanup_(socket_bind_bpf_freep
) struct socket_bind_bpf
*obj
= NULL
;
59 size_t allow_count
= 0, deny_count
= 0;
60 int allow_map_fd
, deny_map_fd
, r
;
61 CGroupSocketBindItem
*item
;
65 LIST_FOREACH(socket_bind_items
, item
, allow
)
68 LIST_FOREACH(socket_bind_items
, item
, deny
)
71 if (allow_count
> SOCKET_BIND_MAX_RULES
)
72 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_WARNING
, SYNTHETIC_ERRNO(EINVAL
),
73 "Maximum number of socket bind rules=%u is exceeded", SOCKET_BIND_MAX_RULES
);
75 if (deny_count
> SOCKET_BIND_MAX_RULES
)
76 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_WARNING
, SYNTHETIC_ERRNO(EINVAL
),
77 "Maximum number of socket bind rules=%u is exceeded", SOCKET_BIND_MAX_RULES
);
79 obj
= socket_bind_bpf__open();
81 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_DEBUG
, SYNTHETIC_ERRNO(ENOMEM
),
82 "Failed to open BPF object");
84 if (sym_bpf_map__resize(obj
->maps
.sd_bind_allow
, MAX(allow_count
, 1u)) != 0)
85 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_WARNING
, errno
,
86 "Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj
->maps
.sd_bind_allow
));
88 if (sym_bpf_map__resize(obj
->maps
.sd_bind_deny
, MAX(deny_count
, 1u)) != 0)
89 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_WARNING
, errno
,
90 "Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj
->maps
.sd_bind_deny
));
92 if (socket_bind_bpf__load(obj
) != 0)
93 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_DEBUG
, errno
,
94 "Failed to load BPF object: %m");
96 allow_map_fd
= sym_bpf_map__fd(obj
->maps
.sd_bind_allow
);
97 assert(allow_map_fd
>= 0);
99 r
= update_rules_map(allow_map_fd
, allow
);
101 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_WARNING
, r
,
102 "Failed to put socket bind allow rules into BPF map '%s'",
103 sym_bpf_map__name(obj
->maps
.sd_bind_allow
));
105 deny_map_fd
= sym_bpf_map__fd(obj
->maps
.sd_bind_deny
);
106 assert(deny_map_fd
>= 0);
108 r
= update_rules_map(deny_map_fd
, deny
);
110 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_WARNING
, r
,
111 "Failed to put socket bind deny rules into BPF map '%s'",
112 sym_bpf_map__name(obj
->maps
.sd_bind_deny
));
114 *ret_obj
= TAKE_PTR(obj
);
118 int bpf_socket_bind_supported(void) {
119 _cleanup_(socket_bind_bpf_freep
) struct socket_bind_bpf
*obj
= NULL
;
122 r
= cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER
);
124 return log_debug_errno(r
, "Can't determine whether the unified hierarchy is used: %m");
126 log_debug("Not running with unified cgroup hierarchy, BPF is not supported");
130 if (dlopen_bpf() < 0)
133 if (!sym_bpf_probe_prog_type(BPF_PROG_TYPE_CGROUP_SOCK_ADDR
, /*ifindex=*/0)) {
134 log_debug("BPF program type cgroup_sock_addr is not supported");
138 r
= prepare_socket_bind_bpf(/*unit=*/NULL
, /*allow_rules=*/NULL
, /*deny_rules=*/NULL
, &obj
);
140 log_debug_errno(r
, "BPF based socket_bind is not supported: %m");
144 return bpf_can_link_program(obj
->progs
.sd_bind4
);
147 int bpf_socket_bind_add_initial_link_fd(Unit
*u
, int fd
) {
152 if (!u
->initial_socket_bind_link_fds
) {
153 u
->initial_socket_bind_link_fds
= fdset_new();
154 if (!u
->initial_socket_bind_link_fds
)
158 r
= fdset_put(u
->initial_socket_bind_link_fds
, fd
);
160 return log_unit_error_errno(u
, r
, "Failed to put socket-bind BPF link fd %d to initial fdset", fd
);
165 static int socket_bind_install_impl(Unit
*u
) {
166 _cleanup_(bpf_link_freep
) struct bpf_link
*ipv4
= NULL
, *ipv6
= NULL
;
167 _cleanup_(socket_bind_bpf_freep
) struct socket_bind_bpf
*obj
= NULL
;
168 _cleanup_free_
char *cgroup_path
= NULL
;
169 _cleanup_close_
int cgroup_fd
= -1;
175 cc
= unit_get_cgroup_context(u
);
179 r
= cg_get_path(SYSTEMD_CGROUP_CONTROLLER
, u
->cgroup_path
, NULL
, &cgroup_path
);
181 return log_unit_error_errno(u
, r
, "Failed to get cgroup path: %m");
183 if (!cc
->socket_bind_allow
&& !cc
->socket_bind_deny
)
186 r
= prepare_socket_bind_bpf(u
, cc
->socket_bind_allow
, cc
->socket_bind_deny
, &obj
);
188 return log_unit_error_errno(u
, r
, "Failed to load BPF object: %m");
190 cgroup_fd
= open(cgroup_path
, O_RDONLY
| O_CLOEXEC
, 0);
192 return log_unit_error_errno(u
, errno
, "Failed to open cgroup=%s for reading: %m", cgroup_path
);
194 ipv4
= sym_bpf_program__attach_cgroup(obj
->progs
.sd_bind4
, cgroup_fd
);
195 r
= sym_libbpf_get_error(ipv4
);
197 return log_unit_error_errno(u
, r
, "Failed to link '%s' cgroup-bpf program: %m",
198 sym_bpf_program__name(obj
->progs
.sd_bind4
));
200 ipv6
= sym_bpf_program__attach_cgroup(obj
->progs
.sd_bind6
, cgroup_fd
);
201 r
= sym_libbpf_get_error(ipv6
);
203 return log_unit_error_errno(u
, r
, "Failed to link '%s' cgroup-bpf program: %m",
204 sym_bpf_program__name(obj
->progs
.sd_bind6
));
206 u
->ipv4_socket_bind_link
= TAKE_PTR(ipv4
);
207 u
->ipv6_socket_bind_link
= TAKE_PTR(ipv6
);
212 int bpf_socket_bind_install(Unit
*u
) {
217 r
= socket_bind_install_impl(u
);
221 fdset_close(u
->initial_socket_bind_link_fds
);
225 int bpf_serialize_socket_bind(Unit
*u
, FILE *f
, FDSet
*fds
) {
230 r
= bpf_serialize_link(f
, fds
, "ipv4-socket-bind-bpf-link", u
->ipv4_socket_bind_link
);
234 return bpf_serialize_link(f
, fds
, "ipv6-socket-bind-bpf-link", u
->ipv6_socket_bind_link
);
237 #else /* ! BPF_FRAMEWORK */
238 int bpf_socket_bind_supported(void) {
242 int bpf_socket_bind_add_initial_link_fd(Unit
*u
, int fd
) {
246 int bpf_socket_bind_install(Unit
*u
) {
247 return log_unit_debug_errno(u
, SYNTHETIC_ERRNO(EOPNOTSUPP
), "Failed to install socket bind: BPF framework is not supported");
250 int bpf_serialize_socket_bind(Unit
*u
, FILE *f
, FDSet
*fds
) {