summaryrefslogtreecommitdiffstats
path: root/patches/source/glibc/patches
diff options
context:
space:
mode:
Diffstat (limited to 'patches/source/glibc/patches')
-rw-r--r--patches/source/glibc/patches/0001-nsswitch-return-result-when-nss-database-is-locked.patch47
-rw-r--r--patches/source/glibc/patches/CVE-2021-27645.patch20
-rw-r--r--patches/source/glibc/patches/CVE-2021-33574_1.patch71
-rw-r--r--patches/source/glibc/patches/CVE-2021-33574_2.patch53
-rw-r--r--patches/source/glibc/patches/CVE-2021-35942.patch41
-rw-r--r--patches/source/glibc/patches/CVE-2021-38604.patch40
-rw-r--r--patches/source/glibc/patches/CVE-2024-2961_glibc2.33.patch205
-rw-r--r--patches/source/glibc/patches/cdc31409bd4f878577059e70dbd52a28643ec609.patch237
-rw-r--r--patches/source/glibc/patches/glibc.CVE-2021-3998.patch123
-rw-r--r--patches/source/glibc/patches/glibc.CVE-2021-3999.patch356
10 files changed, 1193 insertions, 0 deletions
diff --git a/patches/source/glibc/patches/0001-nsswitch-return-result-when-nss-database-is-locked.patch b/patches/source/glibc/patches/0001-nsswitch-return-result-when-nss-database-is-locked.patch
new file mode 100644
index 000000000..458369251
--- /dev/null
+++ b/patches/source/glibc/patches/0001-nsswitch-return-result-when-nss-database-is-locked.patch
@@ -0,0 +1,47 @@
+From c3479fb7939898ec22c655c383454d6e8b982a67 Mon Sep 17 00:00:00 2001
+From: Sergei Trofimovich <slyfox@gentoo.org>
+Date: Fri, 5 Feb 2021 07:32:18 +0000
+Subject: [PATCH] nsswitch: return result when nss database is locked [BZ
+ #27343]
+
+Before the change nss_database_check_reload_and_get() did not populate
+the '*result' value when it returned success in a case of chroot
+detection. This caused initgroups() to use garage pointer in the
+following test (extracted from unbound):
+
+```
+
+int main() {
+ // load some NSS modules
+ struct passwd * pw = getpwnam("root");
+
+ chdir("/tmp");
+ chroot("/tmp");
+ chdir("/");
+ // access nsswitch.conf in a chroot
+ initgroups("root", 0);
+}
+```
+
+Reviewed-by: DJ Delorie <dj@redhat.com>
+---
+ nss/nss_database.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/nss/nss_database.c b/nss/nss_database.c
+index cf0306adc4..e1bef6bd75 100644
+--- a/nss/nss_database.c
++++ b/nss/nss_database.c
+@@ -398,8 +398,9 @@ nss_database_check_reload_and_get (struct nss_database_state *local,
+ && (str.st_ino != local->root_ino
+ || str.st_dev != local->root_dev)))
+ {
+- /* Change detected; disable reloading. */
++ /* Change detected; disable reloading and return current state. */
+ atomic_store_release (&local->data.reload_disabled, 1);
++ *result = local->data.services[database_index];
+ __libc_lock_unlock (local->lock);
+ __nss_module_disable_loading ();
+ return true;
+--
+2.27.0
diff --git a/patches/source/glibc/patches/CVE-2021-27645.patch b/patches/source/glibc/patches/CVE-2021-27645.patch
new file mode 100644
index 000000000..c568dd16b
--- /dev/null
+++ b/patches/source/glibc/patches/CVE-2021-27645.patch
@@ -0,0 +1,20 @@
+--- ./nscd/netgroupcache.c.orig 2021-08-07 13:20:02.459057859 -0500
++++ ./nscd/netgroupcache.c 2021-08-07 13:22:08.983060689 -0500
+@@ -248,7 +248,7 @@
+ : NULL);
+ ndomain = (ndomain ? newbuf + ndomaindiff
+ : NULL);
+- buffer = newbuf;
++ *tofreep = buffer = newbuf;
+ }
+
+ nhost = memcpy (buffer + bufused,
+@@ -319,7 +319,7 @@
+ else if (status == NSS_STATUS_TRYAGAIN && e == ERANGE)
+ {
+ buflen *= 2;
+- buffer = xrealloc (buffer, buflen);
++ *tofreep = buffer = xrealloc (buffer, buflen);
+ }
+ else if (status == NSS_STATUS_RETURN
+ || status == NSS_STATUS_NOTFOUND
diff --git a/patches/source/glibc/patches/CVE-2021-33574_1.patch b/patches/source/glibc/patches/CVE-2021-33574_1.patch
new file mode 100644
index 000000000..20f1889ce
--- /dev/null
+++ b/patches/source/glibc/patches/CVE-2021-33574_1.patch
@@ -0,0 +1,71 @@
+From 42d359350510506b87101cf77202fefcbfc790cb Mon Sep 17 00:00:00 2001
+From: Andreas Schwab <schwab@linux-m68k.org>
+Date: Thu, 27 May 2021 12:49:47 +0200
+Subject: [PATCH] Use __pthread_attr_copy in mq_notify (bug 27896)
+
+Make a deep copy of the pthread attribute object to remove a potential
+use-after-free issue.
+---
+ NEWS | 4 ++++
+ sysdeps/unix/sysv/linux/mq_notify.c | 15 ++++++++++-----
+ 2 files changed, 14 insertions(+), 5 deletions(-)
+
+diff --git a/NEWS b/NEWS
+index 6f4d325d55..1bf3daa502 100644
+--- a/NEWS
++++ b/NEWS
+@@ -62,6 +62,10 @@ Security related changes:
+ potentially resulting in degraded service or Denial of Service on the
+ local system. Reported by Chris Schanzle.
+
++ CVE-2021-33574: The mq_notify function has a potential use-after-free
++ issue when using a notification type of SIGEV_THREAD and a thread
++ attribute with a non-default affinity mask.
++
+ The following bugs are resolved with this release:
+
+ [The release manager will add the list generated by
+diff --git a/sysdeps/unix/sysv/linux/mq_notify.c b/sysdeps/unix/sysv/linux/mq_notify.c
+index cc575a0cdd..f7ddfe5a6c 100644
+--- a/sysdeps/unix/sysv/linux/mq_notify.c
++++ b/sysdeps/unix/sysv/linux/mq_notify.c
+@@ -133,8 +133,11 @@ helper_thread (void *arg)
+ (void) __pthread_barrier_wait (&notify_barrier);
+ }
+ else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED)
+- /* The only state we keep is the copy of the thread attributes. */
+- free (data.attr);
++ {
++ /* The only state we keep is the copy of the thread attributes. */
++ pthread_attr_destroy (data.attr);
++ free (data.attr);
++ }
+ }
+ return NULL;
+ }
+@@ -255,8 +258,7 @@ mq_notify (mqd_t mqdes, const struct sigevent *notification)
+ if (data.attr == NULL)
+ return -1;
+
+- memcpy (data.attr, notification->sigev_notify_attributes,
+- sizeof (pthread_attr_t));
++ __pthread_attr_copy (data.attr, notification->sigev_notify_attributes);
+ }
+
+ /* Construct the new request. */
+@@ -270,7 +272,10 @@ mq_notify (mqd_t mqdes, const struct sigevent *notification)
+
+ /* If it failed, free the allocated memory. */
+ if (__glibc_unlikely (retval != 0))
+- free (data.attr);
++ {
++ pthread_attr_destroy (data.attr);
++ free (data.attr);
++ }
+
+ return retval;
+ }
+--
+2.27.0
+
+
diff --git a/patches/source/glibc/patches/CVE-2021-33574_2.patch b/patches/source/glibc/patches/CVE-2021-33574_2.patch
new file mode 100644
index 000000000..608dbfdc5
--- /dev/null
+++ b/patches/source/glibc/patches/CVE-2021-33574_2.patch
@@ -0,0 +1,53 @@
+From 217b6dc298156bdb0d6aea9ea93e7e394a5ff091 Mon Sep 17 00:00:00 2001
+From: Florian Weimer <fweimer@redhat.com>
+Date: Tue, 1 Jun 2021 17:51:41 +0200
+Subject: [PATCH] Fix use of __pthread_attr_copy in mq_notify (bug 27896)
+
+__pthread_attr_copy can fail and does not initialize the attribute
+structure in that case.
+
+If __pthread_attr_copy is never called and there is no allocated
+attribute, pthread_attr_destroy should not be called, otherwise
+there is a null pointer dereference in rt/tst-mqueue6.
+
+Fixes commit 42d359350510506b87101cf77202fefcbfc790cb
+("Use __pthread_attr_copy in mq_notify (bug 27896)").
+
+Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
+---
+ sysdeps/unix/sysv/linux/mq_notify.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/sysdeps/unix/sysv/linux/mq_notify.c b/sysdeps/unix/sysv/linux/mq_notify.c
+index f7ddfe5a6c..6f46d29d1d 100644
+--- a/sysdeps/unix/sysv/linux/mq_notify.c
++++ b/sysdeps/unix/sysv/linux/mq_notify.c
+@@ -258,7 +258,14 @@ mq_notify (mqd_t mqdes, const struct sigevent *notification)
+ if (data.attr == NULL)
+ return -1;
+
+- __pthread_attr_copy (data.attr, notification->sigev_notify_attributes);
++ int ret = __pthread_attr_copy (data.attr,
++ notification->sigev_notify_attributes);
++ if (ret != 0)
++ {
++ free (data.attr);
++ __set_errno (ret);
++ return -1;
++ }
+ }
+
+ /* Construct the new request. */
+@@ -271,7 +278,7 @@ mq_notify (mqd_t mqdes, const struct sigevent *notification)
+ int retval = INLINE_SYSCALL (mq_notify, 2, mqdes, &se);
+
+ /* If it failed, free the allocated memory. */
+- if (__glibc_unlikely (retval != 0))
++ if (retval != 0 && data.attr != NULL)
+ {
+ pthread_attr_destroy (data.attr);
+ free (data.attr);
+--
+2.27.0
+
+
diff --git a/patches/source/glibc/patches/CVE-2021-35942.patch b/patches/source/glibc/patches/CVE-2021-35942.patch
new file mode 100644
index 000000000..fde0fbdb3
--- /dev/null
+++ b/patches/source/glibc/patches/CVE-2021-35942.patch
@@ -0,0 +1,41 @@
+From 5adda61f62b77384718b4c0d8336ade8f2b4b35c Mon Sep 17 00:00:00 2001
+From: Andreas Schwab <schwab@linux-m68k.org>
+Date: Fri, 25 Jun 2021 15:02:47 +0200
+Subject: [PATCH] wordexp: handle overflow in positional parameter number (bug
+ 28011)
+
+Use strtoul instead of atoi so that overflow can be detected.
+---
+ posix/wordexp-test.c | 1 +
+ posix/wordexp.c | 2 +-
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/posix/wordexp-test.c b/posix/wordexp-test.c
+index f93a546d7e..9df02dbbb3 100644
+--- a/posix/wordexp-test.c
++++ b/posix/wordexp-test.c
+@@ -183,6 +183,7 @@ struct test_case_struct
+ { 0, NULL, "$var", 0, 0, { NULL, }, IFS },
+ { 0, NULL, "\"\\n\"", 0, 1, { "\\n", }, IFS },
+ { 0, NULL, "", 0, 0, { NULL, }, IFS },
++ { 0, NULL, "${1234567890123456789012}", 0, 0, { NULL, }, IFS },
+
+ /* Flags not already covered (testit() has special handling for these) */
+ { 0, NULL, "one two", WRDE_DOOFFS, 2, { "one", "two", }, IFS },
+diff --git a/posix/wordexp.c b/posix/wordexp.c
+index bcbe96e48d..1f3b09f721 100644
+--- a/posix/wordexp.c
++++ b/posix/wordexp.c
+@@ -1399,7 +1399,7 @@ envsubst:
+ /* Is it a numeric parameter? */
+ else if (isdigit (env[0]))
+ {
+- int n = atoi (env);
++ unsigned long n = strtoul (env, NULL, 10);
+
+ if (n >= __libc_argc)
+ /* Substitute NULL. */
+--
+2.27.0
+
+
diff --git a/patches/source/glibc/patches/CVE-2021-38604.patch b/patches/source/glibc/patches/CVE-2021-38604.patch
new file mode 100644
index 000000000..ad0a81588
--- /dev/null
+++ b/patches/source/glibc/patches/CVE-2021-38604.patch
@@ -0,0 +1,40 @@
+From b805aebd42364fe696e417808a700fdb9800c9e8 Mon Sep 17 00:00:00 2001
+From: Nikita Popov <npv1310@gmail.com>
+Date: Mon, 9 Aug 2021 20:17:34 +0530
+Subject: [PATCH] librt: fix NULL pointer dereference (bug 28213)
+
+Helper thread frees copied attribute on NOTIFY_REMOVED message
+received from the OS kernel. Unfortunately, it fails to check whether
+copied attribute actually exists (data.attr != NULL). This worked
+earlier because free() checks passed pointer before actually
+attempting to release corresponding memory. But
+__pthread_attr_destroy assumes pointer is not NULL.
+
+So passing NULL pointer to __pthread_attr_destroy will result in
+segmentation fault. This scenario is possible if
+notification->sigev_notify_attributes == NULL (which means default
+thread attributes should be used).
+
+Signed-off-by: Nikita Popov <npv1310@gmail.com>
+Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
+---
+ sysdeps/unix/sysv/linux/mq_notify.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/sysdeps/unix/sysv/linux/mq_notify.c b/sysdeps/unix/sysv/linux/mq_notify.c
+index 9799dcdaa4..eccae2e4c6 100644
+--- a/sysdeps/unix/sysv/linux/mq_notify.c
++++ b/sysdeps/unix/sysv/linux/mq_notify.c
+@@ -131,7 +131,7 @@ helper_thread (void *arg)
+ to wait until it is done with it. */
+ (void) __pthread_barrier_wait (&notify_barrier);
+ }
+- else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED)
++ else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED && data.attr != NULL)
+ {
+ /* The only state we keep is the copy of the thread attributes. */
+ __pthread_attr_destroy (data.attr);
+--
+2.27.0
+
+
diff --git a/patches/source/glibc/patches/CVE-2024-2961_glibc2.33.patch b/patches/source/glibc/patches/CVE-2024-2961_glibc2.33.patch
new file mode 100644
index 000000000..211bd38c7
--- /dev/null
+++ b/patches/source/glibc/patches/CVE-2024-2961_glibc2.33.patch
@@ -0,0 +1,205 @@
+From ed4f16ff6bed3037266f1fa682ebd32a18fce29c Mon Sep 17 00:00:00 2001
+From: Charles Fol <folcharles@gmail.com>
+Date: Thu, 28 Mar 2024 12:25:38 -0300
+Subject: [PATCH] iconv: ISO-2022-CN-EXT: fix out-of-bound writes when writing
+ escape sequence (CVE-2024-2961)
+
+ISO-2022-CN-EXT uses escape sequences to indicate character set changes
+(as specified by RFC 1922). While the SOdesignation has the expected
+bounds checks, neither SS2designation nor SS3designation have its;
+allowing a write overflow of 1, 2, or 3 bytes with fixed values:
+'$+I', '$+J', '$+K', '$+L', '$+M', or '$*H'.
+
+Checked on aarch64-linux-gnu.
+
+Co-authored-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
+Reviewed-by: Carlos O'Donell <carlos@redhat.com>
+Tested-by: Carlos O'Donell <carlos@redhat.com>
+
+(cherry picked from commit f9dc609e06b1136bb0408be9605ce7973a767ada)
+---
+ iconvdata/Makefile | 5 +-
+ iconvdata/iso-2022-cn-ext.c | 12 +++
+ iconvdata/tst-iconv-iso-2022-cn-ext.c | 128 ++++++++++++++++++++++++++
+ 3 files changed, 144 insertions(+), 1 deletion(-)
+ create mode 100644 iconvdata/tst-iconv-iso-2022-cn-ext.c
+
+--- ./iconvdata/iso-2022-cn-ext.c.orig 2021-02-01 11:15:33.000000000 -0600
++++ ./iconvdata/iso-2022-cn-ext.c 2024-04-18 13:10:47.597086361 -0500
+@@ -575,6 +575,12 @@
+ { \
+ const char *escseq; \
+ \
++ if (outptr + 4 > outend) \
++ { \
++ result = __GCONV_FULL_OUTPUT; \
++ break; \
++ } \
++ \
+ assert (used == CNS11643_2_set); /* XXX */ \
+ escseq = "*H"; \
+ *outptr++ = ESC; \
+@@ -588,6 +594,12 @@
+ { \
+ const char *escseq; \
+ \
++ if (outptr + 4 > outend) \
++ { \
++ result = __GCONV_FULL_OUTPUT; \
++ break; \
++ } \
++ \
+ assert ((used >> 5) >= 3 && (used >> 5) <= 7); \
+ escseq = "+I+J+K+L+M" + ((used >> 5) - 3) * 2; \
+ *outptr++ = ESC; \
+--- ./iconvdata/tst-iconv-iso-2022-cn-ext.c.orig 2024-04-18 13:10:47.597086361 -0500
++++ ./iconvdata/tst-iconv-iso-2022-cn-ext.c 2024-04-18 13:10:47.597086361 -0500
+@@ -0,0 +1,128 @@
++/* Verify ISO-2022-CN-EXT does not write out of the bounds.
++ 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 <stdio.h>
++#include <string.h>
++
++#include <errno.h>
++#include <iconv.h>
++#include <sys/mman.h>
++
++#include <support/xunistd.h>
++#include <support/check.h>
++#include <support/support.h>
++
++/* The test sets up a two memory page buffer with the second page marked
++ PROT_NONE to trigger a fault if the conversion writes beyond the exact
++ expected amount. Then we carry out various conversions and precisely
++ place the start of the output buffer in order to trigger a SIGSEGV if the
++ process writes anywhere between 1 and page sized bytes more (only one
++ PROT_NONE page is setup as a canary) than expected. These tests exercise
++ all three of the cases in ISO-2022-CN-EXT where the converter must switch
++ character sets and may run out of buffer space while doing the
++ operation. */
++
++static int
++do_test (void)
++{
++ iconv_t cd = iconv_open ("ISO-2022-CN-EXT", "UTF-8");
++ TEST_VERIFY_EXIT (cd != (iconv_t) -1);
++
++ char *ntf;
++ size_t ntfsize;
++ char *outbufbase;
++ {
++ int pgz = getpagesize ();
++ TEST_VERIFY_EXIT (pgz > 0);
++ ntfsize = 2 * pgz;
++
++ ntf = xmmap (NULL, ntfsize, PROT_READ | PROT_WRITE, MAP_PRIVATE
++ | MAP_ANONYMOUS, -1);
++ xmprotect (ntf + pgz, pgz, PROT_NONE);
++
++ outbufbase = ntf + pgz;
++ }
++
++ /* Check if SOdesignation escape sequence does not trigger an OOB write. */
++ {
++ char inbuf[] = "\xe4\xba\xa4\xe6\x8d\xa2";
++
++ for (int i = 0; i < 9; i++)
++ {
++ char *inp = inbuf;
++ size_t inleft = sizeof (inbuf) - 1;
++
++ char *outp = outbufbase - i;
++ size_t outleft = i;
++
++ TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft)
++ == (size_t) -1);
++ TEST_COMPARE (errno, E2BIG);
++
++ TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0);
++ }
++ }
++
++ /* Same as before for SS2designation. */
++ {
++ char inbuf[] = "ã´½ \xe3\xb4\xbd";
++
++ for (int i = 0; i < 14; i++)
++ {
++ char *inp = inbuf;
++ size_t inleft = sizeof (inbuf) - 1;
++
++ char *outp = outbufbase - i;
++ size_t outleft = i;
++
++ TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft)
++ == (size_t) -1);
++ TEST_COMPARE (errno, E2BIG);
++
++ TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0);
++ }
++ }
++
++ /* Same as before for SS3designation. */
++ {
++ char inbuf[] = "劄 \xe5\x8a\x84";
++
++ for (int i = 0; i < 14; i++)
++ {
++ char *inp = inbuf;
++ size_t inleft = sizeof (inbuf) - 1;
++
++ char *outp = outbufbase - i;
++ size_t outleft = i;
++
++ TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft)
++ == (size_t) -1);
++ TEST_COMPARE (errno, E2BIG);
++
++ TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0);
++ }
++ }
++
++ TEST_VERIFY_EXIT (iconv_close (cd) != -1);
++
++ xmunmap (ntf, ntfsize);
++
++ return 0;
++}
++
++#include <support/test-driver.c>
+--- ./iconvdata/Makefile.orig 2021-02-01 11:15:33.000000000 -0600
++++ ./iconvdata/Makefile 2024-04-18 13:12:59.503089312 -0500
+@@ -74,7 +74,7 @@
+ tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \
+ tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \
+ bug-iconv10 bug-iconv11 bug-iconv12 tst-iconv-big5-hkscs-to-2ucs4 \
+- bug-iconv13 bug-iconv14
++ bug-iconv13 bug-iconv14 tst-iconv-iso-2022-cn-ext
+ ifeq ($(have-thread-library),yes)
+ tests += bug-iconv3
+ endif
+@@ -324,6 +324,8 @@
+ $(addprefix $(objpfx),$(modules.so))
+ $(objpfx)bug-iconv14.out: $(objpfx)gconv-modules \
+ $(addprefix $(objpfx),$(modules.so))
++$(objpfx)tst-iconv-iso-2022-cn-ext.out: $(addprefix $(objpfx), $(gconv-modules)) \
++ $(addprefix $(objpfx),$(modules.so))
+
+ $(objpfx)iconv-test.out: run-iconv-test.sh $(objpfx)gconv-modules \
+ $(addprefix $(objpfx),$(modules.so)) \
diff --git a/patches/source/glibc/patches/cdc31409bd4f878577059e70dbd52a28643ec609.patch b/patches/source/glibc/patches/cdc31409bd4f878577059e70dbd52a28643ec609.patch
new file mode 100644
index 000000000..96f56ce73
--- /dev/null
+++ b/patches/source/glibc/patches/cdc31409bd4f878577059e70dbd52a28643ec609.patch
@@ -0,0 +1,237 @@
+From cdc31409bd4f878577059e70dbd52a28643ec609 Mon Sep 17 00:00:00 2001
+From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
+Date: Wed, 31 Mar 2021 13:53:34 -0300
+Subject: [PATCH] linux: Normalize and return timeout on select (BZ #27651)
+
+The commit 2433d39b697, which added time64 support to select, changed
+the function to use __NR_pselect6 (or __NR_pelect6_time64) on all
+architectures. However, on architectures where the symbol was
+implemented with __NR_select the kernel normalizes the passed timeout
+instead of return EINVAL. For instance, the input timeval
+{ 0, 5000000 } is interpreted as { 5, 0 }.
+
+And as indicated by BZ #27651, this semantic seems to be expected
+and changing it results in some performance issues (most likely
+the program does not check the return code and keeps issuing
+select with unormalized tv_usec argument).
+
+To avoid a different semantic depending whether which syscall the
+architecture used to issue, select now always normalize the timeout
+input. This is a slight change for some ABIs (for instance aarch64).
+
+Checked on x86_64-linux-gnu and i686-linux-gnu.
+---
+ include/time.h | 5 +++
+ sunrpc/svcauth_des.c | 1 -
+ support/Makefile | 2 ++
+ support/support.h | 8 +++++
+ support/support_select_modify_timeout.c | 29 ++++++++++++++++
+ support/support_select_normalize_timeout.c | 29 ++++++++++++++++
+ sysdeps/unix/sysv/linux/select.c | 40 ++++++++++++++++++----
+ 8 files changed, 123 insertions(+), 8 deletions(-)
+ create mode 100644 support/support_select_modify_timeout.c
+ create mode 100644 support/support_select_normalize_timeout.c
+
+diff --git a/include/time.h b/include/time.h
+index caf2af5e74..e0636132a6 100644
+--- a/include/time.h
++++ b/include/time.h
+@@ -502,6 +502,11 @@ time_now (void)
+ __clock_gettime (TIME_CLOCK_GETTIME_CLOCKID, &ts);
+ return ts.tv_sec;
+ }
++
++#define NSEC_PER_SEC 1000000000L /* Nanoseconds per second. */
++#define USEC_PER_SEC 1000000L /* Microseconds per second. */
++#define NSEC_PER_USEC 1000L /* Nanoseconds per microsecond. */
++
+ #endif
+
+ #endif
+diff --git a/sunrpc/svcauth_des.c b/sunrpc/svcauth_des.c
+index 7607abc818..25a85c9097 100644
+--- a/sunrpc/svcauth_des.c
++++ b/sunrpc/svcauth_des.c
+@@ -58,7 +58,6 @@
+
+ #define debug(msg) /*printf("svcauth_des: %s\n", msg) */
+
+-#define USEC_PER_SEC ((uint32_t) 1000000L)
+ #define BEFORE(t1, t2) timercmp(t1, t2, <)
+
+ /*
+diff --git a/support/Makefile b/support/Makefile
+index 900e17f94f..1e2fc97ee6 100644
+--- a/support/Makefile
++++ b/support/Makefile
+@@ -68,6 +68,8 @@ libsupport-routines = \
+ support_quote_string \
+ support_record_failure \
+ support_run_diff \
++ support_select_modify_timeout \
++ support_select_normalize_timeout \
+ support_set_small_thread_stack_size \
+ support_shared_allocate \
+ support_small_stack_thread_attribute \
+diff --git a/support/support.h b/support/support.h
+index e023d00857..f983783d64 100644
+--- a/support/support.h
++++ b/support/support.h
+@@ -144,6 +144,14 @@ static __inline bool support_path_support_time64 (const char *path)
+ /* Return true if stat supports nanoseconds resolution. */
+ extern bool support_stat_nanoseconds (const char *path);
+
++/* Return true if select modify the timeout to reflect the amount of time
++ no slept. */
++extern bool support_select_modify_timeout (void);
++
++/* Return true if select normalize the timeout input by taking in account
++ tv_usec larger than 1000000. */
++extern bool support_select_normalize_timeout (void);
++
+ __END_DECLS
+
+ #endif /* SUPPORT_H */
+diff --git a/support/support_select_modify_timeout.c b/support/support_select_modify_timeout.c
+new file mode 100644
+index 0000000000..d70a5a5068
+--- /dev/null
++++ b/support/support_select_modify_timeout.c
+@@ -0,0 +1,29 @@
++/* Return whether select modify the timeout.
++ 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/>. */
++
++#include <stdbool.h>
++
++bool
++support_select_modify_timeout (void)
++{
++#ifdef __linux__
++ return true;
++#else
++ return false;
++#endif
++}
+diff --git a/support/support_select_normalize_timeout.c b/support/support_select_normalize_timeout.c
+new file mode 100644
+index 0000000000..447e3ec3e3
+--- /dev/null
++++ b/support/support_select_normalize_timeout.c
+@@ -0,0 +1,29 @@
++/* Return whether select normalize the timeout.
++ 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/>. */
++
++#include <stdbool.h>
++
++bool
++support_select_normalize_timeout (void)
++{
++#ifdef __linux__
++ return true;
++#else
++ return false;
++#endif
++}
+diff --git a/sysdeps/unix/sysv/linux/select.c b/sysdeps/unix/sysv/linux/select.c
+index 415aa87d3c..d075270ff4 100644
+--- a/sysdeps/unix/sysv/linux/select.c
++++ b/sysdeps/unix/sysv/linux/select.c
+@@ -33,12 +33,34 @@ int
+ __select64 (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ struct __timeval64 *timeout)
+ {
+- struct __timespec64 ts64, *pts64 = NULL;
+- if (timeout != NULL)
++ __time64_t s = timeout != NULL ? timeout->tv_sec : 0;
++ int32_t us = timeout != NULL ? timeout->tv_usec : 0;
++ int32_t ns;
++
++ if (s < 0 || us < 0)
++ return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
++
++ /* Normalize the timeout, as legacy Linux __NR_select and __NR__newselect.
++ Different than syscall, it also handle possible overflow. */
++ if (us / USEC_PER_SEC > INT64_MAX - s)
+ {
+- ts64 = timeval64_to_timespec64 (*timeout);
+- pts64 = &ts64;
++ s = INT64_MAX;
++ ns = NSEC_PER_SEC - 1;
+ }
++ else
++ {
++ s += us / USEC_PER_SEC;
++ us = us % USEC_PER_SEC;
++ ns = us * NSEC_PER_USEC;
++ }
++
++ struct __timespec64 ts64, *pts64 = NULL;
++ if (timeout != NULL)
++ {
++ ts64.tv_sec = s;
++ ts64.tv_nsec = ns;
++ pts64 = &ts64;
++ }
+
+ #ifndef __NR_pselect6_time64
+ # define __NR_pselect6_time64 __NR_pselect6
+@@ -52,10 +74,13 @@ __select64 (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ (though the pselect() glibc call suppresses this behavior).
+ Since select() on Linux has the same behavior as the pselect6
+ syscall, we update the timeout here. */
+- if (r == 0 || errno != ENOSYS)
++ if (r >= 0 || errno != ENOSYS)
+ {
+ if (timeout != NULL)
+- TIMEVAL_TO_TIMESPEC (timeout, &ts64);
++ {
++ timeout->tv_sec = ts64.tv_sec;
++ timeout->tv_usec = ts64.tv_nsec / NSEC_PER_USEC;
++ }
+ return r;
+ }
+
+@@ -71,7 +96,8 @@ __select64 (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ __set_errno (EINVAL);
+ return -1;
+ }
+- ts32 = valid_timespec64_to_timespec (ts64);
++ ts32.tv_sec = s;
++ ts32.tv_nsec = ns;
+ pts32 = &ts32;
+ }
+ # ifndef __ASSUME_PSELECT
+--
+2.27.0
+
+
diff --git a/patches/source/glibc/patches/glibc.CVE-2021-3998.patch b/patches/source/glibc/patches/glibc.CVE-2021-3998.patch
new file mode 100644
index 000000000..45602d050
--- /dev/null
+++ b/patches/source/glibc/patches/glibc.CVE-2021-3998.patch
@@ -0,0 +1,123 @@
+From f7a79879c0b2bef0dadd6caaaeeb0d26423e04e5 Mon Sep 17 00:00:00 2001
+From: Siddhesh Poyarekar <siddhesh@sourceware.org>
+Date: Thu, 13 Jan 2022 11:28:36 +0530
+Subject: [PATCH] realpath: Set errno to ENAMETOOLONG for result larger than
+ PATH_MAX [BZ #28770]
+
+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 | 4 +++
+ stdlib/Makefile | 1 +
+ stdlib/canonicalize.c | 12 +++++++--
+ stdlib/tst-realpath-toolong.c | 49 +++++++++++++++++++++++++++++++++++
+ 4 files changed, 64 insertions(+), 2 deletions(-)
+ create mode 100644 stdlib/tst-realpath-toolong.c
+
+--- ./NEWS.orig 2021-02-01 11:15:33.000000000 -0600
++++ ./NEWS 2022-01-24 13:32:24.268678228 -0600
+@@ -118,6 +118,10 @@
+ CVE-2019-25013: A buffer overflow has been fixed in the iconv function when
+ invoked with EUC-KR input containing invalid multibyte input sequences.
+
++ 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:
+
+ [10635] libc: realpath portability patches
+--- ./stdlib/canonicalize.c.orig 2021-02-01 11:15:33.000000000 -0600
++++ ./stdlib/canonicalize.c 2022-01-24 13:32:24.268678228 -0600
+@@ -400,8 +400,16 @@
+
+ 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);
+--- ./stdlib/Makefile.orig 2022-01-24 13:32:24.268678228 -0600
++++ ./stdlib/Makefile 2022-01-24 13:32:59.968676254 -0600
+@@ -86,7 +86,7 @@
+ 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
+--- ./stdlib/tst-realpath-toolong.c.orig 2022-01-24 13:32:24.268678228 -0600
++++ ./stdlib/tst-realpath-toolong.c 2022-01-24 13:32:24.268678228 -0600
+@@ -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>
diff --git a/patches/source/glibc/patches/glibc.CVE-2021-3999.patch b/patches/source/glibc/patches/glibc.CVE-2021-3999.patch
new file mode 100644
index 000000000..0644f798a
--- /dev/null
+++ b/patches/source/glibc/patches/glibc.CVE-2021-3999.patch
@@ -0,0 +1,356 @@
+From 472e799a5f2102bc0c3206dbd5a801765fceb39c Mon Sep 17 00:00:00 2001
+From: Siddhesh Poyarekar <siddhesh@sourceware.org>
+Date: Fri, 21 Jan 2022 23:32:56 +0530
+Subject: [PATCH] getcwd: Set errno to ERANGE for size == 1 (CVE-2021-3999)
+
+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 | 6 +
+ sysdeps/posix/getcwd.c | 7 +
+ sysdeps/unix/sysv/linux/Makefile | 7 +-
+ .../unix/sysv/linux/tst-getcwd-smallbuff.c | 241 ++++++++++++++++++
+ 4 files changed, 260 insertions(+), 1 deletion(-)
+ create mode 100644 sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c
+
+diff --git a/NEWS b/NEWS
+index b4f81c2668..8d7467d2c1 100644
+--- a/NEWS
++++ b/NEWS
+@@ -20,6 +20,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:
+
+ [12889] nptl: Fix race between pthread_kill and thread exit
+diff --git a/sysdeps/posix/getcwd.c b/sysdeps/posix/getcwd.c
+index 13680026ff..b6984a382c 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 76ad06361c..9380d3848d 100644
+--- a/sysdeps/unix/sysv/linux/Makefile
++++ b/sysdeps/unix/sysv/linux/Makefile
+@@ -331,7 +331,12 @@ sysdep_routines += xstatconv internal_statvfs \
+
+ 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.27.0
+
+