* [COMMITTED 2.33 2/7] realpath: Set errno to ENAMETOOLONG for result larger than PATH_MAX [BZ #28770]
2022-01-24 22:48 [COMMITTED 2.33 1/7] support: Add helpers to create paths longer than PATH_MAX Aurelien Jarno
@ 2022-01-24 22:48 ` Aurelien Jarno
2022-01-24 22:48 ` [COMMITTED 2.33 3/7] tst-realpath-toolong: Fix hurd build Aurelien Jarno
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Aurelien Jarno @ 2022-01-24 22:48 UTC (permalink / raw)
To: libc-stable; +Cc: Siddhesh Poyarekar, Adhemerval Zanella
From: Siddhesh Poyarekar <siddhesh@sourceware.org>
realpath returns an allocated string when the result exceeds PATH_MAX,
which is unexpected when its second argument is not NULL. This results
in the second argument (resolved) being uninitialized and also results
in a memory leak since the caller expects resolved to be the same as the
returned value.
Return NULL and set errno to ENAMETOOLONG if the result exceeds
PATH_MAX. This fixes [BZ #28770], which is CVE-2021-3998.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
(cherry picked from commit ee8d5e33adb284601c00c94687bc907e10aec9bb)
---
NEWS | 5 ++++
stdlib/Makefile | 3 ++-
stdlib/canonicalize.c | 12 +++++++--
stdlib/tst-realpath-toolong.c | 49 +++++++++++++++++++++++++++++++++++
4 files changed, 66 insertions(+), 3 deletions(-)
create mode 100644 stdlib/tst-realpath-toolong.c
diff --git a/NEWS b/NEWS
index eba875d1f6..5352599d7f 100644
--- a/NEWS
+++ b/NEWS
@@ -26,6 +26,10 @@ Security related changes:
CVE-2022-23218: Passing an overlong file name to the svcunix_create
legacy function could result in a stack-based buffer overflow.
+ CVE-2021-3998: Passing a path longer than PATH_MAX to the realpath
+ function could result in a memory leak and potential access of
+ uninitialized memory. Reported by Qualys.
+
The following bugs are resolved with this release:
[15271] dlfcn function failure after dlmopen terminates process
@@ -46,6 +50,7 @@ The following bugs are resolved with this release:
[28524] Conversion from ISO-2022-JP-3 with iconv may emit spurious NULs
[28532] powerpc64[le]: CFI for assembly templated syscalls is incorrect
[28768] CVE-2022-23218: Buffer overflow in sunrpc svcunix_create
+ [28770] CVE-2021-3998: Unexpected return value from realpath() for too long results
\f
Version 2.33
diff --git a/stdlib/Makefile b/stdlib/Makefile
index b3b30ab73e..b1eebd568f 100644
--- a/stdlib/Makefile
+++ b/stdlib/Makefile
@@ -86,7 +86,8 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \
tst-makecontext-align test-bz22786 tst-strtod-nan-sign \
tst-swapcontext1 tst-setcontext4 tst-setcontext5 \
tst-setcontext6 tst-setcontext7 tst-setcontext8 \
- tst-setcontext9 tst-bz20544 tst-canon-bz26341
+ tst-setcontext9 tst-bz20544 tst-canon-bz26341 \
+ tst-realpath-toolong
tests-internal := tst-strtod1i tst-strtod3 tst-strtod4 tst-strtod5i \
tst-tls-atexit tst-tls-atexit-nodelete
diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c
index 698f9ede25..7a23a51b3a 100644
--- a/stdlib/canonicalize.c
+++ b/stdlib/canonicalize.c
@@ -400,8 +400,16 @@ realpath_stk (const char *name, char *resolved,
error:
*dest++ = '\0';
- if (resolved != NULL && dest - rname <= get_path_max ())
- rname = strcpy (resolved, rname);
+ if (resolved != NULL)
+ {
+ if (dest - rname <= get_path_max ())
+ rname = strcpy (resolved, rname);
+ else
+ {
+ failed = true;
+ __set_errno (ENAMETOOLONG);
+ }
+ }
error_nomem:
scratch_buffer_free (&extra_buffer);
diff --git a/stdlib/tst-realpath-toolong.c b/stdlib/tst-realpath-toolong.c
new file mode 100644
index 0000000000..8bed772460
--- /dev/null
+++ b/stdlib/tst-realpath-toolong.c
@@ -0,0 +1,49 @@
+/* Verify that realpath returns NULL with ENAMETOOLONG if the result exceeds
+ NAME_MAX.
+ Copyright The GNU Toolchain Authors.
+ 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 <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <support/check.h>
+#include <support/temp_file.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define BASENAME "tst-realpath-toolong."
+
+int
+do_test (void)
+{
+ char *base = support_create_and_chdir_toolong_temp_directory (BASENAME);
+
+ char buf[PATH_MAX + 1];
+ const char *res = realpath (".", buf);
+
+ /* canonicalize.c states that if the real path is >= PATH_MAX, then
+ realpath returns NULL and sets ENAMETOOLONG. */
+ TEST_VERIFY (res == NULL);
+ TEST_VERIFY (errno == ENAMETOOLONG);
+
+ free (base);
+ return 0;
+}
+
+#include <support/test-driver.c>
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [COMMITTED 2.33 3/7] tst-realpath-toolong: Fix hurd build
2022-01-24 22:48 [COMMITTED 2.33 1/7] support: Add helpers to create paths longer than PATH_MAX Aurelien Jarno
2022-01-24 22:48 ` [COMMITTED 2.33 2/7] realpath: Set errno to ENAMETOOLONG for result larger than PATH_MAX [BZ #28770] Aurelien Jarno
@ 2022-01-24 22:48 ` Aurelien Jarno
2022-01-24 22:48 ` [COMMITTED 2.33 4/7] support: Add xclone Aurelien Jarno
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Aurelien Jarno @ 2022-01-24 22:48 UTC (permalink / raw)
To: libc-stable; +Cc: Siddhesh Poyarekar
From: Siddhesh Poyarekar <siddhesh@sourceware.org>
Define PATH_MAX to a constant if it isn't already defined, like in hurd.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
(cherry picked from commit 976db046bc3a3738f69255ae00b0a09b8e77fd9c)
---
stdlib/tst-realpath-toolong.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/stdlib/tst-realpath-toolong.c b/stdlib/tst-realpath-toolong.c
index 8bed772460..4388890294 100644
--- a/stdlib/tst-realpath-toolong.c
+++ b/stdlib/tst-realpath-toolong.c
@@ -29,6 +29,10 @@
#define BASENAME "tst-realpath-toolong."
+#ifndef PATH_MAX
+# define PATH_MAX 1024
+#endif
+
int
do_test (void)
{
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [COMMITTED 2.33 4/7] support: Add xclone
2022-01-24 22:48 [COMMITTED 2.33 1/7] support: Add helpers to create paths longer than PATH_MAX Aurelien Jarno
2022-01-24 22:48 ` [COMMITTED 2.33 2/7] realpath: Set errno to ENAMETOOLONG for result larger than PATH_MAX [BZ #28770] Aurelien Jarno
2022-01-24 22:48 ` [COMMITTED 2.33 3/7] tst-realpath-toolong: Fix hurd build Aurelien Jarno
@ 2022-01-24 22:48 ` Aurelien Jarno
2022-01-24 22:48 ` [COMMITTED 2.33 5/7] getcwd: Set errno to ERANGE for size == 1 (CVE-2021-3999) Aurelien Jarno
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Aurelien Jarno @ 2022-01-24 22:48 UTC (permalink / raw)
To: libc-stable
From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
It is a wrapper for Linux clone syscall, to simplify the call to the
use only the most common arguments and remove architecture specific
handling (such as ia64 different name and signature).
(cherry picked from commit de8995a2a04163617c1a233b4b81356ef9f9741f)
---
support/Makefile | 1 +
support/xclone.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++
support/xsched.h | 34 ++++++++++++++++++++++++++++++++
3 files changed, 85 insertions(+)
create mode 100644 support/xclone.c
create mode 100644 support/xsched.h
diff --git a/support/Makefile b/support/Makefile
index 3c0eb200c2..f631846c07 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -92,6 +92,7 @@ libsupport-routines = \
xchdir \
xchroot \
xclock_gettime \
+ xclone \
xclose \
xchmod \
xconnect \
diff --git a/support/xclone.c b/support/xclone.c
new file mode 100644
index 0000000000..924d2b8754
--- /dev/null
+++ b/support/xclone.c
@@ -0,0 +1,50 @@
+/* Auxiliary functions to issue the clone syscall.
+ Copyright (C) 2021 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/>. */
+
+#ifdef __linux__
+# include <support/check.h>
+# include <stackinfo.h> /* For _STACK_GROWS_{UP,DOWN}. */
+# include <xsched.h>
+
+pid_t
+xclone (int (*fn) (void *arg), void *arg, void *stack, size_t stack_size,
+ int flags)
+{
+ pid_t r = -1;
+
+# ifdef __ia64__
+ extern int __clone2 (int (*fn) (void *arg), void *stack, size_t stack_size,
+ int flags, void *arg, ...);
+ r = __clone2 (f, stack, stack_size, flags, arg, /* ptid */ NULL,
+ /* tls */ NULL, /* ctid */ ctid);
+# else
+# if _STACK_GROWS_DOWN
+ r = clone (fn, stack + stack_size, flags, arg, /* ptid */ NULL,
+ /* tls */ NULL, /* ctid */ NULL);
+# elif _STACK_GROWS_UP
+ r = clone (fn, stack, flags, arg, /* ptid */ NULL, /* tls */ NULL,
+ &ctid);
+# endif
+# endif
+
+ if (r < 0)
+ FAIL_EXIT1 ("clone: %m");
+
+ return r;
+}
+#endif
diff --git a/support/xsched.h b/support/xsched.h
new file mode 100644
index 0000000000..eefd731940
--- /dev/null
+++ b/support/xsched.h
@@ -0,0 +1,34 @@
+/* Wrapper for sched.h functions.
+ Copyright (C) 2021 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/>. */
+
+#ifndef SUPPORT_XSCHED_H
+#define SUPPORT_XSCHED_H
+
+__BEGIN_DECLS
+
+#include <sched.h>
+#include <sys/types.h>
+
+#ifdef __linux__
+pid_t xclone (int (*fn) (void *arg), void *arg, void *stack,
+ size_t stack_size, int flags);
+#endif
+
+__END_DECLS
+
+#endif
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [COMMITTED 2.33 5/7] getcwd: Set errno to ERANGE for size == 1 (CVE-2021-3999)
2022-01-24 22:48 [COMMITTED 2.33 1/7] support: Add helpers to create paths longer than PATH_MAX Aurelien Jarno
` (2 preceding siblings ...)
2022-01-24 22:48 ` [COMMITTED 2.33 4/7] support: Add xclone Aurelien Jarno
@ 2022-01-24 22:48 ` Aurelien Jarno
2022-01-24 22:48 ` [COMMITTED 2.33 6/7] realpath: Avoid overwriting preexisting error (CVE-2021-3998) Aurelien Jarno
2022-01-24 22:48 ` [COMMITTED 2.33 7/7] Linux: Detect user namespace support in io/tst-getcwd-smallbuff Aurelien Jarno
5 siblings, 0 replies; 7+ messages in thread
From: Aurelien Jarno @ 2022-01-24 22:48 UTC (permalink / raw)
To: libc-stable
Cc: Siddhesh Poyarekar, Andreas Schwab, Adhemerval Zanella,
Qualys Security Advisory
From: Siddhesh Poyarekar <siddhesh@sourceware.org>
No valid path returned by getcwd would fit into 1 byte, so reject the
size early and return NULL with errno set to ERANGE. This change is
prompted by CVE-2021-3999, which describes a single byte buffer
underflow and overflow when all of the following conditions are met:
- The buffer size (i.e. the second argument of getcwd) is 1 byte
- The current working directory is too long
- '/' is also mounted on the current working directory
Sequence of events:
- In sysdeps/unix/sysv/linux/getcwd.c, the syscall returns ENAMETOOLONG
because the linux kernel checks for name length before it checks
buffer size
- The code falls back to the generic getcwd in sysdeps/posix
- In the generic func, the buf[0] is set to '\0' on line 250
- this while loop on line 262 is bypassed:
while (!(thisdev == rootdev && thisino == rootino))
since the rootfs (/) is bind mounted onto the directory and the flow
goes on to line 449, where it puts a '/' in the byte before the
buffer.
- Finally on line 458, it moves 2 bytes (the underflowed byte and the
'\0') to the buf[0] and buf[1], resulting in a 1 byte buffer overflow.
- buf is returned on line 469 and errno is not set.
This resolves BZ #28769.
Reviewed-by: Andreas Schwab <schwab@linux-m68k.org>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Signed-off-by: Qualys Security Advisory <qsa@qualys.com>
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
(cherry picked from commit 23e0e8f5f1fb5ed150253d986ecccdc90c2dcd5e)
---
NEWS | 7 +
sysdeps/posix/getcwd.c | 7 +
sysdeps/unix/sysv/linux/Makefile | 7 +-
.../unix/sysv/linux/tst-getcwd-smallbuff.c | 241 ++++++++++++++++++
4 files changed, 261 insertions(+), 1 deletion(-)
create mode 100644 sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c
diff --git a/NEWS b/NEWS
index 5352599d7f..cc026f03b1 100644
--- a/NEWS
+++ b/NEWS
@@ -30,6 +30,12 @@ Security related changes:
function could result in a memory leak and potential access of
uninitialized memory. Reported by Qualys.
+ CVE-2021-3999: Passing a buffer of size exactly 1 byte to the getcwd
+ function may result in an off-by-one buffer underflow and overflow
+ when the current working directory is longer than PATH_MAX and also
+ corresponds to the / directory through an unprivileged mount
+ namespace. Reported by Qualys.
+
The following bugs are resolved with this release:
[15271] dlfcn function failure after dlmopen terminates process
@@ -50,6 +56,7 @@ The following bugs are resolved with this release:
[28524] Conversion from ISO-2022-JP-3 with iconv may emit spurious NULs
[28532] powerpc64[le]: CFI for assembly templated syscalls is incorrect
[28768] CVE-2022-23218: Buffer overflow in sunrpc svcunix_create
+ [28769] CVE-2021-3999: Off-by-one buffer overflow/underflow in getcwd()
[28770] CVE-2021-3998: Unexpected return value from realpath() for too long results
\f
Version 2.33
diff --git a/sysdeps/posix/getcwd.c b/sysdeps/posix/getcwd.c
index f11644aae7..242e4dbe45 100644
--- a/sysdeps/posix/getcwd.c
+++ b/sysdeps/posix/getcwd.c
@@ -187,6 +187,13 @@ __getcwd_generic (char *buf, size_t size)
size_t allocated = size;
size_t used;
+ /* A size of 1 byte is never useful. */
+ if (allocated == 1)
+ {
+ __set_errno (ERANGE);
+ return NULL;
+ }
+
#if HAVE_MINIMALLY_WORKING_GETCWD
/* If AT_FDCWD is not defined, the algorithm below is O(N**2) and
this is much slower than the system getcwd (at least on
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 472eab700d..9531641f82 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -282,7 +282,12 @@ sysdep_routines += xstatconv internal_statvfs internal_statvfs64 \
sysdep_headers += bits/fcntl-linux.h
-tests += tst-fallocate tst-fallocate64 tst-o_path-locks
+tests += \
+ tst-fallocate \
+ tst-fallocate64 \
+ tst-getcwd-smallbuff \
+ tst-o_path-locks \
+# tests
endif
ifeq ($(subdir),elf)
diff --git a/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c b/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c
new file mode 100644
index 0000000000..d460d6e766
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c
@@ -0,0 +1,241 @@
+/* Verify that getcwd returns ERANGE for size 1 byte and does not underflow
+ buffer when the CWD is too long and is also a mount target of /. See bug
+ #28769 or CVE-2021-3999 for more context.
+ Copyright The GNU Toolchain Authors.
+ 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 <errno.h>
+#include <fcntl.h>
+#include <intprops.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <support/check.h>
+#include <support/temp_file.h>
+#include <support/xsched.h>
+#include <support/xunistd.h>
+
+static char *base;
+#define BASENAME "tst-getcwd-smallbuff"
+#define MOUNT_NAME "mpoint"
+static int sockfd[2];
+
+static void
+do_cleanup (void)
+{
+ support_chdir_toolong_temp_directory (base);
+ TEST_VERIFY_EXIT (rmdir (MOUNT_NAME) == 0);
+ free (base);
+}
+
+static void
+send_fd (const int sock, const int fd)
+{
+ struct msghdr msg = {0};
+ union
+ {
+ struct cmsghdr hdr;
+ char buf[CMSG_SPACE (sizeof (int))];
+ } cmsgbuf = {0};
+ struct cmsghdr *cmsg;
+ struct iovec vec;
+ char ch = 'A';
+ ssize_t n;
+
+ msg.msg_control = &cmsgbuf.buf;
+ msg.msg_controllen = sizeof (cmsgbuf.buf);
+
+ cmsg = CMSG_FIRSTHDR (&msg);
+ cmsg->cmsg_len = CMSG_LEN (sizeof (int));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ memcpy (CMSG_DATA (cmsg), &fd, sizeof (fd));
+
+ vec.iov_base = &ch;
+ vec.iov_len = 1;
+ msg.msg_iov = &vec;
+ msg.msg_iovlen = 1;
+
+ while ((n = sendmsg (sock, &msg, 0)) == -1 && errno == EINTR);
+
+ TEST_VERIFY_EXIT (n == 1);
+}
+
+static int
+recv_fd (const int sock)
+{
+ struct msghdr msg = {0};
+ union
+ {
+ struct cmsghdr hdr;
+ char buf[CMSG_SPACE(sizeof(int))];
+ } cmsgbuf = {0};
+ struct cmsghdr *cmsg;
+ struct iovec vec;
+ ssize_t n;
+ char ch = '\0';
+ int fd = -1;
+
+ vec.iov_base = &ch;
+ vec.iov_len = 1;
+ msg.msg_iov = &vec;
+ msg.msg_iovlen = 1;
+
+ msg.msg_control = &cmsgbuf.buf;
+ msg.msg_controllen = sizeof (cmsgbuf.buf);
+
+ while ((n = recvmsg (sock, &msg, 0)) == -1 && errno == EINTR);
+ if (n != 1 || ch != 'A')
+ return -1;
+
+ cmsg = CMSG_FIRSTHDR (&msg);
+ if (cmsg == NULL)
+ return -1;
+ if (cmsg->cmsg_type != SCM_RIGHTS)
+ return -1;
+ memcpy (&fd, CMSG_DATA (cmsg), sizeof (fd));
+ if (fd < 0)
+ return -1;
+ return fd;
+}
+
+static int
+child_func (void * const arg)
+{
+ xclose (sockfd[0]);
+ const int sock = sockfd[1];
+ char ch;
+
+ TEST_VERIFY_EXIT (read (sock, &ch, 1) == 1);
+ TEST_VERIFY_EXIT (ch == '1');
+
+ if (mount ("/", MOUNT_NAME, NULL, MS_BIND | MS_REC, NULL))
+ FAIL_EXIT1 ("mount failed: %m\n");
+ const int fd = xopen ("mpoint",
+ O_RDONLY | O_PATH | O_DIRECTORY | O_NOFOLLOW, 0);
+
+ send_fd (sock, fd);
+ xclose (fd);
+
+ TEST_VERIFY_EXIT (read (sock, &ch, 1) == 1);
+ TEST_VERIFY_EXIT (ch == 'a');
+
+ xclose (sock);
+ return 0;
+}
+
+static void
+update_map (char * const mapping, const char * const map_file)
+{
+ const size_t map_len = strlen (mapping);
+
+ const int fd = xopen (map_file, O_WRONLY, 0);
+ xwrite (fd, mapping, map_len);
+ xclose (fd);
+}
+
+static void
+proc_setgroups_write (const long child_pid, const char * const str)
+{
+ const size_t str_len = strlen(str);
+
+ char setgroups_path[sizeof ("/proc//setgroups") + INT_STRLEN_BOUND (long)];
+
+ snprintf (setgroups_path, sizeof (setgroups_path),
+ "/proc/%ld/setgroups", child_pid);
+
+ const int fd = open (setgroups_path, O_WRONLY);
+
+ if (fd < 0)
+ {
+ TEST_VERIFY_EXIT (errno == ENOENT);
+ FAIL_UNSUPPORTED ("/proc/%ld/setgroups not found\n", child_pid);
+ }
+
+ xwrite (fd, str, str_len);
+ xclose(fd);
+}
+
+static char child_stack[1024 * 1024];
+
+int
+do_test (void)
+{
+ base = support_create_and_chdir_toolong_temp_directory (BASENAME);
+
+ xmkdir (MOUNT_NAME, S_IRWXU);
+ atexit (do_cleanup);
+
+ TEST_VERIFY_EXIT (socketpair (AF_UNIX, SOCK_STREAM, 0, sockfd) == 0);
+ pid_t child_pid = xclone (child_func, NULL, child_stack,
+ sizeof (child_stack),
+ CLONE_NEWUSER | CLONE_NEWNS | SIGCHLD);
+
+ xclose (sockfd[1]);
+ const int sock = sockfd[0];
+
+ char map_path[sizeof ("/proc//uid_map") + INT_STRLEN_BOUND (long)];
+ char map_buf[sizeof ("0 1") + INT_STRLEN_BOUND (long)];
+
+ snprintf (map_path, sizeof (map_path), "/proc/%ld/uid_map",
+ (long) child_pid);
+ snprintf (map_buf, sizeof (map_buf), "0 %ld 1", (long) getuid());
+ update_map (map_buf, map_path);
+
+ proc_setgroups_write ((long) child_pid, "deny");
+ snprintf (map_path, sizeof (map_path), "/proc/%ld/gid_map",
+ (long) child_pid);
+ snprintf (map_buf, sizeof (map_buf), "0 %ld 1", (long) getgid());
+ update_map (map_buf, map_path);
+
+ TEST_VERIFY_EXIT (send (sock, "1", 1, MSG_NOSIGNAL) == 1);
+ const int fd = recv_fd (sock);
+ TEST_VERIFY_EXIT (fd >= 0);
+ TEST_VERIFY_EXIT (fchdir (fd) == 0);
+
+ static char buf[2 * 10 + 1];
+ memset (buf, 'A', sizeof (buf));
+
+ /* Finally, call getcwd and check if it resulted in a buffer underflow. */
+ char * cwd = getcwd (buf + sizeof (buf) / 2, 1);
+ TEST_VERIFY (cwd == NULL);
+ TEST_VERIFY (errno == ERANGE);
+
+ for (int i = 0; i < sizeof (buf); i++)
+ if (buf[i] != 'A')
+ {
+ printf ("buf[%d] = %02x\n", i, (unsigned int) buf[i]);
+ support_record_failure ();
+ }
+
+ TEST_VERIFY_EXIT (send (sock, "a", 1, MSG_NOSIGNAL) == 1);
+ xclose (sock);
+ TEST_VERIFY_EXIT (xwaitpid (child_pid, NULL, 0) == child_pid);
+
+ return 0;
+}
+
+#define CLEANUP_HANDLER do_cleanup
+#include <support/test-driver.c>
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [COMMITTED 2.33 6/7] realpath: Avoid overwriting preexisting error (CVE-2021-3998)
2022-01-24 22:48 [COMMITTED 2.33 1/7] support: Add helpers to create paths longer than PATH_MAX Aurelien Jarno
` (3 preceding siblings ...)
2022-01-24 22:48 ` [COMMITTED 2.33 5/7] getcwd: Set errno to ERANGE for size == 1 (CVE-2021-3999) Aurelien Jarno
@ 2022-01-24 22:48 ` Aurelien Jarno
2022-01-24 22:48 ` [COMMITTED 2.33 7/7] Linux: Detect user namespace support in io/tst-getcwd-smallbuff Aurelien Jarno
5 siblings, 0 replies; 7+ messages in thread
From: Aurelien Jarno @ 2022-01-24 22:48 UTC (permalink / raw)
To: libc-stable; +Cc: Siddhesh Poyarekar, Andreas Schwab
From: Siddhesh Poyarekar <siddhesh@sourceware.org>
Set errno and failure for paths that are too long only if no other error
occurred earlier.
Related: BZ #28770
Reviewed-by: Andreas Schwab <schwab@linux-m68k.org>
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
(cherry picked from commit 84d2d0fe20bdf94feed82b21b4d7d136db471f03)
---
stdlib/canonicalize.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c
index 7a23a51b3a..e2d4244fc7 100644
--- a/stdlib/canonicalize.c
+++ b/stdlib/canonicalize.c
@@ -404,7 +404,7 @@ error:
{
if (dest - rname <= get_path_max ())
rname = strcpy (resolved, rname);
- else
+ else if (!failed)
{
failed = true;
__set_errno (ENAMETOOLONG);
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [COMMITTED 2.33 7/7] Linux: Detect user namespace support in io/tst-getcwd-smallbuff
2022-01-24 22:48 [COMMITTED 2.33 1/7] support: Add helpers to create paths longer than PATH_MAX Aurelien Jarno
` (4 preceding siblings ...)
2022-01-24 22:48 ` [COMMITTED 2.33 6/7] realpath: Avoid overwriting preexisting error (CVE-2021-3998) Aurelien Jarno
@ 2022-01-24 22:48 ` Aurelien Jarno
5 siblings, 0 replies; 7+ messages in thread
From: Aurelien Jarno @ 2022-01-24 22:48 UTC (permalink / raw)
To: libc-stable; +Cc: Florian Weimer, Siddhesh Poyarekar
From: Florian Weimer <fweimer@redhat.com>
Otherwise the test fails with certain container runtimes.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
(cherry picked from commit 5b8e7980c5dabd9aaefeba4f0208baa8cf7653ee)
---
sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c b/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c
index d460d6e766..55362f6060 100644
--- a/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c
+++ b/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c
@@ -34,6 +34,7 @@
#include <sys/un.h>
#include <support/check.h>
#include <support/temp_file.h>
+#include <support/test-driver.h>
#include <support/xsched.h>
#include <support/xunistd.h>
@@ -188,6 +189,23 @@ do_test (void)
xmkdir (MOUNT_NAME, S_IRWXU);
atexit (do_cleanup);
+ /* Check whether user namespaces are supported. */
+ {
+ pid_t pid = xfork ();
+ if (pid == 0)
+ {
+ if (unshare (CLONE_NEWUSER | CLONE_NEWNS) != 0)
+ _exit (EXIT_UNSUPPORTED);
+ else
+ _exit (0);
+ }
+ int status;
+ xwaitpid (pid, &status, 0);
+ TEST_VERIFY_EXIT (WIFEXITED (status));
+ if (WEXITSTATUS (status) != 0)
+ return WEXITSTATUS (status);
+ }
+
TEST_VERIFY_EXIT (socketpair (AF_UNIX, SOCK_STREAM, 0, sockfd) == 0);
pid_t child_pid = xclone (child_func, NULL, child_stack,
sizeof (child_stack),
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread