Skip to content

Fix Java bridge crash on Android 17 (API 37) arm64#398

Merged
oleavr merged 1 commit into
frida:mainfrom
Wes765:fix/android-17-art-java-bridge
Jun 22, 2026
Merged

Fix Java bridge crash on Android 17 (API 37) arm64#398
oleavr merged 1 commit into
frida:mainfrom
Wes765:fix/android-17-art-java-bridge

Conversation

@Wes765

@Wes765 Wes765 commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

On a Pixel 10 Pro XL running Android 17 (SDK 37, arm64), Java.perform()
SIGBUSes the target process. Two independent bugs are involved. Both
reproduce on a stock frida-server; neither is device-specific beyond the
new ART build, and both are fixed here.

1. ArtMethod access-flags offset detection

_getArtMethodSpec() locates ArtMethod.access_flags_ by masking the
runtime-only nterp flags off a probe method (Process.getElapsedCpuTime)
and matching against kAccPublic|kAccStatic|kAccFinal|kAccNative. The mask
stripped kAccNterpInvokeFastPathFlag but not
kAccNterpEntryPointFastPathFlag. On API 37 the probe method carries the
latter, so its real flags at offset 4 (0x50300119) no longer matched, and
the scan latched onto the next ArtMethod's flags one 32-byte stride over
(offset 36), corrupting the flag offset for every method.

Fix: also mask kAccNterpEntryPointFastPathFlag.

2. Unresolved literal pool in the thread-state-transition thunk

makeArtThreadStateTransitionImpl() recompiles art::JNI::ExceptionClear
and emits an invokeCallback subroutine whose
putCallAddressWithArguments() loads callback via a PC-relative literal
(±1 MiB reach). The literal pool was only emitted at writer.dispose(),
after the relocated ExceptionClear body. On Android 17 ExceptionClear
and the following function sit ~2 MiB apart, so the relocated body pushes
the pool out of the load's range, and it is left as ldr xN, #0, which
reads its own instruction bytes (0x...58000001) and branches to them,
giving a PC-alignment SIGBUS at the first withRunnableArtThread().

Fix: emit the invokeCallback subroutine first and flush the literal pool
immediately after it (it sits after a ret, so it is never executed),
then use the relocated transition body as the entrypoint.

Verification

Pixel 10 Pro XL, Android 17 (SDK 37): Java.use, static field reads,
method invocation, and method replacement (.implementation) all work.

Two bugs make Java.perform() SIGBUS on API 37.

_getArtMethodSpec() left kAccNterpEntryPointFastPathFlag unmasked,
which the API 37 probe method carries, so the access_flags scan
latched onto the next ArtMethod and corrupted the flag offset.

makeArtThreadStateTransitionImpl()'s invokeCallback loads callback
through a PC-relative literal flushed too late: the relocated
ExceptionClear body pushes the pool out of ±1 MiB reach. Emit
invokeCallback first, flush after its ret, enter via the relocated
body.
@oleavr oleavr force-pushed the fix/android-17-art-java-bridge branch from f923041 to 67f1b11 Compare June 22, 2026 09:56
@oleavr oleavr merged commit 302a588 into frida:main Jun 22, 2026
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.

2 participants