]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/restrict-ifaces.c
Merge pull request #29458 from poettering/serialize-pidref
[thirdparty/systemd.git] / src / core / restrict-ifaces.c
CommitLineData
948def4a 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
6f50d4f7
MV
2
3#include "fd-util.h"
4#include "restrict-ifaces.h"
5#include "netlink-util.h"
6
7#if BPF_FRAMEWORK
8/* libbpf, clang and llc compile time dependencies are satisfied */
9
10#include "bpf-dlopen.h"
11#include "bpf-link.h"
bb0b01ed 12#include "bpf-util.h"
d40ce018 13#include "bpf/restrict_ifaces/restrict-ifaces-skel.h"
6f50d4f7
MV
14
15static struct restrict_ifaces_bpf *restrict_ifaces_bpf_free(struct restrict_ifaces_bpf *obj) {
16 restrict_ifaces_bpf__destroy(obj);
17 return NULL;
18}
19
20DEFINE_TRIVIAL_CLEANUP_FUNC(struct restrict_ifaces_bpf *, restrict_ifaces_bpf_free);
21
cc8943b8
YW
22static int prepare_restrict_ifaces_bpf(
23 Unit* u,
24 bool is_allow_list,
6f50d4f7
MV
25 const Set *restrict_network_interfaces,
26 struct restrict_ifaces_bpf **ret_object) {
cc8943b8 27
6f50d4f7
MV
28 _cleanup_(restrict_ifaces_bpf_freep) struct restrict_ifaces_bpf *obj = NULL;
29 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
30 char *iface;
31 int r, map_fd;
32
33 assert(ret_object);
34
35 obj = restrict_ifaces_bpf__open();
36 if (!obj)
b1acbc08 37 return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, errno, "restrict-interfaces: Failed to open BPF object: %m");
6f50d4f7 38
6b8085db 39 r = sym_bpf_map__set_max_entries(obj->maps.sd_restrictif, MAX(set_size(restrict_network_interfaces), 1u));
6f50d4f7 40 if (r != 0)
8f048bb7 41 return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, r,
b1acbc08 42 "restrict-interfaces: Failed to resize BPF map '%s': %m",
6f50d4f7
MV
43 sym_bpf_map__name(obj->maps.sd_restrictif));
44
45 obj->rodata->is_allow_list = is_allow_list;
46
47 r = restrict_ifaces_bpf__load(obj);
48 if (r != 0)
b1acbc08 49 return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, r, "restrict-interfaces: Failed to load BPF object: %m");
6f50d4f7
MV
50
51 map_fd = sym_bpf_map__fd(obj->maps.sd_restrictif);
52
53 SET_FOREACH(iface, restrict_network_interfaces) {
54 uint8_t dummy = 0;
55 int ifindex;
cc8943b8 56
6f50d4f7
MV
57 ifindex = rtnl_resolve_interface(&rtnl, iface);
58 if (ifindex < 0) {
b1acbc08
ZJS
59 log_unit_warning_errno(u, ifindex,
60 "restrict-interfaces: Couldn't find index of network interface '%s', ignoring: %m",
61 iface);
6f50d4f7
MV
62 continue;
63 }
64
65 if (sym_bpf_map_update_elem(map_fd, &ifindex, &dummy, BPF_ANY))
8f048bb7 66 return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, errno,
b1acbc08 67 "restrict-interfaces: Failed to update BPF map '%s' fd: %m",
8f048bb7 68 sym_bpf_map__name(obj->maps.sd_restrictif));
6f50d4f7
MV
69 }
70
71 *ret_object = TAKE_PTR(obj);
72 return 0;
73}
74
75int restrict_network_interfaces_supported(void) {
76 _cleanup_(restrict_ifaces_bpf_freep) struct restrict_ifaces_bpf *obj = NULL;
6f50d4f7 77 static int supported = -1;
3de3fd3d 78 int r;
6f50d4f7
MV
79
80 if (supported >= 0)
81 return supported;
82
bb0b01ed
ZJS
83 if (!cgroup_bpf_supported())
84 return (supported = false);
6f50d4f7 85
87e462f7 86 if (!compat_libbpf_probe_bpf_prog_type(BPF_PROG_TYPE_CGROUP_SKB, /*opts=*/NULL)) {
b1acbc08 87 log_debug("restrict-interfaces: BPF program type cgroup_skb is not supported");
bb0b01ed 88 return (supported = false);
6f50d4f7
MV
89 }
90
91 r = prepare_restrict_ifaces_bpf(NULL, true, NULL, &obj);
3de3fd3d 92 if (r < 0) {
b1acbc08 93 log_debug_errno(r, "restrict-interfaces: Failed to load BPF object: %m");
bb0b01ed 94 return (supported = false);
3de3fd3d 95 }
6f50d4f7 96
bb0b01ed 97 return (supported = bpf_can_link_program(obj->progs.sd_restrictif_i));
6f50d4f7
MV
98}
99
100static 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;
254d1313 104 _cleanup_close_ int cgroup_fd = -EBADF;
6f50d4f7
MV
105 CGroupContext *cc;
106 int r;
107
108 cc = unit_get_cgroup_context(u);
109 if (!cc)
110 return 0;
111
112 r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, NULL, &cgroup_path);
113 if (r < 0)
b1acbc08 114 return log_unit_error_errno(u, r, "restrict-interfaces: Failed to get cgroup path: %m");
6f50d4f7
MV
115
116 if (!cc->restrict_network_interfaces)
117 return 0;
118
119 r = prepare_restrict_ifaces_bpf(u,
120 cc->restrict_network_interfaces_is_allow_list,
121 cc->restrict_network_interfaces,
122 &obj);
123 if (r < 0)
124 return r;
125
126 cgroup_fd = open(cgroup_path, O_RDONLY | O_CLOEXEC | O_DIRECTORY, 0);
127 if (cgroup_fd < 0)
128 return -errno;
129
130 ingress_link = sym_bpf_program__attach_cgroup(obj->progs.sd_restrictif_i, cgroup_fd);
131 r = sym_libbpf_get_error(ingress_link);
132 if (r != 0)
b1acbc08 133 return log_unit_error_errno(u, r, "restrict-interfaces: Failed to create ingress cgroup link: %m");
6f50d4f7
MV
134
135 egress_link = sym_bpf_program__attach_cgroup(obj->progs.sd_restrictif_e, cgroup_fd);
136 r = sym_libbpf_get_error(egress_link);
137 if (r != 0)
b1acbc08 138 return log_unit_error_errno(u, r, "restrict-interfaces: Failed to create egress cgroup link: %m");
6f50d4f7
MV
139
140 u->restrict_ifaces_ingress_bpf_link = TAKE_PTR(ingress_link);
141 u->restrict_ifaces_egress_bpf_link = TAKE_PTR(egress_link);
142
143 return 0;
144}
145
146int restrict_network_interfaces_install(Unit *u) {
147 int r = restrict_network_interfaces_install_impl(u);
148 fdset_close(u->initial_restric_ifaces_link_fds);
149 return r;
150}
151
152int serialize_restrict_network_interfaces(Unit *u, FILE *f, FDSet *fds) {
153 int r;
154
155 assert(u);
156
157 r = bpf_serialize_link(f, fds, "restrict-ifaces-bpf-fd", u->restrict_ifaces_ingress_bpf_link);
158 if (r < 0)
159 return r;
160
161 return bpf_serialize_link(f, fds, "restrict-ifaces-bpf-fd", u->restrict_ifaces_egress_bpf_link);
162}
163
164int restrict_network_interfaces_add_initial_link_fd(Unit *u, int fd) {
165 int r;
166
167 assert(u);
168
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)
172 return log_oom();
173 }
174
175 r = fdset_put(u->initial_restric_ifaces_link_fds, fd);
176 if (r < 0)
b1acbc08
ZJS
177 return log_unit_error_errno(u, r,
178 "restrict-interfaces: Failed to put restrict-ifaces-bpf-fd %d to restored fdset: %m", fd);
6f50d4f7
MV
179
180 return 0;
181}
182
183#else /* ! BPF_FRAMEWORK */
184int restrict_network_interfaces_supported(void) {
185 return 0;
186}
187
188int restrict_network_interfaces_install(Unit *u) {
189 return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP),
b1acbc08 190 "restrict-interfaces: Failed to install; BPF programs built from source code are not supported: %m");
6f50d4f7
MV
191}
192
193int serialize_restrict_network_interfaces(Unit *u, FILE *f, FDSet *fds) {
194 return 0;
195}
196
197int restrict_network_interfaces_add_initial_link_fd(Unit *u, int fd) {
198 return 0;
199}
200#endif