Skip to content

__pthread_internal_remap_stack_with_mte: stop setting stack top guard to RW - #75

Open
rdevshp wants to merge 48 commits into
GrapheneOS:17from
rdevshp:mte_remap
Open

rdevshp wants to merge 48 commits into
GrapheneOS:17from
rdevshp:mte_remap

Conversation

@rdevshp

@rdevshp rdevshp commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

(the following is pasted from #67 )
pthread_create.cpp __allocate_thread_mapping does the following:

// Layout from the end of the mmap-ed region (before the top PTHREAD_GUARD_SIZE):
//
// [ PTHREAD_GUARD_SIZE ]
// [ libgen_buffers_padded_size (for dedicated page(s) for libgen buffers) ]
// [ static_tls_layout_size ]
// [ thread_page_size (for pthread_internal_t) ]
// [ gap_size (for (random) guard page(s)) ]
// [ stack_size ]
// [ stack_guard_size ]

ThreadMapping result = {};
result.mmap_base = space;
result.mmap_size = mmap_size;
result.mmap_base_unguarded = space + stack_guard_size;
result.mmap_size_unguarded = mmap_size - stack_guard_size - PTHREAD_GUARD_SIZE;

This means that after

mprotect(t->mmap_base_unguarded, t->mmap_size_unguarded,
                 PROT_READ | PROT_WRITE | PROT_MTE)

is executed in __pthread_internal_remap_stack_with_mte, the stack top guard is set to RW.
This PR proposes a fix for this issue.

thestinger and others added 30 commits May 21, 2026 11:20
Clang, GCC and other compilers special-case standard C functions like
memset. Calls to memset will be optimized out.

OpenBSD provides explicit_bzero to work around this but Android simply
defines it as memset so nothing prevents it from being optimized away.

This implementation uses a memory read constraint via empty inline
assembly rather than something that may be broken via link-time
optimization in the future.
Pretend that there is never room to grow the heap in order to prevent
usage of these unsafe legacy functions. There are likely no users of
these in practice as it is inherently broken to use them outside of
malloc.

Signed-off-by: anupritaisno1 <www.anuprita804@gmail.com>
Adding a field above this results in either that field or the tid field
(depending on if it's above that too) being set to zero by vfork.
Ideally that assembly would be replaced with a C++ wrapper but in the
meantime this adds a comment to save time for someone else.

Signed-off-by: anupritaisno1 <www.anuprita804@gmail.com>
memtag_stack struct member is required to be at its exact position by static_assert below.

Signed-off-by: anupritaisno1 <www.anuprita804@gmail.com>
Guarantee that junk filled pointers will fault, at least on pure 64-bit.

Signed-off-by: anupritaisno1 <www.anuprita804@gmail.com>
This is required by the AArch64 ABI for the default stack probe size of
64kiB.
This reverts commit 37407d6.

This has to be reverted for now due to Facebook adding a buggy stack
overflow check to the React Native Hermes JavaScript engine.
This reduces entropy of the canary from 64-bit to 56-bit in exchange for
mitigating non-terminated C string overflows.
In some cases, it can be useful to load libraries from zip files that
are only available by fd reference. For example, file descriptors of
APKs containing native libraries may be sent via Binder IPC for clients
to use.

Unfortunately, while this linker does support loading libraries from
file descriptors using android_dlopen_ext, using that API is not an
option because our dlopen calls originate from JNI loadLibrary requests
in ART.

This is necessary for compatibility with Google Play Services' dynamic
module system (Dynamite) without weakening the SELinux sandbox to allow
other apps to open module APKs from
/data/user_de/0/com.google.android.gms/app_chimera/m.

Squashed with 7b3fc50

Change-Id: If44d5c3faf4f50e4704688b520b197ff151ae05a
This function checks if a source address is available for sending data
to this sample IPv4 address by making a UDP socket and calling connect
which does not perform I/O with the socket since this is UDP, not TCP.

The purpose of _find_src_addr is to check whether an attempt could be
made to connect or send data to the IP without doing it.
64-bit Scudo can be swithed to at runtime, see the next commit.

Squashed with 6562b94

Co-authored-by: anupritaisno1 <www.anuprita804@gmail.com>
It weakens hardened_malloc protections, especially when memory tagging is enabled.
This is needed for forcibly enabling memory tagging in apps that call

mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_NONE)

despite being compatible with memory tagging.

Some of them likely do this to disable top-byte-ignore (M_HEAP_TAGGING_LEVEL_TBI is disableable
with the same API call).

Note that switching between M_HEAP_TAGGING_LEVEL_ASYNC and M_HEAP_TAGGING_LEVEL_SYNC is
intentionally not blocked: when the device is configured to use "SYNC" memory tagging, it'll use it
both in M_HEAP_TAGGING_LEVEL_ASYNC and M_HEAP_TAGGING_LEVEL_SYNC modes.

M_HEAP_TAGGING_LEVEL_SYNC is intended for debugging, it enables allocation stack trace collection
in Scudo, which significantly lowers performance.
This is needed for forcibly enabling memory tagging for apps that use custom crash handlers, which
ignore SIGSEGV in some cases. Even if SIGSEGV isn't ignored by such handler, it usually breaks
detection of memory tagging-related crashes (MTEAERR/MTESERR signal codes are consumed by them).

Requires the corresponding patch to sigchainlib in art (sigchainlib overrides sigaction() and
signal()).
muhomorr and others added 18 commits June 15, 2026 12:52
use page size for static TLS guard page
Fixes build errors:

error: frameworks/libs/native_bridge_support/android_api/libc/Android.bp:27:1: m
  odule "libnative_bridge_guest_libc" variant "android_native_bridge_arm64_armv8-a
  _static": module source path "frameworks/libs/native_bridge_support/android_api/
  libc/bionic/h_malloc_wrapper.cpp" does not exist

Test: lunch aosp_cf_x86_64_only_phone-cur-userdebug with hardened_malloc fix boots
Widevine Rikers is the proprietary Widevine DRM HAL service.  In the crash path, its internal
resolver decodes requested symbol names such as signal, uses GNU hash metadata to find the matching
libc .dynsym entry, and caches the resolved function pointer. The faulting PC is the resolver’s `ldg
x8, [x8] instruction` at Rikers offset 0x11c51e8, where x8 points at execute-only libc text for
`signal @@ LIBC`, causing SEGV_ACCERR when MTE is enabled.

All the tests suites below have encountered failures with the SEGV_ACCERR prior to this commit.

Test: atest CtsMediaDrmFrameworkTestCases
Test: atest CtsVirtualDevicesAppLaunchTestCases:android.virtualdevice.cts.applaunch.VirtualDeviceDrmTest
Test: atest VtsAidlHalDrmTargetTest (requires userdebug with locked bootloader)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants