dhcpcd-discuss

Re: seccomp violation (unexpected syscall 55)

Roy Marples

Fri Dec 11 22:14:56 2020

Hi Mantas

On 11/12/2020 13:54, Mantas Mikulėnas wrote:
On Arch Linux x86_64, dhcpcd 9.3.4 will exit several seconds after
startup with SIGSYS and (after rebuilding with seccomp debugging) the
following message:

dhcpcd[556]: ps_seccomp_violation: unexpected syscall 55 (arch=0xc000003e)
dhcpcd[556]: ps_ctl_listen: read: Success

Syscall 55 seems to be getsockopt() here. The crash appears to happen
as soon as the Bird routing daemon starts, so I suspect it's related
to Bird inserting thousands of kernel routes and dhcpcd receiving
thousands of "new route added" messages over its netlink socket, at
which point it will call getsockopt() from dhcpcd_linkoverflow()...

The full service log is:

systemd[1]: Starting dhcpcd@eno1.service...
dhcpcd[545]: dhcpcd-9.3.4 starting
dhcpcd[556]: DUID 00:04:38:4a:31:51:41:35:5a:43:31:37:30:31:30:30:4e:30
dhcpcd[556]: eno1: waiting for carrier
dhcpcd[556]: eno1: carrier acquired
dhcpcd[556]: eno1: IAID 82:38:e4:80
dhcpcd[556]: eno1: adding address fe80::9618:82ff:fe38:e480
dhcpcd[556]: eno1: rebinding lease of 193.219.181.219
dhcpcd[556]: eno1: soliciting an IPv6 router
dhcpcd[556]: eno1: DHCP lease expired
dhcpcd[545]: eno1: DHCP lease expired
dhcpcd[556]: eno1: soliciting a DHCP lease
dhcpcd[556]: eno1: offered 193.219.181.219 from 193.219.181.204
dhcpcd[556]: eno1: probing address 193.219.181.219/26
dhcpcd[556]: eno1: Router Advertisement from fe80::215:17ff:fe91:dba3
dhcpcd[556]: eno1: adding address 2001:778:e27f:0:9618:82ff:fe38:e480/64
dhcpcd[556]: eno1: adding route to 2001:778:e27f::/64
dhcpcd[556]: eno1: adding default route via fe80::215:17ff:fe91:dba3
systemd[1]: Started dhcpcd@eno1.service.
dhcpcd[556]: gre-home: new hardware address: (null)
dhcpcd[556]: gre-land: new hardware address: (null)
dhcpcd[556]: gre-sky: new hardware address: (null)
dhcpcd[556]: gre-star: new hardware address: (null)
dhcpcd[556]: gre-wind: new hardware address: (null)
dhcpcd[556]: eno1: leased 193.219.181.219 for 3600 seconds
dhcpcd[556]: eno1: adding route to 193.219.181.192/26
dhcpcd[556]: eno1: adding default route via 193.219.181.193
dhcpcd[556]: gre-wolke: new hardware address: (null)
dhcpcd[556]: ps_seccomp_violation: unexpected syscall 55 (arch=0xc000003e)
dhcpcd[556]: ps_ctl_listen: read: Success
systemd[1]: dhcpcd@eno1.service: Main process exited, code=exited,
status=1/FAILURE
dhcpcd[556]: ps_sendcmdmsg: Connection refused
dhcpcd[556]: ps_inet_recvra: Connection refused
systemd[1]: dhcpcd@eno1.service: State 'stop-sigterm' timed out. Killing.
systemd[1]: dhcpcd@eno1.service: Killing process 556 (dhcpcd) with
signal SIGKILL.
systemd[1]: dhcpcd@eno1.service: Killing process 601 (dhcpcd) with
signal SIGKILL.
systemd[1]: dhcpcd@eno1.service: Killing process 603 (dhcpcd) with
signal SIGKILL.
systemd[1]: dhcpcd@eno1.service: Killing process 634 (dhcpcd) with
signal SIGKILL.
systemd[1]: dhcpcd@eno1.service: Killing process 852 (dhcpcd) with
signal SIGKILL.
systemd[1]: dhcpcd@eno1.service: Failed with result 'exit-code'.

Hmmmm yes.
The attached patch allows this and should clean up the new hardware address: null messages.

Let me know how it works for you.

Roy
diff --git a/src/dhcpcd.c b/src/dhcpcd.c
index 306d1d00..908d4d4a 100644
--- a/src/dhcpcd.c
+++ b/src/dhcpcd.c
@@ -695,33 +695,52 @@ dhcpcd_reportssid(struct interface *ifp)
 	loginfox("%s: connected to Access Point: %s", ifp->name, pssid);
 }
 
+static void
+dhcpcd_abort(struct interface *ifp)
+{
+
+#ifdef ARP
+	arp_drop(ifp);
+#endif
+#ifdef INET
+	dhcp_abort(ifp);
+#endif
+#ifdef DHCP6
+	dhcp6_abort(ifp);
+#endif
+}
+
 void
 dhcpcd_handlecarrier(struct interface *ifp, int carrier, unsigned int flags)
 {
 	bool was_link_up = if_is_link_up(ifp);
+	bool was_roaming = if_roaming(ifp);
 
 	ifp->carrier = carrier;
 	ifp->flags = flags;
 
 	if (!if_is_link_up(ifp)) {
-		if (!was_link_up || !ifp->active)
+		if (!ifp->active || (!was_link_up && !was_roaming))
 			return;
 		loginfox("%s: carrier lost", ifp->name);
 		script_runreason(ifp, "NOCARRIER");
+
+		/*
+		 * If the interface is roaming (generally on wireless)
+		 * then while we are not up, we are not down either.
+		 * Preserve the network state until we either disconnect
+		 * or re-connect.
+		 */
+		if (if_roaming(ifp)) {
+			dhcpcd_abort(ifp);
+			return;
+		}
+
 #ifdef NOCARRIER_PRESERVE_IP
 		if (ifp->flags & IFF_UP &&
 		    !(ifp->options->options & DHCPCD_ANONYMOUS))
-		{
-#ifdef ARP
-			arp_drop(ifp);
-#endif
-#ifdef INET
-			dhcp_abort(ifp);
-#endif
-#ifdef DHCP6
-			dhcp6_abort(ifp);
-#endif
-		} else
+			dhcpcd_abort(ifp);
+		else
 #endif
 			dhcpcd_drop(ifp, 0);
 		if (ifp->options->options & DHCPCD_ANONYMOUS) {
@@ -774,9 +793,7 @@ dhcpcd_handlecarrier(struct interface *ifp, int carrier, unsigned int flags)
 		    memcmp(ifp->ssid, ossid, ifp->ssid_len)) && ifp->active)
 		{
 			dhcpcd_reportssid(ifp);
-#ifdef NOCARRIER_PRESERVE_IP
 			dhcpcd_drop(ifp, 0);
-#endif
 #ifdef IPV4LL
 			ipv4ll_reset(ifp);
 #endif
@@ -788,17 +805,17 @@ dhcpcd_handlecarrier(struct interface *ifp, int carrier, unsigned int flags)
 
 	dhcpcd_initstate(ifp, 0);
 	script_runreason(ifp, "CARRIER");
+
 #ifdef INET6
-#ifdef NOCARRIER_PRESERVE_IP
 	/* Set any IPv6 Routers we remembered to expire faster than they
 	 * would normally as we maybe on a new network. */
 	ipv6nd_startexpire(ifp);
-#endif
 #ifdef IPV6_MANAGETEMPADDR
 	/* RFC4941 Section 3.5 */
 	ipv6_regentempaddrs(ifp);
 #endif
 #endif
+
 	dhcpcd_startinterface(ifp);
 }
 
diff --git a/src/if-bsd.c b/src/if-bsd.c
index 94f58b31..62e4a83c 100644
--- a/src/if-bsd.c
+++ b/src/if-bsd.c
@@ -410,6 +410,13 @@ if_carrier(struct interface *ifp, const void *ifadata)
 	return LINK_DOWN;
 }
 
+bool
+if_roaming(__unused struct interface *ifp)
+{
+
+	return false;
+}
+
 static void
 if_linkaddr(struct sockaddr_dl *sdl, const struct interface *ifp)
 {
diff --git a/src/if-linux.c b/src/if-linux.c
index eaa5a4d6..69f75e12 100644
--- a/src/if-linux.c
+++ b/src/if-linux.c
@@ -515,6 +515,21 @@ if_carrier(struct interface *ifp, __unused const void *ifadata)
 	return ifp->flags & IFF_RUNNING ? LINK_UP : LINK_DOWN;
 }
 
+bool
+if_roaming(struct interface *ifp)
+{
+
+#ifdef IFF_LOWER_UP
+	if (!ifp->wireless ||
+	    ifp->flags & IFF_RUNNING ||
+	    (ifp->flags & (IFF_UP | IFF_LOWER_UP)) != (IFF_UP | IFF_LOWER_UP))
+		return false;
+	return true;
+#else
+	return false;
+#endif
+}
+
 int
 if_getnetlink(struct dhcpcd_ctx *ctx, struct iovec *iov, int fd, int flags,
     int (*cb)(struct dhcpcd_ctx *, void *, struct nlmsghdr *), void *cbarg)
diff --git a/src/if-sun.c b/src/if-sun.c
index 51c0cfd5..019076e7 100644
--- a/src/if-sun.c
+++ b/src/if-sun.c
@@ -245,6 +245,13 @@ err:
 	return LINK_UNKNOWN;
 }
 
+bool
+if_roaming(__unused struct interface *ifp)
+{
+
+	return false;
+}
+
 int
 if_mtu_os(const struct interface *ifp)
 {
diff --git a/src/if.h b/src/if.h
index 8474deb7..9a2f262a 100644
--- a/src/if.h
+++ b/src/if.h
@@ -161,6 +161,7 @@ int if_domtu(const struct interface *, short int);
 #define if_getmtu(ifp) if_domtu((ifp), 0)
 #define if_setmtu(ifp, mtu) if_domtu((ifp), (mtu))
 int if_carrier(struct interface *, const void *);
+bool if_roaming(struct interface *);
 
 #ifdef ALIAS_ADDR
 int if_makealias(char *, size_t, const char *, int);
diff --git a/src/ipv6nd.c b/src/ipv6nd.c
index f0a79d51..b9ba57f4 100644
--- a/src/ipv6nd.c
+++ b/src/ipv6nd.c
@@ -1155,7 +1155,6 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 		return;
 	}
 
-#ifdef NOCARRIER_PRESERVE_IP
 	/*
 	 * Because we preserve RA's and expire them quickly after
 	 * carrier up, it's important to reset the kernels notion of
@@ -1168,7 +1167,6 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
 	}
 	if (rap != NULL && rap->willexpire)
 		ipv6nd_applyra(ifp);
-#endif
 
 	TAILQ_FOREACH(rap, ctx->ra_routers, next) {
 		if (ifp == rap->iface &&

Follow-Ups:
Re: seccomp violation (unexpected syscall 55)Roy Marples
References:
seccomp violation (unexpected syscall 55)Mantas Mikulėnas
Archive administrator: postmaster@marples.name