forked from rpms/glibc
import glibc-2.28-219.el8
This commit is contained in:
parent
108aa5b0a9
commit
ee9c4ccfc2
449
SOURCES/glibc-rh2116938.patch
Normal file
449
SOURCES/glibc-rh2116938.patch
Normal file
@ -0,0 +1,449 @@
|
||||
1. Added "$(objpfx)tst-cmsghdr: $(libdl)" to socket/Makefile since we still
|
||||
need $(libdl) in RHEL8.
|
||||
|
||||
2. Included stddef.h in socket/tst-cmsghdr-skeleton.c because it uses NULL.
|
||||
|
||||
commit 9c443ac4559a47ed99859bd80d14dc4b6dd220a1
|
||||
Author: Arjun Shankar <arjun@redhat.com>
|
||||
Date: Tue Aug 2 11:10:25 2022 +0200
|
||||
|
||||
socket: Check lengths before advancing pointer in CMSG_NXTHDR
|
||||
|
||||
The inline and library functions that the CMSG_NXTHDR macro may expand
|
||||
to increment the pointer to the header before checking the stride of
|
||||
the increment against available space. Since C only allows incrementing
|
||||
pointers to one past the end of an array, the increment must be done
|
||||
after a length check. This commit fixes that and includes a regression
|
||||
test for CMSG_FIRSTHDR and CMSG_NXTHDR.
|
||||
|
||||
The Linux, Hurd, and generic headers are all changed.
|
||||
|
||||
Tested on Linux on armv7hl, i686, x86_64, aarch64, ppc64le, and s390x.
|
||||
|
||||
[BZ #28846]
|
||||
|
||||
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||
|
||||
Conflicts:
|
||||
socket/Makefile
|
||||
(usual test backport differences)
|
||||
|
||||
diff --git a/bits/socket.h b/bits/socket.h
|
||||
index 725798882e4b803b..0474613a9c003eeb 100644
|
||||
--- a/bits/socket.h
|
||||
+++ b/bits/socket.h
|
||||
@@ -245,6 +245,12 @@ struct cmsghdr
|
||||
+ CMSG_ALIGN (sizeof (struct cmsghdr)))
|
||||
#define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
|
||||
|
||||
+/* Given a length, return the additional padding necessary such that
|
||||
+ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
|
||||
+#define __CMSG_PADDING(len) ((sizeof (size_t) \
|
||||
+ - ((len) & (sizeof (size_t) - 1))) \
|
||||
+ & (sizeof (size_t) - 1))
|
||||
+
|
||||
extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
|
||||
struct cmsghdr *__cmsg) __THROW;
|
||||
#ifdef __USE_EXTERN_INLINES
|
||||
@@ -254,18 +260,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
|
||||
_EXTERN_INLINE struct cmsghdr *
|
||||
__NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
|
||||
{
|
||||
+ /* We may safely assume that __cmsg lies between __mhdr->msg_control and
|
||||
+ __mhdr->msg_controllen because the user is required to obtain the first
|
||||
+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
|
||||
+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
|
||||
+ trust the value of __cmsg->cmsg_len and therefore do not use it in any
|
||||
+ pointer arithmetic until we check its value. */
|
||||
+
|
||||
+ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
|
||||
+ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
|
||||
+
|
||||
+ size_t __size_needed = sizeof (struct cmsghdr)
|
||||
+ + __CMSG_PADDING (__cmsg->cmsg_len);
|
||||
+
|
||||
+ /* The current header is malformed, too small to be a full header. */
|
||||
if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
|
||||
- /* The kernel header does this so there may be a reason. */
|
||||
return (struct cmsghdr *) 0;
|
||||
|
||||
+ /* There isn't enough space between __cmsg and the end of the buffer to
|
||||
+ hold the current cmsg *and* the next one. */
|
||||
+ if (((size_t)
|
||||
+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
|
||||
+ < __size_needed)
|
||||
+ || ((size_t)
|
||||
+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
|
||||
+ - __size_needed)
|
||||
+ < __cmsg->cmsg_len))
|
||||
+
|
||||
+ return (struct cmsghdr *) 0;
|
||||
+
|
||||
+ /* Now, we trust cmsg_len and can use it to find the next header. */
|
||||
__cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
|
||||
+ CMSG_ALIGN (__cmsg->cmsg_len));
|
||||
- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
|
||||
- + __mhdr->msg_controllen)
|
||||
- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
|
||||
- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
|
||||
- /* No more entries. */
|
||||
- return (struct cmsghdr *) 0;
|
||||
return __cmsg;
|
||||
}
|
||||
#endif /* Use `extern inline'. */
|
||||
diff --git a/socket/Makefile b/socket/Makefile
|
||||
index 8975a65c2aabbfbc..a445383f8739351e 100644
|
||||
--- a/socket/Makefile
|
||||
+++ b/socket/Makefile
|
||||
@@ -31,7 +31,12 @@ routines := accept bind connect getpeername getsockname getsockopt \
|
||||
setsockopt shutdown socket socketpair isfdtype opensock \
|
||||
sockatmark accept4 recvmmsg sendmmsg sockaddr_un_set
|
||||
|
||||
-tests := tst-accept4
|
||||
+tests := \
|
||||
+ tst-accept4 \
|
||||
+ tst-cmsghdr \
|
||||
+ # tests
|
||||
+
|
||||
+$(objpfx)tst-cmsghdr: $(libdl)
|
||||
|
||||
tests-internal := \
|
||||
tst-sockaddr_un_set \
|
||||
diff --git a/socket/tst-cmsghdr-skeleton.c b/socket/tst-cmsghdr-skeleton.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..7accfa6e54708e2a
|
||||
--- /dev/null
|
||||
+++ b/socket/tst-cmsghdr-skeleton.c
|
||||
@@ -0,0 +1,93 @@
|
||||
+/* Test ancillary data header creation.
|
||||
+ Copyright (C) 2022 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/>. */
|
||||
+
|
||||
+/* We use the preprocessor to generate the function/macro tests instead of
|
||||
+ using indirection because having all the macro expansions alongside
|
||||
+ each other lets the compiler warn us about suspicious pointer
|
||||
+ arithmetic across subsequent CMSG_{FIRST,NXT}HDR expansions. */
|
||||
+
|
||||
+#include <stdint.h>
|
||||
+#include <stddef.h>
|
||||
+
|
||||
+#define RUN_TEST_CONCAT(suffix) run_test_##suffix
|
||||
+#define RUN_TEST_FUNCNAME(suffix) RUN_TEST_CONCAT (suffix)
|
||||
+
|
||||
+static void
|
||||
+RUN_TEST_FUNCNAME (CMSG_NXTHDR_IMPL) (void)
|
||||
+{
|
||||
+ struct msghdr m = {0};
|
||||
+ struct cmsghdr *cmsg;
|
||||
+ char cmsgbuf[3 * CMSG_SPACE (sizeof (PAYLOAD))] = {0};
|
||||
+
|
||||
+ m.msg_control = cmsgbuf;
|
||||
+ m.msg_controllen = sizeof (cmsgbuf);
|
||||
+
|
||||
+ /* First header should point to the start of the buffer. */
|
||||
+ cmsg = CMSG_FIRSTHDR (&m);
|
||||
+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
|
||||
+
|
||||
+ /* If the first header length consumes the entire buffer, there is no
|
||||
+ space remaining for additional headers. */
|
||||
+ cmsg->cmsg_len = sizeof (cmsgbuf);
|
||||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||||
+ TEST_VERIFY_EXIT (cmsg == NULL);
|
||||
+
|
||||
+ /* The first header length is so big, using it would cause an overflow. */
|
||||
+ cmsg = CMSG_FIRSTHDR (&m);
|
||||
+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
|
||||
+ cmsg->cmsg_len = SIZE_MAX;
|
||||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||||
+ TEST_VERIFY_EXIT (cmsg == NULL);
|
||||
+
|
||||
+ /* The first header leaves just enough space to hold another header. */
|
||||
+ cmsg = CMSG_FIRSTHDR (&m);
|
||||
+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
|
||||
+ cmsg->cmsg_len = sizeof (cmsgbuf) - sizeof (struct cmsghdr);
|
||||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||||
+ TEST_VERIFY_EXIT (cmsg != NULL);
|
||||
+
|
||||
+ /* The first header leaves space but not enough for another header. */
|
||||
+ cmsg = CMSG_FIRSTHDR (&m);
|
||||
+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
|
||||
+ cmsg->cmsg_len ++;
|
||||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||||
+ TEST_VERIFY_EXIT (cmsg == NULL);
|
||||
+
|
||||
+ /* The second header leaves just enough space to hold another header. */
|
||||
+ cmsg = CMSG_FIRSTHDR (&m);
|
||||
+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
|
||||
+ cmsg->cmsg_len = CMSG_LEN (sizeof (PAYLOAD));
|
||||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||||
+ TEST_VERIFY_EXIT (cmsg != NULL);
|
||||
+ cmsg->cmsg_len = sizeof (cmsgbuf)
|
||||
+ - CMSG_SPACE (sizeof (PAYLOAD)) /* First header. */
|
||||
+ - sizeof (struct cmsghdr);
|
||||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||||
+ TEST_VERIFY_EXIT (cmsg != NULL);
|
||||
+
|
||||
+ /* The second header leaves space but not enough for another header. */
|
||||
+ cmsg = CMSG_FIRSTHDR (&m);
|
||||
+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
|
||||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||||
+ TEST_VERIFY_EXIT (cmsg != NULL);
|
||||
+ cmsg->cmsg_len ++;
|
||||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||||
+ TEST_VERIFY_EXIT (cmsg == NULL);
|
||||
+
|
||||
+ return;
|
||||
+}
|
||||
diff --git a/socket/tst-cmsghdr.c b/socket/tst-cmsghdr.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..68c96d3c9dd2bce8
|
||||
--- /dev/null
|
||||
+++ b/socket/tst-cmsghdr.c
|
||||
@@ -0,0 +1,56 @@
|
||||
+/* Test ancillary data header creation.
|
||||
+ Copyright (C) 2022 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 <sys/socket.h>
|
||||
+#include <gnu/lib-names.h>
|
||||
+#include <support/xdlfcn.h>
|
||||
+#include <support/check.h>
|
||||
+
|
||||
+#define PAYLOAD "Hello, World!"
|
||||
+
|
||||
+/* CMSG_NXTHDR is a macro that calls an inline function defined in
|
||||
+ bits/socket.h. In case the function cannot be inlined, libc.so carries
|
||||
+ a copy. Both versions need to be tested. */
|
||||
+
|
||||
+#define CMSG_NXTHDR_IMPL CMSG_NXTHDR
|
||||
+#include "tst-cmsghdr-skeleton.c"
|
||||
+#undef CMSG_NXTHDR_IMPL
|
||||
+
|
||||
+static struct cmsghdr * (* cmsg_nxthdr) (struct msghdr *, struct cmsghdr *);
|
||||
+
|
||||
+#define CMSG_NXTHDR_IMPL cmsg_nxthdr
|
||||
+#include "tst-cmsghdr-skeleton.c"
|
||||
+#undef CMSG_NXTHDR_IMPL
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ static void *handle;
|
||||
+
|
||||
+ run_test_CMSG_NXTHDR ();
|
||||
+
|
||||
+ handle = xdlopen (LIBC_SO, RTLD_LAZY);
|
||||
+ cmsg_nxthdr = (struct cmsghdr * (*) (struct msghdr *, struct cmsghdr *))
|
||||
+ xdlsym (handle, "__cmsg_nxthdr");
|
||||
+
|
||||
+ run_test_cmsg_nxthdr ();
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/sysdeps/mach/hurd/bits/socket.h b/sysdeps/mach/hurd/bits/socket.h
|
||||
index 18959139dc7d325b..cc66684061e3e179 100644
|
||||
--- a/sysdeps/mach/hurd/bits/socket.h
|
||||
+++ b/sysdeps/mach/hurd/bits/socket.h
|
||||
@@ -249,6 +249,12 @@ struct cmsghdr
|
||||
+ CMSG_ALIGN (sizeof (struct cmsghdr)))
|
||||
#define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
|
||||
|
||||
+/* Given a length, return the additional padding necessary such that
|
||||
+ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
|
||||
+#define __CMSG_PADDING(len) ((sizeof (size_t) \
|
||||
+ - ((len) & (sizeof (size_t) - 1))) \
|
||||
+ & (sizeof (size_t) - 1))
|
||||
+
|
||||
extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
|
||||
struct cmsghdr *__cmsg) __THROW;
|
||||
#ifdef __USE_EXTERN_INLINES
|
||||
@@ -258,18 +264,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
|
||||
_EXTERN_INLINE struct cmsghdr *
|
||||
__NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
|
||||
{
|
||||
+ /* We may safely assume that __cmsg lies between __mhdr->msg_control and
|
||||
+ __mhdr->msg_controllen because the user is required to obtain the first
|
||||
+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
|
||||
+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
|
||||
+ trust the value of __cmsg->cmsg_len and therefore do not use it in any
|
||||
+ pointer arithmetic until we check its value. */
|
||||
+
|
||||
+ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
|
||||
+ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
|
||||
+
|
||||
+ size_t __size_needed = sizeof (struct cmsghdr)
|
||||
+ + __CMSG_PADDING (__cmsg->cmsg_len);
|
||||
+
|
||||
+ /* The current header is malformed, too small to be a full header. */
|
||||
if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
|
||||
- /* The kernel header does this so there may be a reason. */
|
||||
return (struct cmsghdr *) 0;
|
||||
|
||||
+ /* There isn't enough space between __cmsg and the end of the buffer to
|
||||
+ hold the current cmsg *and* the next one. */
|
||||
+ if (((size_t)
|
||||
+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
|
||||
+ < __size_needed)
|
||||
+ || ((size_t)
|
||||
+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
|
||||
+ - __size_needed)
|
||||
+ < __cmsg->cmsg_len))
|
||||
+
|
||||
+ return (struct cmsghdr *) 0;
|
||||
+
|
||||
+ /* Now, we trust cmsg_len and can use it to find the next header. */
|
||||
__cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
|
||||
+ CMSG_ALIGN (__cmsg->cmsg_len));
|
||||
- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
|
||||
- + __mhdr->msg_controllen)
|
||||
- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
|
||||
- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
|
||||
- /* No more entries. */
|
||||
- return (struct cmsghdr *) 0;
|
||||
return __cmsg;
|
||||
}
|
||||
#endif /* Use `extern inline'. */
|
||||
diff --git a/sysdeps/unix/sysv/linux/bits/socket.h b/sysdeps/unix/sysv/linux/bits/socket.h
|
||||
index c3fbb2110296273c..6b895b89831d2cb5 100644
|
||||
--- a/sysdeps/unix/sysv/linux/bits/socket.h
|
||||
+++ b/sysdeps/unix/sysv/linux/bits/socket.h
|
||||
@@ -302,6 +302,12 @@ struct cmsghdr
|
||||
+ CMSG_ALIGN (sizeof (struct cmsghdr)))
|
||||
#define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
|
||||
|
||||
+/* Given a length, return the additional padding necessary such that
|
||||
+ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
|
||||
+#define __CMSG_PADDING(len) ((sizeof (size_t) \
|
||||
+ - ((len) & (sizeof (size_t) - 1))) \
|
||||
+ & (sizeof (size_t) - 1))
|
||||
+
|
||||
extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
|
||||
struct cmsghdr *__cmsg) __THROW;
|
||||
#ifdef __USE_EXTERN_INLINES
|
||||
@@ -311,18 +317,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
|
||||
_EXTERN_INLINE struct cmsghdr *
|
||||
__NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
|
||||
{
|
||||
+ /* We may safely assume that __cmsg lies between __mhdr->msg_control and
|
||||
+ __mhdr->msg_controllen because the user is required to obtain the first
|
||||
+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
|
||||
+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
|
||||
+ trust the value of __cmsg->cmsg_len and therefore do not use it in any
|
||||
+ pointer arithmetic until we check its value. */
|
||||
+
|
||||
+ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
|
||||
+ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
|
||||
+
|
||||
+ size_t __size_needed = sizeof (struct cmsghdr)
|
||||
+ + __CMSG_PADDING (__cmsg->cmsg_len);
|
||||
+
|
||||
+ /* The current header is malformed, too small to be a full header. */
|
||||
if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
|
||||
- /* The kernel header does this so there may be a reason. */
|
||||
return (struct cmsghdr *) 0;
|
||||
|
||||
+ /* There isn't enough space between __cmsg and the end of the buffer to
|
||||
+ hold the current cmsg *and* the next one. */
|
||||
+ if (((size_t)
|
||||
+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
|
||||
+ < __size_needed)
|
||||
+ || ((size_t)
|
||||
+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
|
||||
+ - __size_needed)
|
||||
+ < __cmsg->cmsg_len))
|
||||
+
|
||||
+ return (struct cmsghdr *) 0;
|
||||
+
|
||||
+ /* Now, we trust cmsg_len and can use it to find the next header. */
|
||||
__cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
|
||||
+ CMSG_ALIGN (__cmsg->cmsg_len));
|
||||
- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
|
||||
- + __mhdr->msg_controllen)
|
||||
- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
|
||||
- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
|
||||
- /* No more entries. */
|
||||
- return (struct cmsghdr *) 0;
|
||||
return __cmsg;
|
||||
}
|
||||
#endif /* Use `extern inline'. */
|
||||
diff --git a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
|
||||
index bab0be6884d9da1c..16594622211c1c8b 100644
|
||||
--- a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
|
||||
+++ b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
|
||||
@@ -23,18 +23,38 @@
|
||||
struct cmsghdr *
|
||||
__cmsg_nxthdr (struct msghdr *mhdr, struct cmsghdr *cmsg)
|
||||
{
|
||||
+ /* We may safely assume that cmsg lies between mhdr->msg_control and
|
||||
+ mhdr->msg_controllen because the user is required to obtain the first
|
||||
+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
|
||||
+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
|
||||
+ trust the value of cmsg->cmsg_len and therefore do not use it in any
|
||||
+ pointer arithmetic until we check its value. */
|
||||
+
|
||||
+ unsigned char * msg_control_ptr = (unsigned char *) mhdr->msg_control;
|
||||
+ unsigned char * cmsg_ptr = (unsigned char *) cmsg;
|
||||
+
|
||||
+ size_t size_needed = sizeof (struct cmsghdr)
|
||||
+ + __CMSG_PADDING (cmsg->cmsg_len);
|
||||
+
|
||||
+ /* The current header is malformed, too small to be a full header. */
|
||||
if ((size_t) cmsg->cmsg_len < sizeof (struct cmsghdr))
|
||||
- /* The kernel header does this so there may be a reason. */
|
||||
- return NULL;
|
||||
+ return (struct cmsghdr *) 0;
|
||||
+
|
||||
+ /* There isn't enough space between cmsg and the end of the buffer to
|
||||
+ hold the current cmsg *and* the next one. */
|
||||
+ if (((size_t)
|
||||
+ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr)
|
||||
+ < size_needed)
|
||||
+ || ((size_t)
|
||||
+ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr
|
||||
+ - size_needed)
|
||||
+ < cmsg->cmsg_len))
|
||||
+
|
||||
+ return (struct cmsghdr *) 0;
|
||||
|
||||
+ /* Now, we trust cmsg_len and can use it to find the next header. */
|
||||
cmsg = (struct cmsghdr *) ((unsigned char *) cmsg
|
||||
+ CMSG_ALIGN (cmsg->cmsg_len));
|
||||
- if ((unsigned char *) (cmsg + 1) > ((unsigned char *) mhdr->msg_control
|
||||
- + mhdr->msg_controllen)
|
||||
- || ((unsigned char *) cmsg + CMSG_ALIGN (cmsg->cmsg_len)
|
||||
- > ((unsigned char *) mhdr->msg_control + mhdr->msg_controllen)))
|
||||
- /* No more entries. */
|
||||
- return NULL;
|
||||
return cmsg;
|
||||
}
|
||||
libc_hidden_def (__cmsg_nxthdr)
|
202
SOURCES/glibc-rh2121746-1.patch
Normal file
202
SOURCES/glibc-rh2121746-1.patch
Normal file
@ -0,0 +1,202 @@
|
||||
From d0e357ff45a75553dee3b17ed7d303bfa544f6fe Mon Sep 17 00:00:00 2001
|
||||
From: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri, 26 Aug 2022 21:15:43 +0200
|
||||
Subject: elf: Call __libc_early_init for reused namespaces (bug 29528)
|
||||
|
||||
libc_map is never reset to NULL, neither during dlclose nor on a
|
||||
dlopen call which reuses the namespace structure. As a result, if a
|
||||
namespace is reused, its libc is not initialized properly. The most
|
||||
visible result is a crash in the <ctype.h> functions.
|
||||
|
||||
To prevent similar bugs on namespace reuse from surfacing,
|
||||
unconditionally initialize the chosen namespace to zero using memset.
|
||||
|
||||
[Note from DJ: Regenerated for new line numbers and context, added
|
||||
link dependency on libdl]]
|
||||
|
||||
diff -rupN a/elf/Makefile b/elf/Makefile
|
||||
--- a/elf/Makefile 2022-10-05 15:04:11.814901849 -0400
|
||||
+++ b/elf/Makefile 2022-10-05 17:02:19.858635958 -0400
|
||||
@@ -367,6 +367,7 @@ tests += \
|
||||
tst-dlmopen3 \
|
||||
tst-dlmopen-dlerror \
|
||||
tst-dlmopen-gethostbyname \
|
||||
+ tst-dlmopen-twice \
|
||||
tst-dlopenfail \
|
||||
tst-dlopenfail-2 \
|
||||
tst-dlopenrpath \
|
||||
@@ -671,6 +672,8 @@ modules-names = \
|
||||
tst-dlmopen1mod \
|
||||
tst-dlmopen-dlerror-mod \
|
||||
tst-dlmopen-gethostbyname-mod \
|
||||
+ tst-dlmopen-twice-mod1 \
|
||||
+ tst-dlmopen-twice-mod2 \
|
||||
tst-dlopenfaillinkmod \
|
||||
tst-dlopenfailmod1 \
|
||||
tst-dlopenfailmod2 \
|
||||
@@ -2569,3 +2572,9 @@ $(objpfx)tst-audit-tlsdesc.out: $(objpfx
|
||||
tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
|
||||
$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so
|
||||
tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
|
||||
+
|
||||
+
|
||||
+$(objpfx)tst-dlmopen-twice: $(libdl)
|
||||
+$(objpfx)tst-dlmopen-twice.out: \
|
||||
+ $(objpfx)tst-dlmopen-twice-mod1.so \
|
||||
+ $(objpfx)tst-dlmopen-twice-mod2.so
|
||||
diff -rupN a/elf/dl-open.c b/elf/dl-open.c
|
||||
--- a/elf/dl-open.c 2022-10-05 15:04:11.635894932 -0400
|
||||
+++ b/elf/dl-open.c 2022-10-05 15:10:31.667638060 -0400
|
||||
@@ -836,11 +836,14 @@ _dl_open (const char *file, int mode, co
|
||||
_dl_signal_error (EINVAL, file, NULL, N_("\
|
||||
no more namespaces available for dlmopen()"));
|
||||
}
|
||||
- else if (nsid == GL(dl_nns))
|
||||
- {
|
||||
- __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock);
|
||||
- ++GL(dl_nns);
|
||||
- }
|
||||
+
|
||||
+ if (nsid == GL(dl_nns))
|
||||
+ ++GL(dl_nns);
|
||||
+
|
||||
+ /* Initialize the new namespace. Most members are
|
||||
+ zero-initialized, only the lock needs special treatment. */
|
||||
+ memset (&GL(dl_ns)[nsid], 0, sizeof (GL(dl_ns)[nsid]));
|
||||
+ __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock);
|
||||
|
||||
_dl_debug_initialize (0, nsid)->r_state = RT_CONSISTENT;
|
||||
}
|
||||
diff -rupN a/elf/tst-dlmopen-twice-mod1.c b/elf/tst-dlmopen-twice-mod1.c
|
||||
--- a/elf/tst-dlmopen-twice-mod1.c 1969-12-31 19:00:00.000000000 -0500
|
||||
+++ b/elf/tst-dlmopen-twice-mod1.c 2022-10-05 15:10:31.671638216 -0400
|
||||
@@ -0,0 +1,37 @@
|
||||
+/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 1.
|
||||
+ Copyright (C) 2022 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>
|
||||
+
|
||||
+static void __attribute__ ((constructor))
|
||||
+init (void)
|
||||
+{
|
||||
+ puts ("info: tst-dlmopen-twice-mod1.so loaded");
|
||||
+ fflush (stdout);
|
||||
+}
|
||||
+
|
||||
+static void __attribute__ ((destructor))
|
||||
+fini (void)
|
||||
+{
|
||||
+ puts ("info: tst-dlmopen-twice-mod1.so about to be unloaded");
|
||||
+ fflush (stdout);
|
||||
+}
|
||||
+
|
||||
+/* Large allocation. The second module does not have this, so it
|
||||
+ should load libc at a different address. */
|
||||
+char large_allocate[16 * 1024 * 1024];
|
||||
diff -rupN a/elf/tst-dlmopen-twice-mod2.c b/elf/tst-dlmopen-twice-mod2.c
|
||||
--- a/elf/tst-dlmopen-twice-mod2.c 1969-12-31 19:00:00.000000000 -0500
|
||||
+++ b/elf/tst-dlmopen-twice-mod2.c 2022-10-05 15:10:31.676638411 -0400
|
||||
@@ -0,0 +1,50 @@
|
||||
+/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 2.
|
||||
+ Copyright (C) 2022 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 <ctype.h>
|
||||
+#include <stdio.h>
|
||||
+
|
||||
+static void __attribute__ ((constructor))
|
||||
+init (void)
|
||||
+{
|
||||
+ puts ("info: tst-dlmopen-twice-mod2.so loaded");
|
||||
+ fflush (stdout);
|
||||
+}
|
||||
+
|
||||
+static void __attribute__ ((destructor))
|
||||
+fini (void)
|
||||
+{
|
||||
+ puts ("info: tst-dlmopen-twice-mod2.so about to be unloaded");
|
||||
+ fflush (stdout);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+run_check (void)
|
||||
+{
|
||||
+ puts ("info: about to call isalpha");
|
||||
+ fflush (stdout);
|
||||
+
|
||||
+ volatile char ch = 'a';
|
||||
+ if (!isalpha (ch))
|
||||
+ {
|
||||
+ puts ("error: isalpha ('a') is not true");
|
||||
+ fflush (stdout);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
diff -rupN a/elf/tst-dlmopen-twice.c b/elf/tst-dlmopen-twice.c
|
||||
--- a/elf/tst-dlmopen-twice.c 1969-12-31 19:00:00.000000000 -0500
|
||||
+++ b/elf/tst-dlmopen-twice.c 2022-10-05 15:10:31.679638528 -0400
|
||||
@@ -0,0 +1,34 @@
|
||||
+/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Main.
|
||||
+ Copyright (C) 2022 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/xdlfcn.h>
|
||||
+#include <support/check.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so", RTLD_NOW);
|
||||
+ xdlclose (handle);
|
||||
+ handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod2.so", RTLD_NOW);
|
||||
+ int (*run_check) (void) = xdlsym (handle, "run_check");
|
||||
+ TEST_COMPARE (run_check (), 0);
|
||||
+ xdlclose (handle);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
98
SOURCES/glibc-rh2121746-2.patch
Normal file
98
SOURCES/glibc-rh2121746-2.patch
Normal file
@ -0,0 +1,98 @@
|
||||
From 2c42257314536b94cc8d52edede86e94e98c1436 Mon Sep 17 00:00:00 2001
|
||||
From: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri, 14 Oct 2022 11:02:25 +0200
|
||||
Subject: [PATCH] elf: Do not completely clear reused namespace in dlmopen (bug
|
||||
29600)
|
||||
Content-type: text/plain; charset=UTF-8
|
||||
|
||||
The data in the _ns_debug member must be preserved, otherwise
|
||||
_dl_debug_initialize enters an infinite loop. To be conservative,
|
||||
only clear the libc_map member for now, to fix bug 29528.
|
||||
|
||||
Fixes commit d0e357ff45a75553dee3b17ed7d303bfa544f6fe
|
||||
("elf: Call __libc_early_init for reused namespaces (bug 29528)"),
|
||||
by reverting most of it.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
Tested-by: Carlos O'Donell <carlos@redhat.com>
|
||||
---
|
||||
elf/dl-open.c | 14 ++++++--------
|
||||
elf/tst-dlmopen-twice.c | 28 ++++++++++++++++++++++++----
|
||||
2 files changed, 30 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||
index 46e8066fd8..e7db5e9642 100644
|
||||
--- a/elf/dl-open.c
|
||||
+++ b/elf/dl-open.c
|
||||
@@ -836,15 +836,13 @@ _dl_open (const char *file, int mode, co
|
||||
_dl_signal_error (EINVAL, file, NULL, N_("\
|
||||
no more namespaces available for dlmopen()"));
|
||||
}
|
||||
+ else if (nsid == GL(dl_nns))
|
||||
+ {
|
||||
+ __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock);
|
||||
+ ++GL(dl_nns);
|
||||
+ }
|
||||
|
||||
- if (nsid == GL(dl_nns))
|
||||
- ++GL(dl_nns);
|
||||
-
|
||||
- /* Initialize the new namespace. Most members are
|
||||
- zero-initialized, only the lock needs special treatment. */
|
||||
- memset (&GL(dl_ns)[nsid], 0, sizeof (GL(dl_ns)[nsid]));
|
||||
- __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock);
|
||||
-
|
||||
+ GL(dl_ns)[nsid].libc_map = NULL;
|
||||
_dl_debug_initialize (0, nsid)->r_state = RT_CONSISTENT;
|
||||
}
|
||||
/* Never allow loading a DSO in a namespace which is empty. Such
|
||||
diff --git a/elf/tst-dlmopen-twice.c b/elf/tst-dlmopen-twice.c
|
||||
index 449f3c8fa9..70c71fe19c 100644
|
||||
--- a/elf/tst-dlmopen-twice.c
|
||||
+++ b/elf/tst-dlmopen-twice.c
|
||||
@@ -16,18 +16,38 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
-#include <support/xdlfcn.h>
|
||||
+#include <stdio.h>
|
||||
#include <support/check.h>
|
||||
+#include <support/xdlfcn.h>
|
||||
|
||||
-static int
|
||||
-do_test (void)
|
||||
+/* Run the test multiple times, to check finding a new namespace while
|
||||
+ another namespace is already in use. This used to trigger bug 29600. */
|
||||
+static void
|
||||
+recurse (int depth)
|
||||
{
|
||||
- void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so", RTLD_NOW);
|
||||
+ if (depth == 0)
|
||||
+ return;
|
||||
+
|
||||
+ printf ("info: running at depth %d\n", depth);
|
||||
+ void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so",
|
||||
+ RTLD_NOW);
|
||||
xdlclose (handle);
|
||||
handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod2.so", RTLD_NOW);
|
||||
int (*run_check) (void) = xdlsym (handle, "run_check");
|
||||
TEST_COMPARE (run_check (), 0);
|
||||
+ recurse (depth - 1);
|
||||
xdlclose (handle);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ /* First run the test without nesting. */
|
||||
+ recurse (1);
|
||||
+
|
||||
+ /* Then with nesting. The constant needs to be less than the
|
||||
+ internal DL_NNS namespace constant. */
|
||||
+ recurse (10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.31.1
|
||||
|
472
SOURCES/glibc-rh2122501-1.patch
Normal file
472
SOURCES/glibc-rh2122501-1.patch
Normal file
@ -0,0 +1,472 @@
|
||||
commit c6fad4fa149485a307207f707e5851216f190fc8
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Mar 19 18:32:28 2020 -0300
|
||||
|
||||
stdio: Remove memory leak from multibyte convertion [BZ#25691]
|
||||
|
||||
This is an updated version of a previous patch [1] with the
|
||||
following changes:
|
||||
|
||||
- Use compiler overflow builtins on done_add_func function.
|
||||
- Define the scratch +utstring_converted_wide_string using
|
||||
CHAR_T.
|
||||
- Added a testcase and mention the bug report.
|
||||
|
||||
Both default and wide printf functions might leak memory when
|
||||
manipulate multibyte characters conversion depending of the size
|
||||
of the input (whether __libc_use_alloca trigger or not the fallback
|
||||
heap allocation).
|
||||
|
||||
This patch fixes it by removing the extra memory allocation on
|
||||
string formatting with conversion parts.
|
||||
|
||||
The testcase uses input argument size that trigger memory leaks
|
||||
on unpatched code (using a scratch buffer the threashold to use
|
||||
heap allocation is lower).
|
||||
|
||||
Checked on x86_64-linux-gnu and i686-linux-gnu.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
[1] https://sourceware.org/pipermail/libc-alpha/2017-June/082098.html
|
||||
|
||||
(cherry picked from commit 3cc4a8367c23582b7db14cf4e150e4068b7fd461)
|
||||
|
||||
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
|
||||
index ae412e4b8444aea2..dab56b6ba2c7bdbe 100644
|
||||
--- a/stdio-common/vfprintf.c
|
||||
+++ b/stdio-common/vfprintf.c
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <locale/localeinfo.h>
|
||||
#include <stdio.h>
|
||||
#include <scratch_buffer.h>
|
||||
+#include <intprops.h>
|
||||
|
||||
/* This code is shared between the standard stdio implementation found
|
||||
in GNU C library and the libio implementation originally found in
|
||||
@@ -64,23 +65,40 @@
|
||||
} while (0)
|
||||
#define UNBUFFERED_P(S) ((S)->_flags & _IO_UNBUFFERED)
|
||||
|
||||
-#define done_add(val) \
|
||||
- do { \
|
||||
- unsigned int _val = val; \
|
||||
- assert ((unsigned int) done < (unsigned int) INT_MAX); \
|
||||
- if (__glibc_unlikely (INT_MAX - done < _val)) \
|
||||
- { \
|
||||
- done = -1; \
|
||||
- __set_errno (EOVERFLOW); \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
- done += _val; \
|
||||
- } while (0)
|
||||
+/* Add LENGTH to DONE. Return the new value of DONE, or -1 on
|
||||
+ overflow (and set errno accordingly). */
|
||||
+static inline int
|
||||
+done_add_func (size_t length, int done)
|
||||
+{
|
||||
+ if (done < 0)
|
||||
+ return done;
|
||||
+ int ret;
|
||||
+ if (INT_ADD_WRAPV (done, length, &ret))
|
||||
+ {
|
||||
+ __set_errno (EOVERFLOW);
|
||||
+ return -1;
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+#define done_add(val) \
|
||||
+ do \
|
||||
+ { \
|
||||
+ /* Ensure that VAL has a type similar to int. */ \
|
||||
+ _Static_assert (sizeof (val) == sizeof (int), "value int size"); \
|
||||
+ _Static_assert ((__typeof__ (val)) -1 < 0, "value signed"); \
|
||||
+ done = done_add_func ((val), done); \
|
||||
+ if (done < 0) \
|
||||
+ goto all_done; \
|
||||
+ } \
|
||||
+ while (0)
|
||||
|
||||
#ifndef COMPILE_WPRINTF
|
||||
# define vfprintf _IO_vfprintf_internal
|
||||
# define CHAR_T char
|
||||
+# define CHAR_T char
|
||||
# define UCHAR_T unsigned char
|
||||
+# define OTHER_CHAR_T wchar_t
|
||||
# define INT_T int
|
||||
typedef const char *THOUSANDS_SEP_T;
|
||||
# define L_(Str) Str
|
||||
@@ -88,22 +106,10 @@ typedef const char *THOUSANDS_SEP_T;
|
||||
# define STR_LEN(Str) strlen (Str)
|
||||
|
||||
# define PUT(F, S, N) _IO_sputn ((F), (S), (N))
|
||||
-# define PAD(Padchar) \
|
||||
- do { \
|
||||
- if (width > 0) \
|
||||
- { \
|
||||
- ssize_t written = _IO_padn (s, (Padchar), width); \
|
||||
- if (__glibc_unlikely (written != width)) \
|
||||
- { \
|
||||
- done = -1; \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
- done_add (written); \
|
||||
- } \
|
||||
- } while (0)
|
||||
# define PUTC(C, F) _IO_putc_unlocked (C, F)
|
||||
# define ORIENT if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\
|
||||
return -1
|
||||
+# define CONVERT_FROM_OTHER_STRING __wcsrtombs
|
||||
#else
|
||||
# define vfprintf _IO_vfwprintf
|
||||
# define CHAR_T wchar_t
|
||||
@@ -118,21 +124,11 @@ typedef wchar_t THOUSANDS_SEP_T;
|
||||
# include <_itowa.h>
|
||||
|
||||
# define PUT(F, S, N) _IO_sputn ((F), (S), (N))
|
||||
-# define PAD(Padchar) \
|
||||
- do { \
|
||||
- if (width > 0) \
|
||||
- { \
|
||||
- ssize_t written = _IO_wpadn (s, (Padchar), width); \
|
||||
- if (__glibc_unlikely (written != width)) \
|
||||
- { \
|
||||
- done = -1; \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
- done_add (written); \
|
||||
- } \
|
||||
- } while (0)
|
||||
# define PUTC(C, F) _IO_putwc_unlocked (C, F)
|
||||
# define ORIENT if (_IO_fwide (s, 1) != 1) return -1
|
||||
+# define CONVERT_FROM_OTHER_STRING __mbsrtowcs
|
||||
+# define CHAR_T wchar_t
|
||||
+# define OTHER_CHAR_T char
|
||||
|
||||
# undef _itoa
|
||||
# define _itoa(Val, Buf, Base, Case) _itowa (Val, Buf, Base, Case)
|
||||
@@ -141,6 +137,33 @@ typedef wchar_t THOUSANDS_SEP_T;
|
||||
# define EOF WEOF
|
||||
#endif
|
||||
|
||||
+static inline int
|
||||
+pad_func (FILE *s, CHAR_T padchar, int width, int done)
|
||||
+{
|
||||
+ if (width > 0)
|
||||
+ {
|
||||
+ ssize_t written;
|
||||
+#ifndef COMPILE_WPRINTF
|
||||
+ written = _IO_padn (s, padchar, width);
|
||||
+#else
|
||||
+ written = _IO_wpadn (s, padchar, width);
|
||||
+#endif
|
||||
+ if (__glibc_unlikely (written != width))
|
||||
+ return -1;
|
||||
+ return done_add_func (width, done);
|
||||
+ }
|
||||
+ return done;
|
||||
+}
|
||||
+
|
||||
+#define PAD(Padchar) \
|
||||
+ do \
|
||||
+ { \
|
||||
+ done = pad_func (s, (Padchar), width, done); \
|
||||
+ if (done < 0) \
|
||||
+ goto all_done; \
|
||||
+ } \
|
||||
+ while (0)
|
||||
+
|
||||
#include "_i18n_number.h"
|
||||
|
||||
/* Include the shared code for parsing the format string. */
|
||||
@@ -160,24 +183,115 @@ typedef wchar_t THOUSANDS_SEP_T;
|
||||
} \
|
||||
while (0)
|
||||
|
||||
-#define outstring(String, Len) \
|
||||
- do \
|
||||
- { \
|
||||
- assert ((size_t) done <= (size_t) INT_MAX); \
|
||||
- if ((size_t) PUT (s, (String), (Len)) != (size_t) (Len)) \
|
||||
- { \
|
||||
- done = -1; \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
- if (__glibc_unlikely (INT_MAX - done < (Len))) \
|
||||
- { \
|
||||
- done = -1; \
|
||||
- __set_errno (EOVERFLOW); \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
- done += (Len); \
|
||||
- } \
|
||||
- while (0)
|
||||
+static inline int
|
||||
+outstring_func (FILE *s, const UCHAR_T *string, size_t length, int done)
|
||||
+{
|
||||
+ assert ((size_t) done <= (size_t) INT_MAX);
|
||||
+ if ((size_t) PUT (s, string, length) != (size_t) (length))
|
||||
+ return -1;
|
||||
+ return done_add_func (length, done);
|
||||
+}
|
||||
+
|
||||
+#define outstring(String, Len) \
|
||||
+ do \
|
||||
+ { \
|
||||
+ const void *string_ = (String); \
|
||||
+ done = outstring_func (s, string_, (Len), done); \
|
||||
+ if (done < 0) \
|
||||
+ goto all_done; \
|
||||
+ } \
|
||||
+ while (0)
|
||||
+
|
||||
+/* Write the string SRC to S. If PREC is non-negative, write at most
|
||||
+ PREC bytes. If LEFT is true, perform left justification. */
|
||||
+static int
|
||||
+outstring_converted_wide_string (FILE *s, const OTHER_CHAR_T *src, int prec,
|
||||
+ int width, bool left, int done)
|
||||
+{
|
||||
+ /* Use a small buffer to combine processing of multiple characters.
|
||||
+ CONVERT_FROM_OTHER_STRING expects the buffer size in (wide)
|
||||
+ characters, and buf_length counts that. */
|
||||
+ enum { buf_length = 256 / sizeof (CHAR_T) };
|
||||
+ CHAR_T buf[buf_length];
|
||||
+ _Static_assert (sizeof (buf) > MB_LEN_MAX,
|
||||
+ "buffer is large enough for a single multi-byte character");
|
||||
+
|
||||
+ /* Add the initial padding if needed. */
|
||||
+ if (width > 0 && !left)
|
||||
+ {
|
||||
+ /* Make a first pass to find the output width, so that we can
|
||||
+ add the required padding. */
|
||||
+ mbstate_t mbstate = { 0 };
|
||||
+ const OTHER_CHAR_T *src_copy = src;
|
||||
+ size_t total_written;
|
||||
+ if (prec < 0)
|
||||
+ total_written = CONVERT_FROM_OTHER_STRING
|
||||
+ (NULL, &src_copy, 0, &mbstate);
|
||||
+ else
|
||||
+ {
|
||||
+ /* The source might not be null-terminated. Enforce the
|
||||
+ limit manually, based on the output length. */
|
||||
+ total_written = 0;
|
||||
+ size_t limit = prec;
|
||||
+ while (limit > 0 && src_copy != NULL)
|
||||
+ {
|
||||
+ size_t write_limit = buf_length;
|
||||
+ if (write_limit > limit)
|
||||
+ write_limit = limit;
|
||||
+ size_t written = CONVERT_FROM_OTHER_STRING
|
||||
+ (buf, &src_copy, write_limit, &mbstate);
|
||||
+ if (written == (size_t) -1)
|
||||
+ return -1;
|
||||
+ if (written == 0)
|
||||
+ break;
|
||||
+ total_written += written;
|
||||
+ limit -= written;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Output initial padding. */
|
||||
+ if (total_written < width)
|
||||
+ {
|
||||
+ done = pad_func (s, L_(' '), width - total_written, done);
|
||||
+ if (done < 0)
|
||||
+ return done;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Convert the input string, piece by piece. */
|
||||
+ size_t total_written = 0;
|
||||
+ {
|
||||
+ mbstate_t mbstate = { 0 };
|
||||
+ /* If prec is negative, remaining is not decremented, otherwise,
|
||||
+ it serves as the write limit. */
|
||||
+ size_t remaining = -1;
|
||||
+ if (prec >= 0)
|
||||
+ remaining = prec;
|
||||
+ while (remaining > 0 && src != NULL)
|
||||
+ {
|
||||
+ size_t write_limit = buf_length;
|
||||
+ if (remaining < write_limit)
|
||||
+ write_limit = remaining;
|
||||
+ size_t written = CONVERT_FROM_OTHER_STRING
|
||||
+ (buf, &src, write_limit, &mbstate);
|
||||
+ if (written == (size_t) -1)
|
||||
+ return -1;
|
||||
+ if (written == 0)
|
||||
+ break;
|
||||
+ done = outstring_func (s, (const UCHAR_T *) buf, written, done);
|
||||
+ if (done < 0)
|
||||
+ return done;
|
||||
+ total_written += written;
|
||||
+ if (prec >= 0)
|
||||
+ remaining -= written;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Add final padding. */
|
||||
+ if (width > 0 && left && total_written < width)
|
||||
+ return pad_func (s, L_(' '), width - total_written, done);
|
||||
+ return done;
|
||||
+}
|
||||
|
||||
/* For handling long_double and longlong we use the same flag. If
|
||||
`long' and `long long' are effectively the same type define it to
|
||||
@@ -975,7 +1089,6 @@ static const uint8_t jump_table[] =
|
||||
LABEL (form_string): \
|
||||
{ \
|
||||
size_t len; \
|
||||
- int string_malloced; \
|
||||
\
|
||||
/* The string argument could in fact be `char *' or `wchar_t *'. \
|
||||
But this should not make a difference here. */ \
|
||||
@@ -987,7 +1100,6 @@ static const uint8_t jump_table[] =
|
||||
/* Entry point for printing other strings. */ \
|
||||
LABEL (print_string): \
|
||||
\
|
||||
- string_malloced = 0; \
|
||||
if (string == NULL) \
|
||||
{ \
|
||||
/* Write "(null)" if there's space. */ \
|
||||
@@ -1004,41 +1116,12 @@ static const uint8_t jump_table[] =
|
||||
} \
|
||||
else if (!is_long && spec != L_('S')) \
|
||||
{ \
|
||||
- /* This is complicated. We have to transform the multibyte \
|
||||
- string into a wide character string. */ \
|
||||
- const char *mbs = (const char *) string; \
|
||||
- mbstate_t mbstate; \
|
||||
- \
|
||||
- len = prec != -1 ? __strnlen (mbs, (size_t) prec) : strlen (mbs); \
|
||||
- \
|
||||
- /* Allocate dynamically an array which definitely is long \
|
||||
- enough for the wide character version. Each byte in the \
|
||||
- multi-byte string can produce at most one wide character. */ \
|
||||
- if (__glibc_unlikely (len > SIZE_MAX / sizeof (wchar_t))) \
|
||||
- { \
|
||||
- __set_errno (EOVERFLOW); \
|
||||
- done = -1; \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
- else if (__libc_use_alloca (len * sizeof (wchar_t))) \
|
||||
- string = (CHAR_T *) alloca (len * sizeof (wchar_t)); \
|
||||
- else if ((string = (CHAR_T *) malloc (len * sizeof (wchar_t))) \
|
||||
- == NULL) \
|
||||
- { \
|
||||
- done = -1; \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
- else \
|
||||
- string_malloced = 1; \
|
||||
- \
|
||||
- memset (&mbstate, '\0', sizeof (mbstate_t)); \
|
||||
- len = __mbsrtowcs (string, &mbs, len, &mbstate); \
|
||||
- if (len == (size_t) -1) \
|
||||
- { \
|
||||
- /* Illegal multibyte character. */ \
|
||||
- done = -1; \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
+ done = outstring_converted_wide_string \
|
||||
+ (s, (const char *) string, prec, width, left, done); \
|
||||
+ if (done < 0) \
|
||||
+ goto all_done; \
|
||||
+ /* The padding has already been written. */ \
|
||||
+ break; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
@@ -1061,8 +1144,6 @@ static const uint8_t jump_table[] =
|
||||
outstring (string, len); \
|
||||
if (left) \
|
||||
PAD (L' '); \
|
||||
- if (__glibc_unlikely (string_malloced)) \
|
||||
- free (string); \
|
||||
} \
|
||||
break;
|
||||
#else
|
||||
@@ -1111,7 +1192,6 @@ static const uint8_t jump_table[] =
|
||||
LABEL (form_string): \
|
||||
{ \
|
||||
size_t len; \
|
||||
- int string_malloced; \
|
||||
\
|
||||
/* The string argument could in fact be `char *' or `wchar_t *'. \
|
||||
But this should not make a difference here. */ \
|
||||
@@ -1123,7 +1203,6 @@ static const uint8_t jump_table[] =
|
||||
/* Entry point for printing other strings. */ \
|
||||
LABEL (print_string): \
|
||||
\
|
||||
- string_malloced = 0; \
|
||||
if (string == NULL) \
|
||||
{ \
|
||||
/* Write "(null)" if there's space. */ \
|
||||
@@ -1149,51 +1228,12 @@ static const uint8_t jump_table[] =
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
- const wchar_t *s2 = (const wchar_t *) string; \
|
||||
- mbstate_t mbstate; \
|
||||
- \
|
||||
- memset (&mbstate, '\0', sizeof (mbstate_t)); \
|
||||
- \
|
||||
- if (prec >= 0) \
|
||||
- { \
|
||||
- /* The string `s2' might not be NUL terminated. */ \
|
||||
- if (__libc_use_alloca (prec)) \
|
||||
- string = (char *) alloca (prec); \
|
||||
- else if ((string = (char *) malloc (prec)) == NULL) \
|
||||
- { \
|
||||
- done = -1; \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
- else \
|
||||
- string_malloced = 1; \
|
||||
- len = __wcsrtombs (string, &s2, prec, &mbstate); \
|
||||
- } \
|
||||
- else \
|
||||
- { \
|
||||
- len = __wcsrtombs (NULL, &s2, 0, &mbstate); \
|
||||
- if (len != (size_t) -1) \
|
||||
- { \
|
||||
- assert (__mbsinit (&mbstate)); \
|
||||
- s2 = (const wchar_t *) string; \
|
||||
- if (__libc_use_alloca (len + 1)) \
|
||||
- string = (char *) alloca (len + 1); \
|
||||
- else if ((string = (char *) malloc (len + 1)) == NULL) \
|
||||
- { \
|
||||
- done = -1; \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
- else \
|
||||
- string_malloced = 1; \
|
||||
- (void) __wcsrtombs (string, &s2, len + 1, &mbstate); \
|
||||
- } \
|
||||
- } \
|
||||
- \
|
||||
- if (len == (size_t) -1) \
|
||||
- { \
|
||||
- /* Illegal wide-character string. */ \
|
||||
- done = -1; \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
+ done = outstring_converted_wide_string \
|
||||
+ (s, (const wchar_t *) string, prec, width, left, done); \
|
||||
+ if (done < 0) \
|
||||
+ goto all_done; \
|
||||
+ /* The padding has already been written. */ \
|
||||
+ break; \
|
||||
} \
|
||||
\
|
||||
if ((width -= len) < 0) \
|
||||
@@ -1207,8 +1247,6 @@ static const uint8_t jump_table[] =
|
||||
outstring (string, len); \
|
||||
if (left) \
|
||||
PAD (' '); \
|
||||
- if (__glibc_unlikely (string_malloced)) \
|
||||
- free (string); \
|
||||
} \
|
||||
break;
|
||||
#endif
|
160
SOURCES/glibc-rh2122501-2.patch
Normal file
160
SOURCES/glibc-rh2122501-2.patch
Normal file
@ -0,0 +1,160 @@
|
||||
commit 29b12753b51866b227a6c0ac96c2c6c0e20f3497
|
||||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
Date: Thu Mar 19 18:35:46 2020 -0300
|
||||
|
||||
stdio: Add tests for printf multibyte convertion leak [BZ#25691]
|
||||
|
||||
Checked on x86_64-linux-gnu and i686-linux-gnu.
|
||||
|
||||
(cherry picked from commit 910a835dc96c1f518ac2a6179fc622ba81ffb159)
|
||||
|
||||
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
|
||||
index a10f12ab3ccbd76e..51062a7dbf698931 100644
|
||||
--- a/stdio-common/Makefile
|
||||
+++ b/stdio-common/Makefile
|
||||
@@ -63,6 +63,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
|
||||
tst-vfprintf-mbs-prec \
|
||||
tst-scanf-round \
|
||||
tst-renameat2 \
|
||||
+ tst-printf-bz25691 \
|
||||
|
||||
test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble
|
||||
|
||||
@@ -71,10 +72,12 @@ tests-special += $(objpfx)tst-unbputc.out $(objpfx)tst-printf.out \
|
||||
$(objpfx)tst-printf-bz18872-mem.out \
|
||||
$(objpfx)tst-setvbuf1-cmp.out \
|
||||
$(objpfx)tst-vfprintf-width-prec-mem.out \
|
||||
- $(objpfx)tst-printfsz-islongdouble.out
|
||||
+ $(objpfx)tst-printfsz-islongdouble.out \
|
||||
+ $(objpfx)tst-printf-bz25691-mem.out
|
||||
generated += tst-printf-bz18872.c tst-printf-bz18872.mtrace \
|
||||
tst-printf-bz18872-mem.out \
|
||||
- tst-vfprintf-width-prec.mtrace tst-vfprintf-width-prec-mem.out
|
||||
+ tst-vfprintf-width-prec.mtrace tst-vfprintf-width-prec-mem.out \
|
||||
+ tst-printf-bz25691.mtrace tst-printf-bz25691-mem.out
|
||||
endif
|
||||
|
||||
include ../Rules
|
||||
@@ -96,6 +99,8 @@ endif
|
||||
tst-printf-bz18872-ENV = MALLOC_TRACE=$(objpfx)tst-printf-bz18872.mtrace
|
||||
tst-vfprintf-width-prec-ENV = \
|
||||
MALLOC_TRACE=$(objpfx)tst-vfprintf-width-prec.mtrace
|
||||
+tst-printf-bz25691-ENV = \
|
||||
+ MALLOC_TRACE=$(objpfx)tst-printf-bz25691.mtrace
|
||||
|
||||
$(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc
|
||||
$(SHELL) $< $(common-objpfx) '$(test-program-prefix)' > $@; \
|
||||
diff --git a/stdio-common/tst-printf-bz25691.c b/stdio-common/tst-printf-bz25691.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..37b30a3a8a7dc5e2
|
||||
--- /dev/null
|
||||
+++ b/stdio-common/tst-printf-bz25691.c
|
||||
@@ -0,0 +1,108 @@
|
||||
+/* Test for memory leak with large width (BZ#25691).
|
||||
+ Copyright (C) 2020 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 <stdlib.h>
|
||||
+#include <string.h>
|
||||
+#include <wchar.h>
|
||||
+#include <stdint.h>
|
||||
+#include <locale.h>
|
||||
+
|
||||
+#include <mcheck.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/support.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ mtrace ();
|
||||
+
|
||||
+ /* For 's' conversion specifier with 'l' modifier the array must be
|
||||
+ converted to multibyte characters up to the precision specific
|
||||
+ value. */
|
||||
+ {
|
||||
+ /* The input size value is to force a heap allocation on temporary
|
||||
+ buffer (in the old implementation). */
|
||||
+ const size_t winputsize = 64 * 1024 + 1;
|
||||
+ wchar_t *winput = xmalloc (winputsize * sizeof (wchar_t));
|
||||
+ wmemset (winput, L'a', winputsize - 1);
|
||||
+ winput[winputsize - 1] = L'\0';
|
||||
+
|
||||
+ char result[9];
|
||||
+ const char expected[] = "aaaaaaaa";
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = snprintf (result, sizeof (result), "%.65537ls", winput);
|
||||
+ TEST_COMPARE (ret, winputsize - 1);
|
||||
+ TEST_COMPARE_BLOB (result, sizeof (result), expected, sizeof (expected));
|
||||
+
|
||||
+ ret = snprintf (result, sizeof (result), "%ls", winput);
|
||||
+ TEST_COMPARE (ret, winputsize - 1);
|
||||
+ TEST_COMPARE_BLOB (result, sizeof (result), expected, sizeof (expected));
|
||||
+
|
||||
+ free (winput);
|
||||
+ }
|
||||
+
|
||||
+ /* For 's' converstion specifier the array is interpreted as a multibyte
|
||||
+ character sequence and converted to wide characters up to the precision
|
||||
+ specific value. */
|
||||
+ {
|
||||
+ /* The input size value is to force a heap allocation on temporary
|
||||
+ buffer (in the old implementation). */
|
||||
+ const size_t mbssize = 32 * 1024;
|
||||
+ char *mbs = xmalloc (mbssize);
|
||||
+ memset (mbs, 'a', mbssize - 1);
|
||||
+ mbs[mbssize - 1] = '\0';
|
||||
+
|
||||
+ const size_t expectedsize = 32 * 1024;
|
||||
+ wchar_t *expected = xmalloc (expectedsize * sizeof (wchar_t));
|
||||
+ wmemset (expected, L'a', expectedsize - 1);
|
||||
+ expected[expectedsize-1] = L'\0';
|
||||
+
|
||||
+ const size_t resultsize = mbssize * sizeof (wchar_t);
|
||||
+ wchar_t *result = xmalloc (resultsize);
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = swprintf (result, resultsize, L"%.65537s", mbs);
|
||||
+ TEST_COMPARE (ret, mbssize - 1);
|
||||
+ TEST_COMPARE_BLOB (result, (ret + 1) * sizeof (wchar_t),
|
||||
+ expected, expectedsize * sizeof (wchar_t));
|
||||
+
|
||||
+ ret = swprintf (result, resultsize, L"%1$.65537s", mbs);
|
||||
+ TEST_COMPARE (ret, mbssize - 1);
|
||||
+ TEST_COMPARE_BLOB (result, (ret + 1) * sizeof (wchar_t),
|
||||
+ expected, expectedsize * sizeof (wchar_t));
|
||||
+
|
||||
+ /* Same test, but with an invalid multibyte sequence. */
|
||||
+ mbs[mbssize - 2] = 0xff;
|
||||
+
|
||||
+ ret = swprintf (result, resultsize, L"%.65537s", mbs);
|
||||
+ TEST_COMPARE (ret, -1);
|
||||
+
|
||||
+ ret = swprintf (result, resultsize, L"%1$.65537s", mbs);
|
||||
+ TEST_COMPARE (ret, -1);
|
||||
+
|
||||
+ free (mbs);
|
||||
+ free (result);
|
||||
+ free (expected);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
356
SOURCES/glibc-rh2122501-3.patch
Normal file
356
SOURCES/glibc-rh2122501-3.patch
Normal file
@ -0,0 +1,356 @@
|
||||
commit e1c0c00cc2bdd147bfcf362ada1443bee90465ec
|
||||
Author: Joseph Myers <joseph@codesourcery.com>
|
||||
Date: Tue Jul 7 14:54:12 2020 +0000
|
||||
|
||||
Remove most vfprintf width/precision-dependent allocations (bug 14231, bug 26211).
|
||||
|
||||
The vfprintf implementation (used for all printf-family functions)
|
||||
contains complicated logic to allocate internal buffers of a size
|
||||
depending on the width and precision used for a format, using either
|
||||
malloc or alloca depending on that size, and with consequent checks
|
||||
for size overflow and allocation failure.
|
||||
|
||||
As noted in bug 26211, the version of that logic used when '$' plus
|
||||
argument number formats are in use is missing the overflow checks,
|
||||
which can result in segfaults (quite possibly exploitable, I didn't
|
||||
try to work that out) when the width or precision is in the range
|
||||
0x7fffffe0 through 0x7fffffff (maybe smaller values as well in the
|
||||
wprintf case on 32-bit systems, when the multiplication by sizeof
|
||||
(CHAR_T) can overflow).
|
||||
|
||||
All that complicated logic in fact appears to be useless. As far as I
|
||||
can tell, there has been no need (outside the floating-point printf
|
||||
code, which does its own allocations) for allocations depending on
|
||||
width or precision since commit
|
||||
3e95f6602b226e0de06aaff686dc47b282d7cc16 ("Remove limitation on size
|
||||
of precision for integers", Sun Sep 12 21:23:32 1999 +0000). Thus,
|
||||
this patch removes that logic completely, thereby fixing both problems
|
||||
with excessive allocations for large width and precision for
|
||||
non-floating-point formats, and the problem with missing overflow
|
||||
checks with such allocations. Note that this does have the
|
||||
consequence that width and precision up to INT_MAX are now allowed
|
||||
where previously INT_MAX / sizeof (CHAR_T) - EXTSIZ or more would have
|
||||
been rejected, so could potentially expose any other overflows where
|
||||
the value would previously have been rejected by those removed checks.
|
||||
|
||||
I believe this completely fixes bugs 14231 and 26211.
|
||||
|
||||
Excessive allocations are still possible in the floating-point case
|
||||
(bug 21127), as are other integer or buffer overflows (see bug 26201).
|
||||
This does not address the cases where a precision larger than INT_MAX
|
||||
(embedded in the format string) would be meaningful without printf's
|
||||
return value overflowing (when it's used with a string format, or %g
|
||||
without the '#' flag, so the actual output will be much smaller), as
|
||||
mentioned in bug 17829 comment 8; using size_t internally for
|
||||
precision to handle that case would be complicated by struct
|
||||
printf_info being a public ABI. Nor does it address the matter of an
|
||||
INT_MIN width being negated (bug 17829 comment 7; the same logic
|
||||
appears a second time in the file as well, in the form of multiplying
|
||||
by -1). There may be other sources of memory allocations with malloc
|
||||
in printf functions as well (bug 24988, bug 16060). From inspection,
|
||||
I think there are also integer overflows in two copies of "if ((width
|
||||
-= len) < 0)" logic (where width is int, len is size_t and a very long
|
||||
string could result in spurious padding being output on a 32-bit
|
||||
system before printf overflows the count of output characters).
|
||||
|
||||
Tested for x86-64 and x86.
|
||||
|
||||
(cherry picked from commit 6caddd34bd7ffb5ac4f36c8e036eee100c2cc535)
|
||||
|
||||
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
|
||||
index 51062a7dbf698931..d76b47bd5f932f69 100644
|
||||
--- a/stdio-common/Makefile
|
||||
+++ b/stdio-common/Makefile
|
||||
@@ -64,6 +64,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
|
||||
tst-scanf-round \
|
||||
tst-renameat2 \
|
||||
tst-printf-bz25691 \
|
||||
+ tst-vfprintf-width-prec-alloc
|
||||
|
||||
test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble
|
||||
|
||||
diff --git a/stdio-common/bug22.c b/stdio-common/bug22.c
|
||||
index b26399acb7dfc775..e12b01731e1b4ac8 100644
|
||||
--- a/stdio-common/bug22.c
|
||||
+++ b/stdio-common/bug22.c
|
||||
@@ -42,7 +42,7 @@ do_test (void)
|
||||
|
||||
ret = fprintf (fp, "%." SN3 "d", 1);
|
||||
printf ("ret = %d\n", ret);
|
||||
- if (ret != -1 || errno != EOVERFLOW)
|
||||
+ if (ret != N3)
|
||||
return 1;
|
||||
|
||||
ret = fprintf (fp, "%" SN2 "d%" SN2 "d", 1, 1);
|
||||
diff --git a/stdio-common/tst-vfprintf-width-prec-alloc.c b/stdio-common/tst-vfprintf-width-prec-alloc.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..0a74b53a3389d699
|
||||
--- /dev/null
|
||||
+++ b/stdio-common/tst-vfprintf-width-prec-alloc.c
|
||||
@@ -0,0 +1,41 @@
|
||||
+/* Test large width or precision does not involve large allocation.
|
||||
+ Copyright (C) 2020 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 <sys/resource.h>
|
||||
+#include <support/check.h>
|
||||
+
|
||||
+char test_string[] = "test";
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ struct rlimit limit;
|
||||
+ TEST_VERIFY_EXIT (getrlimit (RLIMIT_AS, &limit) == 0);
|
||||
+ limit.rlim_cur = 200 * 1024 * 1024;
|
||||
+ TEST_VERIFY_EXIT (setrlimit (RLIMIT_AS, &limit) == 0);
|
||||
+ FILE *fp = fopen ("/dev/null", "w");
|
||||
+ TEST_VERIFY_EXIT (fp != NULL);
|
||||
+ TEST_COMPARE (fprintf (fp, "%1000000000d", 1), 1000000000);
|
||||
+ TEST_COMPARE (fprintf (fp, "%.1000000000s", test_string), 4);
|
||||
+ TEST_COMPARE (fprintf (fp, "%1000000000d %1000000000d", 1, 2), 2000000001);
|
||||
+ TEST_COMPARE (fprintf (fp, "%2$.*1$s", 0x7fffffff, test_string), 4);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
|
||||
index dab56b6ba2c7bdbe..6b83ba91a12cdcd5 100644
|
||||
--- a/stdio-common/vfprintf.c
|
||||
+++ b/stdio-common/vfprintf.c
|
||||
@@ -42,10 +42,6 @@
|
||||
|
||||
#include <libioP.h>
|
||||
|
||||
-/* In some cases we need extra space for all the output which is not
|
||||
- counted in the width of the string. We assume 32 characters is
|
||||
- enough. */
|
||||
-#define EXTSIZ 32
|
||||
#define ARGCHECK(S, Format) \
|
||||
do \
|
||||
{ \
|
||||
@@ -1295,7 +1291,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
||||
|
||||
/* Buffer intermediate results. */
|
||||
CHAR_T work_buffer[WORK_BUFFER_SIZE];
|
||||
- CHAR_T *workstart = NULL;
|
||||
CHAR_T *workend;
|
||||
|
||||
/* We have to save the original argument pointer. */
|
||||
@@ -1404,7 +1399,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
||||
UCHAR_T pad = L_(' ');/* Padding character. */
|
||||
CHAR_T spec;
|
||||
|
||||
- workstart = NULL;
|
||||
workend = work_buffer + WORK_BUFFER_SIZE;
|
||||
|
||||
/* Get current character in format string. */
|
||||
@@ -1496,31 +1490,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
||||
pad = L_(' ');
|
||||
left = 1;
|
||||
}
|
||||
-
|
||||
- if (__glibc_unlikely (width >= INT_MAX / sizeof (CHAR_T) - EXTSIZ))
|
||||
- {
|
||||
- __set_errno (EOVERFLOW);
|
||||
- done = -1;
|
||||
- goto all_done;
|
||||
- }
|
||||
-
|
||||
- if (width >= WORK_BUFFER_SIZE - EXTSIZ)
|
||||
- {
|
||||
- /* We have to use a special buffer. */
|
||||
- size_t needed = ((size_t) width + EXTSIZ) * sizeof (CHAR_T);
|
||||
- if (__libc_use_alloca (needed))
|
||||
- workend = (CHAR_T *) alloca (needed) + width + EXTSIZ;
|
||||
- else
|
||||
- {
|
||||
- workstart = (CHAR_T *) malloc (needed);
|
||||
- if (workstart == NULL)
|
||||
- {
|
||||
- done = -1;
|
||||
- goto all_done;
|
||||
- }
|
||||
- workend = workstart + width + EXTSIZ;
|
||||
- }
|
||||
- }
|
||||
}
|
||||
JUMP (*f, step1_jumps);
|
||||
|
||||
@@ -1528,31 +1497,13 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
||||
LABEL (width):
|
||||
width = read_int (&f);
|
||||
|
||||
- if (__glibc_unlikely (width == -1
|
||||
- || width >= INT_MAX / sizeof (CHAR_T) - EXTSIZ))
|
||||
+ if (__glibc_unlikely (width == -1))
|
||||
{
|
||||
__set_errno (EOVERFLOW);
|
||||
done = -1;
|
||||
goto all_done;
|
||||
}
|
||||
|
||||
- if (width >= WORK_BUFFER_SIZE - EXTSIZ)
|
||||
- {
|
||||
- /* We have to use a special buffer. */
|
||||
- size_t needed = ((size_t) width + EXTSIZ) * sizeof (CHAR_T);
|
||||
- if (__libc_use_alloca (needed))
|
||||
- workend = (CHAR_T *) alloca (needed) + width + EXTSIZ;
|
||||
- else
|
||||
- {
|
||||
- workstart = (CHAR_T *) malloc (needed);
|
||||
- if (workstart == NULL)
|
||||
- {
|
||||
- done = -1;
|
||||
- goto all_done;
|
||||
- }
|
||||
- workend = workstart + width + EXTSIZ;
|
||||
- }
|
||||
- }
|
||||
if (*f == L_('$'))
|
||||
/* Oh, oh. The argument comes from a positional parameter. */
|
||||
goto do_positional;
|
||||
@@ -1601,34 +1552,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
||||
}
|
||||
else
|
||||
prec = 0;
|
||||
- if (prec > width && prec > WORK_BUFFER_SIZE - EXTSIZ)
|
||||
- {
|
||||
- /* Deallocate any previously allocated buffer because it is
|
||||
- too small. */
|
||||
- if (__glibc_unlikely (workstart != NULL))
|
||||
- free (workstart);
|
||||
- workstart = NULL;
|
||||
- if (__glibc_unlikely (prec >= INT_MAX / sizeof (CHAR_T) - EXTSIZ))
|
||||
- {
|
||||
- __set_errno (EOVERFLOW);
|
||||
- done = -1;
|
||||
- goto all_done;
|
||||
- }
|
||||
- size_t needed = ((size_t) prec + EXTSIZ) * sizeof (CHAR_T);
|
||||
-
|
||||
- if (__libc_use_alloca (needed))
|
||||
- workend = (CHAR_T *) alloca (needed) + prec + EXTSIZ;
|
||||
- else
|
||||
- {
|
||||
- workstart = (CHAR_T *) malloc (needed);
|
||||
- if (workstart == NULL)
|
||||
- {
|
||||
- done = -1;
|
||||
- goto all_done;
|
||||
- }
|
||||
- workend = workstart + prec + EXTSIZ;
|
||||
- }
|
||||
- }
|
||||
JUMP (*f, step2_jumps);
|
||||
|
||||
/* Process 'h' modifier. There might another 'h' following. */
|
||||
@@ -1692,10 +1615,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
||||
/* The format is correctly handled. */
|
||||
++nspecs_done;
|
||||
|
||||
- if (__glibc_unlikely (workstart != NULL))
|
||||
- free (workstart);
|
||||
- workstart = NULL;
|
||||
-
|
||||
/* Look for next format specifier. */
|
||||
#ifdef COMPILE_WPRINTF
|
||||
f = __find_specwc ((end_of_spec = ++f));
|
||||
@@ -1713,18 +1632,11 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
||||
|
||||
/* Hand off processing for positional parameters. */
|
||||
do_positional:
|
||||
- if (__glibc_unlikely (workstart != NULL))
|
||||
- {
|
||||
- free (workstart);
|
||||
- workstart = NULL;
|
||||
- }
|
||||
done = printf_positional (s, format, readonly_format, ap, &ap_save,
|
||||
done, nspecs_done, lead_str_end, work_buffer,
|
||||
save_errno, grouping, thousands_sep);
|
||||
|
||||
all_done:
|
||||
- if (__glibc_unlikely (workstart != NULL))
|
||||
- free (workstart);
|
||||
/* Unlock the stream. */
|
||||
_IO_funlockfile (s);
|
||||
_IO_cleanup_region_end (0);
|
||||
@@ -1767,8 +1679,6 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
|
||||
/* Just a counter. */
|
||||
size_t cnt;
|
||||
|
||||
- CHAR_T *workstart = NULL;
|
||||
-
|
||||
if (grouping == (const char *) -1)
|
||||
{
|
||||
#ifdef COMPILE_WPRINTF
|
||||
@@ -1957,7 +1867,6 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
|
||||
char pad = specs[nspecs_done].info.pad;
|
||||
CHAR_T spec = specs[nspecs_done].info.spec;
|
||||
|
||||
- workstart = NULL;
|
||||
CHAR_T *workend = work_buffer + WORK_BUFFER_SIZE;
|
||||
|
||||
/* Fill in last information. */
|
||||
@@ -1991,27 +1900,6 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
|
||||
prec = specs[nspecs_done].info.prec;
|
||||
}
|
||||
|
||||
- /* Maybe the buffer is too small. */
|
||||
- if (MAX (prec, width) + EXTSIZ > WORK_BUFFER_SIZE)
|
||||
- {
|
||||
- if (__libc_use_alloca ((MAX (prec, width) + EXTSIZ)
|
||||
- * sizeof (CHAR_T)))
|
||||
- workend = ((CHAR_T *) alloca ((MAX (prec, width) + EXTSIZ)
|
||||
- * sizeof (CHAR_T))
|
||||
- + (MAX (prec, width) + EXTSIZ));
|
||||
- else
|
||||
- {
|
||||
- workstart = (CHAR_T *) malloc ((MAX (prec, width) + EXTSIZ)
|
||||
- * sizeof (CHAR_T));
|
||||
- if (workstart == NULL)
|
||||
- {
|
||||
- done = -1;
|
||||
- goto all_done;
|
||||
- }
|
||||
- workend = workstart + (MAX (prec, width) + EXTSIZ);
|
||||
- }
|
||||
- }
|
||||
-
|
||||
/* Process format specifiers. */
|
||||
while (1)
|
||||
{
|
||||
@@ -2085,18 +1973,12 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
|
||||
break;
|
||||
}
|
||||
|
||||
- if (__glibc_unlikely (workstart != NULL))
|
||||
- free (workstart);
|
||||
- workstart = NULL;
|
||||
-
|
||||
/* Write the following constant string. */
|
||||
outstring (specs[nspecs_done].end_of_fmt,
|
||||
specs[nspecs_done].next_fmt
|
||||
- specs[nspecs_done].end_of_fmt);
|
||||
}
|
||||
all_done:
|
||||
- if (__glibc_unlikely (workstart != NULL))
|
||||
- free (workstart);
|
||||
scratch_buffer_free (&argsbuf);
|
||||
scratch_buffer_free (&specsbuf);
|
||||
return done;
|
86
SOURCES/glibc-rh2122501-4.patch
Normal file
86
SOURCES/glibc-rh2122501-4.patch
Normal file
@ -0,0 +1,86 @@
|
||||
commit 211a30a92b72a18ea4caa35ed503b70bc644923e
|
||||
Author: Joseph Myers <joseph@codesourcery.com>
|
||||
Date: Mon Nov 8 19:11:51 2021 +0000
|
||||
|
||||
Fix memmove call in vfprintf-internal.c:group_number
|
||||
|
||||
A recent GCC mainline change introduces errors of the form:
|
||||
|
||||
vfprintf-internal.c: In function 'group_number':
|
||||
vfprintf-internal.c:2093:15: error: 'memmove' specified bound between 9223372036854775808 and 18446744073709551615 exceeds maximum object size 9223372036854775807 [-Werror=stringop-overflow=]
|
||||
2093 | memmove (w, s, (front_ptr -s) * sizeof (CHAR_T));
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This is a genuine bug in the glibc code: s > front_ptr is always true
|
||||
at this point in the code, and the intent is clearly for the
|
||||
subtraction to be the other way round. The other arguments to the
|
||||
memmove call here also appear to be wrong; w and s point just *after*
|
||||
the destination and source for copying the rest of the number, so the
|
||||
size needs to be subtracted to get appropriate pointers for the
|
||||
copying. Adjust the memmove call to conform to the apparent intent of
|
||||
the code, so fixing the -Wstringop-overflow error.
|
||||
|
||||
Now, if the original code were ever executed, a buffer overrun would
|
||||
result. However, I believe this code (introduced in commit
|
||||
edc1686af0c0fc2eb535f1d38cdf63c1a5a03675, "vfprintf: Reuse work_buffer
|
||||
in group_number", so in glibc 2.26) is unreachable in prior glibc
|
||||
releases (so there is no need for a bug in Bugzilla, no need to
|
||||
consider any backports unless someone wants to build older glibc
|
||||
releases with GCC 12 and no possibility of this buffer overrun
|
||||
resulting in a security issue).
|
||||
|
||||
work_buffer is 1000 bytes / 250 wide characters. This case is only
|
||||
reachable if an initial part of the number, plus a grouped copy of the
|
||||
rest of the number, fail to fit in that space; that is, if the grouped
|
||||
number fails to fit in the space. In the wide character case,
|
||||
grouping is always one wide character, so even with a locale (of which
|
||||
there aren't any in glibc) grouping every digit, a number would need
|
||||
to occupy at least 125 wide characters to overflow, and a 64-bit
|
||||
integer occupies at most 23 characters in octal including a leading 0.
|
||||
In the narrow character case, the multibyte encoding of the grouping
|
||||
separator would need to be at least 42 bytes to overflow, again
|
||||
supposing grouping every digit, but MB_LEN_MAX is 16. So even if we
|
||||
admit the case of artificially constructed locales not shipped with
|
||||
glibc, given that such a locale would need to use one of the character
|
||||
sets supported by glibc, this code cannot be reached at present. (And
|
||||
POSIX only actually specifies the ' flag for grouping for decimal
|
||||
output, though glibc acts on it for other bases as well.)
|
||||
|
||||
With binary output (if you consider use of grouping there to be
|
||||
valid), you'd need a 15-byte multibyte character for overflow; I don't
|
||||
know if any supported character set has such a character (if, again,
|
||||
we admit constructed locales using grouping every digit and a grouping
|
||||
separator chosen to have a multibyte encoding as long as possible, as
|
||||
well as accepting use of grouping with binary), but given that we have
|
||||
this code at all (clearly it's not *correct*, or in accordance with
|
||||
the principle of avoiding arbitrary limits, to skip grouping on
|
||||
running out of internal space like that), I don't think it should need
|
||||
any further changes for binary printf support to go in.
|
||||
|
||||
On the other hand, support for large sizes of _BitInt in printf (see
|
||||
the N2858 proposal) *would* require something to be done about such
|
||||
arbitrary limits (presumably using dynamic allocation in printf again,
|
||||
for sufficiently large _BitInt arguments only - currently only
|
||||
floating-point uses dynamic allocation, and, as previously discussed,
|
||||
that could actually be replaced by bounded allocation given smarter
|
||||
code).
|
||||
|
||||
Tested with build-many-glibcs.py for aarch64-linux-gnu (GCC mainline).
|
||||
Also tested natively for x86_64.
|
||||
|
||||
(cherry picked from commit db6c4935fae6005d46af413b32aa92f4f6059dce)
|
||||
|
||||
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
|
||||
index 6b83ba91a12cdcd5..2d434ba45a67911e 100644
|
||||
--- a/stdio-common/vfprintf.c
|
||||
+++ b/stdio-common/vfprintf.c
|
||||
@@ -2101,7 +2101,8 @@ group_number (CHAR_T *front_ptr, CHAR_T *w, CHAR_T *rear_ptr,
|
||||
copy_rest:
|
||||
/* No further grouping to be done. Copy the rest of the
|
||||
number. */
|
||||
- memmove (w, s, (front_ptr -s) * sizeof (CHAR_T));
|
||||
+ w -= s - front_ptr;
|
||||
+ memmove (w, front_ptr, (s - front_ptr) * sizeof (CHAR_T));
|
||||
break;
|
||||
}
|
||||
else if (*grouping != '\0')
|
81
SOURCES/glibc-rh2122501-5.patch
Normal file
81
SOURCES/glibc-rh2122501-5.patch
Normal file
@ -0,0 +1,81 @@
|
||||
commit 8b915921fbf4d32bf68fc3d637413cf96236b3fd
|
||||
Author: Andreas Schwab <schwab@suse.de>
|
||||
Date: Mon Aug 29 15:05:40 2022 +0200
|
||||
|
||||
Add test for bug 29530
|
||||
|
||||
This tests for a bug that was introduced in commit edc1686af0 ("vfprintf:
|
||||
Reuse work_buffer in group_number") and fixed as a side effect of commit
|
||||
6caddd34bd ("Remove most vfprintf width/precision-dependent allocations
|
||||
(bug 14231, bug 26211).").
|
||||
|
||||
(cherry picked from commit ca6466e8be32369a658035d69542d47603e58a99)
|
||||
|
||||
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
|
||||
index d76b47bd5f932f69..ac61093660ef9063 100644
|
||||
--- a/stdio-common/Makefile
|
||||
+++ b/stdio-common/Makefile
|
||||
@@ -64,7 +64,9 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
|
||||
tst-scanf-round \
|
||||
tst-renameat2 \
|
||||
tst-printf-bz25691 \
|
||||
- tst-vfprintf-width-prec-alloc
|
||||
+ tst-vfprintf-width-prec-alloc \
|
||||
+ tst-grouping2 \
|
||||
+ # tests
|
||||
|
||||
test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble
|
||||
|
||||
@@ -91,6 +93,7 @@ $(objpfx)bug14.out: $(gen-locales)
|
||||
$(objpfx)scanf13.out: $(gen-locales)
|
||||
$(objpfx)test-vfprintf.out: $(gen-locales)
|
||||
$(objpfx)tst-grouping.out: $(gen-locales)
|
||||
+$(objpfx)tst-grouping2.out: $(gen-locales)
|
||||
$(objpfx)tst-sprintf.out: $(gen-locales)
|
||||
$(objpfx)tst-sscanf.out: $(gen-locales)
|
||||
$(objpfx)tst-swprintf.out: $(gen-locales)
|
||||
diff --git a/stdio-common/tst-grouping2.c b/stdio-common/tst-grouping2.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..3024c942a60e51bf
|
||||
--- /dev/null
|
||||
+++ b/stdio-common/tst-grouping2.c
|
||||
@@ -0,0 +1,39 @@
|
||||
+/* Test printf with grouping and large width (bug 29530)
|
||||
+ Copyright (C) 2022 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 <locale.h>
|
||||
+#include <stdio.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/support.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ const int field_width = 1000;
|
||||
+ char buf[field_width + 1];
|
||||
+
|
||||
+ xsetlocale (LC_NUMERIC, "de_DE.UTF-8");
|
||||
+
|
||||
+ /* This used to crash in group_number. */
|
||||
+ TEST_COMPARE (sprintf (buf, "%'*d", field_width, 1000), field_width);
|
||||
+ TEST_COMPARE_STRING (buf + field_width - 6, " 1.000");
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
@ -1,6 +1,6 @@
|
||||
%define glibcsrcdir glibc-2.28
|
||||
%define glibcversion 2.28
|
||||
%define glibcrelease 216%{?dist}
|
||||
%define glibcrelease 219%{?dist}
|
||||
# Pre-release tarballs are pulled in from git using a command that is
|
||||
# effectively:
|
||||
#
|
||||
@ -978,6 +978,14 @@ Patch785: glibc-rh1871383-4.patch
|
||||
Patch786: glibc-rh1871383-5.patch
|
||||
Patch787: glibc-rh1871383-6.patch
|
||||
Patch788: glibc-rh1871383-7.patch
|
||||
Patch789: glibc-rh2122501-1.patch
|
||||
Patch790: glibc-rh2122501-2.patch
|
||||
Patch791: glibc-rh2122501-3.patch
|
||||
Patch792: glibc-rh2122501-4.patch
|
||||
Patch793: glibc-rh2122501-5.patch
|
||||
Patch794: glibc-rh2121746-1.patch
|
||||
Patch795: glibc-rh2121746-2.patch
|
||||
Patch796: glibc-rh2116938.patch
|
||||
|
||||
##############################################################################
|
||||
# Continued list of core "glibc" package information:
|
||||
@ -2808,6 +2816,16 @@ fi
|
||||
%files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared
|
||||
|
||||
%changelog
|
||||
* Mon Oct 24 2022 Arjun Shankar <arjun@redhat.com> - 2.28-219
|
||||
- Fix -Wstrict-overflow warning when using CMSG_NXTHDR macro (#2116938)
|
||||
|
||||
* Fri Oct 14 2022 DJ Delorie <dj@redhat.com> - 2.28-218
|
||||
- Fix dlmopen/dlclose/dlmopen sequence and libc initialization (#2121746)
|
||||
|
||||
* Thu Oct 13 2022 Arjun Shankar <arjun@redhat.com> - 2.28-217
|
||||
- Fix memory corruption in printf with thousands separators and large
|
||||
integer width (#2122501)
|
||||
|
||||
* Wed Oct 05 2022 Arjun Shankar <arjun@redhat.com> - 2.28-216
|
||||
- Retain .gnu_debuglink section for libc.so.6 (#2115830)
|
||||
- Remove .annobin* symbols from ld.so
|
||||
|
Loading…
Reference in New Issue
Block a user