1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include "restrict-ifaces.h"
5 #include "netlink-util.h"
8 /* libbpf, clang and llc compile time dependencies are satisfied */
10 #include "bpf-dlopen.h"
13 #include "bpf/restrict_ifaces/restrict-ifaces-skel.h"
15 static struct restrict_ifaces_bpf
*restrict_ifaces_bpf_free(struct restrict_ifaces_bpf
*obj
) {
16 restrict_ifaces_bpf__destroy(obj
);
20 DEFINE_TRIVIAL_CLEANUP_FUNC(struct restrict_ifaces_bpf
*, restrict_ifaces_bpf_free
);
22 static int prepare_restrict_ifaces_bpf(
25 const Set
*restrict_network_interfaces
,
26 struct restrict_ifaces_bpf
**ret_object
) {
28 _cleanup_(restrict_ifaces_bpf_freep
) struct restrict_ifaces_bpf
*obj
= NULL
;
29 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
35 obj
= restrict_ifaces_bpf__open();
37 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_DEBUG
, errno
, "restrict-interfaces: Failed to open BPF object: %m");
39 r
= sym_bpf_map__set_max_entries(obj
->maps
.sd_restrictif
, MAX(set_size(restrict_network_interfaces
), 1u));
41 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_WARNING
, r
,
42 "restrict-interfaces: Failed to resize BPF map '%s': %m",
43 sym_bpf_map__name(obj
->maps
.sd_restrictif
));
45 obj
->rodata
->is_allow_list
= is_allow_list
;
47 r
= restrict_ifaces_bpf__load(obj
);
49 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_DEBUG
, r
, "restrict-interfaces: Failed to load BPF object: %m");
51 map_fd
= sym_bpf_map__fd(obj
->maps
.sd_restrictif
);
53 SET_FOREACH(iface
, restrict_network_interfaces
) {
57 ifindex
= rtnl_resolve_interface(&rtnl
, iface
);
59 log_unit_warning_errno(u
, ifindex
,
60 "restrict-interfaces: Couldn't find index of network interface '%s', ignoring: %m",
65 if (sym_bpf_map_update_elem(map_fd
, &ifindex
, &dummy
, BPF_ANY
))
66 return log_unit_full_errno(u
, u
? LOG_ERR
: LOG_WARNING
, errno
,
67 "restrict-interfaces: Failed to update BPF map '%s' fd: %m",
68 sym_bpf_map__name(obj
->maps
.sd_restrictif
));
71 *ret_object
= TAKE_PTR(obj
);
75 int restrict_network_interfaces_supported(void) {
76 _cleanup_(restrict_ifaces_bpf_freep
) struct restrict_ifaces_bpf
*obj
= NULL
;
77 static int supported
= -1;
83 if (!cgroup_bpf_supported())
84 return (supported
= false);
86 if (!compat_libbpf_probe_bpf_prog_type(BPF_PROG_TYPE_CGROUP_SKB
, /*opts=*/NULL
)) {
87 log_debug("restrict-interfaces: BPF program type cgroup_skb is not supported");
88 return (supported
= false);
91 r
= prepare_restrict_ifaces_bpf(NULL
, true, NULL
, &obj
);
93 log_debug_errno(r
, "restrict-interfaces: Failed to load BPF object: %m");
94 return (supported
= false);
97 return (supported
= bpf_can_link_program(obj
->progs
.sd_restrictif_i
));
100 static int restrict_network_interfaces_install_impl(Unit
*u
) {
101 _cleanup_(bpf_link_freep
) struct bpf_link
*egress_link
= NULL
, *ingress_link
= NULL
;
102 _cleanup_(restrict_ifaces_bpf_freep
) struct restrict_ifaces_bpf
*obj
= NULL
;
103 _cleanup_free_
char *cgroup_path
= NULL
;
104 _cleanup_close_
int cgroup_fd
= -EBADF
;
108 cc
= unit_get_cgroup_context(u
);
112 r
= cg_get_path(SYSTEMD_CGROUP_CONTROLLER
, u
->cgroup_path
, NULL
, &cgroup_path
);
114 return log_unit_error_errno(u
, r
, "restrict-interfaces: Failed to get cgroup path: %m");
116 if (!cc
->restrict_network_interfaces
)
119 r
= prepare_restrict_ifaces_bpf(u
,
120 cc
->restrict_network_interfaces_is_allow_list
,
121 cc
->restrict_network_interfaces
,
126 cgroup_fd
= open(cgroup_path
, O_RDONLY
| O_CLOEXEC
| O_DIRECTORY
, 0);
130 ingress_link
= sym_bpf_program__attach_cgroup(obj
->progs
.sd_restrictif_i
, cgroup_fd
);
131 r
= sym_libbpf_get_error(ingress_link
);
133 return log_unit_error_errno(u
, r
, "restrict-interfaces: Failed to create ingress cgroup link: %m");
135 egress_link
= sym_bpf_program__attach_cgroup(obj
->progs
.sd_restrictif_e
, cgroup_fd
);
136 r
= sym_libbpf_get_error(egress_link
);
138 return log_unit_error_errno(u
, r
, "restrict-interfaces: Failed to create egress cgroup link: %m");
140 u
->restrict_ifaces_ingress_bpf_link
= TAKE_PTR(ingress_link
);
141 u
->restrict_ifaces_egress_bpf_link
= TAKE_PTR(egress_link
);
146 int restrict_network_interfaces_install(Unit
*u
) {
147 int r
= restrict_network_interfaces_install_impl(u
);
148 fdset_close(u
->initial_restric_ifaces_link_fds
);
152 int serialize_restrict_network_interfaces(Unit
*u
, FILE *f
, FDSet
*fds
) {
157 r
= bpf_serialize_link(f
, fds
, "restrict-ifaces-bpf-fd", u
->restrict_ifaces_ingress_bpf_link
);
161 return bpf_serialize_link(f
, fds
, "restrict-ifaces-bpf-fd", u
->restrict_ifaces_egress_bpf_link
);
164 int restrict_network_interfaces_add_initial_link_fd(Unit
*u
, int fd
) {
169 if (!u
->initial_restric_ifaces_link_fds
) {
170 u
->initial_restric_ifaces_link_fds
= fdset_new();
171 if (!u
->initial_restric_ifaces_link_fds
)
175 r
= fdset_put(u
->initial_restric_ifaces_link_fds
, fd
);
177 return log_unit_error_errno(u
, r
,
178 "restrict-interfaces: Failed to put restrict-ifaces-bpf-fd %d to restored fdset: %m", fd
);
183 #else /* ! BPF_FRAMEWORK */
184 int restrict_network_interfaces_supported(void) {
188 int restrict_network_interfaces_install(Unit
*u
) {
189 return log_unit_debug_errno(u
, SYNTHETIC_ERRNO(EOPNOTSUPP
),
190 "restrict-interfaces: Failed to install; BPF programs built from source code are not supported: %m");
193 int serialize_restrict_network_interfaces(Unit
*u
, FILE *f
, FDSet
*fds
) {
197 int restrict_network_interfaces_add_initial_link_fd(Unit
*u
, int fd
) {