]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/restrict-ifaces.c
Merge pull request #29458 from poettering/serialize-pidref
[thirdparty/systemd.git] / src / core / restrict-ifaces.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
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"
12 #include "bpf-util.h"
13 #include "bpf/restrict_ifaces/restrict-ifaces-skel.h"
14
15 static struct restrict_ifaces_bpf *restrict_ifaces_bpf_free(struct restrict_ifaces_bpf *obj) {
16 restrict_ifaces_bpf__destroy(obj);
17 return NULL;
18 }
19
20 DEFINE_TRIVIAL_CLEANUP_FUNC(struct restrict_ifaces_bpf *, restrict_ifaces_bpf_free);
21
22 static int prepare_restrict_ifaces_bpf(
23 Unit* u,
24 bool is_allow_list,
25 const Set *restrict_network_interfaces,
26 struct restrict_ifaces_bpf **ret_object) {
27
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)
37 return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, errno, "restrict-interfaces: Failed to open BPF object: %m");
38
39 r = sym_bpf_map__set_max_entries(obj->maps.sd_restrictif, MAX(set_size(restrict_network_interfaces), 1u));
40 if (r != 0)
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));
44
45 obj->rodata->is_allow_list = is_allow_list;
46
47 r = restrict_ifaces_bpf__load(obj);
48 if (r != 0)
49 return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, r, "restrict-interfaces: Failed to load BPF object: %m");
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;
56
57 ifindex = rtnl_resolve_interface(&rtnl, iface);
58 if (ifindex < 0) {
59 log_unit_warning_errno(u, ifindex,
60 "restrict-interfaces: Couldn't find index of network interface '%s', ignoring: %m",
61 iface);
62 continue;
63 }
64
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));
69 }
70
71 *ret_object = TAKE_PTR(obj);
72 return 0;
73 }
74
75 int restrict_network_interfaces_supported(void) {
76 _cleanup_(restrict_ifaces_bpf_freep) struct restrict_ifaces_bpf *obj = NULL;
77 static int supported = -1;
78 int r;
79
80 if (supported >= 0)
81 return supported;
82
83 if (!cgroup_bpf_supported())
84 return (supported = false);
85
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);
89 }
90
91 r = prepare_restrict_ifaces_bpf(NULL, true, NULL, &obj);
92 if (r < 0) {
93 log_debug_errno(r, "restrict-interfaces: Failed to load BPF object: %m");
94 return (supported = false);
95 }
96
97 return (supported = bpf_can_link_program(obj->progs.sd_restrictif_i));
98 }
99
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;
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)
114 return log_unit_error_errno(u, r, "restrict-interfaces: Failed to get cgroup path: %m");
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)
133 return log_unit_error_errno(u, r, "restrict-interfaces: Failed to create ingress cgroup link: %m");
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)
138 return log_unit_error_errno(u, r, "restrict-interfaces: Failed to create egress cgroup link: %m");
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
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);
149 return r;
150 }
151
152 int 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
164 int 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)
177 return log_unit_error_errno(u, r,
178 "restrict-interfaces: Failed to put restrict-ifaces-bpf-fd %d to restored fdset: %m", fd);
179
180 return 0;
181 }
182
183 #else /* ! BPF_FRAMEWORK */
184 int restrict_network_interfaces_supported(void) {
185 return 0;
186 }
187
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");
191 }
192
193 int serialize_restrict_network_interfaces(Unit *u, FILE *f, FDSet *fds) {
194 return 0;
195 }
196
197 int restrict_network_interfaces_add_initial_link_fd(Unit *u, int fd) {
198 return 0;
199 }
200 #endif