117 lines
4.4 KiB
Diff
117 lines
4.4 KiB
Diff
From 5f1ae50a78d3f66b195668f1b863832d85d27f2f Mon Sep 17 00:00:00 2001
|
|
From: Florian Weimer <fweimer@redhat.com>
|
|
Date: Mon, 10 Dec 2018 16:50:37 +0100
|
|
Subject: [PATCH 52] compat getdents64: Use correct offset for retry [BZ
|
|
#23972]
|
|
|
|
d_off is the offset of the *next* entry, not the offset of the current
|
|
entry.
|
|
|
|
(cherry picked from commit 8d20a2f414fa52aceef8a0e3675415df54a840db)
|
|
---
|
|
ChangeLog | 10 ++++++++++
|
|
NEWS | 1 +
|
|
sysdeps/unix/sysv/linux/getdents64.c | 16 +++++++++++++---
|
|
sysdeps/unix/sysv/linux/tst-readdir64-compat.c | 4 ++++
|
|
4 files changed, 28 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/ChangeLog b/ChangeLog
|
|
index fb57e61a22..67213d487f 100644
|
|
--- a/ChangeLog
|
|
+++ b/ChangeLog
|
|
@@ -1,3 +1,13 @@
|
|
+2018-12-10 Florian Weimer <fweimer@redhat.com>
|
|
+
|
|
+ [BZ #23972]
|
|
+ * sysdeps/unix/sysv/linux/getdents64.c (handle_overflow): Check
|
|
+ offset instead of count for clarity. Fix typo in comment.
|
|
+ (__old_getdents64): Keep track of previous offset. Use it to call
|
|
+ handle_overflow.
|
|
+ * sysdeps/unix/sysv/linux/tst-readdir64-compat.c (do_test): Check
|
|
+ that d_off is never zero.
|
|
+
|
|
2018-11-30 Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
|
|
|
|
[BZ #23690]
|
|
diff --git a/NEWS b/NEWS
|
|
index 5290e21da9..4d4a5a1911 100644
|
|
--- a/NEWS
|
|
+++ b/NEWS
|
|
@@ -26,6 +26,7 @@ The following bugs are resolved with this release:
|
|
[23821] si_band in siginfo_t has wrong type long int on sparc64
|
|
[23822] ia64 static libm.a is missing exp2f, log2f and powf symbols
|
|
[23927] Linux if_nametoindex() does not close descriptor (CVE-2018-19591)
|
|
+ [23972] __old_getdents64 uses wrong d_off value on overflow
|
|
|
|
Security related changes:
|
|
|
|
diff --git a/sysdeps/unix/sysv/linux/getdents64.c b/sysdeps/unix/sysv/linux/getdents64.c
|
|
index bc140b5a7f..46eb5f4419 100644
|
|
--- a/sysdeps/unix/sysv/linux/getdents64.c
|
|
+++ b/sysdeps/unix/sysv/linux/getdents64.c
|
|
@@ -41,14 +41,14 @@ 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 (count == 0)
|
|
+ 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.. */
|
|
+ will report the error, and return the data read so far. */
|
|
if (__lseek64 (fd, offset, SEEK_SET) != 0)
|
|
return -1;
|
|
return count;
|
|
@@ -70,6 +70,15 @@ __old_getdents64 (int fd, char *buf, size_t nbytes)
|
|
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)
|
|
@@ -84,7 +93,7 @@ __old_getdents64 (int fd, char *buf, size_t nbytes)
|
|
|
|
/* Check for ino_t overflow. */
|
|
if (__glibc_unlikely (ino != source->d_ino))
|
|
- return handle_overflow (fd, offset, p - buf);
|
|
+ return handle_overflow (fd, previous_offset, p - buf);
|
|
|
|
/* Convert to the target layout. Use a separate struct and
|
|
memcpy to side-step aliasing issues. */
|
|
@@ -107,6 +116,7 @@ __old_getdents64 (int fd, char *buf, size_t nbytes)
|
|
reclen - offsetof (struct dirent64, d_name));
|
|
|
|
p += reclen;
|
|
+ previous_offset = offset;
|
|
}
|
|
}
|
|
return retval;
|
|
diff --git a/sysdeps/unix/sysv/linux/tst-readdir64-compat.c b/sysdeps/unix/sysv/linux/tst-readdir64-compat.c
|
|
index 43c4a8477c..cb78bc9be4 100644
|
|
--- a/sysdeps/unix/sysv/linux/tst-readdir64-compat.c
|
|
+++ b/sysdeps/unix/sysv/linux/tst-readdir64-compat.c
|
|
@@ -88,6 +88,10 @@ do_test (void)
|
|
else
|
|
TEST_VERIFY_EXIT (entry_test != NULL);
|
|
|
|
+ /* d_off is never zero because it is the offset of the next
|
|
+ entry (not the current entry). */
|
|
+ TEST_VERIFY (entry_reference->d_off > 0);
|
|
+
|
|
/* Check that the entries are the same. */
|
|
TEST_COMPARE_BLOB (entry_reference->d_name,
|
|
strlen (entry_reference->d_name),
|
|
|