]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
ioctl: The POSIX signature differs from BSD and glibc
authorRoy Marples <roy@marples.name>
Wed, 8 Jan 2020 20:13:20 +0000 (20:13 +0000)
committerRoy Marples <roy@marples.name>
Wed, 8 Jan 2020 20:13:20 +0000 (20:13 +0000)
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.

configure
src/if.c
src/if.h
src/privsep-bpf.c
src/privsep-inet.c
src/privsep-root.c
src/privsep-root.h

index 0cb27ce147988582f44dd26de0f3dc9b9c0bf913..263afbf77566dbcf1abe0283c0b0642c94e79f5f 100755 (executable)
--- a/configure
+++ b/configure
@@ -549,7 +549,7 @@ if [ "$PRIVSEP" = yes ]; then
                        fi
                done
        fi
-       : ${PRIVSEP_USER:= _dhcpcd}
+       : ${PRIVSEP_USER:=_dhcpcd}
 
        echo "CPPFLAGS+=        -DPRIVSEP" >>$CONFIG_MK
        echo "#ifndef PRIVSEP_USER" >>$CONFIG_H
@@ -737,6 +737,27 @@ fi
 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>
index 26324286be609ed2d2bddaeb98d4d1516d2a09ba..a96ac5c192a947edf6f5d4d8dbe2aa9f2796657a 100644 (file)
--- a/src/if.c
+++ b/src/if.c
@@ -133,7 +133,7 @@ if_closesockets(struct dhcpcd_ctx *ctx)
 }
 
 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
index 8165a49841cb710d84f047ba0302d30956101ad1..e371e970e48321905a406c0cb81a6c280ba87ebc 100644 (file)
--- a/src/if.h
+++ b/src/if.h
 #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_getifaddrs(struct ifaddrs **);
 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))
index 0985bd2e0a9ba018e706f9272aae340bb79c375c..bb6ee083c41aae5d5b72c9f23722dcd5e566ff7a 100644 (file)
@@ -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>
index 2d5e30db9724184966ee5fde4f313c7a4bda0b5d..01761eb2b7308042ecb1703a821875c50bf9faf4 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <signal.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
index dd60a4ff9aca4836f2cf617b63fc8f88861376e8..4736362416236679eef831d55ad72bb0d5f48ffe 100644 (file)
@@ -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 @@ ps_root_doioctl(unsigned long req, void *data, size_t len)
 
        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 @@ ps_root_script(const struct interface *ifp, const void *data, size_t len)
 }
 
 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);
 }
index 4f6ac9558f1819d23db700e12faee01a7d82d6e3..57862626ff9286bc82fd3484c4dd01ce9d3b3545 100644 (file)
 #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);