]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-manager.c
networkd: fix use-after-free
[thirdparty/systemd.git] / src / network / networkd-manager.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <resolv.h>
23
24 #include "path-util.h"
25 #include "networkd.h"
26 #include "libudev-private.h"
27 #include "udev-util.h"
28 #include "rtnl-util.h"
29 #include "mkdir.h"
30 #include "virt.h"
31
32 const char* const network_dirs[] = {
33 "/etc/systemd/network",
34 "/run/systemd/network",
35 "/usr/lib/systemd/network",
36 #ifdef HAVE_SPLIT_USR
37 "/lib/systemd/network",
38 #endif
39 NULL};
40
41 static int dispatch_sigterm(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
42 Manager *m = userdata;
43
44 assert(m);
45
46 log_received_signal(LOG_INFO, si);
47
48 sd_event_exit(m->event, 0);
49 return 0;
50 }
51
52 static int setup_signals(Manager *m) {
53 sigset_t mask;
54 int r;
55
56 assert(m);
57
58 assert_se(sigemptyset(&mask) == 0);
59 sigset_add_many(&mask, SIGINT, SIGTERM, -1);
60 assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
61
62 r = sd_event_add_signal(m->event, &m->sigterm_event_source, SIGTERM, dispatch_sigterm, m);
63 if (r < 0)
64 return r;
65
66 r = sd_event_add_signal(m->event, &m->sigint_event_source, SIGINT, dispatch_sigterm, m);
67 if (r < 0)
68 return r;
69
70 return 0;
71 }
72
73 int manager_new(Manager **ret) {
74 _cleanup_manager_free_ Manager *m = NULL;
75 int r;
76
77 m = new0(Manager, 1);
78 if (!m)
79 return -ENOMEM;
80
81 r = sd_event_default(&m->event);
82 if (r < 0)
83 return r;
84
85 sd_event_set_watchdog(m->event, true);
86
87 r = sd_rtnl_open(&m->rtnl, RTMGRP_LINK | RTMGRP_IPV4_IFADDR);
88 if (r < 0)
89 return r;
90
91 r = sd_bus_default_system(&m->bus);
92 if (r < 0 && r != -ENOENT) /* TODO: drop when we can rely on kdbus */
93 return r;
94
95 r = setup_signals(m);
96 if (r < 0)
97 return r;
98
99 m->udev = udev_new();
100 if (!m->udev)
101 return -ENOMEM;
102
103 /* udev does not initialize devices inside containers,
104 * so we rely on them being already initialized before
105 * entering the container */
106 if (detect_container(NULL) > 0) {
107 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "kernel");
108 if (!m->udev_monitor)
109 return -ENOMEM;
110 } else {
111 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
112 if (!m->udev_monitor)
113 return -ENOMEM;
114 }
115
116 m->links = hashmap_new(uint64_hash_func, uint64_compare_func);
117 if (!m->links)
118 return -ENOMEM;
119
120 m->netdevs = hashmap_new(string_hash_func, string_compare_func);
121 if (!m->netdevs)
122 return -ENOMEM;
123
124 LIST_HEAD_INIT(m->networks);
125
126 *ret = m;
127 m = NULL;
128
129 return 0;
130 }
131
132 void manager_free(Manager *m) {
133 Network *network;
134 NetDev *netdev;
135 Link *link;
136
137 if (!m)
138 return;
139
140 udev_monitor_unref(m->udev_monitor);
141 udev_unref(m->udev);
142 sd_bus_unref(m->bus);
143 sd_event_source_unref(m->udev_event_source);
144 sd_event_source_unref(m->sigterm_event_source);
145 sd_event_source_unref(m->sigint_event_source);
146 sd_event_unref(m->event);
147
148 while ((link = hashmap_first(m->links)))
149 link_free(link);
150 hashmap_free(m->links);
151
152 while ((network = m->networks))
153 network_free(network);
154
155 while ((netdev = hashmap_first(m->netdevs)))
156 netdev_free(netdev);
157 hashmap_free(m->netdevs);
158
159 sd_rtnl_unref(m->rtnl);
160
161 free(m);
162 }
163
164 int manager_load_config(Manager *m) {
165 int r;
166
167 /* update timestamp */
168 paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
169
170 r = netdev_load(m);
171 if (r < 0)
172 return r;
173
174 r = network_load(m);
175 if (r < 0)
176 return r;
177
178 return 0;
179 }
180
181 bool manager_should_reload(Manager *m) {
182 return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
183 }
184
185 static int manager_process_link(Manager *m, struct udev_device *device) {
186 Link *link = NULL;
187 int r;
188
189 assert(m);
190 assert(device);
191
192 link_get(m, udev_device_get_ifindex(device), &link);
193
194 if (streq_ptr(udev_device_get_action(device), "remove")) {
195 log_debug("%s: link removed", udev_device_get_sysname(device));
196
197 if (link)
198 link_free(link);
199 } else {
200 if (link) {
201 log_debug("%s: link already exists, ignoring",
202 link->ifname);
203 return 0;
204 }
205
206 r = link_add(m, device, &link);
207 if (r < 0) {
208 log_error("%s: could not handle link: %s",
209 udev_device_get_sysname(device),
210 strerror(-r));
211 } else
212 log_debug("%s: link (with ifindex %" PRIu64") added",
213 link->ifname, link->ifindex);
214 }
215
216 return 0;
217 }
218
219 int manager_udev_enumerate_links(Manager *m) {
220 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
221 struct udev_list_entry *item = NULL, *first = NULL;
222 int r;
223
224 assert(m);
225
226 e = udev_enumerate_new(m->udev);
227 if (!e)
228 return -ENOMEM;
229
230 r = udev_enumerate_add_match_subsystem(e, "net");
231 if (r < 0)
232 return r;
233
234 /* udev does not initialize devices inside containers,
235 * so we rely on them being already initialized before
236 * entering the container */
237 if (detect_container(NULL) <= 0) {
238 r = udev_enumerate_add_match_is_initialized(e);
239 if (r < 0)
240 return r;
241 }
242
243 r = udev_enumerate_scan_devices(e);
244 if (r < 0)
245 return r;
246
247 first = udev_enumerate_get_list_entry(e);
248 udev_list_entry_foreach(item, first) {
249 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
250 int k;
251
252 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
253 if (!d)
254 return -ENOMEM;
255
256 k = manager_process_link(m, d);
257 if (k < 0)
258 r = k;
259 }
260
261 return r;
262 }
263
264 static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
265 Manager *m = userdata;
266 struct udev_monitor *monitor = m->udev_monitor;
267 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
268
269 device = udev_monitor_receive_device(monitor);
270 if (!device)
271 return -ENOMEM;
272
273 manager_process_link(m, device);
274 return 0;
275 }
276
277 int manager_udev_listen(Manager *m) {
278 int r;
279
280 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
281 if (r < 0) {
282 log_error("Could not add udev monitor filter: %s", strerror(-r));
283 return r;
284 }
285
286 r = udev_monitor_enable_receiving(m->udev_monitor);
287 if (r < 0) {
288 log_error("Could not enable udev monitor");
289 return r;
290 }
291
292 r = sd_event_add_io(m->event,
293 &m->udev_event_source,
294 udev_monitor_get_fd(m->udev_monitor),
295 EPOLLIN, manager_dispatch_link_udev,
296 m);
297 if (r < 0)
298 return r;
299
300 return 0;
301 }
302
303 static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
304 Manager *m = userdata;
305 Link *link;
306 char *name;
307 int r, ifindex;
308
309 assert(rtnl);
310 assert(message);
311 assert(m);
312
313 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
314 if (r < 0 || ifindex <= 0) {
315 log_warning("received RTM_NEWLINK message without valid ifindex");
316 return 0;
317 }
318
319 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &name);
320 if (r < 0)
321 log_warning("received RTM_NEWLINK message without valid ifname");
322 else {
323 NetDev *netdev;
324
325 r = netdev_get(m, name, &netdev);
326 if (r >= 0)
327 netdev_set_ifindex(netdev, message);
328 }
329
330 r = link_get(m, ifindex, &link);
331 if (r < 0) {
332 log_debug("received RTM_NEWLINK message for untracked ifindex %d", ifindex);
333 return 0;
334 }
335
336 /* only track the status of links we want to manage */
337 if (link->network) {
338 r = link_update(link, message);
339 if (r < 0)
340 return 0;
341 } else
342 log_debug("%s: received RTM_NEWLINK message for unmanaged link", link->ifname);
343
344 return 1;
345 }
346
347 int manager_rtnl_listen(Manager *m) {
348 int r;
349
350 r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
351 if (r < 0)
352 return r;
353
354 r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
355 if (r < 0)
356 return r;
357
358 return 0;
359 }
360
361 int manager_bus_listen(Manager *m) {
362 int r;
363
364 assert(m->event);
365
366 if (!m->bus) /* TODO: drop when we can rely on kdbus */
367 return 0;
368
369 r = sd_bus_attach_event(m->bus, m->event, 0);
370 if (r < 0)
371 return r;
372
373 return 0;
374 }
375
376 static void append_dns(FILE *f, struct in_addr *dns, unsigned char family, unsigned *count) {
377 char buf[INET6_ADDRSTRLEN];
378 const char *address;
379
380 address = inet_ntop(family, dns, buf, INET6_ADDRSTRLEN);
381 if (!address) {
382 log_warning("Invalid DNS address. Ignoring.");
383 return;
384 }
385
386 if (*count == MAXNS)
387 fputs("# Too many DNS servers configured, the following entries "
388 "will be ignored\n", f);
389
390 fprintf(f, "nameserver %s\n", address);
391
392 (*count) ++;
393 }
394
395 int manager_update_resolv_conf(Manager *m) {
396 _cleanup_free_ char *temp_path = NULL;
397 _cleanup_fclose_ FILE *f = NULL;
398 Link *link;
399 Iterator i;
400 unsigned count = 0;
401 const char *domainname = NULL;
402 int r;
403
404 assert(m);
405
406 r = fopen_temporary("/run/systemd/network/resolv.conf", &f, &temp_path);
407 if (r < 0)
408 return r;
409
410 fchmod(fileno(f), 0644);
411
412 fputs("# This file is managed by systemd-networkd(8). Do not edit.\n#\n"
413 "# Third party programs must not access this file directly, but\n"
414 "# only through the symlink at /etc/resolv.conf. To manage\n"
415 "# resolv.conf(5) in a different way, replace the symlink by a\n"
416 "# static file or a different symlink.\n\n", f);
417
418 HASHMAP_FOREACH(link, m->links, i) {
419 if (link->dhcp_lease) {
420 struct in_addr *nameservers;
421 size_t nameservers_size;
422
423 if (link->network->dhcp_dns) {
424 r = sd_dhcp_lease_get_dns(link->dhcp_lease, &nameservers, &nameservers_size);
425 if (r >= 0) {
426 unsigned j;
427
428 for (j = 0; j < nameservers_size; j++)
429 append_dns(f, &nameservers[j], AF_INET, &count);
430 }
431 }
432
433 if (link->network->dhcp_domainname && !domainname) {
434 r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
435 if (r >= 0)
436 fprintf(f, "domain %s\n", domainname);
437 }
438 }
439 }
440
441 HASHMAP_FOREACH(link, m->links, i) {
442 if (link->network && link->network->dns) {
443 Address *address;
444 Iterator j;
445
446 SET_FOREACH(address, link->network->dns, j) {
447 append_dns(f, &address->in_addr.in,
448 address->family, &count);
449 }
450 }
451 }
452
453 fflush(f);
454
455 if (ferror(f) || rename(temp_path, "/run/systemd/network/resolv.conf") < 0) {
456 r = -errno;
457 unlink("/run/systemd/network/resolv.conf");
458 unlink(temp_path);
459 return r;
460 }
461
462 return 0;
463 }