changeset 4948:b664b38faf10 draft

ioctl: The POSIX signature differs from BSD and glibc BSD and glibc have the signature for request as unsigned long. musl and Solaris have a signed int. As such, we need to detect this at compile time and adjust the signature of our internal ioctl functions to match. To keep the onwire format the same, memcpy the request to the unsigned long request and back again, thus preserving the signedness.
author Roy Marples <roy@marples.name>
date Wed, 08 Jan 2020 20:13:20 +0000
parents 5d4046aa9571
children a8410b82249b
files configure src/if.c src/if.h src/privsep-bpf.c src/privsep-inet.c src/privsep-root.c src/privsep-root.h
diffstat 7 files changed, 60 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/configure	Wed Jan 08 16:57:46 2020 +0000
+++ b/configure	Wed Jan 08 20:13:20 2020 +0000
@@ -549,7 +549,7 @@
 			fi
 		done
 	fi
-	: ${PRIVSEP_USER:= _dhcpcd}
+	: ${PRIVSEP_USER:=_dhcpcd}
 
 	echo "CPPFLAGS+=	-DPRIVSEP" >>$CONFIG_MK
 	echo "#ifndef PRIVSEP_USER" >>$CONFIG_H
@@ -737,6 +737,27 @@
 rm -f _clock_gettime.c _clock_gettime
 $abort && exit 1
 
+printf "Testing ioctl request type ... "
+cat <<EOF >_ioctl.c
+#include <sys/ioctl.h>
+int main(void) {
+	unsigned long req = 0;
+	return ioctl(3, req, &req);
+}
+EOF
+if $XCC _ioctl.c -o _ioctl 2>&3; then
+	IOCTL_REQ="unsigned long"
+else
+	IOCTL_REQ="int"
+fi
+echo "$IOCTL_REQ"
+# Our default is unsigned long
+# We can still define it, but it makes the code path slightly bigger
+if [ "$IOCTL_REQ" != "unsigned long" ]; then
+	echo "#define	IOCTL_REQUEST_TYPE	$IOCTL_REQ" >>$CONFIG_H
+fi
+rm -f _ioctl.c _ioctl
+
 printf "Testing for inet_ntoa ... "
 cat <<EOF >_inet_ntoa.c
 #include <netinet/in.h>
--- a/src/if.c	Wed Jan 08 16:57:46 2020 +0000
+++ b/src/if.c	Wed Jan 08 20:13:20 2020 +0000
@@ -133,7 +133,7 @@
 }
 
 int
-if_ioctl(struct dhcpcd_ctx *ctx, unsigned long req, void *data, size_t len)
+if_ioctl(struct dhcpcd_ctx *ctx, ioctl_request_t req, void *data, size_t len)
 {
 
 #ifdef PRIVSEP
--- a/src/if.h	Wed Jan 08 16:57:46 2020 +0000
+++ b/src/if.h	Wed Jan 08 20:13:20 2020 +0000
@@ -62,6 +62,16 @@
 #endif
 
 #include "config.h"
+
+/* POSIX defines ioctl request as an int, which Solaris and musl use.
+ * Everyone else use an unsigned long, which happens to be the bigger one
+ * so we use that in our on wire API. */
+#ifdef IOCTL_REQUEST_TYPE
+typedef IOCTL_REQUEST_TYPE	ioctl_request_t;
+#else
+typedef unsigned long		ioctl_request_t;
+#endif
+
 #include "dhcpcd.h"
 #include "ipv4.h"
 #include "ipv6.h"
@@ -110,7 +120,7 @@
 int if_getsubnet(struct dhcpcd_ctx *, const char *, int, void *, size_t);
 #endif
 
-int if_ioctl(struct dhcpcd_ctx *, unsigned long, void *, size_t);
+int if_ioctl(struct dhcpcd_ctx *, ioctl_request_t, void *, size_t);
 int if_getflags(struct interface *ifp);
 int if_setflag(struct interface *ifp, short flag);
 #define if_up(ifp) if_setflag((ifp), (IFF_UP | IFF_RUNNING))
--- a/src/privsep-bpf.c	Wed Jan 08 16:57:46 2020 +0000
+++ b/src/privsep-bpf.c	Wed Jan 08 20:13:20 2020 +0000
@@ -40,6 +40,7 @@
 #include <assert.h>
 #include <pwd.h>
 #include <errno.h>
+#include <signal.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
--- a/src/privsep-inet.c	Wed Jan 08 16:57:46 2020 +0000
+++ b/src/privsep-inet.c	Wed Jan 08 20:13:20 2020 +0000
@@ -31,6 +31,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <signal.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
--- a/src/privsep-root.c	Wed Jan 08 16:57:46 2020 +0000
+++ b/src/privsep-root.c	Wed Jan 08 20:13:20 2020 +0000
@@ -46,6 +46,8 @@
 #include "privsep.h"
 #include "script.h"
 
+__CTASSERT(sizeof(ioctl_request_t) <= sizeof(unsigned long));
+
 struct psr_error
 {
 	ssize_t psr_result;
@@ -130,7 +132,16 @@
 
 	s = socket(PF_INET, SOCK_DGRAM, 0);
 	if (s != -1)
+#ifdef IOCTL_REQUEST_TYPE
+	{
+		ioctl_request_t reqt;
+
+		memcpy(&reqt, &req, sizeof(reqt));
+		err = ioctl(s, reqt, data, len);
+	}
+#else
 		err = ioctl(s, req, data, len);
+#endif
 	else
 		err = -1;
 	if (s != -1)
@@ -410,9 +421,18 @@
 }
 
 ssize_t
-ps_root_ioctl(struct dhcpcd_ctx *ctx, unsigned long req, void *data, size_t len)
+ps_root_ioctl(struct dhcpcd_ctx *ctx, ioctl_request_t req, void *data,
+    size_t len)
 {
+#ifdef IOCTL_REQUEST_TYPE
+	unsigned long ulreq = 0;
+
+	memcpy(&ulreq, &req, sizeof(req));
+	if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IOCTL, ulreq, data, len) == -1)
+		return -1;
+#else
 	if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IOCTL, req, data, len) == -1)
 		return -1;
+#endif
 	return ps_root_readerror(ctx);
 }
--- a/src/privsep-root.h	Wed Jan 08 16:57:46 2020 +0000
+++ b/src/privsep-root.h	Wed Jan 08 20:13:20 2020 +0000
@@ -29,11 +29,13 @@
 #ifndef PRIVSEP_ROOT_H
 #define PRIVSEP_ROOT_H
 
+#include "if.h"
+
 pid_t ps_root_start(struct dhcpcd_ctx *ctx);
 int ps_root_stop(struct dhcpcd_ctx *ctx);
 
 ssize_t ps_root_readerror(struct dhcpcd_ctx *);
-ssize_t ps_root_ioctl(struct dhcpcd_ctx *, unsigned long, void *, size_t);
+ssize_t ps_root_ioctl(struct dhcpcd_ctx *, ioctl_request_t, void *, size_t);
 ssize_t ps_root_os(struct ps_msghdr *, struct msghdr *);
 #if defined(BSD) || defined(__sun)
 ssize_t ps_root_route(struct dhcpcd_ctx *, void *, size_t);