Skip to content

Fix dex2oat wrapper SELinux check on Android 14+#785

Open
pbzin wants to merge 1 commit into
JingMatrix:masterfrom
pbzin:agent/fix-artd-dex2oat-selinux
Open

Fix dex2oat wrapper SELinux check on Android 14+#785
pbzin wants to merge 1 commit into
JingMatrix:masterfrom
pbzin:agent/fix-artd-dex2oat-selinux

Conversation

@pbzin

@pbzin pbzin commented Jul 16, 2026

Copy link
Copy Markdown

Summary

  • detect the Android 14+ artd to dex2oat_exec transition when selecting the wrapper file context
  • keep the existing dex2oat execute_no_trans check for Android versions before 14

Root cause

Android 14 introduced the artd service path for dex2oat. The previous check queried dex2oat with execute_no_trans; on Android 16 this check fails because the supported path is the artd -> dex2oat_exec -> dex2oat domain transition. Vector therefore selected the xposed_file fallback for its bind-mounted wrapper. artd then failed to execute the wrapper because the module policy only grants xposed_file access to the older domains.

The fix uses the platform transition already defined by AOSP, so it does not broaden the module policy with an artd access rule for xposed_file.

Validation

  • Reproduced on a Redmi Note 13 4G running an Android 16 user build: the old path mounted dex2oat64 with xposed_file, and artd logged Permission denied.
  • Confirmed the installed AOSP Android 16 policy defines domain_auto_trans(artd, dex2oat_exec, dex2oat).
  • git diff --check passes.
  • No full build was run.

@JingMatrix

Copy link
Copy Markdown
Owner

@pbzin Please upload your logs in Redmi Note 13 4G for me to better understand what you described.

@pbzin

pbzin commented Jul 19, 2026

Copy link
Copy Markdown
Author

@pbzin Please upload your logs in Redmi Note 13 4G for me to better understand what you described.

avc: denied { execute }
avc: denied { execute_no_trans }
scontext=u:r:untrusted_app:s0
tcontext=u:object_r:dex2oat_exec:s0

LSPosedService: failed to change feature flags
ClassNotFoundException: android.app.FeatureFlagsImpl
SQLiteException: no such table: assignment

No IPC binder obtained ... Skipping injection

@JingMatrix

Copy link
Copy Markdown
Owner

@pbzin Please upload the original logs, not the filtered one.

@pbzin

pbzin commented Jul 23, 2026

Copy link
Copy Markdown
Author

@pbzinPor favor, envie os registros originais, não a versão filtrada.

I'm trying to reproduce it again and for some reason it doesn't give me the error, I messed around a lot with my crdroid rom so it could be that or magisk, I don't know, so the only explanation and log I can find is the previous one with codex and below with gemini, maybe it will help

Technical Context:

On Android 14+ (SDK 34+), AOSP refactored dex2oat invocations to go through the artd daemon, establishing the domain transition artd -> dex2oat_exec -> dex2oat.

In the legacy code, canUseDex2OatExec() checks:

kotlin

SELinux.checkSELinuxAccess("u:r:dex2oat:s0", "u:object_r:dex2oat_exec:s0", "file", "execute_no_trans")
Why it fails on stock Android 14+ / AOSP builds: Since AOSP removed execute_no_trans for the legacy dex2oat domain on Android 14+, checkSELinuxAccess() returns false. This forces Vector into the fallback path:

kotlin

SELinux.setFileContext(WRAPPER, xposedFile)
artd is not granted access to xposed_file, resulting in an SELinux denial (avc: denied { execute }) when artd attempts to launch the bind-mounted wrapper.

Why it might pass on some devices/custom setups: If a custom ROM or root solution (Magisk/KernelSU sepolicy patches) injects permissive rules or relaxes legacy dex2oat access, checkSELinuxAccess may evaluate to true, hiding the bug. However, on pure AOSP or strict OEM policies (Android 14–16), it consistently breaks.

Solution in this PR: Check the current AOSP-defined domain transition for Android 14+ (u:r:artd:s0 -> u:object_r:dex2oat_exec:s0 with execute), ensuring the wrapper is always labeled with dex2oat_exec without relying on legacy fallback rules.

@marcinmajsc

marcinmajsc commented Jul 24, 2026

Copy link
Copy Markdown

I think have same this problem on my device:

----part 2 start----
[ 2026-07-24T04:30:00.788     2000: 11694: 11694 D/Vector          ] ParasiticHooker: pkg=com.android.shell, prc=org.lsposed.manager - Saved state for org.lsposed.manager.ui.activity.MainActivity
[ 2026-07-24T04:30:03.163        0: 12956: 12956 I/VectorNative    ] Manager app detected. Granting internet permissions.
[ 2026-07-24T04:30:03.177     1000:  2183:  2433 D/VectorZygiskBridge ] onTransact: action=GET_BINDER, callerUid=2000
[ 2026-07-24T04:30:03.248     2000: 12956: 12956 V/VectorDeopter   ] Skipping deopt for android.app.Instrumentation#newApplication: android.app.Instrumentation.newApplication [class java.lang.ClassLoader, class android.content.Context]
[ 2026-07-24T04:30:03.298     2000: 12956: 12956 D/Vector          ] Vector manager injected successfully into process.
[ 2026-07-24T04:30:03.298     2000: 12956: 12956 I/Vector          ] Manager (parasitic) loaded into host, skipping standard bootstrap.
[ 2026-07-24T04:30:03.312     2000: 12956: 12956 D/Vector          ] ParasiticHooker: pkg=null, prc=null - ActivityThread#handleBindApplication() starts
[ 2026-07-24T04:30:03.346     2000: 12956: 12956 D/Vector          ] ParasiticHooker: pkg=com.android.shell, prc=org.lsposed.manager - Injecting DEX into LoadedApk ClassLoader: dalvik.system.PathClassLoader[DexPathList[[zip file "/proc/self/fd/79"],nativeLibraryDirectories=[/system/priv-app/Shell/lib/arm64, /system/lib64, /system_ext/lib64]]]
[ 2026-07-24T04:30:03.435     2000: 12956: 12956 D/Vector          ] ParasiticHooker: pkg=com.android.shell, prc=org.lsposed.manager - Restoring state for Activity: org.lsposed.manager.ui.activity.MainActivity
[ 2026-07-24T04:30:03.448     2000: 12956: 12973 I/LSPosedManager  ] repo: loadLocalData(updateRemoteRepo=true), cacheExists=true
[ 2026-07-24T04:30:03.550     2000: 12956: 12973 I/LSPosedManager  ] repo: loadLocalData parsed 801 modules from cache (1211124 bytes)
[ 2026-07-24T04:30:03.550     2000: 12956: 12973 I/LSPosedManager  ] repo: onlineModules replaced, now 801 modules (channel=CHANNEL_NIGHTLY)
[ 2026-07-24T04:30:03.914        0:  1851:  1905 E/SELinux         ] avc:  denied  { execute_no_trans } for  scontext=u:r:dex2oat:s0 tcontext=u:object_r:dex2oat_exec:s0 tclass=file permissive=0
[ 2026-07-24T04:30:04.060     2000: 12956: 12973 I/LSPosedManager  ] repo: fetched module list from https://backup.modules.lsposed.org/ (801 entries, 1184718 bytes)
[ 2026-07-24T04:30:04.061     2000: 12956: 12973 I/LSPosedManager  ] repo: onlineModules replaced, now 801 modules (channel=CHANNEL_NIGHTLY)
[ 2026-07-24T04:30:04.863     2000: 12956: 12970 E/LSPosedManager  ] downloadNewZipSync: /data/user/0/com.android.shell/cache/Vector-v2.0-3021-Debug.zip: open failed: EACCES (Permission denied)
[ 2026-07-24T04:30:40.605     2000: 12956: 12956 D/Vector          ] ParasiticHooker: pkg=com.android.shell, prc=org.lsposed.manager - Saved state for org.lsposed.manager.ui.activity.MainActivity
[ 2026-07-24T04:30:45.278     2000: 12956: 12956 D/Vector          ] ParasiticHooker: pkg=com.android.shell, prc=org.lsposed.manager - Saved state for org.lsposed.manager.ui.activity.MainActivity
[ 2026-07-24T04:31:19.619     1000:  2183:  4457 D/VectorZygiskBridge ] onTransact: action=GET_BINDER, callerUid=10182
[ 2026-07-24T04:33:50.526     1000:  2183: 11499 D/VectorZygiskBridge ] onTransact: action=GET_BINDER, callerUid=10181
[ 2026-07-24T04:33:50.537     1000:  2183:  2345 D/VectorZygiskBridge ] onTransact: action=GET_BINDER, callerUid=10185
[ 2026-07-24T04:34:33.121        0:  1851:  1905 E/SELinux         ] avc:  denied  { execute_no_trans } for  scontext=u:r:dex2oat:s0 tcontext=u:object_r:dex2oat_exec:s0 tclass=file permissive=0
[ 2026-07-24T04:35:28.026     2000: 12956: 12956 D/Vector          ] ParasiticHooker: pkg=com.android.shell, prc=org.lsposed.manager - Saved state for org.lsposed.manager.ui.activity.MainActivity
[ 2026-07-24T04:35:30.830     2000: 12956: 12956 D/Vector          ] ParasiticHooker: pkg=com.android.shell, prc=org.lsposed.manager - Saved state for org.lsposed.manager.ui.activity.MainActivity

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.

3 participants