This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH] posix: Fix generic p{read,write}v buffer allocation (BZ#22457)
- From: Adhemerval Zanella <adhemerval dot zanella at linaro dot org>
- To: libc-alpha at sourceware dot org
- Date: Thu, 23 Nov 2017 14:38:50 -0200
- Subject: [PATCH] posix: Fix generic p{read,write}v buffer allocation (BZ#22457)
- Authentication-results: sourceware.org; auth=none
As described in BZ#22457 an interpose malloc can free an invalid
pointer for fallback preadv implementation. Fortunately this is
just and issue on microblaze-linux-gnu running kernels older than
3.15.
This patch fixes it by calling mmap/unmap instead of posix_memalign/
free. A sanity check is address to certify buffer alignment (since
POSIX does not enforces a particular alignment on returned mmap
value, just for MMAP_FIXED input).
Checked on microblaze-linux-gnu check with run-built-tests=no and
by using the sysdeps/posix implementation on x86_64-linux-gnu (just
for sanity test where it shown no regression).
* include/libc-pointer-arith.h (PTR_IS_ALIGNED): New macro.
* sysdeps/posix/preadv_common.c (PREADV): Use mmap/munmap instead of
posix_memalign/free.
* sysdeps/posix/pwritev_common.c (PWRITEV): Likewise.
---
ChangeLog | 7 +++++++
include/libc-pointer-arith.h | 4 ++++
sysdeps/posix/preadv_common.c | 10 +++++++---
sysdeps/posix/pwritev_common.c | 10 +++++++---
4 files changed, 25 insertions(+), 6 deletions(-)
diff --git a/include/libc-pointer-arith.h b/include/libc-pointer-arith.h
index 715cbc1..c918023 100644
--- a/include/libc-pointer-arith.h
+++ b/include/libc-pointer-arith.h
@@ -57,4 +57,8 @@
#define PTR_ALIGN_UP(base, size) \
((__typeof__ (base)) ALIGN_UP ((uintptr_t) (base), (size)))
+/* Check if base is aligned to boundary. */
+#define PTR_IS_ALIGNED(base, boundary) \
+ (((uintptr_t) (base) & ((uintptr_t) ((boundary)) - 1)) == 0)
+
#endif
diff --git a/sysdeps/posix/preadv_common.c b/sysdeps/posix/preadv_common.c
index 37efdc0..099c37b 100644
--- a/sysdeps/posix/preadv_common.c
+++ b/sysdeps/posix/preadv_common.c
@@ -24,6 +24,7 @@
#include <malloc.h>
#include <ldsodefs.h>
+#include <libc-pointer-arith.h>
/* Read data from file descriptor FD at the given position OFFSET
without change the file pointer, and put the result in the buffers
@@ -54,8 +55,11 @@ PREADV (int fd, const struct iovec *vector, int count, OFF_T offset)
but 1. it is system specific (not meant in generic implementation), and
2. it would make the implementation more complex, and 3. it will require
another syscall (fcntl). */
- void *buffer = NULL;
- if (__posix_memalign (&buffer, GLRO(dl_pagesize), bytes) != 0)
+ size_t mmap_size = ALIGN_UP (bytes, GLRO(dl_pagesize));
+ void *buffer = __mmap (NULL, mmap_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (__glibc_unlikely (buffer == MAP_FAILED)
+ || __glibc_unlikely (!PTR_IS_ALIGNED (buffer, GLRO(dl_pagesize))))
return -1;
ssize_t bytes_read = PREAD (fd, buffer, bytes, offset);
@@ -78,6 +82,6 @@ PREADV (int fd, const struct iovec *vector, int count, OFF_T offset)
}
end:
- free (buffer);
+ __munmap (buffer, mmap_size);
return bytes_read;
}
diff --git a/sysdeps/posix/pwritev_common.c b/sysdeps/posix/pwritev_common.c
index 0383065..610c54e 100644
--- a/sysdeps/posix/pwritev_common.c
+++ b/sysdeps/posix/pwritev_common.c
@@ -24,6 +24,7 @@
#include <malloc.h>
#include <ldsodefs.h>
+#include <libc-pointer-arith.h>
/* Write data pointed by the buffers described by IOVEC, which is a
vector of COUNT 'struct iovec's, to file descriptor FD at the given
@@ -54,8 +55,11 @@ PWRITEV (int fd, const struct iovec *vector, int count, OFF_T offset)
but 1. it is system specific (not meant in generic implementation), and
2. it would make the implementation more complex, and 3. it will require
another syscall (fcntl). */
- void *buffer = NULL;
- if (__posix_memalign (&buffer, GLRO(dl_pagesize), bytes) != 0)
+ size_t mmap_size = ALIGN_UP (bytes, GLRO(dl_pagesize));
+ void *buffer = __mmap (NULL, mmap_size, PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (__glibc_unlikely (buffer == MAP_FAILED)
+ || __glibc_unlikely (!PTR_IS_ALIGNED (buffer, GLRO(dl_pagesize))))
return -1;
/* Copy the data from BUFFER into the memory specified by VECTOR. */
@@ -66,7 +70,7 @@ PWRITEV (int fd, const struct iovec *vector, int count, OFF_T offset)
ssize_t ret = PWRITE (fd, buffer, bytes, offset);
- free (buffer);
+ __munmap (buffer, mmap_size);
return ret;
}
--
2.7.4