From f2ef8b28a5266a0070b0cb8b6375e418a5300975 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 May 2021 10:37:18 +0200 Subject: [PATCH 1/4] networkd: add bus property exposing network namepace ID we run in This is useful for clients to determine whether they are running in the same network namespace as networkd. Note that access to /proc/$PID/ns/ is restricted and only permitted to equally privileged programs. This new bus property is primarily a way to work around this, so that unprivileged clients can determine the networkd netns, too. --- src/network/networkd-manager-bus.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c index 23c1fb57c6..1c6230b393 100644 --- a/src/network/networkd-manager-bus.c +++ b/src/network/networkd-manager-bus.c @@ -263,6 +263,34 @@ static int bus_method_describe(sd_bus_message *message, void *userdata, sd_bus_e return sd_bus_send(NULL, reply, NULL); } +static int property_get_namespace_id( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + uint64_t id = 0; + struct stat st; + + assert(bus); + assert(reply); + + /* Returns our own network namespace ID, i.e. the inode number of /proc/self/ns/net. This allows + * unprivileged clients to determine whether they are in the same network namespace as us (note that + * access to that path is restricted, thus they can't check directly unless privileged). */ + + if (stat("/proc/self/ns/net", &st) < 0) { + log_warning_errno(errno, "Failed to stat network namespace, ignoring: %m"); + id = 0; + } else + id = st.st_ino; + + return sd_bus_message_append(reply, "t", id); +} + const sd_bus_vtable manager_vtable[] = { SD_BUS_VTABLE_START(0), @@ -272,6 +300,7 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_PROPERTY("IPv4AddressState", "s", property_get_address_state, offsetof(Manager, ipv4_address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("IPv6AddressState", "s", property_get_address_state, offsetof(Manager, ipv6_address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("OnlineState", "s", property_get_online_state, offsetof(Manager, online_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("NamespaceId", "t", property_get_namespace_id, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_METHOD_WITH_ARGS("ListLinks", SD_BUS_NO_ARGS, From 3b085db3b67d72065defa94a823b8ac62131a0b7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 May 2021 10:39:33 +0200 Subject: [PATCH 2/4] networkctl: politely refuse being called from a different netns than the networkd instance we talk to Otherwise things get very confusing since we mix up netens data from our client side and from the data we retrieve from networkd. In the long run we should teach networkctl some switch to operate safely on other netns, and in that case also determine the right networkd instance for that namespace. Fixes: #19236 --- src/network/networkctl.c | 43 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 9d3e3f033b..619ef91288 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -2993,6 +2993,45 @@ static int networkctl_main(int argc, char *argv[]) { return dispatch_verb(argc, argv, verbs, NULL); } +static int check_netns_match(void) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + struct stat st; + uint64_t id; + int r; + + r = sd_bus_open_system(&bus); + if (r < 0) + return log_error_errno(r, "Failed to connect system bus: %m"); + + r = sd_bus_get_property_trivial( + bus, + "org.freedesktop.network1", + "/org/freedesktop/network1", + "org.freedesktop.network1.Manager", + "NamespaceId", + &error, + 't', + &id); + if (r < 0) { + log_debug_errno(r, "Failed to query network namespace of networkd, ignoring: %s", bus_error_message(&error, r)); + return 0; + } + if (id == 0) { + log_debug("systemd-networkd.service not running in a network namespace (?), skipping netns check."); + return 0; + } + + if (stat("/proc/self/ns/net", &st) < 0) + return log_error_errno(r, "Failed to determine our own network namespace ID: %m"); + + if (id != st.st_ino) + return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), + "networkctl must be invoked in same network namespace as systemd-networkd.service."); + + return 0; +} + static void warn_networkd_missing(void) { if (access("/run/systemd/netif/state", F_OK) >= 0) @@ -3010,6 +3049,10 @@ static int run(int argc, char* argv[]) { if (r <= 0) return r; + r = check_netns_match(); + if (r < 0) + return r; + warn_networkd_missing(); return networkctl_main(argc, argv); From 618da3e7d51df0c23d786c7b4dcdc41cba025971 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 26 May 2021 21:13:56 +0900 Subject: [PATCH 3/4] test-network: wait for that the link is in configuring state at the beginning --- test/test-network/systemd-networkd-tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index d6b790bc35..0c5fe461f4 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -2785,7 +2785,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): for iteration in range(4): with self.subTest(iteration=iteration, expect_up=expect_up): operstate = 'routable' if expect_up else 'off' - setup_state = 'configured' if expect_up else None + setup_state = 'configured' if expect_up else ('configuring' if iteration == 0 else None) self.wait_operstate('test1', operstate, setup_state=setup_state, setup_timeout=20) if expect_up: From 06043c78219e817b88dc3d1f74ebc2b7326cc9f6 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 26 May 2021 21:22:13 +0900 Subject: [PATCH 4/4] test-network: refuse RA if not necessary --- test/test-network/conf/25-activation-policy.network | 1 + test/test-network/conf/25-nexthop-dummy.network | 1 + test/test-network/conf/25-wireguard-23-peers.network | 1 + test/test-network/conf/25-wireguard.network | 1 + test/test-network/conf/agent-client-peer.network | 3 +++ test/test-network/conf/agent-client.network | 2 ++ test/test-network/conf/agent-server-peer.network | 2 ++ test/test-network/conf/agent-server.network | 2 ++ 8 files changed, 13 insertions(+) diff --git a/test/test-network/conf/25-activation-policy.network b/test/test-network/conf/25-activation-policy.network index c53e0919c4..873e260ebf 100644 --- a/test/test-network/conf/25-activation-policy.network +++ b/test/test-network/conf/25-activation-policy.network @@ -4,3 +4,4 @@ Name=test1 [Network] Address=192.168.10.30/24 Gateway=192.168.10.1 +IPv6AcceptRA=no diff --git a/test/test-network/conf/25-nexthop-dummy.network b/test/test-network/conf/25-nexthop-dummy.network index e494aca8e3..9d754bf25a 100644 --- a/test/test-network/conf/25-nexthop-dummy.network +++ b/test/test-network/conf/25-nexthop-dummy.network @@ -3,6 +3,7 @@ Name=dummy98 [Network] Address=192.168.20.20/24 +IPv6AcceptRA=no [NextHop] Id=20 diff --git a/test/test-network/conf/25-wireguard-23-peers.network b/test/test-network/conf/25-wireguard-23-peers.network index 033ffa155d..ee70e3c5e8 100644 --- a/test/test-network/conf/25-wireguard-23-peers.network +++ b/test/test-network/conf/25-wireguard-23-peers.network @@ -4,6 +4,7 @@ Name=wg98 [Network] Address=192.168.123.123/24 Address=fd8d:4d6d:3ccb:0500::1/64 +IPv6AcceptRA=no # nat64 via 1 [Route] diff --git a/test/test-network/conf/25-wireguard.network b/test/test-network/conf/25-wireguard.network index 163a56ff29..565e85ea8d 100644 --- a/test/test-network/conf/25-wireguard.network +++ b/test/test-network/conf/25-wireguard.network @@ -3,3 +3,4 @@ Name=wg99 [Network] Address=192.168.124.1/24 +IPv6AcceptRA=no diff --git a/test/test-network/conf/agent-client-peer.network b/test/test-network/conf/agent-client-peer.network index 4142938056..b053c2c6b4 100644 --- a/test/test-network/conf/agent-client-peer.network +++ b/test/test-network/conf/agent-client-peer.network @@ -1,9 +1,12 @@ [Match] Name=client-peer + [Network] Address=192.168.6.2/24 DHCPServer=yes IPForward=ipv4 +IPv6AcceptRA=no + [DHCPServer] RelayTarget=192.168.5.1 BindToInterface=no diff --git a/test/test-network/conf/agent-client.network b/test/test-network/conf/agent-client.network index 773dc8a4fb..7787bb631f 100644 --- a/test/test-network/conf/agent-client.network +++ b/test/test-network/conf/agent-client.network @@ -1,5 +1,7 @@ [Match] Name=client + [Network] DHCP=yes IPForward=ipv4 +IPv6AcceptRA=no diff --git a/test/test-network/conf/agent-server-peer.network b/test/test-network/conf/agent-server-peer.network index fdb235e1ff..6aec2974a8 100644 --- a/test/test-network/conf/agent-server-peer.network +++ b/test/test-network/conf/agent-server-peer.network @@ -1,5 +1,7 @@ [Match] Name=server-peer + [Network] Address=192.168.5.2/24 IPForward=ipv4 +IPv6AcceptRA=no diff --git a/test/test-network/conf/agent-server.network b/test/test-network/conf/agent-server.network index 65bcc54dc1..c8da15c3ec 100644 --- a/test/test-network/conf/agent-server.network +++ b/test/test-network/conf/agent-server.network @@ -1,9 +1,11 @@ [Match] Name=server + [Network] Address=192.168.5.1/24 IPForward=ipv4 DHCPServer=yes +IPv6AcceptRA=no [DHCPServer] BindToInterface=no