216 lines
6.1 KiB
Diff
216 lines
6.1 KiB
Diff
From d57e9e705b1257e5e241922dc29b333e090302c4 Mon Sep 17 00:00:00 2001
|
|
From: Martin Kletzander <mkletzan@redhat.com>
|
|
Date: Wed, 7 Jul 2021 13:15:40 +0200
|
|
Subject: [PATCH] macOS: Simple cloexec/nonblock fix
|
|
|
|
This is the most trivial way to fix the issue with macOS not having SOCK_CLOEXEC
|
|
and SOCK_NONBLOCK. This is the only way to make it work on such platform(s)
|
|
unless they are fixed.
|
|
|
|
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
|
|
(cherry picked from commit 61132c8e9804787e66974020ebb96e3995e0f6dc)
|
|
---
|
|
fuzzing/libnbd-fuzz-wrapper.c | 4 +
|
|
fuzzing/libnbd-libfuzzer-test.c | 4 +
|
|
generator/states-connect-socket-activation.c | 2 +-
|
|
generator/states-connect.c | 11 +--
|
|
lib/internal.h | 9 +++
|
|
lib/utils.c | 80 ++++++++++++++++++++
|
|
6 files changed, 104 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/fuzzing/libnbd-fuzz-wrapper.c b/fuzzing/libnbd-fuzz-wrapper.c
|
|
index 99a6d80..eb18809 100644
|
|
--- a/fuzzing/libnbd-fuzz-wrapper.c
|
|
+++ b/fuzzing/libnbd-fuzz-wrapper.c
|
|
@@ -38,6 +38,10 @@
|
|
|
|
#include <libnbd.h>
|
|
|
|
+#ifndef SOCK_CLOEXEC
|
|
+#define SOCK_CLOEXEC 0 /* This file doesn't use exec */
|
|
+#endif
|
|
+
|
|
static void client (int s);
|
|
static void server (int fd, int s);
|
|
|
|
diff --git a/fuzzing/libnbd-libfuzzer-test.c b/fuzzing/libnbd-libfuzzer-test.c
|
|
index 5ee29b8..c8d6423 100644
|
|
--- a/fuzzing/libnbd-libfuzzer-test.c
|
|
+++ b/fuzzing/libnbd-libfuzzer-test.c
|
|
@@ -38,6 +38,10 @@
|
|
|
|
#include <libnbd.h>
|
|
|
|
+#ifndef SOCK_CLOEXEC
|
|
+#define SOCK_CLOEXEC 0 /* This file doesn't use exec */
|
|
+#endif
|
|
+
|
|
static void client (int sock);
|
|
static void server (const uint8_t *data, size_t size, int sock);
|
|
|
|
diff --git a/generator/states-connect-socket-activation.c b/generator/states-connect-socket-activation.c
|
|
index e601c9b..8a2add3 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 fcac86f..8de1218 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/internal.h b/lib/internal.h
|
|
index 01f9d8a..0e205ab 100644
|
|
--- a/lib/internal.h
|
|
+++ b/lib/internal.h
|
|
@@ -467,4 +467,13 @@ 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);
|
|
|
|
+/* These are wrappers around socket(2) and socketpair(2). They
|
|
+ * always set SOCK_CLOEXEC. nbd_internal_socket can set SOCK_NONBLOCK
|
|
+ * according to the nonblock parameter.
|
|
+ */
|
|
+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/lib/utils.c b/lib/utils.c
|
|
index 260fd6a..3d3b7f4 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,82 @@ nbd_internal_printable_string_list (char **list)
|
|
return s;
|
|
|
|
}
|
|
+
|
|
+int nbd_internal_socket(int domain,
|
|
+ int type,
|
|
+ int protocol,
|
|
+ bool nonblock)
|
|
+{
|
|
+ int fd;
|
|
+
|
|
+ /* So far we do not know about any platform that has SOCK_CLOEXEC and
|
|
+ * lacks SOCK_NONBLOCK at the same time.
|
|
+ *
|
|
+ * The workaround for missing SOCK_CLOEXEC introduces a race which
|
|
+ * cannot be fixed until support for SOCK_CLOEXEC is added (or other
|
|
+ * fix is implemented).
|
|
+ */
|
|
+#ifndef SOCK_CLOEXEC
|
|
+ int flags;
|
|
+#else
|
|
+ type |= SOCK_CLOEXEC;
|
|
+ if (nonblock)
|
|
+ type |= SOCK_NONBLOCK;
|
|
+#endif
|
|
+
|
|
+ fd = socket (domain, type, protocol);
|
|
+
|
|
+#ifndef SOCK_CLOEXEC
|
|
+ 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;
|
|
+
|
|
+ /*
|
|
+ * Same as with nbd_internal_socket() this workaround for missing
|
|
+ * SOCK_CLOEXEC introduces a race which cannot be fixed until support
|
|
+ * for SOCK_CLOEXEC is added (or other fix is implemented).
|
|
+ */
|
|
+#ifndef SOCK_CLOEXEC
|
|
+ size_t i;
|
|
+#else
|
|
+ type |= SOCK_CLOEXEC;
|
|
+#endif
|
|
+
|
|
+ ret = socketpair (domain, type, protocol, fds);
|
|
+
|
|
+#ifndef SOCK_CLOEXEC
|
|
+ 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;
|
|
+}
|
|
--
|
|
2.31.1
|
|
|