From: Lennart Poettering Date: Tue, 26 May 2020 21:27:20 +0000 (+0200) Subject: sd-device: check netlink netns matches host netns before using monitor X-Git-Tag: v246-rc1~256 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f6dbcebdc28cabf36e6665b67d52d43192fb88df;p=thirdparty%2Fsystemd.git sd-device: check netlink netns matches host netns before using monitor Tracking down #15931 confused the hell out of me, since running homed in gdb from the command line worked fine, but doing so as a service failed. Let's make this more debuggable and check if we live in the host netns when allocating a new udev monitor. This is just debug stuff, so that if things don't work, a quick debug run will reveal what is going on. That said, while we are at it, also fix unexpected closing of passed in fd when failing. --- diff --git a/src/basic/missing_socket.h b/src/basic/missing_socket.h index 276be366c3d..8c3fec1e350 100644 --- a/src/basic/missing_socket.h +++ b/src/basic/missing_socket.h @@ -62,3 +62,8 @@ struct sockaddr_vm { #ifndef IP_TRANSPARENT #define IP_TRANSPARENT 19 #endif + +/* linux/sockios.h */ +#ifndef SIOCGSKNS +#define SIOCGSKNS 0x894C +#endif diff --git a/src/libsystemd/sd-device/device-monitor.c b/src/libsystemd/sd-device/device-monitor.c index 20a422c77cf..ee8005833de 100644 --- a/src/libsystemd/sd-device/device-monitor.c +++ b/src/libsystemd/sd-device/device-monitor.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include "sd-device.h" @@ -13,10 +15,12 @@ #include "device-monitor-private.h" #include "device-private.h" #include "device-util.h" +#include "errno-util.h" #include "fd-util.h" #include "format-util.h" #include "hashmap.h" #include "io-util.h" +#include "missing_socket.h" #include "mountpoint-util.h" #include "set.h" #include "socket-util.h" @@ -163,12 +167,54 @@ int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group, if (fd >= 0) { r = monitor_set_nl_address(m); - if (r < 0) - return log_debug_errno(r, "sd-device-monitor: Failed to set netlink address: %m"); + if (r < 0) { + log_debug_errno(r, "sd-device-monitor: Failed to set netlink address: %m"); + goto fail; + } + } + + if (DEBUG_LOGGING) { + _cleanup_close_ int netns = -1; + + /* So here's the thing: only AF_NETLINK sockets from the main network namespace will get + * hardware events. Let's check if ours is from there, and if not generate a debug message, + * since we cannot possibly work correctly otherwise. This is just a safety check to make + * things easier to debug. */ + + netns = ioctl(m->sock, SIOCGSKNS); + if (netns < 0) + log_debug_errno(errno, "sd-device-monitor: Unable to get network namespace of udev netlink socket, unable to determine if we are in host netns: %m"); + else { + struct stat a, b; + + if (fstat(netns, &a) < 0) { + r = log_debug_errno(errno, "sd-device-monitor: Failed to stat netns of udev netlink socket: %m"); + goto fail; + } + + if (stat("/proc/1/ns/net", &b) < 0) { + if (ERRNO_IS_PRIVILEGE(errno)) + /* If we can't access PID1's netns info due to permissions, it's fine, this is a + * safety check only after all. */ + log_debug_errno(errno, "sd-device-monitor: No permission to stat PID1's netns, unable to determine if we are in host netns: %m"); + else + log_debug_errno(errno, "sd-device-monitor: Failed to stat PID1's netns: %m"); + + } else if (a.st_dev != b.st_dev || a.st_ino != b.st_ino) + log_debug("sd-device-monitor: Netlink socket we listen on is not from host netns, we won't see device events."); + } } *ret = TAKE_PTR(m); return 0; + +fail: + /* Let's unset the socket fd in the monitor object before we destroy it so that the fd passed in is + * not closed on failure. */ + if (fd >= 0) + m->sock = -1; + + return r; } _public_ int sd_device_monitor_new(sd_device_monitor **ret) {