diff options
author | Lennart Poettering <lennart@poettering.net> | 2020-05-26 23:27:20 +0200 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2020-05-29 15:28:10 +0900 |
commit | f6dbcebdc28cabf36e6665b67d52d43192fb88df (patch) | |
tree | 78e352676b149fb55ffdb080c28880cea35bf1ea /src | |
parent | 8abbd9a4d94ef3d66b4d04f0584921b35059c3f9 (diff) | |
download | systemd-f6dbcebdc28cabf36e6665b67d52d43192fb88df.tar.gz |
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/basic/missing_socket.h | 5 | ||||
-rw-r--r-- | src/libsystemd/sd-device/device-monitor.c | 50 |
2 files changed, 53 insertions, 2 deletions
diff --git a/src/basic/missing_socket.h b/src/basic/missing_socket.h index 276be366c3..8c3fec1e35 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 20a422c77c..ee8005833d 100644 --- a/src/libsystemd/sd-device/device-monitor.c +++ b/src/libsystemd/sd-device/device-monitor.c @@ -3,6 +3,8 @@ #include <errno.h> #include <linux/filter.h> #include <linux/netlink.h> +#include <linux/sockios.h> +#include <sys/ioctl.h> #include <unistd.h> #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) { |