[Libguestfs] [libnbd PATCH 3/6] macOS: Simple cloexec/nonblock fix

Martin Kletzander
Tue, 13 Jul 2021 21:26:05 -0000

This is the most trivial way to fix the issue with macOS not having SOCK_CLOEXEC
and SOCK_NONBLOCK.  There is not much better way, so this is the only way to
make it work on such platform(s).

Signed-off-by: Martin Kletzander <mkletzan at redhat.com>
---
 lib/internal.h                               |  3 +
 generator/states-connect-socket-activation.c |  2 +-
 generator/states-connect.c                   | 11 ++--
 lib/utils.c                                  | 68 ++++++++++++++++++++
 fuzzing/libnbd-fuzz-wrapper.c                | 30 ++++++++-
 fuzzing/libnbd-libfuzzer-test.c              | 30 ++++++++-
 6 files changed, 136 insertions(+), 8 deletions(-)

diff --git a/lib/internal.h b/lib/internal.h
index 01f9d8ab5fea..8a4c189abe65 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -467,4 +467,7 @@ extern char *nbd_internal_printable_buffer (const void *buf,
size_t count);
 extern char *nbd_internal_printable_string (const char *str);
 extern char *nbd_internal_printable_string_list (char **list);

+extern int nbd_internal_socket(int domain, int type, int protocol, bool
nonblock);
+extern int nbd_internal_socketpair(int domain, int type, int protocol, int
*fds);
+
 #endif /* LIBNBD_INTERNAL_H */
diff --git a/generator/states-connect-socket-activation.c
b/generator/states-connect-socket-activation.c
index e601c9bb56be..8a2add312bc4 100644
--- a/generator/states-connect-socket-activation.c
+++ b/generator/states-connect-socket-activation.c
@@ -131,7 +131,7 @@ STATE_MACHINE {
     return 0;
   }

-  s = socket (AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
+  s = nbd_internal_socket (AF_UNIX, SOCK_STREAM, 0, false);
   if (s == -1) {
     SET_NEXT_STATE (%.DEAD);
     set_error (errno, "socket");
diff --git a/generator/states-connect.c b/generator/states-connect.c
index fcac86f36a34..8de12183d627 100644
--- a/generator/states-connect.c
+++ b/generator/states-connect.c
@@ -52,7 +52,7 @@ STATE_MACHINE {

   assert (!h->sock);
   family = h->connaddr.ss_family;
-  fd = socket (family, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
+  fd = nbd_internal_socket (family, SOCK_STREAM, 0, true);
   if (fd == -1) {
     SET_NEXT_STATE (%.DEAD);
     set_error (errno, "socket");
@@ -162,9 +162,10 @@ STATE_MACHINE {
     return -1;
   }

-  fd = socket (h->rp->ai_family,
-               h->rp->ai_socktype|SOCK_NONBLOCK|SOCK_CLOEXEC,
-               h->rp->ai_protocol);
+  fd = nbd_internal_socket (h->rp->ai_family,
+                            h->rp->ai_socktype,
+                            h->rp->ai_protocol,
+                            true);
   if (fd == -1) {
     SET_NEXT_STATE (%NEXT_ADDRESS);
     return 0;
@@ -227,7 +228,7 @@ STATE_MACHINE {
   assert (!h->sock);
   assert (h->argv.ptr);
   assert (h->argv.ptr[0]);
-  if (socketpair (AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, sv) == -1) {
+  if (nbd_internal_socketpair (AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
     SET_NEXT_STATE (%.DEAD);
     set_error (errno, "socketpair");
     return 0;
diff --git a/lib/utils.c b/lib/utils.c
index 260fd6a25796..972cbc5208a7 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -24,6 +24,7 @@
 #include <unistd.h>
 #include <ctype.h>
 #include <errno.h>
+#include <fcntl.h>

 #include "minmax.h"

@@ -258,3 +259,70 @@ nbd_internal_printable_string_list (char **list)
   return s;

 }
+
+int nbd_internal_socket(int domain,
+                        int type,
+                        int protocol,
+                        bool nonblock)
+{
+  int fd;
+
+#ifdef __APPLE__
+  int flags;
+#else
+  type |= SOCK_CLOEXEC;
+  if (nonblock)
+    type |= SOCK_NONBLOCK;
+#endif
+
+  fd = socket (domain, type, protocol);
+
+#ifdef __APPLE__
+  if (fd == -1)
+    return -1;
+
+  if (fcntl (fd, F_SETFD, FD_CLOEXEC) == -1) {
+    close(fd);
+    return -1;
+  }
+
+  if (nonblock) {
+    flags = fcntl (fd, F_GETFL, 0);
+    if (flags == -1 ||
+        fcntl (fd, F_SETFL, flags|O_NONBLOCK) == -1) {
+      close(fd);
+      return -1;
+    }
+  }
+#endif
+
+  return fd;
+}
+
+int
+nbd_internal_socketpair (int domain, int type, int protocol, int *fds)
+{
+  int ret;
+
+#ifdef __APPLE__
+  size_t i;
+#else
+  type |= SOCK_CLOEXEC;
+#endif
+
+  ret = socketpair (domain, type, protocol, fds);
+
+#ifdef __APPLE__
+  if (ret == 0) {
+    for (i = 0; i < 2; i++) {
+      if (fcntl (fds[i], F_SETFD, FD_CLOEXEC) == -1) {
+        close(fds[0]);
+        close(fds[1]);
+        return -1;
+      }
+    }
+  }
+#endif
+
+  return ret;
+}
diff --git a/fuzzing/libnbd-fuzz-wrapper.c b/fuzzing/libnbd-fuzz-wrapper.c
index 99a6d803258f..3d127e673e9e 100644
--- a/fuzzing/libnbd-fuzz-wrapper.c
+++ b/fuzzing/libnbd-fuzz-wrapper.c
@@ -41,6 +41,34 @@
 static void client (int s);
 static void server (int fd, int s);

+static int
+get_socketpair (int domain, int type, int protocol, int *fds)
+{
+  int ret;
+
+#ifdef __APPLE__
+  size_t i;
+#else
+  type |= SOCK_CLOEXEC;
+#endif
+
+  ret = socketpair (domain, type, protocol, fds);
+
+#ifdef __APPLE__
+  if (ret == 0) {
+    for (i = 0; i < 2; i++) {
+      if (fcntl (fds[i], F_SETFD, FD_CLOEXEC) == -1) {
+        close(fds[0]);
+        close(fds[1]);
+        return -1;
+      }
+    }
+  }
+#endif
+
+  return ret;
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -61,7 +89,7 @@ main (int argc, char *argv[])
   }

   /* Create a connected socket. */
-  if (socketpair (AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, sv) == -1) {
+  if (get_socketpair (AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
     perror ("socketpair");
     exit (EXIT_FAILURE);
   }
diff --git a/fuzzing/libnbd-libfuzzer-test.c b/fuzzing/libnbd-libfuzzer-test.c
index 5ee29b877bdb..0bf988ee8398 100644
--- a/fuzzing/libnbd-libfuzzer-test.c
+++ b/fuzzing/libnbd-libfuzzer-test.c
@@ -41,6 +41,34 @@
 static void client (int sock);
 static void server (const uint8_t *data, size_t size, int sock);

+static int
+get_socketpair (int domain, int type, int protocol, int *fds)
+{
+  int ret;
+
+#ifdef __APPLE__
+  size_t i;
+#else
+  type |= SOCK_CLOEXEC;
+#endif
+
+  ret = socketpair (domain, type, protocol, fds);
+
+#ifdef __APPLE__
+  if (ret == 0) {
+    for (i = 0; i < 2; i++) {
+      if (fcntl (fds[i], F_SETFD, FD_CLOEXEC) == -1) {
+        close(fds[0]);
+        close(fds[1]);
+        return -1;
+      }
+    }
+  }
+#endif
+
+  return ret;
+}
+
 /* This is the entry point called by libFuzzer. */
 int
 LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
@@ -49,7 +77,7 @@ LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
   int sv[2], r, status;

   /* Create a connected socket. */
-  if (socketpair (AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, sv) == -1) {
+  if (nbd_internal_socketpair (AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, sv) == -1)
{
     perror ("socketpair");
     exit (EXIT_FAILURE);
   }
--
2.32.0