From 4358d53cd9e7442557e2235b11ec50c6b472867f Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 6 Jun 2024 21:08:17 +0000 Subject: [PATCH] Move the ILP32 mmap() hackery into legacy_32_bit_support.cpp. Every time I look at mmap.cpp, I fail to realize it's only built for ILP32. Also improve some of the commentary in SYSCALLS.TXT and legacy_32_bit_support.cpp. Change-Id: Ieedfe800b437e30c060c3e8663b6d96d517dbf6f --- libc/Android.bp | 3 -- libc/SYSCALLS.TXT | 11 ++--- libc/bionic/legacy_32_bit_support.cpp | 46 +++++++++++++++++--- libc/bionic/mmap.cpp | 61 --------------------------- 4 files changed, 46 insertions(+), 75 deletions(-) delete mode 100644 libc/bionic/mmap.cpp diff --git a/libc/Android.bp b/libc/Android.bp index 2efca6855..d8467a88a 100644 --- a/libc/Android.bp +++ b/libc/Android.bp @@ -1224,9 +1224,6 @@ cc_library_static { // off64_t/time64_t support on LP32. "bionic/legacy_32_bit_support.cpp", "bionic/time64.c", - - // TODO: move to libc/bionic/legacy_32_bit_support.cpp or #if __LP64__ instead. - "bionic/mmap.cpp", ], }, }, diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT index 0db5d79aa..ce14e49c3 100644 --- a/libc/SYSCALLS.TXT +++ b/libc/SYSCALLS.TXT @@ -174,20 +174,21 @@ int utimensat(int, const char*, const struct timespec times[2], int) all off_t lseek(int, off_t, int) lp32 int __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int) lp32 off_t lseek|lseek64(int, off_t, int) lp64 -int ftruncate64(int, off64_t) lp32 -int ftruncate|ftruncate64(int, off_t) lp64 ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count) lp32 ssize_t sendfile64(int out_fd, int in_fd, off64_t* offset, size_t count) lp32 ssize_t sendfile|sendfile64(int out_fd, int in_fd, off_t* offset, size_t count) lp64 int truncate(const char*, off_t) lp32 int truncate64(const char*, off64_t) lp32 int truncate|truncate64(const char*, off_t) lp64 -# (mmap only gets two lines because we only used the 64-bit variant on 32-bit systems.) -void* __mmap2:mmap2(void*, size_t, int, int, int, long) lp32 -void* mmap|mmap64(void*, size_t, int, int, int, off_t) lp64 # (fallocate only gets two lines because there is no 32-bit variant.) int fallocate64:fallocate(int, int, off64_t, off64_t) lp32 int fallocate|fallocate64(int, int, off_t, off_t) lp64 +# (ftruncate only gets two lines because 32-bit bionic only uses the 64-bit call.) +int ftruncate64(int, off64_t) lp32 +int ftruncate|ftruncate64(int, off_t) lp64 +# (mmap only gets two lines because 32-bit bionic only uses the 64-bit call.) +void* __mmap2:mmap2(void*, size_t, int, int, int, long) lp32 +void* mmap|mmap64(void*, size_t, int, int, int, off_t) lp64 # posix_fadvise64 is awkward: arm has shuffled arguments, # the POSIX functions don't set errno, and no architecture has posix_fadvise. diff --git a/libc/bionic/legacy_32_bit_support.cpp b/libc/bionic/legacy_32_bit_support.cpp index 41108e6af..314fe9bcb 100644 --- a/libc/bionic/legacy_32_bit_support.cpp +++ b/libc/bionic/legacy_32_bit_support.cpp @@ -30,24 +30,28 @@ #include #include -#include +#include +#include #include #include -#include -#include #include +#include "platform/bionic/macros.h" +#include "platform/bionic/page.h" +#include "private/ErrnoRestorer.h" #include "private/bionic_fdtrack.h" #if defined(__LP64__) #error This code is only needed on 32-bit systems! #endif -// System calls we need. +// To implement lseek64() on ILP32, we need to use the _llseek() system call +// which splits the off64_t into two 32-bit arguments and returns the off64_t +// result via a pointer because 32-bit kernels can't accept 64-bit arguments +// or return 64-bit results. (Our symbol is __llseek with two underscores for +// historical reasons, but it's exposed as ABI so we can't fix it.) extern "C" int __llseek(int, unsigned long, unsigned long, off64_t*, int); -// For lseek64 we need to use the llseek system call which splits the off64_t in two and -// returns the off64_t result via a pointer because 32-bit kernels can't return 64-bit results. off64_t lseek64(int fd, off64_t off, int whence) { off64_t result; unsigned long off_hi = static_cast(off >> 32); @@ -101,3 +105,33 @@ int prlimit(pid_t pid, int resource, const rlimit* n32, rlimit* o32) { } return result; } + +// mmap2(2) is like mmap(2), but the offset is in 4096-byte blocks (regardless +// of page size), not bytes, to enable mapping parts of large files past the +// 4GiB limit but without the inconvenience of dealing with 64-bit values, with +// no down side since mappings need to be page aligned anyway, and the 32-bit +// architectures that support this system call all have 4KiB pages. +extern "C" void* __mmap2(void*, size_t, int, int, int, size_t); + +void* mmap64(void* addr, size_t size, int prot, int flags, int fd, off64_t offset) { + static constexpr size_t MMAP2_SHIFT = 12; + + if (offset < 0 || (offset & ((1UL << MMAP2_SHIFT) - 1)) != 0) { + errno = EINVAL; + return MAP_FAILED; + } + + // Prevent allocations large enough for `end - start` to overflow, + // to avoid security bugs. + size_t rounded = __BIONIC_ALIGN(size, page_size()); + if (rounded < size || rounded > PTRDIFF_MAX) { + errno = ENOMEM; + return MAP_FAILED; + } + + return __mmap2(addr, size, prot, flags, fd, offset >> MMAP2_SHIFT); +} + +void* mmap(void* addr, size_t size, int prot, int flags, int fd, off_t offset) { + return mmap64(addr, size, prot, flags, fd, static_cast(offset)); +} diff --git a/libc/bionic/mmap.cpp b/libc/bionic/mmap.cpp deleted file mode 100644 index f05dcb8ce..000000000 --- a/libc/bionic/mmap.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include - -#include "platform/bionic/macros.h" -#include "platform/bionic/page.h" -#include "private/ErrnoRestorer.h" - -// mmap2(2) is like mmap(2), but the offset is in 4096-byte blocks, not bytes. -extern "C" void* __mmap2(void*, size_t, int, int, int, size_t); - -#define MMAP2_SHIFT 12 // 2**12 == 4096 - -void* mmap64(void* addr, size_t size, int prot, int flags, int fd, off64_t offset) { - if (offset < 0 || (offset & ((1UL << MMAP2_SHIFT)-1)) != 0) { - errno = EINVAL; - return MAP_FAILED; - } - - // Prevent allocations large enough for `end - start` to overflow. - size_t rounded = __BIONIC_ALIGN(size, page_size()); - if (rounded < size || rounded > PTRDIFF_MAX) { - errno = ENOMEM; - return MAP_FAILED; - } - - return __mmap2(addr, size, prot, flags, fd, offset >> MMAP2_SHIFT); -} - -void* mmap(void* addr, size_t size, int prot, int flags, int fd, off_t offset) { - return mmap64(addr, size, prot, flags, fd, static_cast(offset)); -}