1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
8 #include "bpf-socket-bind.h"
11 /* libbpf, clang, llvm and bpftool compile time dependencies are satisfied */
12 #include "bpf-dlopen.h"
15 #include "bpf/socket_bind/socket-bind-api.bpf.h"
16 #include "bpf/socket_bind/socket-bind-skel.h"
18 static struct socket_bind_bpf
*socket_bind_bpf_free(struct socket_bind_bpf
*obj
) {
19 /* socket_bind_bpf__destroy handles object == NULL case */
20 (void) socket_bind_bpf__destroy(obj
);
25 DEFINE_TRIVIAL_CLEANUP_FUNC(struct socket_bind_bpf
*, socket_bind_bpf_free
);
27 static int update_rules_map(
29 CGroupSocketBindItem
*head
) {
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
;
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
, errno
, "Failed to open BPF object: %m");
82 if (sym_bpf_map__resize(obj
->maps
.sd_bind_allow
, MAX(allow_count
, 1u)) != 0)
83 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_WARNING
, errno
,
84 "Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj
->maps
.sd_bind_allow
));
86 if (sym_bpf_map__resize(obj
->maps
.sd_bind_deny
, MAX(deny_count
, 1u)) != 0)
87 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_WARNING
, errno
,
88 "Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj
->maps
.sd_bind_deny
));
90 if (socket_bind_bpf__load(obj
) != 0)
91 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_DEBUG
, errno
,
92 "Failed to load BPF object: %m");
94 allow_map_fd
= sym_bpf_map__fd(obj
->maps
.sd_bind_allow
);
95 assert(allow_map_fd
>= 0);
97 r
= update_rules_map(allow_map_fd
, allow
);
99 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_WARNING
, r
,
100 "Failed to put socket bind allow rules into BPF map '%s'",
101 sym_bpf_map__name(obj
->maps
.sd_bind_allow
));
103 deny_map_fd
= sym_bpf_map__fd(obj
->maps
.sd_bind_deny
);
104 assert(deny_map_fd
>= 0);
106 r
= update_rules_map(deny_map_fd
, deny
);
108 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_WARNING
, r
,
109 "Failed to put socket bind deny rules into BPF map '%s'",
110 sym_bpf_map__name(obj
->maps
.sd_bind_deny
));
112 *ret_obj
= TAKE_PTR(obj
);
116 int bpf_socket_bind_supported(void) {
117 _cleanup_(socket_bind_bpf_freep
) struct socket_bind_bpf
*obj
= NULL
;
120 if (!cgroup_bpf_supported())
123 if (!sym_bpf_probe_prog_type(BPF_PROG_TYPE_CGROUP_SOCK_ADDR
, /*ifindex=*/0)) {
124 log_debug("BPF program type cgroup_sock_addr is not supported");
128 r
= prepare_socket_bind_bpf(/*unit=*/NULL
, /*allow_rules=*/NULL
, /*deny_rules=*/NULL
, &obj
);
130 log_debug_errno(r
, "BPF based socket_bind is not supported: %m");
134 return bpf_can_link_program(obj
->progs
.sd_bind4
);
137 int bpf_socket_bind_add_initial_link_fd(Unit
*u
, int fd
) {
142 if (!u
->initial_socket_bind_link_fds
) {
143 u
->initial_socket_bind_link_fds
= fdset_new();
144 if (!u
->initial_socket_bind_link_fds
)
148 r
= fdset_put(u
->initial_socket_bind_link_fds
, fd
);
150 return log_unit_error_errno(u
, r
, "Failed to put socket-bind BPF link fd %d to initial fdset", fd
);
155 static int socket_bind_install_impl(Unit
*u
) {
156 _cleanup_(bpf_link_freep
) struct bpf_link
*ipv4
= NULL
, *ipv6
= NULL
;
157 _cleanup_(socket_bind_bpf_freep
) struct socket_bind_bpf
*obj
= NULL
;
158 _cleanup_free_
char *cgroup_path
= NULL
;
159 _cleanup_close_
int cgroup_fd
= -1;
165 cc
= unit_get_cgroup_context(u
);
169 r
= cg_get_path(SYSTEMD_CGROUP_CONTROLLER
, u
->cgroup_path
, NULL
, &cgroup_path
);
171 return log_unit_error_errno(u
, r
, "Failed to get cgroup path: %m");
173 if (!cc
->socket_bind_allow
&& !cc
->socket_bind_deny
)
176 r
= prepare_socket_bind_bpf(u
, cc
->socket_bind_allow
, cc
->socket_bind_deny
, &obj
);
178 return log_unit_error_errno(u
, r
, "Failed to load BPF object: %m");
180 cgroup_fd
= open(cgroup_path
, O_RDONLY
| O_CLOEXEC
, 0);
182 return log_unit_error_errno(u
, errno
, "Failed to open cgroup=%s for reading: %m", cgroup_path
);
184 ipv4
= sym_bpf_program__attach_cgroup(obj
->progs
.sd_bind4
, cgroup_fd
);
185 r
= sym_libbpf_get_error(ipv4
);
187 return log_unit_error_errno(u
, r
, "Failed to link '%s' cgroup-bpf program: %m",
188 sym_bpf_program__name(obj
->progs
.sd_bind4
));
190 ipv6
= sym_bpf_program__attach_cgroup(obj
->progs
.sd_bind6
, cgroup_fd
);
191 r
= sym_libbpf_get_error(ipv6
);
193 return log_unit_error_errno(u
, r
, "Failed to link '%s' cgroup-bpf program: %m",
194 sym_bpf_program__name(obj
->progs
.sd_bind6
));
196 u
->ipv4_socket_bind_link
= TAKE_PTR(ipv4
);
197 u
->ipv6_socket_bind_link
= TAKE_PTR(ipv6
);
202 int bpf_socket_bind_install(Unit
*u
) {
207 r
= socket_bind_install_impl(u
);
211 fdset_close(u
->initial_socket_bind_link_fds
);
215 int bpf_serialize_socket_bind(Unit
*u
, FILE *f
, FDSet
*fds
) {
220 r
= bpf_serialize_link(f
, fds
, "ipv4-socket-bind-bpf-link", u
->ipv4_socket_bind_link
);
224 return bpf_serialize_link(f
, fds
, "ipv6-socket-bind-bpf-link", u
->ipv6_socket_bind_link
);
227 #else /* ! BPF_FRAMEWORK */
228 int bpf_socket_bind_supported(void) {
232 int bpf_socket_bind_add_initial_link_fd(Unit
*u
, int fd
) {
236 int bpf_socket_bind_install(Unit
*u
) {
237 return log_unit_debug_errno(u
, SYNTHETIC_ERRNO(EOPNOTSUPP
), "Failed to install socket bind: BPF framework is not supported");
240 int bpf_serialize_socket_bind(Unit
*u
, FILE *f
, FDSet
*fds
) {