summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2020-05-26 23:27:20 +0200
committerYu Watanabe <watanabe.yu+github@gmail.com>2020-05-29 15:28:10 +0900
commitf6dbcebdc28cabf36e6665b67d52d43192fb88df (patch)
tree78e352676b149fb55ffdb080c28880cea35bf1ea /src
parent8abbd9a4d94ef3d66b4d04f0584921b35059c3f9 (diff)
downloadsystemd-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.h5
-rw-r--r--src/libsystemd/sd-device/device-monitor.c50
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) {