Add new socket shutdown test (RHEL-50453)
Resolves: RHEL-50453
This commit is contained in:
parent
b4d304b208
commit
7caf5b3af4
215
glibc-RHEL-50453-1.patch
Normal file
215
glibc-RHEL-50453-1.patch
Normal file
@ -0,0 +1,215 @@
|
||||
commit 20b6b8e8a50874dd189687df8f6f8a11d4813b34
|
||||
Author: Frédéric Bérat <fberat@redhat.com>
|
||||
Date: Wed Jun 14 10:52:06 2023 +0200
|
||||
|
||||
tests: replace read by xread
|
||||
|
||||
With fortification enabled, read calls return result needs to be checked,
|
||||
has it gets the __wur macro enabled.
|
||||
|
||||
Note on read call removal from sysdeps/pthread/tst-cancel20.c and
|
||||
sysdeps/pthread/tst-cancel21.c:
|
||||
It is assumed that this second read call was there to overcome the race
|
||||
condition between pipe closure and thread cancellation that could happen
|
||||
in the original code. Since this race condition got fixed by
|
||||
d0e3ffb7a58854248f1d5e737610d50cd0a60f46 the second call seems
|
||||
superfluous. Hence, instead of checking for the return value of read, it
|
||||
looks reasonable to simply remove it.
|
||||
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||
|
||||
diff --git a/dirent/tst-fdopendir.c b/dirent/tst-fdopendir.c
|
||||
index 2c9520574dddfba8..d6a24f47db25b7b6 100644
|
||||
--- a/dirent/tst-fdopendir.c
|
||||
+++ b/dirent/tst-fdopendir.c
|
||||
@@ -45,7 +45,8 @@ do_test (void)
|
||||
}
|
||||
|
||||
char buf[5];
|
||||
- read(fd, buf, sizeof (buf));
|
||||
+ xread(fd, buf, sizeof (buf));
|
||||
+
|
||||
close(fd);
|
||||
|
||||
struct stat64 st2;
|
||||
diff --git a/nptl/tst-cleanup4.c b/nptl/tst-cleanup4.c
|
||||
index 4a275ed950d6c5f8..8c95d944f9440360 100644
|
||||
--- a/nptl/tst-cleanup4.c
|
||||
+++ b/nptl/tst-cleanup4.c
|
||||
@@ -22,6 +22,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
+#include <support/xunistd.h>
|
||||
+
|
||||
/* LinuxThreads pthread_cleanup_{push,pop} helpers. */
|
||||
extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
|
||||
void (*__routine) (void *),
|
||||
@@ -65,7 +67,7 @@ fn_read (void)
|
||||
}
|
||||
|
||||
char c;
|
||||
- read (fds[0], &c, 1);
|
||||
+ xread (fds[0], &c, 1);
|
||||
}
|
||||
|
||||
|
||||
diff --git a/support/Makefile b/support/Makefile
|
||||
index fa3abb39d587a501..e89eeec45eba14a9 100644
|
||||
--- a/support/Makefile
|
||||
+++ b/support/Makefile
|
||||
@@ -210,6 +210,7 @@ libsupport-routines = \
|
||||
xpthread_spin_lock \
|
||||
xpthread_spin_unlock \
|
||||
xraise \
|
||||
+ xread \
|
||||
xreadlink \
|
||||
xrealloc \
|
||||
xrecvfrom \
|
||||
diff --git a/support/test-container.c b/support/test-container.c
|
||||
index 9a9d4b9ac6180c88..df8f74801f5ed641 100644
|
||||
--- a/support/test-container.c
|
||||
+++ b/support/test-container.c
|
||||
@@ -1209,7 +1209,8 @@ main (int argc, char **argv)
|
||||
|
||||
/* Get our "outside" pid from our parent. We use this to help with
|
||||
debugging from outside the container. */
|
||||
- read (pipes[0], &child, sizeof(child));
|
||||
+ xread (pipes[0], &child, sizeof(child));
|
||||
+
|
||||
close (pipes[0]);
|
||||
close (pipes[1]);
|
||||
sprintf (pid_buf, "%lu", (long unsigned)child);
|
||||
diff --git a/support/xread.c b/support/xread.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..19f76fcfeb7165d6
|
||||
--- /dev/null
|
||||
+++ b/support/xread.c
|
||||
@@ -0,0 +1,36 @@
|
||||
+/* read with error checking and retries.
|
||||
+ Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <support/xunistd.h>
|
||||
+
|
||||
+#include <support/check.h>
|
||||
+
|
||||
+void
|
||||
+xread (int fd, void *buffer, size_t length)
|
||||
+{
|
||||
+ char *p = buffer;
|
||||
+ char *end = p + length;
|
||||
+ while (p < end)
|
||||
+ {
|
||||
+ ssize_t ret = read (fd, p, end - p);
|
||||
+ if (ret < 0)
|
||||
+ FAIL_EXIT1 ("read of %zu bytes failed after %td: %m",
|
||||
+ length, p - (char *) buffer);
|
||||
+ p += ret;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/support/xunistd.h b/support/xunistd.h
|
||||
index a4d0d3427204cfe5..68feedef7fc3831d 100644
|
||||
--- a/support/xunistd.h
|
||||
+++ b/support/xunistd.h
|
||||
@@ -78,6 +78,9 @@ void xclose (int);
|
||||
/* Write the buffer. Retry on short writes. */
|
||||
void xwrite (int, const void *, size_t);
|
||||
|
||||
+/* Read to buffer. Retry on short reads. */
|
||||
+void xread (int, void *, size_t);
|
||||
+
|
||||
/* Invoke mmap with a zero file offset. */
|
||||
void *xmmap (void *addr, size_t length, int prot, int flags, int fd);
|
||||
void xmprotect (void *addr, size_t length, int prot);
|
||||
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile
|
||||
index fa70a33e25f23230..e9c54214da1ffb82 100644
|
||||
--- a/sysdeps/pthread/Makefile
|
||||
+++ b/sysdeps/pthread/Makefile
|
||||
@@ -281,7 +281,7 @@ $(objpfx)tst-cancel28: $(librt)
|
||||
|
||||
$(objpfx)tst-fini1: $(shared-thread-library) $(objpfx)tst-fini1mod.so
|
||||
|
||||
-$(objpfx)tst-fini1mod.so: $(shared-thread-library)
|
||||
+$(objpfx)tst-fini1mod.so: $(libsupport) $(shared-thread-library)
|
||||
|
||||
$(objpfx)tst-_res1mod2.so: $(objpfx)tst-_res1mod1.so
|
||||
LDFLAGS-tst-_res1mod1.so = -Wl,-soname,tst-_res1mod1.so
|
||||
diff --git a/sysdeps/pthread/tst-cancel11.c b/sysdeps/pthread/tst-cancel11.c
|
||||
index e485e0827e1895e5..a76638b3b629850a 100644
|
||||
--- a/sysdeps/pthread/tst-cancel11.c
|
||||
+++ b/sysdeps/pthread/tst-cancel11.c
|
||||
@@ -57,7 +57,11 @@ tf (void *arg)
|
||||
|
||||
/* This call should block and be cancelable. */
|
||||
char buf[20];
|
||||
- read (fd[0], buf, sizeof (buf));
|
||||
+ if (read (fd[0], buf, sizeof (buf)))
|
||||
+ {
|
||||
+ puts ("read unexpectedly returned");
|
||||
+ exit (1);
|
||||
+ }
|
||||
|
||||
pthread_cleanup_pop (0);
|
||||
|
||||
diff --git a/sysdeps/pthread/tst-cancel20.c b/sysdeps/pthread/tst-cancel20.c
|
||||
index 194726a0d4c56d53..0bed320bd3785685 100644
|
||||
--- a/sysdeps/pthread/tst-cancel20.c
|
||||
+++ b/sysdeps/pthread/tst-cancel20.c
|
||||
@@ -85,8 +85,6 @@ tf_body (void)
|
||||
exit (1);
|
||||
}
|
||||
|
||||
- read (fd[0], &c, 1);
|
||||
-
|
||||
pthread_cleanup_pop (0);
|
||||
}
|
||||
|
||||
diff --git a/sysdeps/pthread/tst-cancel21.c b/sysdeps/pthread/tst-cancel21.c
|
||||
index 2fe248082ec94b25..bfce7cbb98e53343 100644
|
||||
--- a/sysdeps/pthread/tst-cancel21.c
|
||||
+++ b/sysdeps/pthread/tst-cancel21.c
|
||||
@@ -86,8 +86,6 @@ tf_body (void)
|
||||
exit (1);
|
||||
}
|
||||
|
||||
- read (fd[0], &c, 1);
|
||||
-
|
||||
pthread_cleanup_pop (0);
|
||||
}
|
||||
|
||||
diff --git a/sysdeps/pthread/tst-fini1mod.c b/sysdeps/pthread/tst-fini1mod.c
|
||||
index cc6b9ee98220d63d..b40f9d5c7ba88caa 100644
|
||||
--- a/sysdeps/pthread/tst-fini1mod.c
|
||||
+++ b/sysdeps/pthread/tst-fini1mod.c
|
||||
@@ -21,6 +21,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
+#include <support/xunistd.h>
|
||||
+
|
||||
|
||||
static void *
|
||||
tf (void *arg)
|
||||
@@ -33,7 +35,7 @@ tf (void *arg)
|
||||
}
|
||||
|
||||
char buf[10];
|
||||
- read (fds[0], buf, sizeof (buf));
|
||||
+ xread (fds[0], buf, sizeof (buf));
|
||||
|
||||
puts ("read returned");
|
||||
exit (1);
|
||||
286
glibc-RHEL-50453-2.patch
Normal file
286
glibc-RHEL-50453-2.patch
Normal file
@ -0,0 +1,286 @@
|
||||
commit 50f5a09e68e0c4ea60f5dfee3cc6963df2762e14
|
||||
Author: Sergey Kolosov <skolosov@redhat.com>
|
||||
Date: Tue Jun 25 11:19:03 2024 +0200
|
||||
|
||||
socket: Add new test for shutdown
|
||||
|
||||
This commit adds shutdown test with SHUT_RD, SHUT_WR, SHUT_RDWR for an
|
||||
UNIX socket connection.
|
||||
|
||||
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||
|
||||
diff --git a/socket/Makefile b/socket/Makefile
|
||||
index a74e1f66ce7e5f6e..ca089211687515a9 100644
|
||||
--- a/socket/Makefile
|
||||
+++ b/socket/Makefile
|
||||
@@ -35,6 +35,7 @@ tests := \
|
||||
tst-accept4 \
|
||||
tst-cmsghdr \
|
||||
tst-connect \
|
||||
+ tst-shutdown \
|
||||
tst-sockopt \
|
||||
# tests
|
||||
|
||||
diff --git a/socket/tst-shutdown.c b/socket/tst-shutdown.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..a305e5e494cc38f1
|
||||
--- /dev/null
|
||||
+++ b/socket/tst-shutdown.c
|
||||
@@ -0,0 +1,257 @@
|
||||
+/* Test the shutdown function.
|
||||
+ Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <arpa/inet.h>
|
||||
+#include <errno.h>
|
||||
+#include <fcntl.h>
|
||||
+#include <stdbool.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/support.h>
|
||||
+#include <support/xsocket.h>
|
||||
+#include <support/xunistd.h>
|
||||
+#include <sys/socket.h>
|
||||
+#include <stdio.h>
|
||||
+#include <fcntl.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
+struct connection
|
||||
+{
|
||||
+ int sockets[2];
|
||||
+};
|
||||
+
|
||||
+void
|
||||
+establish_connection (struct connection *conn)
|
||||
+{
|
||||
+ if (socketpair (AF_UNIX, SOCK_STREAM, 0, conn->sockets) != 0)
|
||||
+ {
|
||||
+ FAIL_EXIT1 ("socketpair (AF_UNIX, SOCK_STREAM, 0): %m\n");
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+close_connection (struct connection *conn)
|
||||
+{
|
||||
+ xclose (conn->sockets[0]);
|
||||
+ xclose (conn->sockets[1]);
|
||||
+}
|
||||
+
|
||||
+/* Open a file and check that shutdown fails with the ENOTSOCK error code. */
|
||||
+void
|
||||
+do_test_enotsock (void)
|
||||
+{
|
||||
+ /* Open file and check that shutdown will fail with ENOTSOCK. */
|
||||
+ int fd = xopen ("/dev/null", O_RDWR, 0);
|
||||
+
|
||||
+ int result = shutdown (fd, SHUT_RD);
|
||||
+ if (result == 0 || errno != ENOTSOCK)
|
||||
+ {
|
||||
+ FAIL_EXIT1 ("shutdown should fail with ENOTSOCK");
|
||||
+ }
|
||||
+ xclose (fd);
|
||||
+}
|
||||
+
|
||||
+/* Test shutdown with SHUT_RD. */
|
||||
+void
|
||||
+do_test_shut_rd (void)
|
||||
+{
|
||||
+ struct connection conn;
|
||||
+ const char *str = "AAAAAAA";
|
||||
+ int len = 8;
|
||||
+ int ret;
|
||||
+ void *s_buf = xmalloc (len);
|
||||
+ bzero (s_buf, len);
|
||||
+
|
||||
+ establish_connection (&conn);
|
||||
+ int server = conn.sockets[0];
|
||||
+ int client = conn.sockets[1];
|
||||
+
|
||||
+ /* Call shutdown with SHUT_RD on server socket. */
|
||||
+ if (shutdown (server, SHUT_RD) != 0)
|
||||
+ {
|
||||
+ FAIL_EXIT1 ("shutdown with SHUT_RD on socket %d failed", server);
|
||||
+ }
|
||||
+
|
||||
+ ret = send (server, str, len, 0);
|
||||
+ if (ret <= 0)
|
||||
+ {
|
||||
+ FAIL_EXIT1 ("send (%d, data, %d): %m", server, len);
|
||||
+ }
|
||||
+
|
||||
+ ret = recv (client, s_buf, len, 0);
|
||||
+ if (ret <= 0)
|
||||
+ {
|
||||
+ FAIL_EXIT1 ("recv (%d, data, %d): %m", client, len);
|
||||
+ }
|
||||
+
|
||||
+ TEST_COMPARE_BLOB (str, len, s_buf, len);
|
||||
+
|
||||
+ /* Send data should be disallowed on shutdown socket. */
|
||||
+ errno = 0;
|
||||
+ ret = send (client, str, len, MSG_NOSIGNAL);
|
||||
+ if (ret >= 0 || errno != EPIPE)
|
||||
+ {
|
||||
+ FAIL_EXIT1 ("Send on SHUT_RD socket should be disallowed: %m");
|
||||
+ }
|
||||
+
|
||||
+ /* Recv should return zero and no error. */
|
||||
+ errno = 0;
|
||||
+ ret = recv (server, s_buf, len, 0);
|
||||
+ if (ret != 0 || errno != 0)
|
||||
+ {
|
||||
+ FAIL_EXIT1 ("recv should return 0 without error: %m");
|
||||
+ }
|
||||
+
|
||||
+ close_connection (&conn);
|
||||
+}
|
||||
+
|
||||
+/* Test shutdown with SHUT_WR. */
|
||||
+void
|
||||
+do_test_shut_wr (void)
|
||||
+{
|
||||
+ struct connection conn;
|
||||
+ const char *str1 = "CCCCCCC";
|
||||
+ const char *str2 = "DDDDDDD";
|
||||
+ const char *str3 = "EEEEEEE";
|
||||
+ int len = 8;
|
||||
+ int ret;
|
||||
+ void *c_buf = xmalloc (len);
|
||||
+ void *s_buf = xmalloc (len);
|
||||
+
|
||||
+ establish_connection (&conn);
|
||||
+ int server = conn.sockets[0];
|
||||
+ int client = conn.sockets[1];
|
||||
+
|
||||
+ xwrite (client, str1, len);
|
||||
+
|
||||
+ if (shutdown (client, SHUT_WR) != 0)
|
||||
+ {
|
||||
+ FAIL_EXIT1 ("shutdown with SHUT_WR on socket %d failed", client);
|
||||
+ }
|
||||
+
|
||||
+ ret = send (client, str2, len, MSG_NOSIGNAL);
|
||||
+ if (ret >= 0)
|
||||
+ {
|
||||
+ FAIL_EXIT1 ("send on SHUT_WR socket should fail");
|
||||
+ }
|
||||
+
|
||||
+ /* Read data written before shutdown and check if it's correct. */
|
||||
+ xread (server, s_buf, len);
|
||||
+ TEST_COMPARE_BLOB (str1, len, s_buf, len);
|
||||
+
|
||||
+ /* Second read should return zero without error. */
|
||||
+ errno = 0;
|
||||
+ if (read (server, s_buf, len) != 0 || errno != 0)
|
||||
+ {
|
||||
+ FAIL_EXIT1 ("read after shutdown should return zero without error: %m");
|
||||
+ }
|
||||
+
|
||||
+ /* Write some data to socket and check it still can be read on other side. */
|
||||
+ memcpy (s_buf, str3, len);
|
||||
+ xwrite (server, s_buf, len);
|
||||
+
|
||||
+ xread (client, c_buf, len);
|
||||
+ TEST_COMPARE_BLOB (s_buf, len, c_buf, len);
|
||||
+
|
||||
+ close_connection (&conn);
|
||||
+}
|
||||
+
|
||||
+/* Test shutdown with SHUT_RDWR. */
|
||||
+void
|
||||
+do_test_shut_rdwr (void)
|
||||
+{
|
||||
+ struct connection conn;
|
||||
+ struct sockaddr peer;
|
||||
+ socklen_t peer_len = sizeof (peer);
|
||||
+
|
||||
+ const char *str1 = "FFFFFFF";
|
||||
+ const char *str2 = "GGGGGGG";
|
||||
+ int len = 8;
|
||||
+ int ret;
|
||||
+ void *s_buf = xmalloc (len);
|
||||
+ bzero (s_buf, len);
|
||||
+
|
||||
+ establish_connection (&conn);
|
||||
+ int server = conn.sockets[0];
|
||||
+ int client = conn.sockets[1];
|
||||
+
|
||||
+ /* Send some data to both sockets before shutdown. */
|
||||
+ xwrite (client, str1, len);
|
||||
+ xwrite (server, str2, len);
|
||||
+
|
||||
+ /* Call shutdown with SHUT_RDWR on client socket. */
|
||||
+ if (shutdown (client, SHUT_RDWR) != 0)
|
||||
+ {
|
||||
+ FAIL_EXIT1 ("shutdown with SHUT_RDWR on socket %d failed", client);
|
||||
+ }
|
||||
+
|
||||
+ /* Verify that socket is still connected. */
|
||||
+ xgetsockname (client, &peer, &peer_len);
|
||||
+
|
||||
+ /* Read data written before shutdown. */
|
||||
+ xread (client, s_buf, len);
|
||||
+ TEST_COMPARE_BLOB (s_buf, len, str2, len);
|
||||
+
|
||||
+ /* Second read should return zero, but no error. */
|
||||
+ errno = 0;
|
||||
+ if (read (client, s_buf, len) != 0 || errno != 0)
|
||||
+ {
|
||||
+ FAIL_EXIT1 ("read after shutdown should return zero without error: %m");
|
||||
+ }
|
||||
+
|
||||
+ /* Send some data to shutdown socket and expect error. */
|
||||
+ errno = 0;
|
||||
+ ret = send (server, str2, len, MSG_NOSIGNAL);
|
||||
+ if (ret >= 0 || errno != EPIPE)
|
||||
+ {
|
||||
+ FAIL_EXIT1 ("send to RDWR shutdown socket should fail with EPIPE");
|
||||
+ }
|
||||
+
|
||||
+ /* Read data written before shutdown. */
|
||||
+ xread (server, s_buf, len);
|
||||
+ TEST_COMPARE_BLOB (s_buf, len, str1, len);
|
||||
+
|
||||
+ /* Second read should return zero, but no error. */
|
||||
+ errno = 0;
|
||||
+ if (read (server, s_buf, len) != 0 || errno != 0)
|
||||
+ {
|
||||
+ FAIL_EXIT1 ("read after shutdown should return zero without error: %m");
|
||||
+ }
|
||||
+
|
||||
+ /* Send some data to shutdown socket and expect error. */
|
||||
+ errno = 0;
|
||||
+ ret = send (client, str1, len, MSG_NOSIGNAL);
|
||||
+ if (ret >= 0 || errno != EPIPE)
|
||||
+ {
|
||||
+ FAIL_EXIT1 ("send to RDWR shutdown socket should fail with EPIPE");
|
||||
+ }
|
||||
+
|
||||
+ close_connection (&conn);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ do_test_enotsock ();
|
||||
+ do_test_shut_rd ();
|
||||
+ do_test_shut_wr ();
|
||||
+ do_test_shut_rdwr ();
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
Loading…
Reference in New Issue
Block a user