This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] posix: Fix generic p{read,write}v buffer allocation (BZ#22457)


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]