Backport test implementation to verify readdir behavior
Resolves: RHEL-56542
This commit is contained in:
parent
08cb9d7284
commit
d2c49567f7
56
glibc-RHEL-56542-1.patch
Normal file
56
glibc-RHEL-56542-1.patch
Normal file
@ -0,0 +1,56 @@
|
||||
commit 0e12ca024119ec6c6d2ac852a65046002efa0e80
|
||||
Author: Steve Grubb <sgrubb@redhat.com>
|
||||
Date: Fri Mar 11 15:29:06 2022 -0500
|
||||
|
||||
associate a deallocation for opendir
|
||||
|
||||
This patch associates closedir as a deallocation for opendir and fdopendir.
|
||||
This required moving the closedir declaration above the other 2 functions.
|
||||
|
||||
Reviewed-by: Paul Eggert <eggert@cs.ucla.edu>
|
||||
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||
|
||||
diff --git a/dirent/dirent.h b/dirent/dirent.h
|
||||
index 1d1fab7e55cdad4d..84834e8db9dea874 100644
|
||||
--- a/dirent/dirent.h
|
||||
+++ b/dirent/dirent.h
|
||||
@@ -126,28 +126,30 @@ enum
|
||||
The actual structure is opaque to users. */
|
||||
typedef struct __dirstream DIR;
|
||||
|
||||
+/* Close the directory stream DIRP.
|
||||
+ Return 0 if successful, -1 if not.
|
||||
+
|
||||
+ This function is a possible cancellation point and therefore not
|
||||
+ marked with __THROW. */
|
||||
+extern int closedir (DIR *__dirp) __nonnull ((1));
|
||||
+
|
||||
/* Open a directory stream on NAME.
|
||||
Return a DIR stream on the directory, or NULL if it could not be opened.
|
||||
|
||||
This function is a possible cancellation point and therefore not
|
||||
marked with __THROW. */
|
||||
-extern DIR *opendir (const char *__name) __nonnull ((1));
|
||||
+extern DIR *opendir (const char *__name) __nonnull ((1))
|
||||
+ __attribute_malloc__ __attr_dealloc (closedir, 1);
|
||||
|
||||
#ifdef __USE_XOPEN2K8
|
||||
/* Same as opendir, but open the stream on the file descriptor FD.
|
||||
|
||||
This function is a possible cancellation point and therefore not
|
||||
marked with __THROW. */
|
||||
-extern DIR *fdopendir (int __fd);
|
||||
+extern DIR *fdopendir (int __fd)
|
||||
+ __attribute_malloc__ __attr_dealloc (closedir, 1);
|
||||
#endif
|
||||
|
||||
-/* Close the directory stream DIRP.
|
||||
- Return 0 if successful, -1 if not.
|
||||
-
|
||||
- This function is a possible cancellation point and therefore not
|
||||
- marked with __THROW. */
|
||||
-extern int closedir (DIR *__dirp) __nonnull ((1));
|
||||
-
|
||||
/* Read a directory entry from DIRP. Return a pointer to a `struct
|
||||
dirent' describing the entry, or NULL for EOF or error. The
|
||||
storage returned may be overwritten by a later readdir call on the
|
236
glibc-RHEL-56542-2.patch
Normal file
236
glibc-RHEL-56542-2.patch
Normal file
@ -0,0 +1,236 @@
|
||||
commit 766b73768b290b303f5b56268c6c0d588d5a9267
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Mon Sep 19 08:10:41 2022 +0200
|
||||
|
||||
Linux: Do not skip d_ino == 0 entries in readdir, readdir64 (bug 12165)
|
||||
|
||||
POSIX does not say this value is special. For example, old XFS file
|
||||
systems may still use inode number zero.
|
||||
|
||||
Also update the comment regarding ENOENT. Linux may return ENOENT
|
||||
for some file systems.
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/readdir.c b/sysdeps/unix/sysv/linux/readdir.c
|
||||
index b4801351645d1236..ef95611f09e761a4 100644
|
||||
--- a/sysdeps/unix/sysv/linux/readdir.c
|
||||
+++ b/sysdeps/unix/sysv/linux/readdir.c
|
||||
@@ -28,48 +28,33 @@ __readdir_unlocked (DIR *dirp)
|
||||
struct dirent *dp;
|
||||
int saved_errno = errno;
|
||||
|
||||
- do
|
||||
+ if (dirp->offset >= dirp->size)
|
||||
{
|
||||
- size_t reclen;
|
||||
+ /* We've emptied out our buffer. Refill it. */
|
||||
|
||||
- if (dirp->offset >= dirp->size)
|
||||
+ size_t maxread = dirp->allocation;
|
||||
+ ssize_t bytes;
|
||||
+
|
||||
+ bytes = __getdents (dirp->fd, dirp->data, maxread);
|
||||
+ if (bytes <= 0)
|
||||
{
|
||||
- /* We've emptied out our buffer. Refill it. */
|
||||
-
|
||||
- size_t maxread = dirp->allocation;
|
||||
- ssize_t bytes;
|
||||
-
|
||||
- bytes = __getdents (dirp->fd, dirp->data, maxread);
|
||||
- if (bytes <= 0)
|
||||
- {
|
||||
- /* On some systems getdents fails with ENOENT when the
|
||||
- open directory has been rmdir'd already. POSIX.1
|
||||
- requires that we treat this condition like normal EOF. */
|
||||
- if (bytes < 0 && errno == ENOENT)
|
||||
- bytes = 0;
|
||||
-
|
||||
- /* Don't modifiy errno when reaching EOF. */
|
||||
- if (bytes == 0)
|
||||
- __set_errno (saved_errno);
|
||||
- dp = NULL;
|
||||
- break;
|
||||
- }
|
||||
- dirp->size = (size_t) bytes;
|
||||
-
|
||||
- /* Reset the offset into the buffer. */
|
||||
- dirp->offset = 0;
|
||||
+ /* Linux may fail with ENOENT on some file systems if the
|
||||
+ directory inode is marked as dead (deleted). POSIX
|
||||
+ treats this as a regular end-of-directory condition, so
|
||||
+ do not set errno in that case, to indicate success. */
|
||||
+ if (bytes == 0 || errno == ENOENT)
|
||||
+ __set_errno (saved_errno);
|
||||
+ return NULL;
|
||||
}
|
||||
+ dirp->size = (size_t) bytes;
|
||||
|
||||
- dp = (struct dirent *) &dirp->data[dirp->offset];
|
||||
-
|
||||
- reclen = dp->d_reclen;
|
||||
-
|
||||
- dirp->offset += reclen;
|
||||
-
|
||||
- dirp->filepos = dp->d_off;
|
||||
+ /* Reset the offset into the buffer. */
|
||||
+ dirp->offset = 0;
|
||||
+ }
|
||||
|
||||
- /* Skip deleted files. */
|
||||
- } while (dp->d_ino == 0);
|
||||
+ dp = (struct dirent *) &dirp->data[dirp->offset];
|
||||
+ dirp->offset += dp->d_reclen;
|
||||
+ dirp->filepos = dp->d_off;
|
||||
|
||||
return dp;
|
||||
}
|
||||
diff --git a/sysdeps/unix/sysv/linux/readdir64.c b/sysdeps/unix/sysv/linux/readdir64.c
|
||||
index 52b11eb9d91bb5fd..8a60504649aa54a2 100644
|
||||
--- a/sysdeps/unix/sysv/linux/readdir64.c
|
||||
+++ b/sysdeps/unix/sysv/linux/readdir64.c
|
||||
@@ -37,48 +37,36 @@ __readdir64 (DIR *dirp)
|
||||
__libc_lock_lock (dirp->lock);
|
||||
#endif
|
||||
|
||||
- do
|
||||
+ if (dirp->offset >= dirp->size)
|
||||
{
|
||||
- size_t reclen;
|
||||
+ /* We've emptied out our buffer. Refill it. */
|
||||
|
||||
- if (dirp->offset >= dirp->size)
|
||||
+ size_t maxread = dirp->allocation;
|
||||
+ ssize_t bytes;
|
||||
+
|
||||
+ bytes = __getdents64 (dirp->fd, dirp->data, maxread);
|
||||
+ if (bytes <= 0)
|
||||
{
|
||||
- /* We've emptied out our buffer. Refill it. */
|
||||
-
|
||||
- size_t maxread = dirp->allocation;
|
||||
- ssize_t bytes;
|
||||
-
|
||||
- bytes = __getdents64 (dirp->fd, dirp->data, maxread);
|
||||
- if (bytes <= 0)
|
||||
- {
|
||||
- /* On some systems getdents fails with ENOENT when the
|
||||
- open directory has been rmdir'd already. POSIX.1
|
||||
- requires that we treat this condition like normal EOF. */
|
||||
- if (bytes < 0 && errno == ENOENT)
|
||||
- bytes = 0;
|
||||
-
|
||||
- /* Don't modifiy errno when reaching EOF. */
|
||||
- if (bytes == 0)
|
||||
- __set_errno (saved_errno);
|
||||
- dp = NULL;
|
||||
- break;
|
||||
- }
|
||||
- dirp->size = (size_t) bytes;
|
||||
-
|
||||
- /* Reset the offset into the buffer. */
|
||||
- dirp->offset = 0;
|
||||
+ /* Linux may fail with ENOENT on some file systems if the
|
||||
+ directory inode is marked as dead (deleted). POSIX
|
||||
+ treats this as a regular end-of-directory condition, so
|
||||
+ do not set errno in that case, to indicate success. */
|
||||
+ if (bytes == 0 || errno == ENOENT)
|
||||
+ __set_errno (saved_errno);
|
||||
+#if IS_IN (libc)
|
||||
+ __libc_lock_unlock (dirp->lock);
|
||||
+#endif
|
||||
+ return NULL;
|
||||
}
|
||||
+ dirp->size = (size_t) bytes;
|
||||
|
||||
- dp = (struct dirent64 *) &dirp->data[dirp->offset];
|
||||
-
|
||||
- reclen = dp->d_reclen;
|
||||
-
|
||||
- dirp->offset += reclen;
|
||||
-
|
||||
- dirp->filepos = dp->d_off;
|
||||
+ /* Reset the offset into the buffer. */
|
||||
+ dirp->offset = 0;
|
||||
+ }
|
||||
|
||||
- /* Skip deleted files. */
|
||||
- } while (dp->d_ino == 0);
|
||||
+ dp = (struct dirent64 *) &dirp->data[dirp->offset];
|
||||
+ dirp->offset += dp->d_reclen;
|
||||
+ dirp->filepos = dp->d_off;
|
||||
|
||||
#if IS_IN (libc)
|
||||
__libc_lock_unlock (dirp->lock);
|
||||
@@ -115,48 +103,36 @@ __old_readdir64 (DIR *dirp)
|
||||
__libc_lock_lock (dirp->lock);
|
||||
#endif
|
||||
|
||||
- do
|
||||
+ if (dirp->offset >= dirp->size)
|
||||
{
|
||||
- size_t reclen;
|
||||
+ /* We've emptied out our buffer. Refill it. */
|
||||
|
||||
- if (dirp->offset >= dirp->size)
|
||||
+ size_t maxread = dirp->allocation;
|
||||
+ ssize_t bytes;
|
||||
+
|
||||
+ bytes = __old_getdents64 (dirp->fd, dirp->data, maxread);
|
||||
+ if (bytes <= 0)
|
||||
{
|
||||
- /* We've emptied out our buffer. Refill it. */
|
||||
-
|
||||
- size_t maxread = dirp->allocation;
|
||||
- ssize_t bytes;
|
||||
-
|
||||
- bytes = __old_getdents64 (dirp->fd, dirp->data, maxread);
|
||||
- if (bytes <= 0)
|
||||
- {
|
||||
- /* On some systems getdents fails with ENOENT when the
|
||||
- open directory has been rmdir'd already. POSIX.1
|
||||
- requires that we treat this condition like normal EOF. */
|
||||
- if (bytes < 0 && errno == ENOENT)
|
||||
- bytes = 0;
|
||||
-
|
||||
- /* Don't modifiy errno when reaching EOF. */
|
||||
- if (bytes == 0)
|
||||
- __set_errno (saved_errno);
|
||||
- dp = NULL;
|
||||
- break;
|
||||
- }
|
||||
- dirp->size = (size_t) bytes;
|
||||
-
|
||||
- /* Reset the offset into the buffer. */
|
||||
- dirp->offset = 0;
|
||||
+ /* Linux may fail with ENOENT on some file systems if the
|
||||
+ directory inode is marked as dead (deleted). POSIX
|
||||
+ treats this as a regular end-of-directory condition, so
|
||||
+ do not set errno in that case, to indicate success. */
|
||||
+ if (bytes == 0 || errno == ENOENT)
|
||||
+ __set_errno (saved_errno);
|
||||
+#if IS_IN (libc)
|
||||
+ __libc_lock_unlock (dirp->lock);
|
||||
+#endif
|
||||
+ return NULL;
|
||||
}
|
||||
+ dirp->size = (size_t) bytes;
|
||||
|
||||
- dp = (struct __old_dirent64 *) &dirp->data[dirp->offset];
|
||||
-
|
||||
- reclen = dp->d_reclen;
|
||||
-
|
||||
- dirp->offset += reclen;
|
||||
-
|
||||
- dirp->filepos = dp->d_off;
|
||||
+ /* Reset the offset into the buffer. */
|
||||
+ dirp->offset = 0;
|
||||
+ }
|
||||
|
||||
- /* Skip deleted files. */
|
||||
- } while (dp->d_ino == 0);
|
||||
+ dp = (struct __old_dirent64 *) &dirp->data[dirp->offset];
|
||||
+ dirp->offset += dp->d_reclen;
|
||||
+ dirp->filepos = dp->d_off;
|
||||
|
||||
#if IS_IN (libc)
|
||||
__libc_lock_unlock (dirp->lock);
|
104
glibc-RHEL-56542-3.patch
Normal file
104
glibc-RHEL-56542-3.patch
Normal file
@ -0,0 +1,104 @@
|
||||
commit 4e16d89866e660426438238a47c2345bdc47dd97
|
||||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
Date: Thu Aug 10 08:56:00 2023 -0300
|
||||
|
||||
linux: Make fdopendir fail with O_PATH (BZ 30373)
|
||||
|
||||
It is not strictly required by the POSIX, since O_PATH is a Linux
|
||||
extension, but it is QoI to fail early instead of at readdir. Also
|
||||
the check is free, since fdopendir already checks if the file
|
||||
descriptor is opened for read.
|
||||
|
||||
Checked on x86_64-linux-gnu.
|
||||
|
||||
Conflicts:
|
||||
sysdeps/unix/sysv/linux/Makefile (new test added)
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
|
||||
index 617f7718b2a5779d..74656e56038844aa 100644
|
||||
--- a/sysdeps/unix/sysv/linux/Makefile
|
||||
+++ b/sysdeps/unix/sysv/linux/Makefile
|
||||
@@ -125,6 +125,7 @@ tests += tst-clone tst-clone2 tst-clone3 tst-fanotify tst-personality \
|
||||
tst-prctl \
|
||||
tst-scm_rights \
|
||||
tst-getauxval \
|
||||
+ tst-fdopendir-o_path \
|
||||
# tests
|
||||
|
||||
# Test for the symbol version of fcntl that was replaced in glibc 2.28.
|
||||
diff --git a/sysdeps/unix/sysv/linux/fdopendir.c b/sysdeps/unix/sysv/linux/fdopendir.c
|
||||
index 32ec10e206305e3c..d06eeb3cafa4966c 100644
|
||||
--- a/sysdeps/unix/sysv/linux/fdopendir.c
|
||||
+++ b/sysdeps/unix/sysv/linux/fdopendir.c
|
||||
@@ -37,10 +37,16 @@ __fdopendir (int fd)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
- /* Make sure the descriptor allows for reading. */
|
||||
int flags = __fcntl64_nocancel (fd, F_GETFL);
|
||||
if (__glibc_unlikely (flags == -1))
|
||||
return NULL;
|
||||
+ /* Fail early for descriptors opened with O_PATH. */
|
||||
+ if (__glibc_unlikely (flags & O_PATH))
|
||||
+ {
|
||||
+ __set_errno (EBADF);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ /* Make sure the descriptor allows for reading. */
|
||||
if (__glibc_unlikely ((flags & O_ACCMODE) == O_WRONLY))
|
||||
{
|
||||
__set_errno (EINVAL);
|
||||
diff --git a/sysdeps/unix/sysv/linux/tst-fdopendir-o_path.c b/sysdeps/unix/sysv/linux/tst-fdopendir-o_path.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..2531cf8ddb92ff45
|
||||
--- /dev/null
|
||||
+++ b/sysdeps/unix/sysv/linux/tst-fdopendir-o_path.c
|
||||
@@ -0,0 +1,48 @@
|
||||
+/* Check if fdopendir fails with file descriptor opened with O_PATH (BZ 30737)
|
||||
+ Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <errno.h>
|
||||
+#include <fcntl.h>
|
||||
+#include <dirent.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/temp_file.h>
|
||||
+#include <support/xunistd.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ char *dirname = support_create_temp_directory ("tst-fdopendir-o_path");
|
||||
+
|
||||
+ {
|
||||
+ int fd = xopen (dirname, O_RDONLY | O_DIRECTORY, 0600);
|
||||
+ DIR *dir = fdopendir (fd);
|
||||
+ TEST_VERIFY_EXIT (dir != NULL);
|
||||
+ closedir (dir);
|
||||
+ }
|
||||
+
|
||||
+ {
|
||||
+ int fd = xopen (dirname, O_RDONLY | O_PATH | O_DIRECTORY, 0600);
|
||||
+ TEST_VERIFY (fdopendir (fd) == NULL);
|
||||
+ TEST_COMPARE (errno, EBADF);
|
||||
+ xclose (fd);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
80
glibc-RHEL-56542-4.patch
Normal file
80
glibc-RHEL-56542-4.patch
Normal file
@ -0,0 +1,80 @@
|
||||
commit a4a12af5abe22d63fbebf0a219d8d13eff6db20c
|
||||
Author: Carlos O'Donell <carlos@redhat.com>
|
||||
Date: Thu Jun 8 07:30:33 2023 -0400
|
||||
|
||||
dirent: Reformat Makefile.
|
||||
|
||||
Reflow and sort Makefile.
|
||||
|
||||
Code generation changes present due to link order changes.
|
||||
|
||||
No regressions on x86_64 and i686.
|
||||
|
||||
Conflicts:
|
||||
dirent/Makefile (resorting)
|
||||
|
||||
diff --git a/dirent/Makefile b/dirent/Makefile
|
||||
index 5bad3c112209a2ce..450bcd5d8981f40b 100644
|
||||
--- a/dirent/Makefile
|
||||
+++ b/dirent/Makefile
|
||||
@@ -22,17 +22,49 @@ subdir := dirent
|
||||
|
||||
include ../Makeconfig
|
||||
|
||||
-headers := dirent.h bits/dirent.h bits/dirent_ext.h
|
||||
-routines := opendir closedir readdir readdir_r rewinddir \
|
||||
- seekdir telldir scandir alphasort versionsort \
|
||||
- getdents getdents64 dirfd readdir64 readdir64_r scandir64 \
|
||||
- alphasort64 versionsort64 fdopendir \
|
||||
- scandirat scandirat64 \
|
||||
- scandir-cancel scandir-tail scandir64-tail
|
||||
-
|
||||
-tests := list tst-seekdir opendir-tst1 bug-readdir1 tst-fdopendir \
|
||||
- tst-fdopendir2 tst-scandir tst-scandir64 \
|
||||
- tst-rewinddir \
|
||||
+headers := \
|
||||
+ bits/dirent.h \
|
||||
+ bits/dirent_ext.h \
|
||||
+ dirent.h \
|
||||
+ # headers
|
||||
+routines := \
|
||||
+ alphasort \
|
||||
+ alphasort64 \
|
||||
+ closedir \
|
||||
+ dirfd \
|
||||
+ fdopendir \
|
||||
+ getdents \
|
||||
+ getdents64 \
|
||||
+ opendir \
|
||||
+ readdir \
|
||||
+ readdir64 \
|
||||
+ readdir64_r \
|
||||
+ readdir_r \
|
||||
+ rewinddir \
|
||||
+ scandir \
|
||||
+ scandir-cancel \
|
||||
+ scandir-tail \
|
||||
+ scandir64 \
|
||||
+ scandir64-tail \
|
||||
+ scandirat \
|
||||
+ scandirat64 \
|
||||
+ seekdir \
|
||||
+ telldir \
|
||||
+ versionsort \
|
||||
+ versionsort64 \
|
||||
+ # routines
|
||||
+
|
||||
+tests := \
|
||||
+ bug-readdir1 \
|
||||
+ list \
|
||||
+ opendir-tst1 \
|
||||
+ tst-fdopendir \
|
||||
+ tst-fdopendir2 \
|
||||
+ tst-rewinddir \
|
||||
+ tst-scandir \
|
||||
+ tst-scandir64 \
|
||||
+ tst-seekdir \
|
||||
+ # tests
|
||||
|
||||
CFLAGS-scandir.c += $(uses-callbacks)
|
||||
CFLAGS-scandir64.c += $(uses-callbacks)
|
48
glibc-RHEL-56542-5.patch
Normal file
48
glibc-RHEL-56542-5.patch
Normal file
@ -0,0 +1,48 @@
|
||||
commit 61f2c2e1d1287a791c22d86c943b44bcf66bb8ad
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Aug 30 21:52:23 2024 +0200
|
||||
|
||||
Linux: readdir_r needs to report getdents failures (bug 32124)
|
||||
|
||||
Upon error, return the errno value set by the __getdents call
|
||||
in __readdir_unlocked. Previously, kernel-reported errors
|
||||
were ignored.
|
||||
|
||||
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/readdir_r.c b/sysdeps/unix/sysv/linux/readdir_r.c
|
||||
index 4792d730eb2c1fa1..2a2491e5e3786746 100644
|
||||
--- a/sysdeps/unix/sysv/linux/readdir_r.c
|
||||
+++ b/sysdeps/unix/sysv/linux/readdir_r.c
|
||||
@@ -25,14 +25,22 @@ __readdir_r (DIR *dirp, struct dirent *entry, struct dirent **result)
|
||||
{
|
||||
struct dirent *dp;
|
||||
size_t reclen;
|
||||
+ int saved_errno = errno;
|
||||
|
||||
__libc_lock_lock (dirp->lock);
|
||||
|
||||
while (1)
|
||||
{
|
||||
+ /* If errno is changed from 0, the NULL return value indicates
|
||||
+ an actual error. It overrides a pending ENAMETOOLONG error. */
|
||||
+ __set_errno (0);
|
||||
dp = __readdir_unlocked (dirp);
|
||||
if (dp == NULL)
|
||||
- break;
|
||||
+ {
|
||||
+ if (errno != 0)
|
||||
+ dirp->errcode = errno;
|
||||
+ break;
|
||||
+ }
|
||||
|
||||
reclen = dp->d_reclen;
|
||||
if (reclen <= offsetof (struct dirent, d_name) + NAME_MAX + 1)
|
||||
@@ -61,6 +69,7 @@ __readdir_r (DIR *dirp, struct dirent *entry, struct dirent **result)
|
||||
|
||||
__libc_lock_unlock (dirp->lock);
|
||||
|
||||
+ __set_errno (saved_errno);
|
||||
return dp != NULL ? 0 : dirp->errcode;
|
||||
}
|
||||
|
136
glibc-RHEL-56542-6.patch
Normal file
136
glibc-RHEL-56542-6.patch
Normal file
@ -0,0 +1,136 @@
|
||||
commit 4c09aa31b1aeea1329674109eb02d4ba506b0ad2
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Sat Sep 21 19:32:34 2024 +0200
|
||||
|
||||
dirent: Add tst-closedir-leaks
|
||||
|
||||
It verfies that closedir deallocates memory and closes
|
||||
file descriptors.
|
||||
|
||||
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||
|
||||
diff --git a/dirent/Makefile b/dirent/Makefile
|
||||
index 450bcd5d8981f40b..a0404b82b81ed9e8 100644
|
||||
--- a/dirent/Makefile
|
||||
+++ b/dirent/Makefile
|
||||
@@ -58,6 +58,7 @@ tests := \
|
||||
bug-readdir1 \
|
||||
list \
|
||||
opendir-tst1 \
|
||||
+ tst-closedir-leaks \
|
||||
tst-fdopendir \
|
||||
tst-fdopendir2 \
|
||||
tst-rewinddir \
|
||||
@@ -66,6 +67,18 @@ tests := \
|
||||
tst-seekdir \
|
||||
# tests
|
||||
|
||||
+ifeq ($(run-built-tests),yes)
|
||||
+ifneq ($(PERL),no)
|
||||
+generated += \
|
||||
+ $(objpfx)tst-closedir-leaks-mem.out \
|
||||
+ # generated
|
||||
+
|
||||
+tests-special += \
|
||||
+ $(objpfx)tst-closedir-leaks-mem.out \
|
||||
+ # tests-special
|
||||
+endif # $(PERL) ! no
|
||||
+endif # $(run-built-tests) == yes
|
||||
+
|
||||
CFLAGS-scandir.c += $(uses-callbacks)
|
||||
CFLAGS-scandir64.c += $(uses-callbacks)
|
||||
CFLAGS-scandir-tail.c += $(uses-callbacks)
|
||||
@@ -74,3 +87,10 @@ CFLAGS-scandir64-tail.c += $(uses-callbacks)
|
||||
include ../Rules
|
||||
|
||||
opendir-tst1-ARGS = --test-dir=${common-objpfx}dirent
|
||||
+
|
||||
+tst-closedir-leaks-ENV += MALLOC_TRACE=$(objpfx)tst-closedir-leaks.mtrace \
|
||||
+ LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
|
||||
+
|
||||
+$(objpfx)tst-closedir-leaks-mem.out: $(objpfx)tst-closedir-leaks.out
|
||||
+ $(common-objpfx)malloc/mtrace $(objpfx)tst-closedir-leaks.mtrace > $@; \
|
||||
+ $(evaluate-test)
|
||||
diff --git a/dirent/tst-closedir-leaks.c b/dirent/tst-closedir-leaks.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..d9de119b637ea623
|
||||
--- /dev/null
|
||||
+++ b/dirent/tst-closedir-leaks.c
|
||||
@@ -0,0 +1,77 @@
|
||||
+/* Test for resource leaks in closedir.
|
||||
+ 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 <fcntl.h>
|
||||
+#include <limits.h>
|
||||
+#include <mcheck.h>
|
||||
+#include <stdbool.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/descriptors.h>
|
||||
+#include <support/readdir.h>
|
||||
+#include <support/xdirent.h>
|
||||
+#include <support/xunistd.h>
|
||||
+
|
||||
+static void
|
||||
+one_test (enum support_readdir_op op, unsigned int read_limit,
|
||||
+ bool use_fdopendir)
|
||||
+{
|
||||
+ struct support_descriptors *fds = support_descriptors_list ();
|
||||
+ struct support_dirent e = { 0, };
|
||||
+
|
||||
+ DIR *stream;
|
||||
+ if (use_fdopendir)
|
||||
+ {
|
||||
+ int fd = xopen (".", O_RDONLY | O_DIRECTORY, 0);
|
||||
+ stream = xfdopendir (fd);
|
||||
+ /* The descriptor fd will be closed by closedir below. */
|
||||
+ }
|
||||
+ else
|
||||
+ stream = xopendir (".");
|
||||
+ for (unsigned int i = 0; i < read_limit; ++i)
|
||||
+ if (!support_readdir (stream, op, &e))
|
||||
+ break;
|
||||
+ TEST_COMPARE (closedir (stream), 0);
|
||||
+
|
||||
+ free (e.d_name);
|
||||
+ support_descriptors_check (fds);
|
||||
+ support_descriptors_free (fds);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ mtrace ();
|
||||
+
|
||||
+ for (int use_fdopendir = 0; use_fdopendir < 2; ++use_fdopendir)
|
||||
+ {
|
||||
+ /* No reads, operation does not matter. */
|
||||
+ one_test (SUPPORT_READDIR, 0, use_fdopendir);
|
||||
+
|
||||
+ for (enum support_readdir_op op = 0; op <= support_readdir_op_last();
|
||||
+ ++op)
|
||||
+ {
|
||||
+ one_test (op, 1, use_fdopendir);
|
||||
+ one_test (op, UINT_MAX, use_fdopendir); /* Unlimited reads. */
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
389
glibc-RHEL-56542-7.patch
Normal file
389
glibc-RHEL-56542-7.patch
Normal file
@ -0,0 +1,389 @@
|
||||
commit e92718552e1d17b8eccbffb88bf5bbb2235c4596
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Sat Sep 21 19:32:34 2024 +0200
|
||||
|
||||
Linux: Use readdir64_r for compat __old_readdir64_r (bug 32128)
|
||||
|
||||
It is not necessary to do the conversion at the getdents64
|
||||
layer for readdir64_r. Doing it piecewise for readdir64
|
||||
is slightly simpler and allows deleting __old_getdents64.
|
||||
|
||||
This fixes bug 32128 because readdir64_r handles the length
|
||||
check correctly.
|
||||
|
||||
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/getdents64.c b/sysdeps/unix/sysv/linux/getdents64.c
|
||||
index 6323e003b30ae0e6..6f8e9147fbfb79bc 100644
|
||||
--- a/sysdeps/unix/sysv/linux/getdents64.c
|
||||
+++ b/sysdeps/unix/sysv/linux/getdents64.c
|
||||
@@ -33,100 +33,3 @@ __getdents64 (int fd, void *buf, size_t nbytes)
|
||||
}
|
||||
libc_hidden_def (__getdents64)
|
||||
weak_alias (__getdents64, getdents64)
|
||||
-
|
||||
-#if _DIRENT_MATCHES_DIRENT64
|
||||
-strong_alias (__getdents64, __getdents)
|
||||
-#else
|
||||
-# include <shlib-compat.h>
|
||||
-
|
||||
-# if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2)
|
||||
-# include <olddirent.h>
|
||||
-# include <unistd.h>
|
||||
-
|
||||
-static ssize_t
|
||||
-handle_overflow (int fd, __off64_t offset, ssize_t count)
|
||||
-{
|
||||
- /* If this is the first entry in the buffer, we can report the
|
||||
- error. */
|
||||
- if (offset == 0)
|
||||
- {
|
||||
- __set_errno (EOVERFLOW);
|
||||
- return -1;
|
||||
- }
|
||||
-
|
||||
- /* Otherwise, seek to the overflowing entry, so that the next call
|
||||
- will report the error, and return the data read so far. */
|
||||
- if (__lseek64 (fd, offset, SEEK_SET) != 0)
|
||||
- return -1;
|
||||
- return count;
|
||||
-}
|
||||
-
|
||||
-ssize_t
|
||||
-__old_getdents64 (int fd, char *buf, size_t nbytes)
|
||||
-{
|
||||
- /* We do not move the individual directory entries. This is only
|
||||
- possible if the target type (struct __old_dirent64) is smaller
|
||||
- than the source type. */
|
||||
- _Static_assert (offsetof (struct __old_dirent64, d_name)
|
||||
- <= offsetof (struct dirent64, d_name),
|
||||
- "__old_dirent64 is larger than dirent64");
|
||||
- _Static_assert (__alignof__ (struct __old_dirent64)
|
||||
- <= __alignof__ (struct dirent64),
|
||||
- "alignment of __old_dirent64 is larger than dirent64");
|
||||
-
|
||||
- ssize_t retval = INLINE_SYSCALL_CALL (getdents64, fd, buf, nbytes);
|
||||
- if (retval > 0)
|
||||
- {
|
||||
- /* This is the marker for the first entry. Offset 0 is reserved
|
||||
- for the first entry (see rewinddir). Here, we use it as a
|
||||
- marker for the first entry in the buffer. We never actually
|
||||
- seek to offset 0 because handle_overflow reports the error
|
||||
- directly, so it does not matter that the offset is incorrect
|
||||
- if entries have been read from the descriptor before (so that
|
||||
- the descriptor is not actually at offset 0). */
|
||||
- __off64_t previous_offset = 0;
|
||||
-
|
||||
- char *p = buf;
|
||||
- char *end = buf + retval;
|
||||
- while (p < end)
|
||||
- {
|
||||
- struct dirent64 *source = (struct dirent64 *) p;
|
||||
-
|
||||
- /* Copy out the fixed-size data. */
|
||||
- __ino_t ino = source->d_ino;
|
||||
- __off64_t offset = source->d_off;
|
||||
- unsigned int reclen = source->d_reclen;
|
||||
- unsigned char type = source->d_type;
|
||||
-
|
||||
- /* Check for ino_t overflow. */
|
||||
- if (__glibc_unlikely (ino != source->d_ino))
|
||||
- return handle_overflow (fd, previous_offset, p - buf);
|
||||
-
|
||||
- /* Convert to the target layout. Use a separate struct and
|
||||
- memcpy to side-step aliasing issues. */
|
||||
- struct __old_dirent64 result;
|
||||
- result.d_ino = ino;
|
||||
- result.d_off = offset;
|
||||
- result.d_reclen = reclen;
|
||||
- result.d_type = type;
|
||||
-
|
||||
- /* Write the fixed-sized part of the result to the
|
||||
- buffer. */
|
||||
- size_t result_name_offset = offsetof (struct __old_dirent64, d_name);
|
||||
- memcpy (p, &result, result_name_offset);
|
||||
-
|
||||
- /* Adjust the position of the name if necessary. Copy
|
||||
- everything until the end of the record, including the
|
||||
- terminating NUL byte. */
|
||||
- if (result_name_offset != offsetof (struct dirent64, d_name))
|
||||
- memmove (p + result_name_offset, source->d_name,
|
||||
- reclen - offsetof (struct dirent64, d_name));
|
||||
-
|
||||
- p += reclen;
|
||||
- previous_offset = offset;
|
||||
- }
|
||||
- }
|
||||
- return retval;
|
||||
-}
|
||||
-# endif /* SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) */
|
||||
-#endif /* _DIRENT_MATCHES_DIRENT64 */
|
||||
diff --git a/sysdeps/unix/sysv/linux/olddirent.h b/sysdeps/unix/sysv/linux/olddirent.h
|
||||
index 3e672d47f5a5e421..d1a486e855e744c3 100644
|
||||
--- a/sysdeps/unix/sysv/linux/olddirent.h
|
||||
+++ b/sysdeps/unix/sysv/linux/olddirent.h
|
||||
@@ -34,8 +34,6 @@ extern struct __old_dirent64 *__old_readdir64 (DIR *__dirp);
|
||||
libc_hidden_proto (__old_readdir64);
|
||||
extern int __old_readdir64_r (DIR *__dirp, struct __old_dirent64 *__entry,
|
||||
struct __old_dirent64 **__result);
|
||||
-extern __ssize_t __old_getdents64 (int __fd, char *__buf, size_t __nbytes)
|
||||
- attribute_hidden;
|
||||
int __old_scandir64 (const char * __dir,
|
||||
struct __old_dirent64 *** __namelist,
|
||||
int (*__selector) (const struct __old_dirent64 *),
|
||||
diff --git a/sysdeps/unix/sysv/linux/readdir64.c b/sysdeps/unix/sysv/linux/readdir64.c
|
||||
index 8a60504649aa54a2..c3450b083b6b64cf 100644
|
||||
--- a/sysdeps/unix/sysv/linux/readdir64.c
|
||||
+++ b/sysdeps/unix/sysv/linux/readdir64.c
|
||||
@@ -26,17 +26,13 @@
|
||||
#undef __readdir
|
||||
#undef readdir
|
||||
|
||||
-/* Read a directory entry from DIRP. */
|
||||
-struct dirent64 *
|
||||
-__readdir64 (DIR *dirp)
|
||||
+/* Read a directory entry from DIRP. No locking. */
|
||||
+static struct dirent64 *
|
||||
+__readdir64_unlocked (DIR *dirp)
|
||||
{
|
||||
struct dirent64 *dp;
|
||||
int saved_errno = errno;
|
||||
|
||||
-#if IS_IN (libc)
|
||||
- __libc_lock_lock (dirp->lock);
|
||||
-#endif
|
||||
-
|
||||
if (dirp->offset >= dirp->size)
|
||||
{
|
||||
/* We've emptied out our buffer. Refill it. */
|
||||
@@ -53,9 +49,6 @@ __readdir64 (DIR *dirp)
|
||||
do not set errno in that case, to indicate success. */
|
||||
if (bytes == 0 || errno == ENOENT)
|
||||
__set_errno (saved_errno);
|
||||
-#if IS_IN (libc)
|
||||
- __libc_lock_unlock (dirp->lock);
|
||||
-#endif
|
||||
return NULL;
|
||||
}
|
||||
dirp->size = (size_t) bytes;
|
||||
@@ -68,10 +61,16 @@ __readdir64 (DIR *dirp)
|
||||
dirp->offset += dp->d_reclen;
|
||||
dirp->filepos = dp->d_off;
|
||||
|
||||
-#if IS_IN (libc)
|
||||
- __libc_lock_unlock (dirp->lock);
|
||||
-#endif
|
||||
+ return dp;
|
||||
+}
|
||||
|
||||
+/* Read a directory entry from DIRP. */
|
||||
+struct dirent64 *
|
||||
+__readdir64 (DIR *dirp)
|
||||
+{
|
||||
+ __libc_lock_lock (dirp->lock);
|
||||
+ struct dirent64 *dp = __readdir64_unlocked (dirp);
|
||||
+ __libc_lock_unlock (dirp->lock);
|
||||
return dp;
|
||||
}
|
||||
libc_hidden_def (__readdir64)
|
||||
@@ -99,45 +98,54 @@ __old_readdir64 (DIR *dirp)
|
||||
struct __old_dirent64 *dp;
|
||||
int saved_errno = errno;
|
||||
|
||||
-#if IS_IN (libc)
|
||||
__libc_lock_lock (dirp->lock);
|
||||
-#endif
|
||||
|
||||
- if (dirp->offset >= dirp->size)
|
||||
+ while (1)
|
||||
{
|
||||
- /* We've emptied out our buffer. Refill it. */
|
||||
+ errno = 0;
|
||||
+ struct dirent64 *newdp = __readdir64_unlocked (dirp);
|
||||
+ if (newdp == NULL)
|
||||
+ {
|
||||
+ if (errno == 0 && dirp->errcode != 0)
|
||||
+ __set_errno (dirp->errcode);
|
||||
+ else if (errno == 0)
|
||||
+ __set_errno (saved_errno);
|
||||
+ dp = NULL;
|
||||
+ break;
|
||||
+ }
|
||||
|
||||
- size_t maxread = dirp->allocation;
|
||||
- ssize_t bytes;
|
||||
+ /* Convert to the target layout. Use a separate struct and
|
||||
+ memcpy to side-step aliasing issues. */
|
||||
+ struct __old_dirent64 result;
|
||||
+ result.d_ino = newdp->d_ino;
|
||||
+ result.d_off = newdp->d_off;
|
||||
+ result.d_reclen = newdp->d_reclen;
|
||||
+ result.d_type = newdp->d_type;
|
||||
|
||||
- bytes = __old_getdents64 (dirp->fd, dirp->data, maxread);
|
||||
- if (bytes <= 0)
|
||||
+ /* Check for ino_t overflow. */
|
||||
+ if (__glibc_unlikely (result.d_ino != newdp->d_ino))
|
||||
{
|
||||
- /* Linux may fail with ENOENT on some file systems if the
|
||||
- directory inode is marked as dead (deleted). POSIX
|
||||
- treats this as a regular end-of-directory condition, so
|
||||
- do not set errno in that case, to indicate success. */
|
||||
- if (bytes == 0 || errno == ENOENT)
|
||||
- __set_errno (saved_errno);
|
||||
-#if IS_IN (libc)
|
||||
- __libc_lock_unlock (dirp->lock);
|
||||
-#endif
|
||||
- return NULL;
|
||||
+ dirp->errcode = ENAMETOOLONG;
|
||||
+ continue;
|
||||
}
|
||||
- dirp->size = (size_t) bytes;
|
||||
|
||||
- /* Reset the offset into the buffer. */
|
||||
- dirp->offset = 0;
|
||||
- }
|
||||
+ /* Overwrite the fixed-sized part. */
|
||||
+ dp = (struct __old_dirent64 *) newdp;
|
||||
+ memcpy (dp, &result, offsetof (struct __old_dirent64, d_name));
|
||||
|
||||
- dp = (struct __old_dirent64 *) &dirp->data[dirp->offset];
|
||||
- dirp->offset += dp->d_reclen;
|
||||
- dirp->filepos = dp->d_off;
|
||||
+ /* Move the name. */
|
||||
+ _Static_assert (offsetof (struct __old_dirent64, d_name)
|
||||
+ <= offsetof (struct dirent64, d_name),
|
||||
+ "old struct must be smaller");
|
||||
+ if (offsetof (struct __old_dirent64, d_name)
|
||||
+ != offsetof (struct dirent64, d_name))
|
||||
+ memmove (dp->d_name, newdp->d_name, strlen (newdp->d_name) + 1);
|
||||
|
||||
-#if IS_IN (libc)
|
||||
- __libc_lock_unlock (dirp->lock);
|
||||
-#endif
|
||||
+ __set_errno (saved_errno);
|
||||
+ break;
|
||||
+ }
|
||||
|
||||
+ __libc_lock_unlock (dirp->lock);
|
||||
return dp;
|
||||
}
|
||||
libc_hidden_def (__old_readdir64)
|
||||
diff --git a/sysdeps/unix/sysv/linux/readdir64_r.c b/sysdeps/unix/sysv/linux/readdir64_r.c
|
||||
index 073a6453d1bbbd61..0c60987343b1f37f 100644
|
||||
--- a/sysdeps/unix/sysv/linux/readdir64_r.c
|
||||
+++ b/sysdeps/unix/sysv/linux/readdir64_r.c
|
||||
@@ -135,91 +135,37 @@ attribute_compat_text_section
|
||||
__old_readdir64_r (DIR *dirp, struct __old_dirent64 *entry,
|
||||
struct __old_dirent64 **result)
|
||||
{
|
||||
- struct __old_dirent64 *dp;
|
||||
- size_t reclen;
|
||||
- const int saved_errno = errno;
|
||||
- int ret;
|
||||
-
|
||||
- __libc_lock_lock (dirp->lock);
|
||||
-
|
||||
- do
|
||||
+ while (1)
|
||||
{
|
||||
- if (dirp->offset >= dirp->size)
|
||||
- {
|
||||
- /* We've emptied out our buffer. Refill it. */
|
||||
-
|
||||
- size_t maxread = dirp->allocation;
|
||||
- ssize_t bytes;
|
||||
-
|
||||
- maxread = dirp->allocation;
|
||||
-
|
||||
- bytes = __old_getdents64 (dirp->fd, dirp->data, maxread);
|
||||
- if (bytes <= 0)
|
||||
- {
|
||||
- /* On some systems getdents fails with ENOENT when the
|
||||
- open directory has been rmdir'd already. POSIX.1
|
||||
- requires that we treat this condition like normal EOF. */
|
||||
- if (bytes < 0 && errno == ENOENT)
|
||||
- {
|
||||
- bytes = 0;
|
||||
- __set_errno (saved_errno);
|
||||
- }
|
||||
- if (bytes < 0)
|
||||
- dirp->errcode = errno;
|
||||
+ struct dirent64 new_entry;
|
||||
+ struct dirent64 *newp;
|
||||
+ int ret = __readdir64_r (dirp, &new_entry, &newp);
|
||||
|
||||
- dp = NULL;
|
||||
- break;
|
||||
- }
|
||||
- dirp->size = (size_t) bytes;
|
||||
-
|
||||
- /* Reset the offset into the buffer. */
|
||||
- dirp->offset = 0;
|
||||
+ if (ret != 0)
|
||||
+ return ret;
|
||||
+ else if (newp == NULL)
|
||||
+ {
|
||||
+ *result = NULL;
|
||||
+ return 0;
|
||||
}
|
||||
-
|
||||
- dp = (struct __old_dirent64 *) &dirp->data[dirp->offset];
|
||||
-
|
||||
- reclen = dp->d_reclen;
|
||||
-
|
||||
- dirp->offset += reclen;
|
||||
-
|
||||
- dirp->filepos = dp->d_off;
|
||||
-
|
||||
- if (reclen > offsetof (struct __old_dirent64, d_name) + NAME_MAX + 1)
|
||||
+ else
|
||||
{
|
||||
- /* The record is very long. It could still fit into the
|
||||
- caller-supplied buffer if we can skip padding at the
|
||||
- end. */
|
||||
- size_t namelen = _D_EXACT_NAMLEN (dp);
|
||||
- if (namelen <= NAME_MAX)
|
||||
- reclen = offsetof (struct __old_dirent64, d_name) + namelen + 1;
|
||||
- else
|
||||
+ entry->d_ino = newp->d_ino;
|
||||
+ if (entry->d_ino != newp->d_ino)
|
||||
{
|
||||
- /* The name is too long. Ignore this file. */
|
||||
- dirp->errcode = ENAMETOOLONG;
|
||||
- dp->d_ino = 0;
|
||||
+ dirp->errcode = EOVERFLOW;
|
||||
continue;
|
||||
}
|
||||
+ size_t namelen = strlen (newp->d_name);
|
||||
+ entry->d_off = newp->d_off;
|
||||
+ entry->d_reclen = (offsetof (struct __old_dirent64, d_name)
|
||||
+ + namelen + 1);
|
||||
+ entry->d_type = newp->d_type;
|
||||
+ memcpy (entry->d_name, newp->d_name, namelen + 1);
|
||||
+ *result = entry;
|
||||
+ return 0;
|
||||
}
|
||||
-
|
||||
- /* Skip deleted and ignored files. */
|
||||
- }
|
||||
- while (dp->d_ino == 0);
|
||||
-
|
||||
- if (dp != NULL)
|
||||
- {
|
||||
- *result = memcpy (entry, dp, reclen);
|
||||
- entry->d_reclen = reclen;
|
||||
- ret = 0;
|
||||
}
|
||||
- else
|
||||
- {
|
||||
- *result = NULL;
|
||||
- ret = dirp->errcode;
|
||||
- }
|
||||
-
|
||||
- __libc_lock_unlock (dirp->lock);
|
||||
-
|
||||
- return ret;
|
||||
}
|
||||
|
||||
compat_symbol (libc, __old_readdir64_r, readdir64_r, GLIBC_2_1);
|
264
glibc-RHEL-56542-8.patch
Normal file
264
glibc-RHEL-56542-8.patch
Normal file
@ -0,0 +1,264 @@
|
||||
commit 4ec355af454695556db1212d1c9ca9c3789cddf4
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Sat Sep 21 19:32:34 2024 +0200
|
||||
|
||||
dirent: Add tst-readdir-long
|
||||
|
||||
It tests long names and ENAMETOOLONG handling, specifically
|
||||
for readdir_r. This is a regression test for bug 14699,
|
||||
bug 32124, and bug 32128.
|
||||
|
||||
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||
|
||||
Conflicts:
|
||||
dirent/Makefile (fixup context)
|
||||
|
||||
diff --git a/dirent/Makefile b/dirent/Makefile
|
||||
index a0404b82b81ed9e8..d12be2f0384b184f 100644
|
||||
--- a/dirent/Makefile
|
||||
+++ b/dirent/Makefile
|
||||
@@ -61,6 +61,7 @@ tests := \
|
||||
tst-closedir-leaks \
|
||||
tst-fdopendir \
|
||||
tst-fdopendir2 \
|
||||
+ tst-readdir-long \
|
||||
tst-rewinddir \
|
||||
tst-scandir \
|
||||
tst-scandir64 \
|
||||
diff --git a/dirent/tst-readdir-long.c b/dirent/tst-readdir-long.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..409318fa52fc664f
|
||||
--- /dev/null
|
||||
+++ b/dirent/tst-readdir-long.c
|
||||
@@ -0,0 +1,231 @@
|
||||
+/* Test readdir (+variants) behavior with file names of varying length.
|
||||
+ 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 <dirent.h>
|
||||
+#include <errno.h>
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/fuse.h>
|
||||
+#include <support/support.h>
|
||||
+#include <support/xdirent.h>
|
||||
+#include <support/readdir.h>
|
||||
+
|
||||
+/* If positive, at this length an EMSGSIZE error is injected. */
|
||||
+static _Atomic int inject_error_at_length;
|
||||
+
|
||||
+/* Return a file name, LENGTH bytes long. */
|
||||
+static char *
|
||||
+name_of_length (size_t length)
|
||||
+{
|
||||
+ char *result = xmalloc (length + 1);
|
||||
+ unsigned int prefix = snprintf (result, length + 1, "%zu-", length);
|
||||
+ for (size_t i = prefix; i < length; ++i)
|
||||
+ result[i] = 'A' + ((length + i) % 26);
|
||||
+ result[length] = '\0';
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+/* Add the directory entry at OFFSET to the stream D. */
|
||||
+static uint64_t
|
||||
+add_directory_entry (struct support_fuse_dirstream *d, uint64_t offset)
|
||||
+{
|
||||
+ unsigned int length = offset + 1;
|
||||
+ if (length > 1000)
|
||||
+ /* Longer than what is possible to produce with 256
|
||||
+ UTF-8-encoded Unicode code points. */
|
||||
+ return 0;
|
||||
+
|
||||
+ char *to_free = NULL;
|
||||
+ const char *name;
|
||||
+ uint64_t ino = 1000 + length; /* Arbitrary value, distinct from 1. */
|
||||
+ uint32_t type = DT_REG;
|
||||
+ if (offset <= 1)
|
||||
+ {
|
||||
+ type = DT_DIR;
|
||||
+ name = ".." + !offset; /* "." or "..". */
|
||||
+ ino = 1;
|
||||
+ }
|
||||
+ else if (length == 1000)
|
||||
+ name = "short";
|
||||
+ else
|
||||
+ {
|
||||
+ to_free = name_of_length (length);
|
||||
+ name = to_free;
|
||||
+ }
|
||||
+
|
||||
+ ++offset;
|
||||
+ bool added = support_fuse_dirstream_add (d, ino, offset, type, name);
|
||||
+ free (to_free);
|
||||
+ if (added)
|
||||
+ return offset;
|
||||
+ else
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Set to true if getdents64 should produce only one entry. */
|
||||
+static _Atomic bool one_entry_per_getdents64;
|
||||
+
|
||||
+static void
|
||||
+fuse_thread (struct support_fuse *f, void *closure)
|
||||
+{
|
||||
+ struct fuse_in_header *inh;
|
||||
+ while ((inh = support_fuse_next (f)) != NULL)
|
||||
+ {
|
||||
+ if (support_fuse_handle_mountpoint (f)
|
||||
+ || (inh->nodeid == 1 && support_fuse_handle_directory (f)))
|
||||
+ continue;
|
||||
+ switch (inh->opcode)
|
||||
+ {
|
||||
+ case FUSE_READDIR:
|
||||
+ if (inh->nodeid == 1)
|
||||
+ {
|
||||
+ uint64_t offset = support_fuse_cast (READ, inh)->offset;
|
||||
+ if (inject_error_at_length == offset + 1)
|
||||
+ support_fuse_reply_error (f, EMSGSIZE);
|
||||
+ else
|
||||
+ {
|
||||
+ struct support_fuse_dirstream *d
|
||||
+ = support_fuse_prepare_readdir (f);
|
||||
+ while (true)
|
||||
+ {
|
||||
+ offset = add_directory_entry (d, offset);
|
||||
+ if (offset == 0 || one_entry_per_getdents64
|
||||
+ /* Error will be reported at next READDIR. */
|
||||
+ || offset + 1 == inject_error_at_length)
|
||||
+ break;
|
||||
+ }
|
||||
+ support_fuse_reply_prepared (f);
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ support_fuse_reply_error (f, EIO);
|
||||
+ break;
|
||||
+ default:
|
||||
+ FAIL ("unexpected event %s", support_fuse_opcode (inh->opcode));
|
||||
+ support_fuse_reply_error (f, EIO);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* Run the tests for the specified readdir variant OP. */
|
||||
+static void
|
||||
+run_readdir_tests (struct support_fuse *f, enum support_readdir_op op)
|
||||
+{
|
||||
+ printf ("info: testing %s (inject_error=%d unbuffered=%d)\n",
|
||||
+ support_readdir_function (op), inject_error_at_length,
|
||||
+ (int) one_entry_per_getdents64);
|
||||
+
|
||||
+ bool testing_r = support_readdir_r_variant (op);
|
||||
+
|
||||
+ DIR *dir = xopendir (support_fuse_mountpoint (f));
|
||||
+ struct support_dirent e = { 0, };
|
||||
+ TEST_VERIFY (support_readdir (dir, op, &e));
|
||||
+ TEST_COMPARE (e.d_ino, 1);
|
||||
+ TEST_COMPARE_STRING (e.d_name, ".");
|
||||
+
|
||||
+ TEST_VERIFY (support_readdir (dir, op, &e));
|
||||
+ TEST_COMPARE (e.d_ino, 1);
|
||||
+ TEST_COMPARE_STRING (e.d_name, "..");
|
||||
+
|
||||
+ for (unsigned int i = 3; i < 1000; ++i)
|
||||
+ {
|
||||
+ if (i == inject_error_at_length)
|
||||
+ /* Error expected below. */
|
||||
+ break;
|
||||
+
|
||||
+ if (i >= sizeof ((struct dirent) { 0, }.d_name) && testing_r)
|
||||
+ /* This is a readir_r test. The longer names are not
|
||||
+ available because they do not fit into struct dirent. */
|
||||
+ break;
|
||||
+
|
||||
+ char *expected_name = name_of_length (i);
|
||||
+ TEST_COMPARE (strlen (expected_name), i);
|
||||
+ TEST_VERIFY (support_readdir (dir, op, &e));
|
||||
+ TEST_COMPARE (e.d_ino, 1000 + i);
|
||||
+ TEST_COMPARE_STRING (e.d_name, expected_name);
|
||||
+ free (expected_name);
|
||||
+ }
|
||||
+
|
||||
+ if (inject_error_at_length == 0)
|
||||
+ {
|
||||
+ /* Check that the ENAMETOOLONG error does not prevent reading a
|
||||
+ later short name. */
|
||||
+ TEST_VERIFY (support_readdir (dir, op, &e));
|
||||
+ TEST_COMPARE (e.d_ino, 2000);
|
||||
+ TEST_COMPARE_STRING (e.d_name, "short");
|
||||
+
|
||||
+ if (testing_r)
|
||||
+ /* An earlier name was too long. */
|
||||
+ support_readdir_expect_error (dir, op, ENAMETOOLONG);
|
||||
+ else
|
||||
+ /* Entire directory read without error. */
|
||||
+ TEST_VERIFY (!support_readdir (dir, op, &e));
|
||||
+ }
|
||||
+ else
|
||||
+ support_readdir_expect_error (dir, op, EMSGSIZE);
|
||||
+
|
||||
+ free (e.d_name);
|
||||
+ xclosedir (dir);
|
||||
+}
|
||||
+
|
||||
+/* Run all readdir variants for both fully-buffered an unbuffered
|
||||
+ (one-at-a-time) directory streams. */
|
||||
+static void
|
||||
+run_fully_buffered_and_singleton_buffers (struct support_fuse *f)
|
||||
+{
|
||||
+ for (int do_one_entry = 0; do_one_entry < 2; ++do_one_entry)
|
||||
+ {
|
||||
+ one_entry_per_getdents64 = do_one_entry;
|
||||
+ for (enum support_readdir_op op = 0; op <= support_readdir_op_last();
|
||||
+ ++op)
|
||||
+ run_readdir_tests (f, op);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ /* Smoke test for name_of_length. */
|
||||
+ {
|
||||
+ char *name = name_of_length (5);
|
||||
+ TEST_COMPARE_STRING (name, "5-HIJ");
|
||||
+ free (name);
|
||||
+
|
||||
+ name = name_of_length (6);
|
||||
+ TEST_COMPARE_STRING (name, "6-IJKL");
|
||||
+ free (name);
|
||||
+ }
|
||||
+
|
||||
+ support_fuse_init ();
|
||||
+ struct support_fuse *f = support_fuse_mount (fuse_thread, NULL);
|
||||
+
|
||||
+ run_fully_buffered_and_singleton_buffers (f);
|
||||
+
|
||||
+ inject_error_at_length = 100;
|
||||
+ run_fully_buffered_and_singleton_buffers (f);
|
||||
+
|
||||
+ inject_error_at_length = 300;
|
||||
+ run_fully_buffered_and_singleton_buffers (f);
|
||||
+
|
||||
+ support_fuse_unmount (f);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
214
glibc-RHEL-56542-9.patch
Normal file
214
glibc-RHEL-56542-9.patch
Normal file
@ -0,0 +1,214 @@
|
||||
commit 6f3f6c506cdaf981a4374f1f12863b98ac7fea1a
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Sat Sep 21 19:32:34 2024 +0200
|
||||
|
||||
Linux: readdir64_r should not skip d_ino == 0 entries (bug 32126)
|
||||
|
||||
This is the same bug as bug 12165, but for readdir_r. The
|
||||
regression test covers both bug 12165 and bug 32126.
|
||||
|
||||
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||
|
||||
diff --git a/dirent/Makefile b/dirent/Makefile
|
||||
index d12be2f0384b184f..4cecd169b42c540b 100644
|
||||
--- a/dirent/Makefile
|
||||
+++ b/dirent/Makefile
|
||||
@@ -62,6 +62,7 @@ tests := \
|
||||
tst-fdopendir \
|
||||
tst-fdopendir2 \
|
||||
tst-readdir-long \
|
||||
+ tst-readdir-zero-inode \
|
||||
tst-rewinddir \
|
||||
tst-scandir \
|
||||
tst-scandir64 \
|
||||
diff --git a/dirent/tst-readdir-zero-inode.c b/dirent/tst-readdir-zero-inode.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..af9fb946abe6c483
|
||||
--- /dev/null
|
||||
+++ b/dirent/tst-readdir-zero-inode.c
|
||||
@@ -0,0 +1,134 @@
|
||||
+/* Test that readdir does not skip entries with d_ino == 0 (bug 12165).
|
||||
+ 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 <stdlib.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/fuse.h>
|
||||
+#include <support/readdir.h>
|
||||
+#include <support/xdirent.h>
|
||||
+
|
||||
+/* Add the directory entry at OFFSET to the stream D. */
|
||||
+static uint64_t
|
||||
+add_directory_entry (struct support_fuse_dirstream *d, uint64_t offset)
|
||||
+{
|
||||
+ bool added = false;
|
||||
+ ++offset;
|
||||
+ switch (offset - 1)
|
||||
+ {
|
||||
+ case 0:
|
||||
+ added = support_fuse_dirstream_add (d, 1, offset, DT_DIR, ".");
|
||||
+ break;
|
||||
+ case 1:
|
||||
+ added = support_fuse_dirstream_add (d, 1, offset, DT_DIR, "..");
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ added = support_fuse_dirstream_add (d, 2, offset, DT_REG, "before");
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ added = support_fuse_dirstream_add (d, 0, offset, DT_REG, "zero");
|
||||
+ break;
|
||||
+ case 4:
|
||||
+ added = support_fuse_dirstream_add (d, 3, offset, DT_REG, "after");
|
||||
+ break;
|
||||
+ }
|
||||
+ if (added)
|
||||
+ return offset;
|
||||
+ else
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Set to true if getdents64 should produce only one entry. */
|
||||
+static bool one_entry_per_getdents64;
|
||||
+
|
||||
+static void
|
||||
+fuse_thread (struct support_fuse *f, void *closure)
|
||||
+{
|
||||
+ struct fuse_in_header *inh;
|
||||
+ while ((inh = support_fuse_next (f)) != NULL)
|
||||
+ {
|
||||
+ if (support_fuse_handle_mountpoint (f)
|
||||
+ || (inh->nodeid == 1 && support_fuse_handle_directory (f)))
|
||||
+ continue;
|
||||
+ switch (inh->opcode)
|
||||
+ {
|
||||
+ case FUSE_READDIR:
|
||||
+ if (inh->nodeid == 1)
|
||||
+ {
|
||||
+ uint64_t offset = support_fuse_cast (READ, inh)->offset;
|
||||
+ struct support_fuse_dirstream *d
|
||||
+ = support_fuse_prepare_readdir (f);
|
||||
+ while (true)
|
||||
+ {
|
||||
+ offset = add_directory_entry (d, offset);
|
||||
+ if (offset == 0 || one_entry_per_getdents64)
|
||||
+ break;
|
||||
+ }
|
||||
+ support_fuse_reply_prepared (f);
|
||||
+ }
|
||||
+ else
|
||||
+ support_fuse_reply_error (f, EIO);
|
||||
+ break;
|
||||
+ default:
|
||||
+ FAIL ("unexpected event %s", support_fuse_opcode (inh->opcode));
|
||||
+ support_fuse_reply_error (f, EIO);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ support_fuse_init ();
|
||||
+
|
||||
+ for (enum support_readdir_op op = 0; op <= support_readdir_op_last (); ++op)
|
||||
+ {
|
||||
+ struct support_fuse *f = support_fuse_mount (fuse_thread, NULL);
|
||||
+ DIR *dir = xopendir (support_fuse_mountpoint (f));
|
||||
+ struct support_dirent e = { 0, };
|
||||
+
|
||||
+ TEST_VERIFY (support_readdir (dir, op, &e));
|
||||
+ TEST_COMPARE_STRING (e.d_name, ".");
|
||||
+ TEST_COMPARE (e.d_ino, 1);
|
||||
+
|
||||
+ TEST_VERIFY (support_readdir (dir, op, &e));
|
||||
+ TEST_COMPARE_STRING (e.d_name, "..");
|
||||
+ TEST_COMPARE (e.d_ino, 1);
|
||||
+
|
||||
+ TEST_VERIFY (support_readdir (dir, op, &e));
|
||||
+ TEST_COMPARE_STRING (e.d_name, "before");
|
||||
+ TEST_COMPARE (e.d_ino, 2);
|
||||
+
|
||||
+ TEST_VERIFY (support_readdir (dir, op, &e));
|
||||
+ TEST_COMPARE_STRING (e.d_name, "zero");
|
||||
+ TEST_COMPARE (e.d_ino, 0);
|
||||
+
|
||||
+ TEST_VERIFY (support_readdir (dir, op, &e));
|
||||
+ TEST_COMPARE_STRING (e.d_name, "after");
|
||||
+ TEST_COMPARE (e.d_ino, 3);
|
||||
+
|
||||
+ TEST_VERIFY (!support_readdir (dir, op, &e));
|
||||
+
|
||||
+ free (e.d_name);
|
||||
+ xclosedir (dir);
|
||||
+ support_fuse_unmount (f);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/sysdeps/unix/sysv/linux/readdir64_r.c b/sysdeps/unix/sysv/linux/readdir64_r.c
|
||||
index 0c60987343b1f37f..2e188364ff5aa143 100644
|
||||
--- a/sysdeps/unix/sysv/linux/readdir64_r.c
|
||||
+++ b/sysdeps/unix/sysv/linux/readdir64_r.c
|
||||
@@ -37,7 +37,7 @@ __readdir64_r (DIR *dirp, struct dirent64 *entry, struct dirent64 **result)
|
||||
|
||||
__libc_lock_lock (dirp->lock);
|
||||
|
||||
- do
|
||||
+ while (1)
|
||||
{
|
||||
if (dirp->offset >= dirp->size)
|
||||
{
|
||||
@@ -79,26 +79,21 @@ __readdir64_r (DIR *dirp, struct dirent64 *entry, struct dirent64 **result)
|
||||
|
||||
dirp->filepos = dp->d_off;
|
||||
|
||||
- if (reclen > offsetof (struct dirent64, d_name) + NAME_MAX + 1)
|
||||
+ if (reclen <= offsetof (struct dirent64, d_name) + NAME_MAX + 1)
|
||||
+ break;
|
||||
+
|
||||
+ /* The record is very long. It could still fit into the
|
||||
+ caller-supplied buffer if we can skip padding at the end. */
|
||||
+ size_t namelen = _D_EXACT_NAMLEN (dp);
|
||||
+ if (namelen <= NAME_MAX)
|
||||
{
|
||||
- /* The record is very long. It could still fit into the
|
||||
- caller-supplied buffer if we can skip padding at the
|
||||
- end. */
|
||||
- size_t namelen = _D_EXACT_NAMLEN (dp);
|
||||
- if (namelen <= NAME_MAX)
|
||||
- reclen = offsetof (struct dirent64, d_name) + namelen + 1;
|
||||
- else
|
||||
- {
|
||||
- /* The name is too long. Ignore this file. */
|
||||
- dirp->errcode = ENAMETOOLONG;
|
||||
- dp->d_ino = 0;
|
||||
- continue;
|
||||
- }
|
||||
+ reclen = offsetof (struct dirent64, d_name) + namelen + 1;
|
||||
+ break;
|
||||
}
|
||||
|
||||
- /* Skip deleted and ignored files. */
|
||||
+ /* The name is too long. Ignore this file. */
|
||||
+ dirp->errcode = ENAMETOOLONG;
|
||||
}
|
||||
- while (dp->d_ino == 0);
|
||||
|
||||
if (dp != NULL)
|
||||
{
|
14
glibc.spec
14
glibc.spec
@ -157,7 +157,7 @@ end \
|
||||
Summary: The GNU libc libraries
|
||||
Name: glibc
|
||||
Version: %{glibcversion}
|
||||
Release: 149%{?dist}
|
||||
Release: 150%{?dist}
|
||||
|
||||
# In general, GPLv2+ is used by programs, LGPLv2+ is used for
|
||||
# libraries.
|
||||
@ -1053,6 +1053,15 @@ Patch745: glibc-RHEL-68850-2.patch
|
||||
Patch746: glibc-RHEL-61568.patch
|
||||
Patch747: glibc-RHEL-58979.patch
|
||||
Patch748: glibc-RHEL-65354.patch
|
||||
Patch749: glibc-RHEL-56542-1.patch
|
||||
Patch750: glibc-RHEL-56542-2.patch
|
||||
Patch751: glibc-RHEL-56542-3.patch
|
||||
Patch752: glibc-RHEL-56542-4.patch
|
||||
Patch753: glibc-RHEL-56542-5.patch
|
||||
Patch754: glibc-RHEL-56542-6.patch
|
||||
Patch755: glibc-RHEL-56542-7.patch
|
||||
Patch756: glibc-RHEL-56542-8.patch
|
||||
Patch757: glibc-RHEL-56542-9.patch
|
||||
|
||||
##############################################################################
|
||||
# Continued list of core "glibc" package information:
|
||||
@ -3046,6 +3055,9 @@ update_gconv_modules_cache ()
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Fri Jan 10 2025 Frédéric Bérat <fberat@redhat.com> - 2.34-150
|
||||
- Backport test implementation to verify readdir behavior (RHEL-56542)
|
||||
|
||||
* Wed Jan 08 2025 Frédéric Bérat <fberat@redhat.com> - 2.34-149
|
||||
- Backport: fix the glibc manual to handle spaces for @deftypefun
|
||||
references. (RHEL-65356)
|
||||
|
Loading…
Reference in New Issue
Block a user