Compare commits

...

98 Commits
v26.4 ... v27.0

Author SHA1 Message Date
topjohnwu
2c6adbc69b Release Magisk v27.0 2024-02-02 22:54:41 -08:00
topjohnwu
5280982363 Add v27.0 changelog 2024-02-02 22:47:35 -08:00
topjohnwu
18c45ae289 Update cxx and Rust dependencies 2024-02-02 14:35:30 -08:00
LoveSy
41fbd2a7be Upgrade gradle 2024-02-02 10:55:11 -08:00
LoveSy
5e45884af4 Use Apple Silicon for CI
https://github.blog/changelog/2024-01-30-github-actions-introducing-the-new-m1-macos-runner-available-to-open-source/
2024-02-01 15:09:42 -08:00
topjohnwu
d78ee171bc Release new canary build 2024-01-30 15:59:02 -08:00
LoveSy
356ee1febd Code clean up 2024-01-30 11:07:37 -08:00
LoveSy
cc044ccc4c Fix zygisk unload 2024-01-30 11:07:37 -08:00
LoveSy
9c638cc463 Remove rust workaround 2024-01-29 15:07:21 -08:00
topjohnwu
df786eb2b6 Separate Linux and other jobs 2024-01-29 01:53:09 -08:00
topjohnwu
8e7186eebb Try out composite actions 2024-01-29 01:36:51 -08:00
topjohnwu
74b7b84561 Test all APIs on Linux 2024-01-28 00:46:03 -08:00
topjohnwu
308c9999fa Properly detect package changes 2024-01-28 00:42:43 -08:00
topjohnwu
930bb8687f Minor zygisk refactoring 2024-01-25 00:17:47 -08:00
topjohnwu
f2c4288d2d Run pthread_atfork only once
Close #7704
2024-01-25 00:17:05 -08:00
topjohnwu
b44141ae39 Run tests on Linux 2024-01-22 18:10:26 -08:00
kam821
86e0020964 Update Polish translation
- Added missing strings, fixed translation, escaped quotas.
- Some context dependent values (like target_pid) may require better translation in the future.
- Also, 'DenyList' translation, although correct, could be replaced in the future by better fitting polish equivalent of 'block list' / 'rejection list'.
2024-01-17 16:13:20 -08:00
残页
94d3daeadf Fix Sony init.real check 2024-01-17 16:09:50 -08:00
LoveSy
79334b7702 One stage zygisk loading 2024-01-11 16:19:39 -08:00
LoveSy
df66458db6 Check full path of init.rc instead of its dir
Some devices has `/system/etc/init/hw` but has no init.rc in it.
2024-01-11 16:18:57 -08:00
LoveSy
97705704e2 install or uninstall apk asynchronously 2024-01-11 16:16:36 -08:00
topjohnwu
1206179580 Update dependencies 2024-01-10 15:46:30 -08:00
topjohnwu
a0b8aa4da6 Release new canary build 2023-12-27 01:42:42 +08:00
topjohnwu
65207f96c8 Create custom cxx binding to Utf8CStr 2023-12-26 23:10:55 +08:00
Abhishek Girish
062e498bdd Update Malayalam translations 2023-12-25 18:46:08 +08:00
topjohnwu
1057cb3e3c Set serial on Rust binding 2023-12-24 04:36:58 +08:00
topjohnwu
2dd23b2518 Update system_properties 2023-12-24 04:36:58 +08:00
RafaeloxMC
8cab12998c Update strings.xml / German translation 2023-12-23 16:49:47 +08:00
topjohnwu
48b1c26dc8 Prevent race condition in wait 2023-12-23 06:33:12 +08:00
topjohnwu
f1e0bc3e4a Use platform implementation if possible 2023-12-23 06:24:20 +08:00
topjohnwu
38527cd58f Slightly change wait usage and API 2023-12-23 06:23:29 +08:00
LoveSy
e94d65b4b2 Add resetprop -w for waiting property change
It's very easy to wait for property change both in Java and C++,
but it's not the case in shell script. With this patch, developers
can now easily to wait for property change, just like what we have
in `.rc` files, and to wait for boot complete.
2023-12-23 00:12:42 +08:00
LoveSy
27ece3c7df Keep mirror shared before magic mount
This allows mounting during post-fs-data be kept after magic mount
2023-12-22 21:39:03 +08:00
LoveSy
06687abffc Fix magisk --stop by making mirror shared
Previously mirror is private and then unshared to zygote, which
makes magisk --stop cannot propagate umount mirror to zygote.
2023-12-22 21:39:03 +08:00
vvb2060
deedb462a0 Hide magisk internal mount point 2023-12-22 21:38:15 +08:00
igor
c48962bdf7 Update Portuguese translation 2023-12-22 01:31:55 +08:00
Wang Han
1ef3f6e13b Remove useless rule for prctl PR_SET_MM
* There is no use-case for it now.
2023-12-22 00:36:06 +08:00
topjohnwu
83a34a9004 Update emulator 2023-12-21 21:30:35 +08:00
topjohnwu
e30bda6c8d Rebase libsepol to AOSP main 2023-12-21 19:23:02 +08:00
vvb2060
00e9d76a5a Revert "Avoid doing any unmounts for SysUI" 2023-12-20 17:23:17 +08:00
LoveSy
6cda6c2fae Upgrade github action deps 2023-12-18 16:25:56 +08:00
VD $ VD171 @ Priv8
6dfda6dc39 Update Portuguese Translation 2023-12-18 16:24:14 +08:00
LoveSy
f41994cb52 Skip svc for ro properties
ro properties' triggers should only be triggered once, otherwise it
may undefined behaviour.
This patch avoids triggering ro properties' actions again when using
resetprop to modify them.

Co-authored-by: 5ec1cff <ewtqyqyewtqyqy@gmail.com>
2023-12-18 16:21:08 +08:00
topjohnwu
a003336497 Update system_properties for pre Android 10 2023-12-18 16:21:08 +08:00
LoveSy
401090d6fe Avoid zygiskd restarts when boot-complete 2023-12-18 16:21:08 +08:00
LoveSy
90dcc1cd30 Do not always zero initialize for rust resize vec 2023-12-18 16:21:08 +08:00
LoveSy
2ac464b186 Only compress regular file 2023-12-18 16:21:08 +08:00
LoveSy
8b7fae278b Support compressing during cpio backup 2023-12-18 16:21:08 +08:00
topjohnwu
d73c2daf6d Use special emulator to make tests less flaky 2023-12-16 15:50:53 +08:00
topjohnwu
ca25935de3 Release new canary build 2023-12-14 03:21:22 +08:00
LoveSy
d7750b7220 uiautomator dump to /data/local/tmp 2023-12-13 03:28:30 +08:00
LoveSy
98861f0b5a Clone dir attr for tmpfs in advance 2023-12-13 03:28:30 +08:00
topjohnwu
e35925d520 Properly version zygisk APIs 2023-12-13 03:27:38 +08:00
Kieron Quinn
685a2d2101 Fixes for Android 14 QPR2 B2
Added new method signatures and arguments
2023-12-13 00:16:54 +08:00
LoveSy
f7e471616d Fix clone_attr for newly created dirs 2023-12-10 23:37:47 +08:00
残页
c013a349af Update install guide
- Remove boot vbmeta patching because the checkbox is removed in b1363ee
- Remove meaningless slot argument from `fastboot flash` as it will automatically flash the active slot. Fix #7571
2023-12-10 23:37:02 +08:00
topjohnwu
61ea59a27b API 34 AOSP ATD image is released 2023-12-08 17:59:24 +08:00
VD $ VD171 @ Priv8
e55f338367 Update Portuguese Translation 2023-12-08 17:03:48 +08:00
VD $ VD171 @ Priv8
1425cf4105 Update Portuguese Translation 2023-12-08 17:03:48 +08:00
topjohnwu
b493a985b0 Update dependencies 2023-12-08 17:03:18 +08:00
canyie
1fe9ede940 Update selinux to disable validation for policydb 2023-12-08 16:50:45 +08:00
LoveSy
1fd49e4987 Make tmpfs mount of magic mount atomic
This avoid system libraries disappear temporarily during magic mount,
which causes some dynamic executables fails to run during post-fs-data.
2023-12-08 13:59:02 +08:00
LoveSy
d49b02b274 Fix zygiskd not restart when zygote restarts 2023-12-07 20:44:44 +08:00
LoveSy
d47e70cfaa Fix native symbol strips
`ndkVersion` is also needed by app for striping native symbols.
Set it in `setupCommon` instead.
2023-12-04 00:37:09 +08:00
topjohnwu
40cb031af5 Release new canary build 2023-12-04 00:30:46 +08:00
topjohnwu
1dcf325547 Minor cleanup 2023-12-03 19:32:58 +08:00
LoveSy
4e99997013 Upgrade AGP 2023-12-02 15:25:58 +08:00
LoveSy
334554697d Enable rust parallel front-end
See https://blog.rust-lang.org/2023/11/09/parallel-rustc.html
2023-12-02 15:25:41 +08:00
LoveSy
e77cbd0c15 Upgrade gradle 2023-11-30 11:49:40 +08:00
topjohnwu
46ba008b9d Disable SCCACHE_DIRECT 2023-11-30 01:55:38 +08:00
LoveSy
58aded31c2 Enable iter_intersperse 2023-11-29 23:47:51 +08:00
LoveSy
6f6b0ade06 Correct cpio's norm_path 2023-11-29 23:47:51 +08:00
topjohnwu
d9b67a207b Update ONDK 2023-11-27 17:41:11 +08:00
topjohnwu
c7083659aa Directly guard boot state with mutex 2023-11-27 17:40:58 +08:00
topjohnwu
a6d1803105 Update dependencies 2023-11-26 23:09:20 +08:00
Re*Index. (ot_inc)
66eef75673 Update strings.xml 2023-11-26 22:54:53 +08:00
Alessandro Sangiorgi
367f5f7b44 Update italian translation
Co-authored-by: Francesco Saltori <francescosaltori@gmail.com>
2023-11-26 22:54:33 +08:00
topjohnwu
0edcb03c45 Update test API levels 2023-11-26 21:41:43 +08:00
canyie
63eef153de Warn about unsupported installation methods 2023-11-17 13:58:41 -08:00
canyie
68442f38ac Misc changes
- actions: Update all actions/checkout references to v4
- magiskboot: Add missing new line to dtb help message
- docs: Update documents, fix some errors and remove outdated info
2023-11-17 13:58:41 -08:00
topjohnwu
8d5b9e5329 C++/Rust 2 way binding for MagiskD 2023-11-17 13:35:50 -08:00
topjohnwu
6c0966b795 Move some global state into Rust 2023-11-16 15:38:38 -08:00
topjohnwu
7c2e93d266 Introduce owned_fd 2023-11-16 15:38:38 -08:00
topjohnwu
1ff7b9055f Add LSPosed launch test 2023-11-16 15:38:38 -08:00
topjohnwu
49f241b77c Allow running scripts with incomplete env 2023-11-10 00:55:05 -08:00
topjohnwu
cfb20b0f86 Zygisk refactoring part 2 2023-11-09 20:55:58 -08:00
topjohnwu
6d6f14fcb3 Use bitflags 2023-11-09 14:35:49 -08:00
topjohnwu
977c981265 Make sure native bridge is restored on daemon restart 2023-11-08 17:55:25 -08:00
topjohnwu
ef48abf19d Reorganize zygisk code 2023-11-08 17:46:39 -08:00
topjohnwu
65c18f9c09 Restructure project files 2023-11-08 01:46:02 -08:00
残页
ecb31eed40 Prevent Zygisk from closing new fds created by Zygote itself 2023-11-08 00:34:38 -08:00
topjohnwu
a80cadf587 Refactor hookJniNativeMethods
Utilize NativeBridgeRuntimeCallbacks we obtained from native bridge
to directly fetch and modify registered native JNI methods.
By doing so, we do not need to keep a copy of every single
JNINativeMethod registered in order to provide JNI hooking
functionality.

Co-authored-by: LoveSy <shana@zju.edu.cn>
2023-11-07 23:57:55 -08:00
LoveSy
fce1bf2365 Obtain NativeBridgeRuntimeCallbacks for future use
NativeBridgeRuntimeCallbacks can be used for better JNI method hooking

Co-authored-by: topjohnwu <topjohnwu@gmail.com>
2023-11-07 16:56:40 -08:00
LoveSy
cbc6d40b2c Clean up codes 2023-11-07 14:25:57 -08:00
LoveSy
9fbd079560 Refactor zygisk to use native bridge to inject
Co-authored-by: vvb2060 <vvb2060@gmail.com>
Co-authored-by: topjohnwu <topjohnwu@gmail.com>
2023-11-07 14:25:57 -08:00
LoveSy
42eb928054 Inject zygisk.rc for sync --zygisk-restart 2023-11-06 15:39:48 -08:00
topjohnwu
577483fde1 Release new canary build 2023-11-05 23:49:35 -08:00
topjohnwu
aa6c7c15cc Update README 2023-11-05 23:44:07 -08:00
120 changed files with 3099 additions and 2954 deletions

44
.github/actions/setup/action.yml vendored Normal file
View File

@@ -0,0 +1,44 @@
name: Magisk Setup
runs:
using: "composite"
steps:
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: "temurin"
java-version: "17"
- name: Set up Python 3
uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Set up sccache
uses: hendrikmuhs/ccache-action@v1.2
with:
variant: sccache
key: ${{ runner.os }}-${{ github.sha }}
restore-keys: ${{ runner.os }}
max-size: 10000M
- name: Cache Gradle dependencies
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
!~/.gradle/caches/build-cache-*
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
restore-keys: ${{ runner.os }}-gradle-
- name: Cache build cache
uses: actions/cache@v4
with:
path: |
~/.gradle/caches/build-cache-*
key: ${{ runner.os }}-build-cache-${{ github.sha }}
restore-keys: ${{ runner.os }}-build-cache-
- name: Set up NDK
run: python build.py -v ndk
shell: bash

View File

@@ -17,12 +17,12 @@ on:
jobs:
build:
name: Build on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
name: Build Magisk artifacts
runs-on: ubuntu-latest
env:
SCCACHE_DIRECT: false
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-13]
steps:
- name: Check out
uses: actions/checkout@v4
@@ -30,99 +30,88 @@ jobs:
submodules: "recursive"
fetch-depth: 0
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
distribution: "temurin"
java-version: "17"
- name: Set up Python 3
uses: actions/setup-python@v4
with:
python-version: "3.x"
- name: Set up sccache
uses: hendrikmuhs/ccache-action@v1.2
with:
variant: sccache
key: ${{ runner.os }}-${{ github.sha }}
restore-keys: ${{ runner.os }}
max-size: 10000M
- name: Cache Gradle dependencies
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
!~/.gradle/caches/build-cache-*
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
restore-keys: ${{ runner.os }}-gradle-
- name: Cache build cache
uses: actions/cache@v3
with:
path: |
~/.gradle/caches/build-cache-*
key: ${{ runner.os }}-build-cache-${{ github.sha }}
restore-keys: ${{ runner.os }}-build-cache-
- name: Set up NDK
run: python build.py -v ndk
- name: Setup environment
uses: ./.github/actions/setup
- name: Build release
run: |
python build.py -vr all
run: ./build.py -vr all
- name: Build debug
run: |
python build.py -v all
run: ./build.py -v all
- name: Stop gradle daemon
run: ./gradlew --stop
# Only upload artifacts built on Linux
- name: Upload build artifact
if: runner.os == 'Linux'
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{ github.sha }}
path: out
compression-level: 9
- name: Upload mapping and native debug symbols
if: runner.os == 'Linux'
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{ github.sha }}-symbols
path: app/build/outputs
compression-level: 9
test-build:
name: Test building on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
env:
SCCACHE_DIRECT: false
strategy:
fail-fast: false
matrix:
os: [windows-latest, macos-14]
steps:
- name: Check out
uses: actions/checkout@v4
with:
submodules: "recursive"
fetch-depth: 0
- name: Setup environment
uses: ./.github/actions/setup
- name: Build debug
run: python build.py -v all
- name: Stop gradle daemon
run: ./gradlew --stop
test:
name: Test on ${{ matrix.api }}
runs-on: macos-13
name: Test on API ${{ matrix.api }}
runs-on: ubuntu-latest
needs: build
strategy:
fail-fast: false
matrix:
api: [23, 26, 28, 29, 34]
api: [23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34]
steps:
- name: Check out
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python 3
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Download build artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: ${{ github.sha }}
path: out
- name: AVD test
- name: Enable KVM group perms
run: |
brew install coreutils bash
scripts/avd_test.sh ${{ matrix.api }}
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: AVD test
run: scripts/avd_test.sh ${{ matrix.api }}

3
.gitmodules vendored
View File

@@ -22,9 +22,6 @@
[submodule "zlib"]
path = native/src/external/zlib
url = https://android.googlesource.com/platform/external/zlib
[submodule "parallel-hashmap"]
path = native/src/external/parallel-hashmap
url = https://github.com/greg7mdp/parallel-hashmap.git
[submodule "zopfli"]
path = native/src/external/zopfli
url = https://github.com/google/zopfli.git

View File

@@ -18,8 +18,8 @@ Some highlight features:
[Github](https://github.com/topjohnwu/Magisk/) is the only source where you can get official Magisk information and downloads.
[![](https://img.shields.io/badge/Magisk-v26.3-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v26.3)
[![](https://img.shields.io/badge/Magisk%20Beta-v26.3-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v26.3)
[![](https://img.shields.io/badge/Magisk-v26.4-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v26.4)
[![](https://img.shields.io/badge/Magisk%20Beta-v26.4-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v26.4)
[![](https://img.shields.io/badge/Magisk-Canary-red)](https://raw.githubusercontent.com/topjohnwu/magisk-files/canary/app-release.apk)
[![](https://img.shields.io/badge/Magisk-Debug-red)](https://raw.githubusercontent.com/topjohnwu/magisk-files/canary/app-debug.apk)

View File

@@ -74,13 +74,13 @@ dependencies {
implementation("com.github.topjohnwu:indeterminate-checkbox:1.0.7")
implementation("com.github.topjohnwu:lz4-java:1.7.1")
implementation("com.jakewharton.timber:timber:5.0.1")
implementation("org.bouncycastle:bcpkix-jdk18on:1.76")
implementation("org.bouncycastle:bcpkix-jdk18on:1.77")
implementation("dev.rikka.rikkax.layoutinflater:layoutinflater:1.3.0")
implementation("dev.rikka.rikkax.insets:insets:1.3.0")
implementation("dev.rikka.rikkax.recyclerview:recyclerview-ktx:1.3.2")
implementation("io.noties.markwon:core:4.6.2")
val vLibsu = "5.2.1"
val vLibsu = "5.2.2"
implementation("com.github.topjohnwu.libsu:core:${vLibsu}")
implementation("com.github.topjohnwu.libsu:service:${vLibsu}")
implementation("com.github.topjohnwu.libsu:nio:${vLibsu}")
@@ -99,12 +99,12 @@ dependencies {
implementation("com.squareup.moshi:moshi:${vMoshi}")
kapt("com.squareup.moshi:moshi-kotlin-codegen:${vMoshi}")
val vRoom = "2.6.0"
val vRoom = "2.6.1"
implementation("androidx.room:room-runtime:${vRoom}")
implementation("androidx.room:room-ktx:${vRoom}")
kapt("androidx.room:room-compiler:${vRoom}")
val vNav = "2.7.4"
val vNav = "2.7.6"
implementation("androidx.navigation:navigation-fragment-ktx:${vNav}")
implementation("androidx.navigation:navigation-ui-ktx:${vNav}")
@@ -112,10 +112,10 @@ dependencies {
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.recyclerview:recyclerview:1.3.2")
implementation("androidx.fragment:fragment-ktx:1.6.1")
implementation("androidx.fragment:fragment-ktx:1.6.2")
implementation("androidx.transition:transition:1.4.1")
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.core:core-splashscreen:1.0.1")
implementation("androidx.profileinstaller:profileinstaller:1.3.1")
implementation("com.google.android.material:material:1.10.0")
implementation("com.google.android.material:material:1.11.0")
}

View File

@@ -165,6 +165,9 @@
<string name="settings_su_reauth_summary">Richiedi nuovamente i permessi di root dopo l\'aggiornamento di un\'app</string>
<string name="settings_su_tapjack_title">Protezione anti-tapjacking</string>
<string name="settings_su_tapjack_summary">La schermata di richiesta dei permessi di root non risponderà al tocco mentre è oscurata da altre finestre o elementi in sovraimpressione</string>
<string name="settings_su_auth_title">Autenticazione utente</string>
<string name="settings_su_auth_summary">Richiedi l\'autenticazione dell\'utente per le richieste di accesso root</string>
<string name="settings_su_auth_insecure">Sul dispositivo non è configurato alcun metodo di autenticazione</string>
<string name="settings_customization">Personalizzazione</string>
<string name="setting_add_shortcut_summary">Aggiungi un collegamento alla schermata iniziale se il nome e l\'icona sono difficili da riconoscere dopo aver nascosto l\'app</string>
<string name="settings_doh_title">DNS over HTTPS</string>

View File

@@ -165,6 +165,9 @@
<string name="settings_su_reauth_summary">アプリのアップグレード後にスーパーユーザー権限を再認証します</string>
<string name="settings_su_tapjack_title">タップジャッキング保護を有効にする</string>
<string name="settings_su_tapjack_summary">他のウィンドウやオーバーレイで表示されている間は、スーパーユーザー権限の要求ダイアログが入力に応答しないようにします</string>
<string name="settings_su_auth_title">ユーザー認証</string>
<string name="settings_su_auth_summary">スーパーユーザー権限の要求でユーザー認証を行ないます</string>
<string name="settings_su_auth_insecure">端末の認証方法が設定されていません</string>
<string name="settings_customization">カスタマイズ</string>
<string name="setting_add_shortcut_summary">アプリを隠した後に見つけられなくなったときは、ここでホーム画面にショートカットを追加できます</string>
<string name="settings_doh_title">DNS over HTTPS</string>

View File

@@ -22,7 +22,7 @@
<string name="home_notice_content">ഔദ്യോഗിക ഗിറ്റ്ഹബ് പേജിൽ നിന്ന് മാത്രം മജിസ്‌ക് ഡൗൺലോഡ് ചെയ്യുക. അജ്ഞാത ഉറവിടങ്ങളിൽ നിന്നുള്ള ഫയലുകൾ ക്ഷുദ്രകരമാകാം!</string>
<string name="home_support_title">ഞങ്ങളെ തുണയ്‌ക്കുക</string>
<string name="home_follow_title">ഞങ്ങളെ പിന്തുടരുക</string>
<string name="home_follow_title">ഞങ്ങളെ ഫോളോ ചെയ്യുക</string>
<string name="home_item_source">സോഴ്സ്</string>
<string name="home_support_content">മജിസ്‌ക് എല്ലായ്പ്പോഴും സ്വതന്ത്രവും ഓപ്പൺ സോഴ്‌സും ആയിരിക്കും. എന്നിരുന്നാലും, ഒരു സംഭാവന നൽകിക്കൊണ്ട് നിങ്ങൾ പിന്തുണയ്ക്കുന്നുവെന്ന് ഞങ്ങളെ കാണിക്കാനാകും.</string>
<string name="home_installed_version">ഇൻസ്റ്റാൾ ചെയ്ത പതിപ്പ്</string>
@@ -58,7 +58,7 @@
<string name="grant">അനുവദിക്കുക</string>
<string name="su_warning">നിങ്ങളുടെ ഉപകരണത്തിലേക്ക് പൂർണ്ണ ആക്‌സസ് നൽകും.\nനിങ്ങൾക്ക് ഉറപ്പില്ലെങ്കിൽ നിരസിക്കുക!</string>
<string name="forever">എന്നേക്കും</string>
<string name="once">ഒരിക്കല്</string>
<string name="once">ഒരിക്ക</string>
<string name="tenmin">10 മിനിറ്റ്</string>
<string name="twentymin">20 മിനിറ്റ്</string>
<string name="thirtymin">30 മിനിറ്റ്</string>
@@ -133,8 +133,8 @@
<string name="settings_update_channel_title">അപ്ഡേറ്റിനുള്ള ചാനൽ</string>
<string name="settings_update_stable">സ്റ്റേബിൾ</string>
<string name="settings_update_beta">ബീറ്റ</string>
<string name="settings_update_custom">കസ്റ്റമ്</string>
<string name="settings_update_custom_msg">കസ്റ്റമ് ചാനലിന്റെ URL ചേർക്കുക</string>
<string name="settings_update_custom">കസ്റ്റ</string>
<string name="settings_update_custom_msg">കസ്റ്റ ചാനലിന്റെ URL ചേർക്കുക</string>
<string name="settings_zygisk_summary">സൈഗോട്ട് ഡെമണിൽ മജിസ്കിന്റെ ഭാഗങ്ങൾ പ്രവർത്തിപ്പിക്കുക</string>
<string name="settings_denylist_title">നിഷിദ്ധ പട്ടിക പ്രാബല്യത്തിലാകുക</string>
<string name="settings_denylist_summary">നിഷിദ്ധ പട്ടികയിലെ പ്രോസസ്സുകൾക്കായി എല്ലാ മജിസ്‌ക് പരിഷ്‌ക്കരണങ്ങളും പഴയപടിയാക്കും</string>
@@ -165,10 +165,10 @@
<string name="settings_su_reauth_summary">ആപ്പുകൾ അപ്‌ഗ്രേഡ് ചെയ്‌തതിന് ശേഷം സൂപ്പർയൂസർ അനുമതികൾക്കായി വീണ്ടും ആവശ്യപ്പെടുക</string>
<string name="settings_su_tapjack_title">ടാപ്പ്ജാക്കിംഗ് സംരക്ഷണം</string>
<string name="settings_su_tapjack_summary">സൂപ്പർയൂസർ പ്രോംപ്റ്റ് ഡയലോഗ് മറ്റേതെങ്കിലും വിൻഡോയോ ഓവർലേയോ മറയ്ക്കുമ്പോൾ ഇൻപുട്ടിനോട് പ്രതികരിക്കില്</string>
<string name="settings_customization">Customization</string>
<string name="settings_customization">കസ്റ്റമയിസേഷൻ</string>
<string name="setting_add_shortcut_summary">ആപ്പ് മറച്ചതിന് ശേഷം പേരും ഐക്കണും തിരിച്ചറിയാൻ പ്രയാസമാണെങ്കിൽ ഹോം സ്‌ക്രീനിലേക്ക് മനോഹരമായ ഒരു ഷോർട്ട്ക്കട് ചേർക്കുക</string>
<string name="settings_doh_title">DNS ഓവർ HTTPS</string>
<string name="settings_doh_description">ചില രാജ്യങ്ങളി DNS പോയ്സണിങിന് പരിഹാരം</string>
<string name="settings_doh_description">ചില രാജ്യങ്ങളിലെ DNS പോയ്സണിങിന് പരിഹാരം</string>
<string name="multiuser_mode">മൾട്ടിയൂസർ മോഡ്</string>
<string name="settings_owner_only">ഉപകരണ ഉടമ മാത്രം</string>
@@ -229,7 +229,7 @@
<string name="external_rw_permission_denied">ഈ പ്രവർത്തനം പ്രവർത്തനക്ഷമമാക്കാൻ സ്റ്റോറജ് ​​അനുമതി നൽകുക</string>
<string name="post_notifications_denied">ഈ പ്രവർത്തനം പ്രവർത്തനക്ഷമമാക്കാൻ അറിയിപ്പ്‌ അനുമതി നൽകുക</string>
<string name="install_unknown_denied">ഈ പ്രവർത്തനം പ്രവർത്തനക്ഷമമാക്കാൻ "install unknown apps" അനുവദിക്കുക</string>
<string name="add_shortcut_title">ഹോം സ്ക്രീനിലേക്ക് ഷോർറ്റ്കറ്റ് ചേർക്കുക</string>
<string name="add_shortcut_title">ഹോം സ്ക്രീനിലേക്ക് ഷോർട്ട്കട്ട് ചേർക്കുക</string>
<string name="add_shortcut_msg">ഈ ആപ്പ് മറച്ചതിന് ശേഷം, അതിന്റെ പേരും ഐക്കണും തിരിച്ചറിയാൻ ബുദ്ധിമുട്ടായേക്കാം. ഹോം സ്‌ക്രീനിലേക്ക് മനോഹരമായ ഒരു ഷോർറ്റ്കറ്റ ചേർക്കാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നുണ്ടോ?</string>
<string name="app_not_found">ഈ പ്രവർത്തനം കൈകാര്യം ചെയ്യാൻ ഒരു ആപ്പും കണ്ടെത്തിയില്ല</string>
<string name="reboot_apply_change">മാറ്റങ്ങൾ പ്രയോഗിക്കാൻ റീബൂട്ട് ചെയ്യുക</string>

View File

@@ -8,7 +8,7 @@
<string name="install">Instaluj</string>
<string name="section_home">Strona główna</string>
<string name="section_theme">Motywy</string>
<string name="denylist">Lista odmów</string>
<string name="denylist">Lista odmów (DenyList)</string>
<!--Home-->
<string name="no_connection">Połączenie niedostępne</string>
@@ -28,8 +28,8 @@
<string name="home_installed_version">Zainstalowany</string>
<string name="home_latest_version">Ostatni</string>
<string name="invalid_update_channel">Nieprawidłowy kanał aktualizacji</string>
<string name="uninstall_magisk_title">Odinstaluj Magisk</string>
<string name="uninstall_magisk_msg">Wszystkie moduły zostaną wyłączone/usunięte!\nRoot zostanie usunięty!\nTwoje dane mogą zostać potencjalnie zaszyfrowane, jeśli jeszcze nie są!</string>
<string name="uninstall_magisk_title">Odinstalowywanie Magisk</string>
<string name="uninstall_magisk_msg">Wszystkie moduły zostaną wyłączone/usunięte!\nRoot zostanie usunięty!\nWszelka wewnętrzna pamięć niezaszyfrowana w związku z użytkowaniem Magisk zostanie ponownie zaszyfrowana!</string>
<!--Install-->
<string name="keep_force_encryption">Zachowaj force encryption (wymuszenie szyfrowania)</string>
@@ -40,23 +40,23 @@
<string name="install_method_title">Metoda</string>
<string name="install_next">Dalej</string>
<string name="install_start">Zaczynajmy</string>
<string name="manager_download_install">Naciśnij, aby pobrać i zainstalować</string>
<string name="manager_download_install">Kliknij, aby pobrać i zainstalować</string>
<string name="direct_install">Bezpośrednia instalacja (zalecana)</string>
<string name="install_inactive_slot">Zainstaluj w nieaktywnym gnieździe (po OTA)</string>
<string name="install_inactive_slot_msg">Po restarcie twoje urządzenie zostanie ZMUSZONE do rozruchu z aktualnie nieaktywnego gniazda!\nUżyj tej opcji wyłącznie po ukończeniu aktualizacji OTA.\nKontynuować?</string>
<string name="install_inactive_slot">Zainstaluj w nieaktywnym slocie (po OTA)</string>
<string name="install_inactive_slot_msg">Po ponownym uruchomieniu twoje urządzenie zostanie ZMUSZONE do rozruchu z aktualnie nieaktywnego slotu!\nUżywaj tej opcji tylko po ukończeniu aktualizacji OTA.\nKontynuować?</string>
<string name="setup_title">Dodatkowa konfiguracja</string>
<string name="select_patch_file">Wybierz i załataj plik</string>
<string name="patch_file_msg">Wybierz obraz raw (*.img) lub plik tar ODIN (*.tar)</string>
<string name="patch_file_msg">Wybierz obraz raw (*.img) lub plik tar ODIN (*.tar) lub payload.bin (*.bin)</string>
<string name="reboot_delay_toast">Ponowne uruchomienie za 5 sekund…</string>
<string name="flash_screen_title">Instalacja</string>
<!--Superuser-->
<string name="su_request_title">Żądanie dostępu do Superusera</string>
<string name="touch_filtered_warning">Ponieważ zapytanie o Superuser aplikacji jest przysłonięte, Magisk nie może zweryfikować twojej odpowiedzi.</string>
<string name="touch_filtered_warning">Ponieważ aplikacja zasłania żądanie o Superusera, Magisk nie może zweryfikować twojej odpowiedzi</string>
<string name="deny">Odmów</string>
<string name="prompt">Zapytaj</string>
<string name="grant">Zezwól</string>
<string name="su_warning">Udziela pełnego dostępu do urządzenia.\nOdmów jeśli nie jesteś pewien!</string>
<string name="su_warning">Udziela pełnego dostępu do urządzenia.\nOdmów, jeżeli nie jesteś pewien!</string>
<string name="forever">Zawsze</string>
<string name="once">Raz</string>
<string name="tenmin">10 min</string>
@@ -66,28 +66,31 @@
<string name="su_allow_toast">%1$s otrzymał uprawnienia Superusera</string>
<string name="su_deny_toast">%1$s odmówiono uprawnień Superusera</string>
<string name="su_snack_grant">Przyznano uprawnienia Superusera dla %1$s</string>
<string name="su_snack_deny">Odmówiono uprawnień Superusera dla %1$s</string>
<string name="su_snack_deny">Unieważniono uprawnienia Superusera dla %1$s</string>
<string name="su_snack_notif_on">Włączono powiadomienia dla %1$s</string>
<string name="su_snack_notif_off">Wyłączono powiadomienia dla %1$s</string>
<string name="su_snack_log_on">Włączono logowanie dla %1$s</string>
<string name="su_snack_log_off">Wyłączono logowanie dla %1$s</string>
<string name="su_revoke_title">Odwołać?</string>
<string name="su_revoke_msg">Potwierdzasz odwołanie uprawnień dla %1$s?</string>
<string name="su_revoke_title">Unieważnić?</string>
<string name="su_revoke_msg">Potwierdź, aby unieważnić uprawnienia Superusera dla %1$s</string>
<string name="toast">Wyskakujące powiadomienie</string>
<string name="none">Brak</string>
<string name="superuser_toggle_notification">Powiadomienia</string>
<string name="superuser_toggle_revoke">Odwołaj</string>
<string name="superuser_toggle_revoke">Unieważnij</string>
<string name="superuser_policy_none">Żadna aplikacja nie poprosiła jeszcze o uprawnienia Superusera.</string>
<!--Logs-->
<string name="log_data_none">Logi są puste, spróbuj użyć aplikacji wymagających roota.</string>
<string name="log_data_magisk_none">Logi Magisk są puste, to jest dziwne.</string>
<string name="log_data_none">Nie masz żadnych logów, spróbuj użyć aplikacji wymagających roota</string>
<string name="log_data_magisk_none">Logi Magisk są puste, to jest dziwne</string>
<string name="menuSaveLog">Zapisz log</string>
<string name="menuClearLog">Wyczyść log</string>
<string name="logs_cleared">Log został pomyślnie wyczyszczony.</string>
<string name="logs_cleared">Log został pomyślnie wyczyszczony</string>
<string name="pid">PID: %1$d</string>
<string name="target_uid">Docelowy UID: %1$d</string>
<string name="target_pid">Docelowy PID p.n. montowania: %s</string>
<string name="selinux_context">Kontekst SELinux: %s</string>
<string name="supp_group">Grupa uzupełniająca: %s</string>
<!--SafetyNet-->
@@ -98,7 +101,7 @@
<string name="hide_search">Szukaj</string>
<!--Module -->
<string name="no_info_provided">(Nie umieszczono informacji)</string>
<string name="no_info_provided">(Brak informacji)</string>
<string name="reboot_userspace">Miękki reboot</string>
<string name="reboot_recovery">Reboot do trybu Recovery</string>
<string name="reboot_bootloader">Reboot do trybu Bootloader</string>
@@ -109,11 +112,11 @@
<string name="module_state_restore">Przywróć</string>
<string name="module_action_install_external">Zainstaluj z pamięci</string>
<string name="update_available">Dostępna aktualizacja</string>
<string name="suspend_text_riru">Moduł uśpiony ponieważ %1$s jest włączony</string>
<string name="suspend_text_zygisk">Moduł uśpiony ponieważ %1$s jest wyłączony</string>
<string name="zygisk_module_unloaded">Moduł Zygisk nie załadowany ze względu na niekompatybilność</string>
<string name="module_empty">Żaden moduł nie jest zainstalowany</string>
<string name="confirm_install">Zainstaloać moduł %1$s?</string>
<string name="suspend_text_riru">Moduł jest zawieszony, ponieważ %1$s jest włączony</string>
<string name="suspend_text_zygisk">Moduł jest zawieszony, ponieważ %1$s nie jest włączony</string>
<string name="zygisk_module_unloaded">Moduł Zygisk nie został załadowany z powodu niekompatybilności</string>
<string name="module_empty">Brak zainstalowanych modułów</string>
<string name="confirm_install">Zainstalować moduł %1$s?</string>
<string name="confirm_install_title">Potwierdzenie instalacji</string>
<!--Settings -->
@@ -125,7 +128,7 @@
<string name="settings_download_path_title">Ścieżka pobierania plików</string>
<string name="settings_download_path_message">Pliki zostaną zapisane do %1$s</string>
<string name="settings_hide_app_title">Ukryj aplikację Magisk</string>
<string name="settings_hide_app_summary">Zainstaluj aplikację z losowym ID pakietu i własną etykietą.</string>
<string name="settings_hide_app_summary">Zainstaluj aplikację proxy z losowym ID pakietu i własną etykietą</string>
<string name="settings_restore_app_title">Przywróć aplikację Magisk</string>
<string name="settings_restore_app_summary">Przestań ukrywać aplikację i przywróć oryginalny plik APK</string>
<string name="language">Język</string>
@@ -137,18 +140,18 @@
<string name="settings_update_beta">Beta</string>
<string name="settings_update_custom">Własny kanał</string>
<string name="settings_update_custom_msg">Wprowadź adres URL własnego kanału</string>
<string name="settings_zygisk_summary">Uruchom cześć Magiska w zygocie Demona</string>
<string name="settings_denylist_title">Wymuś Listę Odmów</string>
<string name="settings_denylist_summary">Procesy z Listy Odmów będą miały wszystkie modyfikacje Magisk cofnięte</string>
<string name="settings_denylist_error">Ta funkcja wymaga aby %1$s było włączone</string>
<string name="settings_denylist_config_title">Ustaw Listę Odmów</string>
<string name="settings_denylist_config_summary">Wybierz proces który ma zostać zawarty w Liście Odmów</string>
<string name="settings_zygisk_summary">Uruchom część Magisk w demonie zygote</string>
<string name="settings_denylist_title">Egzekwowanie listy odmów (DenyList)</string>
<string name="settings_denylist_summary">Procesy znajdujące się na liście odmów (DenyList) będą miały cofnięte wszystkie modyfikacje Magisk</string>
<string name="settings_denylist_error">Ta funkcja wymaga, aby %1$s było włączone</string>
<string name="settings_denylist_config_title">Konfiguracja listy odmów (DenyList)</string>
<string name="settings_denylist_config_summary">Wybierz procesy, które mają się znajdować na liście odmów (DenyList)</string>
<string name="settings_hosts_title">Hosty Systemless</string>
<string name="settings_hosts_summary">Wsparcie hostów Systemless dla aplikacji typu Adblock</string>
<string name="settings_hosts_summary">Wsparcie hostów Systemless dla aplikacji blokujących reklamy</string>
<string name="settings_hosts_toast">Dodano moduł hostów Systemless</string>
<string name="settings_app_name_hint">Nowa nazwa</string>
<string name="settings_app_name_helper">Aplikacja zostanie przepakowana do tej nazwy</string>
<string name="settings_app_name_error">Błędny format</string>
<string name="settings_app_name_helper">Aplikacja zostanie przepakowana z tą nazwą</string>
<string name="settings_app_name_error">Nieprawidłowy format</string>
<string name="settings_su_app_adb">Aplikacje i ADB</string>
<string name="settings_su_app">Tylko aplikacje</string>
<string name="settings_su_adb">Tylko ADB</string>
@@ -164,20 +167,23 @@
<string name="request_timeout">Limit czasu żądania</string>
<string name="superuser_notification">Powiadomienia Superusera</string>
<string name="settings_su_reauth_title">Ponowienie uwierzytelniania po aktualizacji</string>
<string name="settings_su_reauth_summary">Ponowienie dostępu do uprawnień Superusera po uaktualnieniu aplikacji</string>
<string name="settings_su_tapjack_title">Włącz ochronę przed Tapjacking (niezamierzone kliknięcie)</string>
<string name="settings_su_tapjack_summary">Pytanie o Superuser nie będzie reagować na odpowiedź jeżeli będzie zasłonięte lub przyćmione.</string>
<string name="settings_su_reauth_summary">Zapytaj ponownie o uprawnienia Superusera po uaktualnieniu aplikacji</string>
<string name="settings_su_tapjack_title">Ochrona przed Tapjackingiem (niezamierzonym kliknięciem)</string>
<string name="settings_su_tapjack_summary">Okno dialogowe z żądaniem Superusera nie będzie reagować na odpowiedź, jeżeli będzie zasłonięte przez inne okno lub nakładkę</string>
<string name="settings_su_auth_title">Uwierzytelnianie użytkownika</string>
<string name="settings_su_auth_summary">Pytaj o uwierzytelnienie użytkownika podczas żądań Superusera</string>
<string name="settings_su_auth_insecure">Nie skonfigurowano żadnej metody uwierzytelniania na tym urządzeniu</string>
<string name="settings_customization">Personalizacja</string>
<string name="setting_add_shortcut_summary">Dodaj ładny skrót na ekranie głównym na wypadek, gdyby nazwa i ikona były trudne do rozpoznania po ukryciu aplikacji</string>
<string name="setting_add_shortcut_summary">Umieść ładny skrót na ekranie głównym na wypadek, gdyby nazwa i ikona były trudne do rozpoznania po ukryciu aplikacji</string>
<string name="settings_doh_title">DNS over HTTPS</string>
<string name="settings_doh_description">Zapobiegaj zatruwaniu DNS (DNS poisoning) w niektórych krajach</string>
<string name="multiuser_mode">Tryb wielu użytkowników (Multiuser)</string>
<string name="settings_owner_only">Tylko właściciel urządzenia</string>
<string name="settings_owner_manage">Zarządzanie przez właściciela urządzenia</string>
<string name="settings_user_independent">Niezależni użytkownicy</string>
<string name="settings_user_independent">Niezależne ustawienia użytkowników</string>
<string name="owner_only_summary">Tylko właściciel ma dostęp do roota</string>
<string name="owner_manage_summary">Tylko właściciel może zarządzać ustawieniami dostępu do roota i otrzymywać żądania dostępu</string>
<string name="owner_manage_summary">Tylko właściciel może zarządzać dostępem do roota i otrzymywać żądania dostępu do roota</string>
<string name="user_independent_summary">Każdy użytkownik ma niezależne ustawienia dostępu do roota</string>
<string name="mount_namespace_mode">Tryb przestrzeni nazw montowania</string>
@@ -185,7 +191,7 @@
<string name="settings_ns_requester">Dziedziczona przestrzeń nazw</string>
<string name="settings_ns_isolate">Izolowana przestrzeń nazw</string>
<string name="global_summary">Wszystkie sesje roota będą używać globalnej przestrzeni nazw montowania</string>
<string name="requester_summary">Sesje roota odziedziczą przestrzeń nazw od żądającego</string>
<string name="requester_summary">Sesje roota odziedziczą przestrzeń nazw żądającego dostępu</string>
<string name="isolate_summary">Każda sesja roota otrzyma własną, izolowaną przestrzeń nazw</string>
<!--Notifications-->
@@ -196,7 +202,7 @@
<string name="download_file_error">Błąd pobierania pliku</string>
<string name="magisk_update_title">Aktualizacja Magisk dostępna!</string>
<string name="updated_title">Magisk zaktualizowany</string>
<string name="updated_text">Naciśnij aby otworzyć applikację</string>
<string name="updated_text">Kliknij, aby otworzyć aplikację</string>
<!--Toasts, Dialogs-->
<string name="yes">Tak</string>
@@ -208,7 +214,7 @@
<string name="flashing">Flashowanie…</string>
<string name="done">Gotowe!</string>
<string name="failure">Błąd</string>
<string name="hide_app_title">Ukrywam aplikację Magisk…</string>
<string name="hide_app_title">Ukrywanie aplikacji Magisk…</string>
<string name="open_link_failed_toast">Nie znaleziono aplikacji do otwarcia linku</string>
<string name="complete_uninstall">Odinstaluj całkowicie</string>
<string name="restore_img">Przywróć obrazy</string>
@@ -216,26 +222,26 @@
<string name="restore_done">Przywracanie zakończone!</string>
<string name="restore_fail">Kopia zapasowa nie istnieje!</string>
<string name="setup_fail">Konfiguracja nieudana</string>
<string name="env_fix_title">Wymaga dodatkowej konfiguracji</string>
<string name="env_fix_msg">Twoje urządzenie wymaga dodatkowej konfiguracji aby Magisk działał właściwie. Czy chcesz kontynuować i uruchomić ponownie?</string>
<string name="env_full_fix_msg">Twoje urządzenie musi wgrać ponowanie Magisk, aby działać poprawnie. Proszę przeinstaluj Magisk w aplikacji, tryb Recovery nie potrafi poprawnie rozpoznać urządzenia.</string>
<string name="env_fix_title">Wymagana dodatkowa konfiguracja</string>
<string name="env_fix_msg">Twoje urządzenie wymaga dodatkowej konfiguracji, aby Magisk działał poprawnie. Czy chcesz kontynuować i uruchomić ponownie?</string>
<string name="env_full_fix_msg">Twoje urządzenie wymaga ponownej instalacji Magisk, aby działać poprawnie. Zainstaluj ponownie Magisk używając aplikacji, tryb recovery nie może uzyskać prawidłowych informacji o urządzeniu.</string>
<string name="setup_msg">Uruchamianie środowiska konfiguracji…</string>
<string name="authenticate">Uwierzytelnianie</string>
<string name="unsupport_magisk_title">Nieobsługiwana wersja Magisk</string>
<string name="unsupport_magisk_msg">Ta wersja aplikacji nie obsługuje Magisk w wersji niższej niż %1$s.\n\nAplikacja będzie zachowywać się tak jakby Magisk nie był zainstalowany, proszę uaktualnij Magisk.</string>
<string name="unsupport_magisk_msg">Ta wersja aplikacji nie obsługuje Magisk w wersji niższej niż %1$s.\n\nAplikacja będzie zachowywać się tak, jakby Magisk nie był zainstalowany, zaktualizuj Magisk tak szybko, jak to możliwe.</string>
<string name="unsupport_general_title">Nieprawidłowy stan</string>
<string name="unsupport_system_app_msg">Uruchomienie tej aplikacji jako systemowa nie jest obsługiwane. Proszę przemienić ją na aplikację użytkownika.</string>
<string name="unsupport_other_su_msg">Wykryto komendę \"su\" nie należącą do Magisk. Proszę usunąć tę drugą aplikację \"su\".</string>
<string name="unsupport_external_storage_msg">Zainstalowano Magisk na pamięci zewnętrznej. Proszę przenieść ją na pamięć wewnętrzną.</string>
<string name="unsupport_nonroot_stub_msg">Ta aplikacja nie może dłużej działać w trybie ukrycia jako że root został utracony. Proszę przywrócić ją do oryginalnego stanu.</string>
<string name="unsupport_system_app_msg">Uruchomienie tej aplikacji jako aplikacja systemowa nie jest obsługiwane. Przywróć aplikację do stanu aplikacji użytkownika.</string>
<string name="unsupport_other_su_msg">Wykryto plik binarny \"su\" nie należący do Magisk. Usuń wszelkie konkurencyjne rozwiązania root i/lub zainstaluj ponownie Magisk.</string>
<string name="unsupport_external_storage_msg">Magisk jest zainstalowany w pamięci zewnętrznej. Przenieś aplikację do pamięci wewnętrznej.</string>
<string name="unsupport_nonroot_stub_msg">Ukryta aplikacja Magisk nie może dłużej działać, ponieważ uprawnienia roota zostały utracone. Przywróć oryginalny plik APK.</string>
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">Zezwól na dostęp do pamięci wewnętrznej, aby włączyć tę funkcję.</string>
<string name="post_notifications_denied">Zezwól na otrzymywanie powiadomień, aby aktywować tą funkcję</string>
<string name="install_unknown_denied">Zezwól na "Instaluj z nieznanych źródeł" by włączyć tą funkcję</string>
<string name="external_rw_permission_denied">Zezwól na dostęp do pamięci, aby włączyć tę funkcję</string>
<string name="post_notifications_denied">Zezwól na otrzymywanie powiadomień, aby włączyć tę funkcję</string>
<string name="install_unknown_denied">Zezwól na \"Instaluj z nieznanych źródeł\", aby włączyć tę funkcję</string>
<string name="add_shortcut_title">Utwórz skrót na ekranie głównym</string>
<string name="add_shortcut_msg">Po ukryciu tej aplikacji, jej nazwa i ikona może być trudna do rozpoznania. Czy chcesz dodać ładny skrót na ekranie głównym?</string>
<string name="app_not_found">Nie znaleziono aplikacji do wykonania tej czynności</string>
<string name="reboot_apply_change">Uruchom ponownie by zastosować zmiany</string>
<string name="restore_app_confirmation">To przywróci ukrytą aplikację z powrotem do orginalnej aplikacji. Czy na pewno chcesz to zrobić?</string>
<string name="reboot_apply_change">Uruchom ponownie, aby zastosować zmiany</string>
<string name="restore_app_confirmation">Spowoduje to przywrócenie ukrytej aplikacji z powrotem do stanu oryginalnej aplikacji. Czy na pewno chcesz to zrobić?</string>
</resources>

View File

@@ -6,20 +6,20 @@
<string name="logs">Registros</string>
<string name="settings">Configurações</string>
<string name="install">Instalar</string>
<string name="section_home">Resumo</string>
<string name="section_home">Início</string>
<string name="section_theme">Temas</string>
<string name="denylist">Lista de Negação</string>
<string name="denylist">Lista de negação</string>
<!--Home-->
<string name="no_connection">Nenhuma conexão disponível</string>
<string name="app_changelog">Registro de alterações</string>
<string name="loading">Carregando…</string>
<string name="update">Atualizar</string>
<string name="not_available">N/A</string>
<string name="not_available">Não disponível</string>
<string name="hide">Ocultar</string>
<string name="home_package">Pacote</string>
<string name="home_app_title">App</string>
<string name="home_notice_content">Baixe o Magisk SOMENTE pela página oficial do Github. Arquivos de fontes desconhecidas podem ser maliciosos e danificar seu aparelho.</string>
<string name="home_notice_content">Baixe o Magisk SOMENTE pela página oficial do GitHub. Arquivos de fontes desconhecidas podem ser maliciosos e podem danificar seu aparelho!</string>
<string name="home_support_title">Apoie</string>
<string name="home_follow_title">Siga</string>
<string name="home_item_source">Fonte</string>
@@ -28,13 +28,13 @@
<string name="home_latest_version">Recente</string>
<string name="invalid_update_channel">Canal de atualização inválido</string>
<string name="uninstall_magisk_title">Desinstalar Magisk</string>
<string name="uninstall_magisk_msg">Todos os módulos serão desativados/removidos!\nA raiz será removida!\nSeus dados não criptografados devido uso do Magisk, serão re-criptografados!</string>
<string name="uninstall_magisk_msg">Todos os módulos serão desativados/removidos!\nO root será removido!\nSeus dados não criptografados devido ao uso do Magisk, serão re-criptografados!</string>
<!--Install-->
<string name="keep_force_encryption">Manter criptografia forçada</string>
<string name="keep_dm_verity">Manter AVB 2.0/dm-verity</string>
<string name="patch_vbmeta">Corrigir vbmeta na imagem de boot</string>
<string name="recovery_mode">Modo de recuperação</string>
<string name="recovery_mode">Modo Recovery</string>
<string name="install_options_title">Opções</string>
<string name="install_method_title">Método</string>
<string name="install_next">Próximo</string>
@@ -51,7 +51,7 @@
<!--Superuser-->
<string name="su_request_title">Solicitação de SuperUsuário</string>
<string name="touch_filtered_warning">Devido um app estar obscurecendo a solicitação de SuperUsuário, o Magisk não pode conferir suas resposta</string>
<string name="touch_filtered_warning">Como um app está ocultando uma solicitação de SuperUsuário, o Magisk não pode verificar sua resposta.</string>
<string name="deny">Negar</string>
<string name="prompt">Perguntar</string>
<string name="grant">Permitir</string>
@@ -62,28 +62,28 @@
<string name="twentymin">20 mins</string>
<string name="thirtymin">30 mins</string>
<string name="sixtymin">60 mins</string>
<string name="su_allow_toast">%1$s foi permitido o acesso SuperUsuário</string>
<string name="su_deny_toast">%1$s foi negado o acesso SuperUsuário</string>
<string name="su_allow_toast">%1$s foi permitido o acesso de SuperUsuário</string>
<string name="su_deny_toast">%1$s foi negado o acesso de SuperUsuário</string>
<string name="su_snack_grant">Os acessos de SuperUsuário de %1$s foram permitidos</string>
<string name="su_snack_deny">Os acessos de SuperUsuário de %1$s foram negados</string>
<string name="su_snack_notif_on">As notificações de %1$s foram ativadas</string>
<string name="su_snack_notif_off">As notificações de %1$s foram desativadas</string>
<string name="su_snack_log_on">Os registros de %1$s foram ativados</string>
<string name="su_snack_log_off">Os registros de %1$s foram desativados</string>
<string name="su_revoke_title">Remover?</string>
<string name="su_revoke_msg">Confirmar a remoção do acesso de %1$s?</string>
<string name="su_revoke_title">Revogar?</string>
<string name="su_revoke_msg">Confirmar a remoção do acesso de SuperUsuário de %1$s?</string>
<string name="toast">Notificação (Pop-up)</string>
<string name="none">Nenhum</string>
<string name="superuser_toggle_notification">Notificações</string>
<string name="superuser_toggle_revoke">Remover</string>
<string name="superuser_policy_none">Nenhum app solicitou permissão de SuperUsuário ainda.</string>
<string name="superuser_toggle_revoke">Revogar</string>
<string name="superuser_policy_none">Nenhum app solicitou permissão de SuperUsuário ainda</string>
<!--Logs-->
<string name="log_data_none">Não há registros. Tente usar os apps permitidos para SuperUsuário.</string>
<string name="log_data_magisk_none">Os Registro de atividade do Magisk estão vazios, isso é estranho.</string>
<string name="menuSaveLog">Salvar Registro</string>
<string name="menuClearLog">Limpar Registro agora</string>
<string name="logs_cleared">Registro limpo com sucesso.</string>
<string name="log_data_none">Não há registros. Tente usar mais seus apps root.</string>
<string name="log_data_magisk_none">Os registros do Magisk estão vazios, isso é estranho.</string>
<string name="menuSaveLog">Salvar registros</string>
<string name="menuClearLog">Limpar registros agora</string>
<string name="logs_cleared">Registros limpo com sucesso</string>
<string name="pid">PID: %1$d</string>
<string name="target_uid">Alvo UID: %1$d</string>
<string name="target_pid">Alvo PID: %s</string>
@@ -91,10 +91,10 @@
<string name="supp_group">Grupo suplementar: %s</string>
<!--MagiskHide-->
<string name="show_system_app">Mostrar apps do Sistema</string>
<string name="show_os_app">Mostrar apps do Sistema</string>
<string name="show_system_app">Mostrar apps do sistema</string>
<string name="show_os_app">Mostrar apps do sistema operacional</string>
<string name="hide_filter_hint">Filtrar pelo nome</string>
<string name="hide_search">Pesquisa</string>
<string name="hide_search">Pesquisar</string>
<!--Module-->
<string name="no_info_provided">(Nenhuma informação fornecida)</string>
@@ -108,48 +108,48 @@
<string name="module_state_restore">Restaurar</string>
<string name="module_action_install_external">Instalar a partir do armazenamento</string>
<string name="update_available">Atualização disponível</string>
<string name="suspend_text_riru">Módulo suspenso porque %1$s está ativo</string>
<string name="suspend_text_zygisk">Módulo suspenso porque %1$s não está ativo</string>
<string name="suspend_text_riru">Módulo suspenso porque %1$s está ativado</string>
<string name="suspend_text_zygisk">Módulo suspenso porque %1$s não está ativado</string>
<string name="zygisk_module_unloaded">Modulo Zygisk não carregado devido a incompatibilidade</string>
<string name="module_empty">Nenhum módulo instalado</string>
<string name="confirm_install">Instalar módulo %1$s?</string>
<string name="confirm_install_title">Confirmação de Instalação</string>
<string name="confirm_install_title">Confirmação de instalação</string>
<!--Settings-->
<string name="settings_dark_mode_title">Modo de tema</string>
<string name="settings_dark_mode_title">Modo do tema</string>
<string name="settings_dark_mode_message">Selecione o modo mais adequado ao seu estilo!</string>
<string name="settings_dark_mode_light">Sempre Claro</string>
<string name="settings_dark_mode_system">Baseado no Sistema</string>
<string name="settings_dark_mode_dark">Sempre Escuro</string>
<string name="settings_download_path_title">Caminho para Baixar</string>
<string name="settings_dark_mode_light">Sempre claro</string>
<string name="settings_dark_mode_system">Mesmo do sistema</string>
<string name="settings_dark_mode_dark">Sempre escuro</string>
<string name="settings_download_path_title">Caminho para baixar</string>
<string name="settings_download_path_message">Os arquivos serão salvos em %1$s</string>
<string name="settings_hide_app_title">Ocultar o app do Magisk</string>
<string name="settings_hide_app_summary">Instala o app oculto com ID aleatório e nome personalizado</string>
<string name="settings_restore_app_title">Restaurar o App do Magisk</string>
<string name="settings_restore_app_title">Restaurar o app do Magisk</string>
<string name="settings_restore_app_summary">Desoculta o app do Magisk e restaura o APK original</string>
<string name="language">Idioma</string>
<string name="system_default">(Padrão do sistema)</string>
<string name="settings_check_update_title">Ativar Verificação de Atualizações</string>
<string name="settings_check_update_summary">Verifica periodicamente em segundo plano se há atualizações</string>
<string name="settings_update_channel_title">Canal de Atualização</string>
<string name="settings_check_update_title">Verificar atualizações</string>
<string name="settings_check_update_summary">Verifica periodicamente se há atualizações em segundo plano</string>
<string name="settings_update_channel_title">Canal de atualização</string>
<string name="settings_update_stable">Estável</string>
<string name="settings_update_beta">Beta</string>
<string name="settings_update_custom">Canal Personalizado</string>
<string name="settings_update_custom_msg">Insira um URL personalizado</string>
<string name="settings_update_custom">Personalizado</string>
<string name="settings_update_custom_msg">Insira um URL de canal personalizado</string>
<string name="settings_zygisk_summary">Executa partes do Magisk no Zygote</string>
<string name="settings_denylist_title">Forçar Aplicação da Lista de Negação</string>
<string name="settings_denylist_summary">Os processos na lista de negação terão revertidas todas as modificações feitas pelo Magisk</string>
<string name="settings_denylist_title">Aplicar Lista de negação</string>
<string name="settings_denylist_summary">Os processos na Lista de negação terão todas as modificações do Magisk revertidas</string>
<string name="settings_denylist_error">Isso requer %1$s para ser ativado</string>
<string name="settings_denylist_config_title">Configurar Lista de Negação</string>
<string name="settings_denylist_config_summary">Selecione os processos a serem incluídos na lista de negação</string>
<string name="settings_hosts_title">Ativar /etc/hosts systemless</string>
<string name="settings_hosts_summary">Suporte de /etc/hosts fora do sistema para aplicativos Adblock</string>
<string name="settings_hosts_toast">Adicionado módulo do /etc/hosts systemless</string>
<string name="settings_denylist_config_title">Configurar Lista de negação</string>
<string name="settings_denylist_config_summary">Selecione os processos a serem incluídos na Lista de negação</string>
<string name="settings_hosts_title">Hosts fora do sistema</string>
<string name="settings_hosts_summary">Suporte de /etc/hosts fora do sistema para apps Adblock</string>
<string name="settings_hosts_toast">Adicionado módulo de /etc/hosts fora do sistema</string>
<string name="settings_app_name_hint">Novo nome</string>
<string name="settings_app_name_helper">O app do Magisk será reinstalado com este nome</string>
<string name="settings_app_name_error">Formato inválido</string>
<string name="settings_su_app_adb">Aplicativos e ADB</string>
<string name="settings_su_app">Apenas aplicativos</string>
<string name="settings_su_app_adb">Apps e ADB</string>
<string name="settings_su_app">Apenas apps</string>
<string name="settings_su_adb">Apenas ADB</string>
<string name="settings_su_disable">Desativado</string>
<string name="settings_su_request_10">10 segundos</string>
@@ -160,30 +160,33 @@
<string name="settings_su_request_60">60 segundos</string>
<string name="superuser_access">Acesso de SuperUsuário</string>
<string name="auto_response">Resposta automática</string>
<string name="request_timeout">Tempo Limite da Solicitação</string>
<string name="request_timeout">Tempo limite da solicitação</string>
<string name="superuser_notification">Notificação de SuperUsuário</string>
<string name="settings_su_reauth_title">Autenticar novamente após a atualização</string>
<string name="settings_su_reauth_summary">Reautenticar permissões de SuperUsuário após atualizar aplicativo</string>
<string name="settings_su_tapjack_title">Ativar Proteção Contra Atividades Sobrepostas</string>
<string name="settings_su_tapjack_summary">A caixa de diálogo do SuperUsuário não responderá à entrada enquanto estiver obscurecida por qualquer outra janela ou sobreposição</string>
<string name="settings_su_reauth_title">Reautenticar após atualização</string>
<string name="settings_su_reauth_summary">Reautenticar permissões de SuperUsuário após atualizar os apps</string>
<string name="settings_su_tapjack_title">Proteção contra atividades sobrepostas</string>
<string name="settings_su_tapjack_summary">A caixa de diálogo do SuperUsuário não responderá à entrada enquanto estiver oculta por qualquer outra janela ou sobreposição</string>
<string name="settings_su_auth_title">Autenticação de usuário</string>
<string name="settings_su_auth_summary">Solicite autenticação de usuário durante solicitações de SuperUsuário</string>
<string name="settings_su_auth_insecure">Nenhum método de autenticação está configurado no dispositivo</string>
<string name="settings_customization">Personalizações</string>
<string name="setting_add_shortcut_summary">Adicione um atalho na tela inicial, caso o nome e o ícone sejam difíceis de reconhecer logo após ocultar o aplicativo</string>
<string name="settings_doh_title">Ativar DNS sobre HTTPS</string>
<string name="setting_add_shortcut_summary">Adicione um atalho na tela inicial, caso o nome e o ícone sejam difíceis de reconhecer logo após ocultar o app.</string>
<string name="settings_doh_title">DNS sobre HTTPS</string>
<string name="settings_doh_description">Solução alternativa para envenenamento de DNS em alguns países</string>
<string name="multiuser_mode">Ativar Modo Multiusuário</string>
<string name="multiuser_mode">Modo Multiusuário</string>
<string name="settings_owner_only">Somente proprietário do dispositivo</string>
<string name="settings_owner_manage">Gerenciado pelo proprietário do dispositivo</string>
<string name="settings_user_independent">Independente do usuário</string>
<string name="owner_only_summary">Somente o proprietário tem acesso ao SuperUsuário</string>
<string name="owner_manage_summary">Somente o proprietário pode gerenciar o acesso do SuperUsuário e receber pedidos de solicitação</string>
<string name="owner_only_summary">Somente o proprietário tem acesso root</string>
<string name="owner_manage_summary">Somente o proprietário pode gerenciar o acesso root e receber pedidos de solicitação</string>
<string name="user_independent_summary">Cada usuário tem suas próprias regras de root separadas</string>
<string name="mount_namespace_mode">Ativar Modo Namespace</string>
<string name="mount_namespace_mode">Montar modo Namespace</string>
<string name="settings_ns_global">Namespace global</string>
<string name="settings_ns_requester">Herdar Namespace</string>
<string name="settings_ns_isolate">Namespace isolado</string>
<string name="global_summary">Todas as sessões root usam o namespace de montagem global</string>
<string name="requester_summary">As sessões root herdarão o namespace do solicitante</string>
<string name="isolate_summary">Cada sessão do SuperUsuário terá seu próprio namespace isolado</string>
<string name="isolate_summary">Cada sessão root terá seu próprio namespace isolado</string>
<!--Notifications-->
<string name="update_channel">Atualizações do Magisk</string>
@@ -191,8 +194,8 @@
<string name="updated_channel">Atualização concluída</string>
<string name="download_complete">Download concluído</string>
<string name="download_file_error">Erro ao baixar arquivo</string>
<string name="magisk_update_title">Nova atualização do Magisk disponível!</string>
<string name="updated_title">Magisk Atualizado</string>
<string name="magisk_update_title">Atualização do Magisk disponível!</string>
<string name="updated_title">Magisk atualizado</string>
<string name="updated_text">Toque para abrir o app</string>
<!--Toasts, Dialogs-->
@@ -202,35 +205,35 @@
<string name="download">Baixar</string>
<string name="reboot">Reiniciar</string>
<string name="release_notes">Notas da atualização</string>
<string name="flashing">Fazendo Flash…</string>
<string name="flashing">Flashando</string>
<string name="done">Concluído!</string>
<string name="failure">Falha</string>
<string name="failure">Falha!</string>
<string name="hide_app_title">Ocultando o app do Magisk…</string>
<string name="open_link_failed_toast">Nenhum app encontrado para abrir o link</string>
<string name="complete_uninstall">Desinstalação completa</string>
<string name="restore_img">Restaurar imagens</string>
<string name="restore_img_msg">Restaurando…</string>
<string name="restore_done">Restauração concluída!</string>
<string name="restore_fail">O backup original não foi encontrado!</string>
<string name="restore_fail">O backup original não existe!</string>
<string name="setup_fail">Falha na instalação</string>
<string name="env_fix_title">Configuração adicional exigida</string>
<string name="env_fix_msg">Seu dispositivo exige uma configuração adicional para o Magisk funcionar corretamente. Deseja continuar e reiniciar?</string>
<string name="env_full_fix_msg">Seu dispositivo precisa refazer o flash do Magisk para funcionar corretamente. Reinstale o Magisk no aplicativo, o modo de recuperação não pode obter as devidas informações do dispositivo.</string>
<string name="env_full_fix_msg">Seu dispositivo precisa refazer o flash do Magisk para funcionar corretamente. Por favor, reinstale o Magisk no app, o modo Recovery não pode obter as devidas informações do dispositivo.</string>
<string name="setup_msg">Executando a configuração do ambiente…</string>
<string name="authenticate">Autenticar</string>
<string name="unsupport_magisk_title">Versão do Magisk não suportada</string>
<string name="unsupport_magisk_msg">Essa versão do app não suporta versão do Magisk inferior a %1$s.\n\nO app irá se comportar como se nenhum Magisk estivesse sido instalado. Por favor, atualize o Magisk assim que possível.</string>
<string name="unsupport_general_title">Estado Anormal</string>
<string name="unsupport_system_app_msg">Não há suporte para executar este app como um app do sistema. Por favor, reverta o app para um app do usuário.</string>
<string name="unsupport_magisk_msg">Esta versão do app não suporta a versão do Magisk inferior a %1$s.\n\nO app irá se comportar como se nenhum Magisk estivesse sido instalado. Por favor, atualize o Magisk assim que possível.</string>
<string name="unsupport_general_title">Estado anormal</string>
<string name="unsupport_system_app_msg">Não há suporte para executar este app como um app do sistema. Por favor, reverta o app para um app de usuário.</string>
<string name="unsupport_other_su_msg">Não foi possível detectar o binário \"su\" do Magisk. Por favor, remova qualquer outro root concorrente e/ou reinstale o Magisk.</string>
<string name="unsupport_external_storage_msg">O app do Magisk está instalado no armazenamento externo, Por favor, mova o app para o armazenamento interno.</string>
<string name="unsupport_nonroot_stub_msg">O app oculto do Magisk não pode continuar a funcionar porque o SuperUsuário foi perdido. Por favor, restaure o APK original.</string>
<string name="unsupport_external_storage_msg">O app do Magisk está instalado no armazenamento externo. Por favor, mova o app para o armazenamento interno.</string>
<string name="unsupport_nonroot_stub_msg">O app oculto do Magisk não pode continuar funcionando porque o root foi perdido. Por favor, restaure o APK original.</string>
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">Autorize a permissão de armazenamento para ativar esta funcionalidade</string>
<string name="post_notifications_denied">Autorize a permissão de notificaçoes para ativar esta funcionalidade</string>
<string name="install_unknown_denied">Permita a "instalação apps desconhecidos" para ativar esta funcionalidade</string>
<string name="add_shortcut_title">Adicionar Atalho à Tela Inicial</string>
<string name="add_shortcut_msg">Depois de ocultar o app do Magisk, o seu nome e ícone ficarão difíceis de reconhecer. Deseja adicionar um atalho na tela inicial?</string>
<string name="external_rw_permission_denied">Conceda permissão de armazenamento para ativar esta funcionalidade</string>
<string name="post_notifications_denied">Conceda permissão às notificações para ativar esta funcionalidade</string>
<string name="install_unknown_denied">Permita a opção "Instalar apps de fontes desconhecidas" para ativar esta funcionalidade</string>
<string name="add_shortcut_title">Adicionar atalho à tela inicial</string>
<string name="add_shortcut_msg">Após ocultar o app do Magisk, seu nome e ícone ficarão difíceis de reconhecer. Deseja adicionar um atalho na tela inicial?</string>
<string name="app_not_found">Nenhum app encontrado para realizar esta ação</string>
<string name="reboot_apply_change">Reinicie para aplicar as mudanças</string>
<string name="restore_app_confirmation">Isso irá restaurar o app oculto do Magisk de volta para o app original. Deseja realmente fazer isso?</string>

View File

@@ -6,20 +6,20 @@
<string name="logs">Registros</string>
<string name="settings">Configurações</string>
<string name="install">Instalar</string>
<string name="section_home">Resumo</string>
<string name="section_home">Início</string>
<string name="section_theme">Temas</string>
<string name="denylist">Lista de Negação</string>
<string name="denylist">Lista de negação</string>
<!--Home-->
<string name="no_connection">Nenhuma conexão disponível</string>
<string name="app_changelog">Registro de alterações</string>
<string name="loading">Carregando…</string>
<string name="update">Atualizar</string>
<string name="not_available">N/A</string>
<string name="not_available">Não disponível</string>
<string name="hide">Ocultar</string>
<string name="home_package">Pacote</string>
<string name="home_app_title">App</string>
<string name="home_notice_content">Baixe o Magisk SOMENTE pela página oficial do Github. Arquivos de fontes desconhecidas podem ser maliciosos e danificar seu aparelho.</string>
<string name="home_notice_content">Baixe o Magisk SOMENTE pela página oficial do GitHub. Arquivos de fontes desconhecidas podem ser maliciosos e podem danificar seu aparelho!</string>
<string name="home_support_title">Apoie</string>
<string name="home_follow_title">Siga</string>
<string name="home_item_source">Fonte</string>
@@ -28,13 +28,13 @@
<string name="home_latest_version">Recente</string>
<string name="invalid_update_channel">Canal de atualização inválido</string>
<string name="uninstall_magisk_title">Desinstalar Magisk</string>
<string name="uninstall_magisk_msg">Todos os módulos serão desativados/removidos!\nA raiz será removida!\nSeus dados não criptografados devido uso do Magisk, serão re-criptografados!</string>
<string name="uninstall_magisk_msg">Todos os módulos serão desativados/removidos!\nO root será removido!\nSeus dados não criptografados devido ao uso do Magisk, serão re-criptografados!</string>
<!--Install-->
<string name="keep_force_encryption">Manter criptografia forçada</string>
<string name="keep_dm_verity">Manter AVB 2.0/dm-verity</string>
<string name="patch_vbmeta">Corrigir vbmeta na imagem de boot</string>
<string name="recovery_mode">Modo de recuperação</string>
<string name="recovery_mode">Modo Recovery</string>
<string name="install_options_title">Opções</string>
<string name="install_method_title">Método</string>
<string name="install_next">Próximo</string>
@@ -51,7 +51,7 @@
<!--Superuser-->
<string name="su_request_title">Solicitação de SuperUsuário</string>
<string name="touch_filtered_warning">Devido um app estar obscurecendo a solicitação de SuperUsuário, o Magisk não pode conferir suas resposta</string>
<string name="touch_filtered_warning">Como um app está ocultando uma solicitação de SuperUsuário, o Magisk não pode verificar sua resposta.</string>
<string name="deny">Negar</string>
<string name="prompt">Perguntar</string>
<string name="grant">Permitir</string>
@@ -62,28 +62,28 @@
<string name="twentymin">20 mins</string>
<string name="thirtymin">30 mins</string>
<string name="sixtymin">60 mins</string>
<string name="su_allow_toast">%1$s foi permitido o acesso SuperUsuário</string>
<string name="su_deny_toast">%1$s foi negado o acesso SuperUsuário</string>
<string name="su_allow_toast">%1$s foi permitido o acesso de SuperUsuário</string>
<string name="su_deny_toast">%1$s foi negado o acesso de SuperUsuário</string>
<string name="su_snack_grant">Os acessos de SuperUsuário de %1$s foram permitidos</string>
<string name="su_snack_deny">Os acessos de SuperUsuário de %1$s foram negados</string>
<string name="su_snack_notif_on">As notificações de %1$s foram ativadas</string>
<string name="su_snack_notif_off">As notificações de %1$s foram desativadas</string>
<string name="su_snack_log_on">Os registros de %1$s foram ativados</string>
<string name="su_snack_log_off">Os registros de %1$s foram desativados</string>
<string name="su_revoke_title">Remover?</string>
<string name="su_revoke_msg">Confirmar a remoção do acesso de %1$s?</string>
<string name="su_revoke_title">Revogar?</string>
<string name="su_revoke_msg">Confirmar a remoção do acesso de SuperUsuário de %1$s?</string>
<string name="toast">Notificação (Pop-up)</string>
<string name="none">Nenhum</string>
<string name="superuser_toggle_notification">Notificações</string>
<string name="superuser_toggle_revoke">Remover</string>
<string name="superuser_policy_none">Nenhum app solicitou permissão de SuperUsuário ainda.</string>
<string name="superuser_toggle_revoke">Revogar</string>
<string name="superuser_policy_none">Nenhum app solicitou permissão de SuperUsuário ainda</string>
<!--Logs-->
<string name="log_data_none">Não há registros. Tente usar os apps permitidos para SuperUsuário.</string>
<string name="log_data_magisk_none">Os Registro de atividade do Magisk estão vazios, isso é estranho.</string>
<string name="menuSaveLog">Salvar Registro</string>
<string name="menuClearLog">Limpar Registro agora</string>
<string name="logs_cleared">Registro limpo com sucesso.</string>
<string name="log_data_none">Não há registros. Tente usar mais seus apps root.</string>
<string name="log_data_magisk_none">Os registros do Magisk estão vazios, isso é estranho.</string>
<string name="menuSaveLog">Salvar registros</string>
<string name="menuClearLog">Limpar registros agora</string>
<string name="logs_cleared">Registros limpo com sucesso</string>
<string name="pid">PID: %1$d</string>
<string name="target_uid">Alvo UID: %1$d</string>
<string name="target_pid">Alvo PID: %s</string>
@@ -91,10 +91,10 @@
<string name="supp_group">Grupo suplementar: %s</string>
<!--MagiskHide-->
<string name="show_system_app">Mostrar apps do Sistema</string>
<string name="show_os_app">Mostrar apps do Sistema</string>
<string name="show_system_app">Mostrar apps do sistema</string>
<string name="show_os_app">Mostrar apps do sistema operacional</string>
<string name="hide_filter_hint">Filtrar pelo nome</string>
<string name="hide_search">Pesquisa</string>
<string name="hide_search">Pesquisar</string>
<!--Module-->
<string name="no_info_provided">(Nenhuma informação fornecida)</string>
@@ -108,48 +108,48 @@
<string name="module_state_restore">Restaurar</string>
<string name="module_action_install_external">Instalar a partir do armazenamento</string>
<string name="update_available">Atualização disponível</string>
<string name="suspend_text_riru">Módulo suspenso porque %1$s está ativo</string>
<string name="suspend_text_zygisk">Módulo suspenso porque %1$s não está ativo</string>
<string name="suspend_text_riru">Módulo suspenso porque %1$s está ativado</string>
<string name="suspend_text_zygisk">Módulo suspenso porque %1$s não está ativado</string>
<string name="zygisk_module_unloaded">Modulo Zygisk não carregado devido a incompatibilidade</string>
<string name="module_empty">Nenhum módulo instalado</string>
<string name="confirm_install">Instalar módulo %1$s?</string>
<string name="confirm_install_title">Confirmação de Instalação</string>
<string name="confirm_install_title">Confirmação de instalação</string>
<!--Settings-->
<string name="settings_dark_mode_title">Modo de tema</string>
<string name="settings_dark_mode_title">Modo do tema</string>
<string name="settings_dark_mode_message">Selecione o modo mais adequado ao seu estilo!</string>
<string name="settings_dark_mode_light">Sempre Claro</string>
<string name="settings_dark_mode_system">Baseado no Sistema</string>
<string name="settings_dark_mode_dark">Sempre Escuro</string>
<string name="settings_download_path_title">Caminho para Baixar</string>
<string name="settings_dark_mode_light">Sempre claro</string>
<string name="settings_dark_mode_system">Mesmo do sistema</string>
<string name="settings_dark_mode_dark">Sempre escuro</string>
<string name="settings_download_path_title">Caminho para baixar</string>
<string name="settings_download_path_message">Os arquivos serão salvos em %1$s</string>
<string name="settings_hide_app_title">Ocultar o app do Magisk</string>
<string name="settings_hide_app_summary">Instala o app oculto com ID aleatório e nome personalizado</string>
<string name="settings_restore_app_title">Restaurar o App do Magisk</string>
<string name="settings_restore_app_title">Restaurar o app do Magisk</string>
<string name="settings_restore_app_summary">Desoculta o app do Magisk e restaura o APK original</string>
<string name="language">Idioma</string>
<string name="system_default">(Padrão do sistema)</string>
<string name="settings_check_update_title">Ativar Verificação de Atualizações</string>
<string name="settings_check_update_summary">Verifica periodicamente em segundo plano se há atualizações</string>
<string name="settings_update_channel_title">Canal de Atualização</string>
<string name="settings_check_update_title">Verificar atualizações</string>
<string name="settings_check_update_summary">Verifica periodicamente se há atualizações em segundo plano</string>
<string name="settings_update_channel_title">Canal de atualização</string>
<string name="settings_update_stable">Estável</string>
<string name="settings_update_beta">Beta</string>
<string name="settings_update_custom">Canal Personalizado</string>
<string name="settings_update_custom_msg">Insira um URL personalizado</string>
<string name="settings_update_custom">Personalizado</string>
<string name="settings_update_custom_msg">Insira um URL de canal personalizado</string>
<string name="settings_zygisk_summary">Executa partes do Magisk no Zygote</string>
<string name="settings_denylist_title">Forçar Aplicação da Lista de Negação</string>
<string name="settings_denylist_summary">Os processos na lista de negação terão revertidas todas as modificações feitas pelo Magisk</string>
<string name="settings_denylist_title">Aplicar Lista de negação</string>
<string name="settings_denylist_summary">Os processos na Lista de negação terão todas as modificações do Magisk revertidas</string>
<string name="settings_denylist_error">Isso requer %1$s para ser ativado</string>
<string name="settings_denylist_config_title">Configurar Lista de Negação</string>
<string name="settings_denylist_config_summary">Selecione os processos a serem incluídos na lista de negação</string>
<string name="settings_hosts_title">Ativar /etc/hosts systemless</string>
<string name="settings_hosts_summary">Suporte de /etc/hosts fora do sistema para aplicativos Adblock</string>
<string name="settings_hosts_toast">Adicionado módulo do /etc/hosts systemless</string>
<string name="settings_denylist_config_title">Configurar Lista de negação</string>
<string name="settings_denylist_config_summary">Selecione os processos a serem incluídos na Lista de negação</string>
<string name="settings_hosts_title">Hosts fora do sistema</string>
<string name="settings_hosts_summary">Suporte de /etc/hosts fora do sistema para apps Adblock</string>
<string name="settings_hosts_toast">Adicionado módulo de /etc/hosts fora do sistema</string>
<string name="settings_app_name_hint">Novo nome</string>
<string name="settings_app_name_helper">O app do Magisk será reinstalado com este nome</string>
<string name="settings_app_name_error">Formato inválido</string>
<string name="settings_su_app_adb">Aplicativos e ADB</string>
<string name="settings_su_app">Apenas aplicativos</string>
<string name="settings_su_app_adb">Apps e ADB</string>
<string name="settings_su_app">Apenas apps</string>
<string name="settings_su_adb">Apenas ADB</string>
<string name="settings_su_disable">Desativado</string>
<string name="settings_su_request_10">10 segundos</string>
@@ -160,30 +160,33 @@
<string name="settings_su_request_60">60 segundos</string>
<string name="superuser_access">Acesso de SuperUsuário</string>
<string name="auto_response">Resposta automática</string>
<string name="request_timeout">Tempo Limite da Solicitação</string>
<string name="request_timeout">Tempo limite da solicitação</string>
<string name="superuser_notification">Notificação de SuperUsuário</string>
<string name="settings_su_reauth_title">Autenticar novamente após a atualização</string>
<string name="settings_su_reauth_summary">Reautenticar permissões de SuperUsuário após atualizar aplicativo</string>
<string name="settings_su_tapjack_title">Ativar Proteção Contra Atividades Sobrepostas</string>
<string name="settings_su_tapjack_summary">A caixa de diálogo do SuperUsuário não responderá à entrada enquanto estiver obscurecida por qualquer outra janela ou sobreposição</string>
<string name="settings_su_reauth_title">Reautenticar após atualização</string>
<string name="settings_su_reauth_summary">Reautenticar permissões de SuperUsuário após atualizar os apps</string>
<string name="settings_su_tapjack_title">Proteção contra atividades sobrepostas</string>
<string name="settings_su_tapjack_summary">A caixa de diálogo do SuperUsuário não responderá à entrada enquanto estiver oculta por qualquer outra janela ou sobreposição</string>
<string name="settings_su_auth_title">Autenticação de usuário</string>
<string name="settings_su_auth_summary">Solicite autenticação de usuário durante solicitações de SuperUsuário</string>
<string name="settings_su_auth_insecure">Nenhum método de autenticação está configurado no dispositivo</string>
<string name="settings_customization">Personalizações</string>
<string name="setting_add_shortcut_summary">Adicione um atalho na tela inicial, caso o nome e o ícone sejam difíceis de reconhecer logo após ocultar o aplicativo</string>
<string name="settings_doh_title">Ativar DNS sobre HTTPS</string>
<string name="setting_add_shortcut_summary">Adicione um atalho na tela inicial, caso o nome e o ícone sejam difíceis de reconhecer logo após ocultar o app.</string>
<string name="settings_doh_title">DNS sobre HTTPS</string>
<string name="settings_doh_description">Solução alternativa para envenenamento de DNS em alguns países</string>
<string name="multiuser_mode">Ativar Modo Multiusuário</string>
<string name="multiuser_mode">Modo Multiusuário</string>
<string name="settings_owner_only">Somente proprietário do dispositivo</string>
<string name="settings_owner_manage">Gerenciado pelo proprietário do dispositivo</string>
<string name="settings_user_independent">Independente do usuário</string>
<string name="owner_only_summary">Somente o proprietário tem acesso ao SuperUsuário</string>
<string name="owner_manage_summary">Somente o proprietário pode gerenciar o acesso do SuperUsuário e receber pedidos de solicitação</string>
<string name="owner_only_summary">Somente o proprietário tem acesso root</string>
<string name="owner_manage_summary">Somente o proprietário pode gerenciar o acesso root e receber pedidos de solicitação</string>
<string name="user_independent_summary">Cada usuário tem suas próprias regras de root separadas</string>
<string name="mount_namespace_mode">Ativar Modo Namespace</string>
<string name="mount_namespace_mode">Montar modo Namespace</string>
<string name="settings_ns_global">Namespace global</string>
<string name="settings_ns_requester">Herdar Namespace</string>
<string name="settings_ns_isolate">Namespace isolado</string>
<string name="global_summary">Todas as sessões root usam o namespace de montagem global</string>
<string name="requester_summary">As sessões root herdarão o namespace do solicitante</string>
<string name="isolate_summary">Cada sessão do SuperUsuário terá seu próprio namespace isolado</string>
<string name="isolate_summary">Cada sessão root terá seu próprio namespace isolado</string>
<!--Notifications-->
<string name="update_channel">Atualizações do Magisk</string>
@@ -191,8 +194,8 @@
<string name="updated_channel">Atualização concluída</string>
<string name="download_complete">Download concluído</string>
<string name="download_file_error">Erro ao baixar arquivo</string>
<string name="magisk_update_title">Nova atualização do Magisk disponível!</string>
<string name="updated_title">Magisk Atualizado</string>
<string name="magisk_update_title">Atualização do Magisk disponível!</string>
<string name="updated_title">Magisk atualizado</string>
<string name="updated_text">Toque para abrir o app</string>
<!--Toasts, Dialogs-->
@@ -202,35 +205,35 @@
<string name="download">Baixar</string>
<string name="reboot">Reiniciar</string>
<string name="release_notes">Notas da atualização</string>
<string name="flashing">Fazendo Flash…</string>
<string name="flashing">Flashando</string>
<string name="done">Concluído!</string>
<string name="failure">Falha</string>
<string name="failure">Falha!</string>
<string name="hide_app_title">Ocultando o app do Magisk…</string>
<string name="open_link_failed_toast">Nenhum app encontrado para abrir o link</string>
<string name="complete_uninstall">Desinstalação completa</string>
<string name="restore_img">Restaurar imagens</string>
<string name="restore_img_msg">Restaurando…</string>
<string name="restore_done">Restauração concluída!</string>
<string name="restore_fail">O backup original não foi encontrado!</string>
<string name="restore_fail">O backup original não existe!</string>
<string name="setup_fail">Falha na instalação</string>
<string name="env_fix_title">Configuração adicional exigida</string>
<string name="env_fix_msg">Seu dispositivo exige uma configuração adicional para o Magisk funcionar corretamente. Deseja continuar e reiniciar?</string>
<string name="env_full_fix_msg">Seu dispositivo precisa refazer o flash do Magisk para funcionar corretamente. Reinstale o Magisk no aplicativo, o modo de recuperação não pode obter as devidas informações do dispositivo.</string>
<string name="env_full_fix_msg">Seu dispositivo precisa refazer o flash do Magisk para funcionar corretamente. Por favor, reinstale o Magisk no app, o modo Recovery não pode obter as devidas informações do dispositivo.</string>
<string name="setup_msg">Executando a configuração do ambiente…</string>
<string name="authenticate">Autenticar</string>
<string name="unsupport_magisk_title">Versão do Magisk não suportada</string>
<string name="unsupport_magisk_msg">Essa versão do app não suporta versão do Magisk inferior a %1$s.\n\nO app irá se comportar como se nenhum Magisk estivesse sido instalado. Por favor, atualize o Magisk assim que possível.</string>
<string name="unsupport_general_title">Estado Anormal</string>
<string name="unsupport_system_app_msg">Não há suporte para executar este app como um app do sistema. Por favor, reverta o app para um app do usuário.</string>
<string name="unsupport_magisk_msg">Esta versão do app não suporta a versão do Magisk inferior a %1$s.\n\nO app irá se comportar como se nenhum Magisk estivesse sido instalado. Por favor, atualize o Magisk assim que possível.</string>
<string name="unsupport_general_title">Estado anormal</string>
<string name="unsupport_system_app_msg">Não há suporte para executar este app como um app do sistema. Por favor, reverta o app para um app de usuário.</string>
<string name="unsupport_other_su_msg">Não foi possível detectar o binário \"su\" do Magisk. Por favor, remova qualquer outro root concorrente e/ou reinstale o Magisk.</string>
<string name="unsupport_external_storage_msg">O app do Magisk está instalado no armazenamento externo, Por favor, mova o app para o armazenamento interno.</string>
<string name="unsupport_nonroot_stub_msg">O app oculto do Magisk não pode continuar a funcionar porque o SuperUsuário foi perdido. Por favor, restaure o APK original.</string>
<string name="unsupport_external_storage_msg">O app do Magisk está instalado no armazenamento externo. Por favor, mova o app para o armazenamento interno.</string>
<string name="unsupport_nonroot_stub_msg">O app oculto do Magisk não pode continuar funcionando porque o root foi perdido. Por favor, restaure o APK original.</string>
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">Autorize a permissão de armazenamento para ativar esta funcionalidade</string>
<string name="post_notifications_denied">Autorize a permissão de notificaçoes para ativar esta funcionalidade</string>
<string name="install_unknown_denied">Permita a "instalação apps desconhecidos" para ativar esta funcionalidade</string>
<string name="add_shortcut_title">Adicionar Atalho à Tela Inicial</string>
<string name="add_shortcut_msg">Depois de ocultar o app do Magisk, o seu nome e ícone ficarão difíceis de reconhecer. Deseja adicionar um atalho na tela inicial?</string>
<string name="external_rw_permission_denied">Conceda permissão de armazenamento para ativar esta funcionalidade</string>
<string name="post_notifications_denied">Conceda permissão às notificações para ativar esta funcionalidade</string>
<string name="install_unknown_denied">Permita a opção "Instalar apps de fontes desconhecidas" para ativar esta funcionalidade</string>
<string name="add_shortcut_title">Adicionar atalho à tela inicial</string>
<string name="add_shortcut_msg">Após ocultar o app do Magisk, seu nome e ícone ficarão difíceis de reconhecer. Deseja adicionar um atalho na tela inicial?</string>
<string name="app_not_found">Nenhum app encontrado para realizar esta ação</string>
<string name="reboot_apply_change">Reinicie para aplicar as mudanças</string>
<string name="restore_app_confirmation">Isso irá restaurar o app oculto do Magisk de volta para o app original. Deseja realmente fazer isso?</string>

View File

@@ -246,7 +246,7 @@ def run_ndk_build(flags):
error("Build binary failed!")
os.chdir("..")
for arch in archs:
for tgt in support_targets + ["libinit-ld.so", "libzygisk-ld.so"]:
for tgt in support_targets + ["libinit-ld.so"]:
source = op.join("native", "libs", arch, tgt)
target = op.join("native", "out", arch, tgt)
mv(source, target)
@@ -256,7 +256,7 @@ def run_cargo(cmds, triple="aarch64-linux-android"):
env = os.environ.copy()
env["PATH"] = f'{rust_bin}{os.pathsep}{env["PATH"]}'
env["CARGO_BUILD_RUSTC"] = op.join(rust_bin, "rustc" + EXE_EXT)
env["RUSTFLAGS"] = "-Clinker-plugin-lto"
env["RUSTFLAGS"] = f"-Clinker-plugin-lto -Zthreads={min(8, cpu_count)}"
env["TARGET_CC"] = op.join(llvm_bin, "clang" + EXE_EXT)
env["TARGET_CFLAGS"] = f"--target={triple}23"
return execv([cargo, *cmds], env)
@@ -342,9 +342,6 @@ def dump_bin_header(args):
preload = op.join("native", "out", arch, "libinit-ld.so")
with open(preload, "rb") as src:
text = binary_dump(src, "init_ld_xz")
preload = op.join("native", "out", arch, "libzygisk-ld.so")
with open(preload, "rb") as src:
text += binary_dump(src, "zygisk_ld", compressor=lambda x: x)
write_if_diff(op.join(native_gen_path, f"{arch}_binaries.h"), text)
@@ -395,8 +392,9 @@ def build_binary(args):
flag = ""
clean = False
if "magisk" in args.target or "magiskinit" in args.target:
flag += " B_PRELOAD=1"
if "magisk" in args.target:
flag += " B_MAGISK=1"
clean = True
if "magiskpolicy" in args.target:
flag += " B_POLICY=1"
@@ -417,14 +415,10 @@ def build_binary(args):
if flag:
run_ndk_build(flag)
# magiskinit and magisk embeds preload.so
# magiskinit embeds preload.so
flag = ""
if "magisk" in args.target:
flag += " B_MAGISK=1"
clean = True
if "magiskinit" in args.target:
flag += " B_INIT=1"

View File

@@ -17,8 +17,8 @@ gradlePlugin {
dependencies {
implementation(embeddedKotlin("gradle-plugin"))
implementation("com.android.tools.build:gradle:8.1.2")
implementation("androidx.navigation:navigation-safe-args-gradle-plugin:2.7.4")
implementation("com.android.tools.build:gradle:8.2.1")
implementation("androidx.navigation:navigation-safe-args-gradle-plugin:2.7.6")
implementation("org.lsposed.lsparanoid:gradle-plugin:0.5.2")
implementation("org.eclipse.jgit:org.eclipse.jgit:6.7.0.202309050840-r")
}

View File

@@ -72,6 +72,7 @@ fun Project.setupCommon() {
compileSdkVersion(34)
buildToolsVersion = "34.0.0"
ndkPath = "$sdkDirectory/ndk/magisk"
ndkVersion = "26.1.10909125"
defaultConfig {
minSdk = 23

View File

@@ -1,5 +1,13 @@
# Magisk Changelog
### v27.0
- [Zygisk] Introduce new code injection mechanism
- [Zygisk] Support new signature introduced in U QPR2
- [SEPolicy] Update libsepol to properly set some policy config bits
- [MagiskBoot] Support compressing `init` so Magisk is installable on devices with small boot partitions
- [ResetProp] Add new wait for property feature `resetprop -w`
### v26.4
- [MagiskBoot] Don't pad zeros if signed boot image is larger

View File

@@ -110,4 +110,4 @@ Before Android 8.0, all allowed su client domains are allowed to directly connec
After Android 8.0, to reduce relaxation of rules in Android's sandbox, a new SELinux model is deployed. The `magisk` binary is labelled with `magisk_exec` file type, and processes running as allowed su client domains executing the `magisk` binary (this includes the `su` command) will transit to `magisk_client` by using a `type_transition` rule. Rules strictly restrict that only `magisk` domain processes are allowed to attribute files to `magisk_exec`. Direct connection to sockets of `magiskd` are not allowed; the only way to access the daemon is through a `magisk_client` process. These changes allow us to keep the sandbox intact, and keep Magisk specific rules separated from the rest of the policies.
The full set of rules can be found in `magiskpolicy/rules.cpp`.
The full set of rules can be found in `sepolicy/rules.cpp`.

View File

@@ -109,7 +109,7 @@ Update JSON format:
#### Shell scripts (`*.sh`)
Please read the [Boot Scripts](#boot-scripts) section to understand the difference between `post-fs-data.sh` and `service.sh`. For most module developers, `service.sh` should be good enough if you just need to run a boot script.
Please read the [Boot Scripts](#boot-scripts) section to understand the difference between `post-fs-data.sh` and `service.sh`. For most module developers, `service.sh` should be good enough if you just need to run a boot script. If you need to wait for boot completed, you can use `resetprop -w sys.boot_completed 0`.
In all scripts of your module, please use `MODDIR=${0%/*}` to get your module's base directory path; do **NOT** hardcode your module path in scripts.
If Zygisk is enabled, the environment variable `ZYGISK_ENABLED` will be set to `1`.
@@ -265,7 +265,7 @@ Overlay files shall be placed in the `overlay.d` folder in boot image ramdisk, a
To add additional files which you can refer to in your custom `*.rc` scripts, add them into `overlay.d/sbin`. The 3 rules above do not apply to anything in this folder; instead, they will be directly copied to Magisk's internal `tmpfs` directory (which used to always be `/sbin`).
Starting from Android 11, the `/sbin` folder may no longer exists, and in that scenario, Magisk randomly generates a different `tmpfs` folder each boot. Every occurrence of the pattern `${MAGISKTMP}` in your `*.rc` scripts will be replaced with the Magisk `tmpfs` folder when `magiskinit` injects it into `init.rc`. On pre Android 11 devices, `${MAGISKTMP}` will simply be replaced with `/sbin`, so **NEVER** hardcode `/sbin` in the `*.rc` scripts when referencing these additional files.
Starting from Android 11, the `/sbin` folder may no longer exists, and in that scenario, Magisk uses `/debug_ramdisk` instead. Every occurrence of the pattern `${MAGISKTMP}` in your `*.rc` scripts will be replaced with the Magisk `tmpfs` folder when `magiskinit` injects it into `init.rc`. On pre Android 11 devices, `${MAGISKTMP}` will simply be replaced with `/sbin`, so **NEVER** hardcode `/sbin` in the `*.rc` scripts when referencing these additional files.
Here is an example of how to setup `overlay.d` with a custom `*.rc` script:

View File

@@ -26,19 +26,10 @@ If your device has boot ramdisk, get a copy of the `boot.img` (or `init_boot.img
If your device does **NOT** have boot ramdisk, get a copy of the `recovery.img`.<br>
You should be able to extract the file you need from official firmware packages or your custom ROM zip.
Next, we need to know whether your device has a separate `vbmeta` partition.
- If your official firmware package contains `vbmeta.img`, then yes, your device **has** a separate `vbmeta` partition
- You can also check by connecting your device to a PC and run the command:<br>
`adb shell ls -l /dev/block/by-name`
- If you find `vbmeta`, `vbmeta_a`, or `vbmeta_b`, then yes, your device **has** a separate `vbmeta` partition
- Otherwise, your device **does not** have a separate `vbmeta` partition.
Quick recap, at this point, you should have known and prepared:
1. Whether your device has boot ramdisk
2. Whether your device has a separate `vbmeta` partition
3. A `boot.img`, `init_boot.img` or `recovery.img` based on (1)
2. A `boot.img`, `init_boot.img` or `recovery.img` based on (1)
Let's continue to [Patching Images](#patching-images).
@@ -47,21 +38,21 @@ Let's continue to [Patching Images](#patching-images).
- Copy the boot/init_boot/recovery image to your device
- Press the **Install** button in the Magisk card
- If you are patching a recovery image, check the **"Recovery Mode"** option
- If your device does **NOT** have a separate `vbmeta` partition, check the **"Patch vbmeta in boot image"** option
- Choose **"Select and Patch a File"** in method, and select the boot/init_boot/recovery image
- Start the installation, and copy the patched image to your PC using ADB:<br>
`adb pull /sdcard/Download/magisk_patched_[random_strings].img`
- Flash the patched boot/init_boot/recovery image to your device;<br>
for most devices, reboot into fastboot mode and flash with command:<br>
`fastboot flash boot[_x] /path/to/magisk_patched_[random_strings].img` or <br>
`fastboot flash init_boot[_x] /path/to/magisk_patched.img_[random_strings]` or <br>
`fastboot flash boot /path/to/magisk_patched_[random_strings].img` or <br>
`fastboot flash init_boot /path/to/magisk_patched.img_[random_strings]` or <br>
`fastboot flash recovery /path/to/magisk_patched.img_[random_strings]`, <br>
where `[_x]` should be `_a` or `_b` or empty depending on your device
- (Optional) If your device has a separate `vbmeta` partition, you can patch the `vbmeta` partition with command:<br>
`fastboot flash vbmeta --disable-verity --disable-verification vbmeta.img` (note that it may **wipe your data**)
- Reboot and launch Magisk app (you will see a stub Magisk app if you have wiped your data; use it to bootstrap to a complete Magisk app), and you will see a prompt asking for environment fix; click and wait for the reboot
- Voila!
> Warning: **NEVER** flash patched image shared by others or patch image on another device even if they have the same device model! You may need to do a full data wipe to recover your device. **ALWAYS** patch boot image **on the same device where you want to install Magisk**.
## Uninstallation
The easiest way to uninstall Magisk is directly through the Magisk app. If you insist on using custom recoveries, rename the Magisk APK to `uninstall.zip` and flash it like any other ordinary flashable zip.

9
docs/releases/27000.md Normal file
View File

@@ -0,0 +1,9 @@
## 2024.2.3 Magisk v27.0
- [Zygisk] Introduce new code injection mechanism
- [Zygisk] Support new signature introduced in U QPR2
- [SEPolicy] Update libsepol to properly set some policy config bits
- [MagiskBoot] Support compressing `init` so Magisk is installable on devices with small boot partitions
- [ResetProp] Add new wait for property feature `resetprop -w`
### Full Changelog: [here](https://topjohnwu.github.io/Magisk/changes.html)

View File

@@ -1,5 +1,6 @@
# Release Notes
- [v27.0](27000.md)
- [v26.4](26400.md)
- [v26.3](26300.md)
- [v26.2](26200.md)

View File

@@ -16,7 +16,7 @@ su -> magisk
A tool to unpack / repack boot images, parse / patch / extract cpio, patch dtb, hex patch binaries, and compress / decompress files with multiple algorithms.
`magiskboot` natively supports (which means it does not rely on external tools) common compression formats including `gzip`, `lz4`, `lz4_legacy` ([only used on LG](https://events.static.linuxfound.org/sites/events/files/lcjpcojp13_klee.pdf)), `lzma`, `xz`, and `bzip2`.
`magiskboot` natively supports (which means it does not rely on external tools) common compression formats including `gzip`, `lz4`, `lz4_legacy` , `lz4_lg` ([the LG edition](https://events.static.linuxfound.org/sites/events/files/lcjpcojp13_klee.pdf) of `lz4_legacy`, only used on LG), `lzma`, `xz`, and `bzip2`.
The concept of `magiskboot` is to make boot image modification simpler. For unpacking, it parses the header and extracts all sections in the image, decompressing on-the-fly if compression is detected in any sections. For repacking, the original boot image is required so the original headers can be used, changing only the necessary entries such as section sizes and checksum. All sections will be compressed back to the original format if required. The tool also supports many CPIO and DTB operations.
@@ -51,6 +51,28 @@ Supported actions:
If env variable PATCHVBMETAFLAG is set to true, all disable flags in
the boot image's vbmeta header will be set.
verify <bootimg> [x509.pem]
Check whether the boot image is signed with AVB 1.0 signature.
Optionally provide a certificate to verify whether the image is
signed by the public key certificate.
Return value:
0:valid 1:error
sign <bootimg> [name] [x509.pem pk8]
Sign <bootimg> with AVB 1.0 signature.
Optionally provide the name of the image (default: '/boot').
Optionally provide the certificate/private key pair for signing.
If the certificate/private key pair is not provided, the AOSP
verity key bundled in the executable will be used.
extract <payload.bin> [partition] [outfile]
Extract [partition] from <payload.bin> to [outfile].
If [outfile] is not specified, then output to '[partition].img'.
If [partition] is not specified, then attempt to extract either
'init_boot' or 'boot'. Which partition was chosen can be determined
by whichever 'init_boot.img' or 'boot.img' exists.
<payload.bin> can be '-' to be STDIN.
hexpatch <file> <hexpattern1> <hexpattern2>
Search <hexpattern1> in <file>, and replace it with <hexpattern2>
@@ -83,8 +105,6 @@ Supported actions:
Create ramdisk backups from ORIG
restore
Restore ramdisk from ramdisk backup stored within incpio
sha1
Print stock boot SHA1 if previously backed up in ramdisk
dtb <file> <action> [args...]
Do dtb related actions to <file>
@@ -222,7 +242,7 @@ Options:
-v print running daemon version
-V print running daemon version code
--list list all available applets
--remove-modules remove all modules and reboot
--remove-modules [-n] remove all modules, reboot if -n is not provided
--install-module ZIP install a module zip file
Advanced Options (Internal APIs):
@@ -237,6 +257,7 @@ Advanced Options (Internal APIs):
--sqlite SQL exec SQL commands to Magisk database
--path print Magisk tmpfs mount path
--denylist ARGS denylist config CLI
--preinit-device resolve a device to store preinit files
Available applets:
su, resetprop
@@ -261,20 +282,24 @@ An applet of `magisk`, the MagiskSU entry point. Good old `su` command.
Usage: su [options] [-] [user [argument...]]
Options:
-c, --command COMMAND pass COMMAND to the invoked shell
-h, --help display this help message and exit
-, -l, --login pretend the shell to be a login shell
-c, --command COMMAND Pass COMMAND to the invoked shell
-g, --group GROUP Specify the primary group
-G, --supp-group GROUP Specify a supplementary group.
The first specified supplementary group is also used
as a primary group if the option -g is not specified.
-Z, --context CONTEXT Change SELinux context
-t, --target PID PID to take mount namespace from
-h, --help Display this help message and exit
-, -l, --login Pretend the shell to be a login shell
-m, -p,
--preserve-environment preserve the entire environment
-s, --shell SHELL use SHELL instead of the default /system/bin/sh
-v, --version display version number and exit
-V display version code and exit
--preserve-environment Preserve the entire environment
-s, --shell SHELL Use SHELL instead of the default /system/bin/sh
-v, --version Display version number and exit
-V Display version code and exit
-mm, -M,
--mount-master force run in the global mount namespace
--mount-master Force run in the global mount namespace
```
Note: even though the `-Z, --context` option is not listed above, the option still exists for CLI compatibility with apps designed for SuperSU. However the option is silently ignored since it's no longer relevant.
### resetprop
An applet of `magisk`. An advanced system property manipulation utility. Check the [Resetprop Details](details.md#resetprop) for more background information.

View File

@@ -27,5 +27,5 @@ android.nonFinalResIds=false
# Magisk
magisk.stubVersion=38
magisk.versionCode=26400
magisk.ondkVersion=r26.1
magisk.versionCode=27000
magisk.ondkVersion=r26.3

Binary file not shown.

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

20
gradlew.bat vendored
View File

@@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail

View File

@@ -7,19 +7,3 @@ target = "aarch64-linux-android"
build-std = ["std", "panic_abort"]
build-std-features = ["panic_immediate_abort"]
profile-rustflags = true
# Workaround bug for undefined symbol errors that occur with the
# combination of `-Zbuild-std`, `opt-level = "z"`, and `lto = true`.
# compiler_builtins are expected to be built with special flags.
# https://github.com/rust-lang/rust/issues/108853
# https://github.com/rust-lang/wg-cargo-std-aware/issues/62
[profile.release.package.compiler_builtins]
rustflags = ["-Zshare-generics=off"]
overflow-checks = false
debug-assertions = false
[profile.dev.package.compiler_builtins]
rustflags = ["-Zshare-generics=off"]
overflow-checks = false
debug-assertions = false

View File

@@ -8,6 +8,7 @@ LIBRARY_PATH = ../out/$(TARGET_ARCH_ABI)/libmagisk-rs.a
ifneq (,$(wildcard $(LOCAL_PATH)/$(LIBRARY_PATH)))
include $(CLEAR_VARS)
LOCAL_MODULE := magisk-rs
LOCAL_EXPORT_C_INCLUDES := src/core/include
LOCAL_SRC_FILES := $(LIBRARY_PATH)
include $(PREBUILT_STATIC_LIBRARY)
endif

View File

@@ -11,7 +11,6 @@ LOCAL_MODULE := magisk
LOCAL_STATIC_LIBRARIES := \
libbase \
libsystemproperties \
libphmap \
liblsplt \
libmagisk-rs
@@ -27,20 +26,19 @@ LOCAL_SRC_FILES := \
core/selinux.cpp \
core/module.cpp \
core/thread.cpp \
core/resetprop/resetprop.cpp \
core/core-rs.cpp \
core/resetprop/resetprop.cpp \
core/su/su.cpp \
core/su/connect.cpp \
core/su/pts.cpp \
core/su/su_daemon.cpp \
zygisk/entry.cpp \
zygisk/main.cpp \
zygisk/utils.cpp \
zygisk/hook.cpp \
zygisk/memory.cpp \
zygisk/deny/cli.cpp \
zygisk/deny/utils.cpp \
zygisk/deny/revert.cpp
core/zygisk/entry.cpp \
core/zygisk/main.cpp \
core/zygisk/module.cpp \
core/zygisk/hook.cpp \
core/deny/cli.cpp \
core/deny/utils.cpp \
core/deny/revert.cpp
LOCAL_LDLIBS := -llog
LOCAL_LDFLAGS := -Wl,--dynamic-list=src/exported_sym.txt
@@ -57,12 +55,6 @@ LOCAL_SRC_FILES := init/preload.c
LOCAL_STRIP_MODE := --strip-all
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := zygisk-ld
LOCAL_SRC_FILES := zygisk/loader.c
LOCAL_STRIP_MODE := --strip-all
include $(BUILD_SHARED_LIBRARY)
endif
ifdef B_INIT

194
native/src/Cargo.lock generated
View File

@@ -4,9 +4,9 @@ version = 3
[[package]]
name = "aho-corasick"
version = "1.1.0"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f2135563fb5c609d2b2b87c1e8ce7bc41b0b45430fa9661f457981503dd5bf0"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
dependencies = [
"memchr",
]
@@ -109,9 +109,9 @@ dependencies = [
[[package]]
name = "bytemuck"
version = "1.14.0"
version = "1.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6"
checksum = "ed2490600f404f2b94c167e31d3ed1d5f3c225a0f3b80230053b3e0b7b962bd9"
dependencies = [
"bytemuck_derive",
]
@@ -129,9 +129,9 @@ dependencies = [
[[package]]
name = "byteorder"
version = "1.4.3"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cc"
@@ -175,24 +175,24 @@ dependencies = [
[[package]]
name = "const-oid"
version = "0.9.5"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f"
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]]
name = "cpufeatures"
version = "0.2.9"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
dependencies = [
"libc",
]
[[package]]
name = "crypto-bigint"
version = "0.5.3"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124"
checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76"
dependencies = [
"generic-array",
"rand_core",
@@ -212,7 +212,7 @@ dependencies = [
[[package]]
name = "cxx"
version = "1.0.105"
version = "1.0.115"
dependencies = [
"cc",
"cxxbridge-flags",
@@ -221,7 +221,7 @@ dependencies = [
[[package]]
name = "cxx-gen"
version = "0.7.105"
version = "0.7.115"
dependencies = [
"codespan-reporting",
"proc-macro2",
@@ -231,11 +231,11 @@ dependencies = [
[[package]]
name = "cxxbridge-flags"
version = "1.0.105"
version = "1.0.115"
[[package]]
name = "cxxbridge-macro"
version = "1.0.105"
version = "1.0.115"
dependencies = [
"proc-macro2",
"quote",
@@ -280,9 +280,9 @@ dependencies = [
[[package]]
name = "ecdsa"
version = "0.16.8"
version = "0.16.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4"
checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca"
dependencies = [
"der",
"digest",
@@ -294,9 +294,9 @@ dependencies = [
[[package]]
name = "elliptic-curve"
version = "0.13.5"
version = "0.13.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b"
checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47"
dependencies = [
"base16ct",
"crypto-bigint",
@@ -361,9 +361,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.10"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
dependencies = [
"cfg-if",
"libc",
@@ -392,9 +392,9 @@ dependencies = [
[[package]]
name = "hkdf"
version = "0.12.3"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437"
checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7"
dependencies = [
"hmac",
]
@@ -428,15 +428,15 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.148"
version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "libm"
version = "0.2.7"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
[[package]]
name = "log"
@@ -504,9 +504,9 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.6.3"
version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
[[package]]
name = "minimal-lexical"
@@ -543,9 +543,9 @@ dependencies = [
[[package]]
name = "num-derive"
version = "0.4.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e"
checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712"
dependencies = [
"proc-macro2",
"quote",
@@ -575,9 +575,9 @@ dependencies = [
[[package]]
name = "num-traits"
version = "0.2.16"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
dependencies = [
"autocfg",
"libm",
@@ -656,18 +656,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "primeorder"
version = "0.13.2"
version = "0.13.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c2fcef82c0ec6eefcc179b978446c399b3cdf73c392c35604e399eee6df1ee3"
checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6"
dependencies = [
"elliptic-curve",
]
[[package]]
name = "proc-macro2"
version = "1.0.67"
version = "1.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
dependencies = [
"unicode-ident",
]
@@ -688,9 +688,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.33"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
dependencies = [
"proc-macro2",
]
@@ -726,9 +726,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.9.5"
version = "1.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47"
checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
dependencies = [
"aho-corasick",
"memchr",
@@ -738,9 +738,9 @@ dependencies = [
[[package]]
name = "regex-automata"
version = "0.3.8"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795"
checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd"
dependencies = [
"aho-corasick",
"memchr",
@@ -749,9 +749,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.7.5"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "rfc6979"
@@ -765,16 +765,14 @@ dependencies = [
[[package]]
name = "rsa"
version = "0.9.2"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ab43bb47d23c1a631b4b680199a45255dce26fa9ab2fa902581f624ff13e6a8"
checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc"
dependencies = [
"byteorder",
"const-oid",
"digest",
"num-bigint-dig",
"num-integer",
"num-iter",
"num-traits",
"pkcs1",
"pkcs8",
@@ -802,18 +800,18 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.188"
version = "1.0.196"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.188"
version = "1.0.196"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
dependencies = [
"proc-macro2",
"quote",
@@ -822,9 +820,9 @@ dependencies = [
[[package]]
name = "sha1"
version = "0.10.5"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if",
"cpufeatures",
@@ -833,9 +831,9 @@ dependencies = [
[[package]]
name = "sha2"
version = "0.10.7"
version = "0.10.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
dependencies = [
"cfg-if",
"cpufeatures",
@@ -844,9 +842,9 @@ dependencies = [
[[package]]
name = "signature"
version = "2.1.0"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
dependencies = [
"digest",
"rand_core",
@@ -860,9 +858,9 @@ checksum = "9fed904c7fb2856d868b92464fc8fa597fce366edea1a9cbfaa8cb5fe080bd6d"
[[package]]
name = "smallvec"
version = "1.11.0"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
[[package]]
name = "spin"
@@ -872,9 +870,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "spki"
version = "0.7.2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a"
checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
dependencies = [
"base64ct",
"der",
@@ -894,9 +892,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "syn"
version = "2.0.37"
version = "2.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
dependencies = [
"proc-macro2",
"quote",
@@ -905,9 +903,9 @@ dependencies = [
[[package]]
name = "termcolor"
version = "1.3.0"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64"
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
dependencies = [
"winapi-util",
]
@@ -923,18 +921,39 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.48"
version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7"
checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.48"
version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35"
checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tls_codec"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e78c9c330f8c85b2bae7c8368f2739157db9991235123aa1b15ef9502bfb6a"
dependencies = [
"tls_codec_derive",
"zeroize",
]
[[package]]
name = "tls_codec_derive"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d9ef545650e79f30233c0003bcc2504d7efac6dad25fca40744de773fe2049c"
dependencies = [
"proc-macro2",
"quote",
@@ -955,9 +974,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-width"
version = "0.1.10"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "vec_map"
@@ -995,9 +1014,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
dependencies = [
"winapi",
]
@@ -1010,17 +1029,32 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "x509-cert"
version = "0.2.4"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25eefca1d99701da3a57feb07e5079fc62abba059fc139e98c13bbb250f3ef29"
checksum = "1301e935010a701ae5f8655edc0ad17c44bad3ac5ce8c39185f75453b720ae94"
dependencies = [
"const-oid",
"der",
"spki",
"tls_codec",
]
[[package]]
name = "zeroize"
version = "1.6.0"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
dependencies = [
"zeroize_derive",
]
[[package]]
name = "zeroize_derive"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

View File

@@ -6,10 +6,12 @@ use std::path::Path;
use std::str::{Utf8Chunks, Utf8Error};
use std::{fmt, mem, slice, str};
use crate::slice_from_ptr_mut;
use cxx::{type_id, ExternType};
use libc::c_char;
use thiserror::Error;
use crate::slice_from_ptr_mut;
// Utf8CStr types are UTF-8 validated and null terminated strings.
//
// Several Utf8CStr types:
@@ -380,6 +382,22 @@ impl DerefMut for Utf8CStr {
}
}
// Notice that we only implement ExternType on Utf8CStr *reference*
unsafe impl ExternType for &Utf8CStr {
type Id = type_id!("rust::Utf8CStr");
type Kind = cxx::kind::Trivial;
}
macro_rules! const_assert_eq {
($left:expr, $right:expr $(,)?) => {
const _: [(); $left] = [(); $right];
};
}
// Assert ABI layout
const_assert_eq!(mem::size_of::<&Utf8CStr>(), mem::size_of::<[usize; 2]>());
const_assert_eq!(mem::align_of::<&Utf8CStr>(), mem::align_of::<[usize; 2]>());
// File system path extensions types
#[repr(transparent)]

View File

@@ -10,7 +10,8 @@ use libc::mode_t;
use crate::logging::CxxResultExt;
pub(crate) use crate::xwrap::*;
use crate::{
clone_attr, fclone_attr, fd_path, map_fd, map_file, Directory, FsPath, Utf8CStr, Utf8CStrBufRef,
clone_attr, cstr, fclone_attr, fd_path, map_fd, map_file, slice_from_ptr, Directory, FsPath,
Utf8CStr, Utf8CStrBufRef,
};
pub(crate) fn fd_path_for_cxx(fd: RawFd, buf: &mut [u8]) -> isize {
@@ -57,12 +58,8 @@ unsafe extern "C" fn frm_rf(fd: OwnedFd) -> bool {
inner(fd).is_ok()
}
pub(crate) fn map_file_for_cxx(path: &[u8], rw: bool) -> &'static mut [u8] {
unsafe {
map_file(Utf8CStr::from_bytes_unchecked(path), rw)
.log_cxx()
.unwrap_or(&mut [])
}
pub(crate) fn map_file_for_cxx(path: &Utf8CStr, rw: bool) -> &'static mut [u8] {
map_file(path, rw).log_cxx().unwrap_or(&mut [])
}
pub(crate) fn map_fd_for_cxx(fd: RawFd, sz: usize, rw: bool) -> &'static mut [u8] {
@@ -171,3 +168,18 @@ unsafe extern "C" fn fclone_attr_for_cxx(a: RawFd, b: RawFd) -> bool {
.log_cxx_with_msg(|w| w.write_str("fclone_attr failed"))
.is_ok()
}
#[export_name = "cxx$utf8str$new"]
unsafe extern "C" fn str_new(this: &mut &Utf8CStr, s: *const u8, len: usize) {
*this = Utf8CStr::from_bytes(slice_from_ptr(s, len)).unwrap_or(cstr!(""));
}
#[export_name = "cxx$utf8str$ptr"]
unsafe extern "C" fn str_ptr(this: &&Utf8CStr) -> *const u8 {
this.as_ptr().cast()
}
#[export_name = "cxx$utf8str$len"]
unsafe extern "C" fn str_len(this: &&Utf8CStr) -> usize {
this.len()
}

View File

@@ -189,7 +189,7 @@ sFILE make_file(FILE *fp) {
}
mmap_data::mmap_data(const char *name, bool rw) {
auto slice = rust::map_file(byte_view(name), rw);
auto slice = rust::map_file(name, rw);
if (!slice.empty()) {
_buf = slice.data();
_sz = slice.size();

View File

@@ -4,7 +4,6 @@
#include "../files.hpp"
#include "../misc.hpp"
#include "../logging.hpp"
#include "../missing.hpp"
#include "../base-rs.hpp"
using rust::xpipe2;

View File

@@ -78,6 +78,21 @@ private:
void resize(size_t new_sz, bool zero = false);
};
class rust_vec_channel : public channel {
public:
rust_vec_channel(rust::Vec<uint8_t> &data) : _data(data) {}
ssize_t read(void *buf, size_t len) override;
bool write(const void *buf, size_t len) override;
off_t seek(off_t off, int whence) override;
private:
rust::Vec<uint8_t> &_data;
size_t _pos = 0;
void ensure_size(size_t sz, bool zero = false);
};
class file_channel : public channel {
public:
bool write(const void *buf, size_t len) final;

View File

@@ -34,16 +34,22 @@ pub mod ffi {
unsafe extern "C++" {
include!("misc.hpp");
#[namespace = "rust"]
#[cxx_name = "Utf8CStr"]
type Utf8CStrRef<'a> = &'a crate::cstr::Utf8CStr;
fn mut_u8_patch(buf: &mut [u8], from: &[u8], to: &[u8]) -> Vec<usize>;
}
extern "Rust" {
#[cxx_name = "log_with_rs"]
fn log_from_cxx(level: LogLevelCxx, msg: &[u8]);
fn log_from_cxx(level: LogLevelCxx, msg: Utf8CStrRef);
#[cxx_name = "set_log_level_state"]
fn set_log_level_state_cxx(level: LogLevelCxx, enabled: bool);
fn exit_on_error(b: bool);
fn cmdline_logging();
fn resize_vec(vec: &mut Vec<u8>, size: usize);
}
#[namespace = "rust"]
@@ -52,7 +58,7 @@ pub mod ffi {
#[cxx_name = "fd_path"]
fn fd_path_for_cxx(fd: i32, buf: &mut [u8]) -> isize;
#[cxx_name = "map_file"]
fn map_file_for_cxx(path: &[u8], rw: bool) -> &'static mut [u8];
fn map_file_for_cxx(path: Utf8CStrRef, rw: bool) -> &'static mut [u8];
#[cxx_name = "map_fd"]
fn map_fd_for_cxx(fd: i32, sz: usize, rw: bool) -> &'static mut [u8];
}
@@ -63,3 +69,12 @@ fn set_log_level_state_cxx(level: ffi::LogLevelCxx, enabled: bool) {
set_log_level_state(level, enabled)
}
}
fn resize_vec(vec: &mut Vec<u8>, size: usize) {
if size > vec.len() {
vec.reserve(size - vec.len());
}
unsafe {
vec.set_len(size);
}
}

View File

@@ -15,7 +15,7 @@ static int fmt_and_log_with_rs(LogLevel level, const char *fmt, va_list ap) {
buf[0] = '\0';
// Fortify logs when a fatal error occurs. Do not run through fortify again
int len = std::min(__call_bypassing_fortify(vsnprintf)(buf, sz, fmt, ap), sz - 1);
log_with_rs(level, byte_view(buf, len + 1));
log_with_rs(level, rust::Utf8CStr(buf, len + 1));
return len;
}

View File

@@ -101,10 +101,8 @@ fn log_with_writer<F: FnOnce(LogWriter)>(level: LogLevel, f: F) {
}
}
pub fn log_from_cxx(level: LogLevelCxx, msg: &[u8]) {
pub fn log_from_cxx(level: LogLevelCxx, msg: &Utf8CStr) {
if let Some(level) = LogLevel::from_i32(level.repr) {
// SAFETY: The null termination is handled on the C++ side
let msg = unsafe { Utf8CStr::from_bytes_unchecked(msg) };
log_with_writer(level, |write| write(level, msg));
}
}

View File

@@ -274,3 +274,19 @@ int ssprintf(char *dest, size_t size, const char *fmt, ...) {
size_t strscpy(char *dest, const char *src, size_t size) {
return std::min(strlcpy(dest, src, size), size - 1);
}
extern "C" void cxx$utf8str$new(rust::Utf8CStr *self, const void *s, size_t len);
extern "C" const char *cxx$utf8str$ptr(const rust::Utf8CStr *self);
extern "C" size_t cxx$utf8str$len(const rust::Utf8CStr *self);
rust::Utf8CStr::Utf8CStr(const char *s, size_t len) {
cxx$utf8str$new(this, s, len);
}
const char *rust::Utf8CStr::data() const {
return cxx$utf8str$ptr(this);
}
size_t rust::Utf8CStr::length() const {
return cxx$utf8str$len(this);
}

View File

@@ -11,11 +11,10 @@
#include "xwrap.hpp"
#define DISALLOW_COPY_AND_MOVE(clazz) \
clazz(const clazz &) = delete; \
clazz(const clazz&) = delete; \
clazz(clazz &&) = delete;
#define ALLOW_MOVE_ONLY(clazz) \
clazz() = default; \
clazz(const clazz&) = delete; \
clazz(clazz &&o) { swap(o); } \
clazz& operator=(clazz &&o) { swap(o); return *this; }
@@ -211,6 +210,7 @@ class byte_channel;
struct heap_data : public byte_data {
ALLOW_MOVE_ONLY(heap_data)
heap_data() = default;
explicit heap_data(size_t sz) : byte_data(calloc(sz, 1), sz) {}
~heap_data() { free(_buf); }
@@ -218,6 +218,21 @@ struct heap_data : public byte_data {
friend byte_channel;
};
struct owned_fd {
ALLOW_MOVE_ONLY(owned_fd)
owned_fd() : fd(-1) {}
owned_fd(int fd) : fd(fd) {}
~owned_fd() { close(fd); fd = -1; }
operator int() { return fd; }
int release() { int f = fd; fd = -1; return f; }
void swap(owned_fd &owned) { std::swap(fd, owned.fd); }
private:
int fd;
};
rust::Vec<size_t> mut_u8_patch(
rust::Slice<uint8_t> buf,
rust::Slice<const uint8_t> from,
@@ -310,3 +325,36 @@ void exec_command_async(Args &&...args) {
};
exec_command(exec);
}
template <typename T>
constexpr auto operator+(T e) noexcept ->
std::enable_if_t<std::is_enum<T>::value, std::underlying_type_t<T>> {
return static_cast<std::underlying_type_t<T>>(e);
}
namespace rust {
struct Utf8CStr {
const char *data() const;
size_t length() const;
Utf8CStr(const char *s, size_t len);
Utf8CStr() : Utf8CStr("", 1) {};
Utf8CStr(const Utf8CStr &o) = default;
Utf8CStr(Utf8CStr &&o) = default;
Utf8CStr(const char *s) : Utf8CStr(s, strlen(s) + 1) {};
Utf8CStr(std::string_view s) : Utf8CStr(s.data(), s.length() + 1) {};
Utf8CStr(std::string s) : Utf8CStr(s.data(), s.length() + 1) {};
const char *c_str() const { return this->data(); }
size_t size() const { return this->length(); }
bool empty() const { return this->length() == 0 ; }
operator std::string_view() { return {data(), length()}; }
private:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-private-field"
std::array<std::uintptr_t, 2> repr;
#pragma clang diagnostic pop
};
} // namespace rust

View File

@@ -1,17 +0,0 @@
#pragma once
#include <sys/syscall.h>
#include <linux/fcntl.h>
#include <unistd.h>
#include <cerrno>
#include <cstdio>
static inline int fexecve(int fd, char* const* argv, char* const* envp) {
syscall(__NR_execveat, fd, "", argv, envp, AT_EMPTY_PATH);
if (errno == ENOSYS) {
char buf[256];
ssprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
execve(buf, argv, envp);
}
return -1;
}

View File

@@ -180,6 +180,49 @@ void byte_channel::resize(size_t new_sz, bool zero) {
}
}
ssize_t rust_vec_channel::read(void *buf, size_t len) {
len = std::min<size_t>(len, _data.size() - _pos);
memcpy(buf, _data.data() + _pos, len);
_pos += len;
return len;
}
bool rust_vec_channel::write(const void *buf, size_t len) {
ensure_size(_pos + len);
memcpy(_data.data() + _pos, buf, len);
_pos += len;
return true;
}
off_t rust_vec_channel::seek(off_t off, int whence) {
off_t np;
switch (whence) {
case SEEK_CUR:
np = _pos + off;
break;
case SEEK_END:
np = _data.size() + off;
break;
case SEEK_SET:
np = off;
break;
default:
return -1;
}
ensure_size(np, true);
_pos = np;
return np;
}
void rust_vec_channel::ensure_size(size_t sz, bool zero) {
size_t old_sz = _data.size();
if (sz > old_sz) {
resize_vec(_data, sz);
if (zero)
memset(_data.data() + old_sz, 0, sz - old_sz);
}
}
ssize_t fd_channel::read(void *buf, size_t len) {
return ::read(fd, buf, len);
}

View File

@@ -1,5 +1,6 @@
#pragma once
#include <unistd.h>
#include <dirent.h>
#include <stdio.h>
#include <poll.h>

View File

@@ -732,3 +732,24 @@ bool decompress(rust::Slice<const uint8_t> buf, int fd) {
}
return true;
}
bool xz(rust::Slice<const uint8_t> buf, rust::Vec<uint8_t> &out) {
auto strm = get_encoder(XZ, make_unique<rust_vec_channel>(out));
if (!strm->write(buf.data(), buf.length())) {
return false;
}
return true;
}
bool unxz(rust::Slice<const uint8_t> buf, rust::Vec<uint8_t> &out) {
format_t type = check_fmt(buf.data(), buf.length());
if (type != XZ) {
LOGE("Input file is not in xz format!\n");
return false;
}
auto strm = get_decoder(XZ, make_unique<rust_vec_channel>(out));
if (!strm->write(buf.data(), buf.length())) {
return false;
}
return true;
}

View File

@@ -10,3 +10,5 @@ out_strm_ptr get_decoder(format_t type, out_strm_ptr &&base);
void compress(const char *method, const char *infile, const char *outfile);
void decompress(char *infile, const char *outfile);
bool decompress(rust::Slice<const uint8_t> buf, int fd);
bool xz(rust::Slice<const uint8_t> buf, rust::Vec<uint8_t> &out);
bool unxz(rust::Slice<const uint8_t> buf, rust::Vec<uint8_t> &out);

View File

@@ -15,6 +15,7 @@ use bytemuck::{from_bytes, Pod, Zeroable};
use num_traits::cast::AsPrimitive;
use size::{Base, Size, Style};
use crate::ffi::{unxz, xz};
use base::libc::{
c_char, dev_t, gid_t, major, makedev, minor, mknod, mode_t, uid_t, S_IFBLK, S_IFCHR, S_IFDIR,
S_IFLNK, S_IFMT, S_IFREG, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP,
@@ -81,6 +82,8 @@ struct Exists {
struct Backup {
#[argh(positional, arg_name = "orig")]
origin: String,
#[argh(switch, short = 'n')]
skip_compress: bool,
}
#[derive(FromArgs)]
@@ -177,8 +180,8 @@ Supported commands:
patch
Apply ramdisk patches
Configure with env variables: KEEPVERITY KEEPFORCEENCRYPT
backup ORIG
Create ramdisk backups from ORIG
backup ORIG [-n]
Create ramdisk backups from ORIG, specify [-n] to skip compression
restore
Restore ramdisk from ramdisk backup stored within incpio
"#
@@ -495,6 +498,34 @@ impl Cpio {
}
}
impl CpioEntry {
pub(crate) fn compress(&mut self) -> bool {
if self.mode & S_IFMT != S_IFREG {
return false;
}
let mut compressed = Vec::new();
if !xz(&self.data, &mut compressed) {
eprintln!("xz compression failed");
return false;
}
self.data = compressed;
true
}
pub(crate) fn decompress(&mut self) -> bool {
if self.mode & S_IFMT != S_IFREG {
return false;
}
let mut decompressed = Vec::new();
if !unxz(&self.data, &mut decompressed) {
eprintln!("xz decompression failed");
return false;
}
self.data = decompressed;
true
}
}
impl Display for CpioEntry {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
@@ -572,9 +603,10 @@ pub fn cpio_commands(argc: i32, argv: *const *const c_char) -> bool {
exit(1);
}
}
CpioSubCommand::Backup(Backup { origin }) => {
cpio.backup(Utf8CStr::from_string(origin))?
}
CpioSubCommand::Backup(Backup {
origin,
skip_compress,
}) => cpio.backup(Utf8CStr::from_string(origin), *skip_compress)?,
CpioSubCommand::Remove(Remove { path, recursive }) => cpio.rm(path, *recursive),
CpioSubCommand::Move(Move { from, to }) => cpio.mv(from, to)?,
CpioSubCommand::MakeDir(MakeDir { mode, dir }) => cpio.mkdir(mode, dir),
@@ -620,11 +652,10 @@ fn align_4(x: usize) -> usize {
#[inline(always)]
fn norm_path(path: &str) -> String {
path.strip_prefix('/')
.unwrap_or(path)
.strip_suffix('/')
.unwrap_or(path)
.to_string()
path.split('/')
.filter(|x| !x.is_empty())
.intersperse("/")
.collect()
}
fn parse_mode(s: &str) -> Result<mode_t, String> {

View File

@@ -49,7 +49,8 @@ fn print_dtb_usage() {
Do dtb related actions to <file>.
Supported actions:
print [-f] Print all contents of dtb for debugging
print [-f]
Print all contents of dtb for debugging
Specify [-f] to only print fstab nodes
patch
Search for fstab and remove verity/avb

View File

@@ -1,5 +1,6 @@
#![feature(format_args_nl)]
#![feature(btree_extract_if)]
#![feature(iter_intersperse)]
pub use base;
use cpio::cpio_commands;
@@ -24,6 +25,8 @@ pub mod ffi {
unsafe extern "C++" {
include!("compress.hpp");
fn decompress(buf: &[u8], fd: i32) -> bool;
fn xz(buf: &[u8], out: &mut Vec<u8>) -> bool;
fn unxz(buf: &[u8], out: &mut Vec<u8>) -> bool;
include!("bootimg.hpp");
#[cxx_name = "boot_img"]

View File

@@ -13,7 +13,7 @@ pub trait MagiskCpio {
fn patch(&mut self);
fn test(&self) -> i32;
fn restore(&mut self) -> LoggedResult<()>;
fn backup(&mut self, origin: &Utf8CStr) -> LoggedResult<()>;
fn backup(&mut self, origin: &Utf8CStr, skip_compress: bool) -> LoggedResult<()>;
}
const MAGISK_PATCHED: i32 = 1 << 0;
@@ -78,7 +78,7 @@ impl MagiskCpio for Cpio {
break;
}
}
if self.exists("init.sony.rc") {
if self.exists("init.real") {
ret |= SONY_INIT;
}
ret
@@ -89,13 +89,17 @@ impl MagiskCpio for Cpio {
let mut rm_list = String::new();
self.entries
.extract_if(|name, _| name.starts_with(".backup/"))
.for_each(|(name, entry)| {
.for_each(|(name, mut entry)| {
if name == ".backup/.rmlist" {
if let Ok(data) = from_utf8(&entry.data) {
rm_list.push_str(data);
}
} else if name != ".backup/.magisk" {
let new_name = &name[8..];
let new_name = if name.ends_with(".xz") && entry.decompress() {
&name[8..name.len() - 3]
} else {
&name[8..]
};
eprintln!("Restore [{}] -> [{}]", name, new_name);
backups.insert(new_name.to_string(), entry);
}
@@ -115,7 +119,7 @@ impl MagiskCpio for Cpio {
Ok(())
}
fn backup(&mut self, origin: &Utf8CStr) -> LoggedResult<()> {
fn backup(&mut self, origin: &Utf8CStr, skip_compress: bool) -> LoggedResult<()> {
let mut backups = HashMap::<String, Box<CpioEntry>>::new();
let mut rm_list = String::new();
backups.insert(
@@ -170,8 +174,12 @@ impl MagiskCpio for Cpio {
}
};
match action {
Action::Backup(name, entry) => {
let backup = format!(".backup/{}", name);
Action::Backup(name, mut entry) => {
let backup = if !skip_compress && entry.compress() {
format!(".backup/{}.xz", name)
} else {
format!(".backup/{}", name)
};
eprintln!("Backup [{}] -> [{}]", name, backup);
backups.insert(backup, entry);
}

View File

@@ -1,6 +1,6 @@
#include <sys/stat.h>
#include <magisk.hpp>
#include <consts.hpp>
#include <selinux.hpp>
#include <base.hpp>

View File

@@ -2,7 +2,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <magisk.hpp>
#include <consts.hpp>
#include <selinux.hpp>
#include <base.hpp>
@@ -31,11 +31,6 @@ int main(int argc, char *argv[]) {
string_view argv0 = basename(argv[0]);
// app_process is actually not an applet
if (argv0.starts_with("app_process")) {
return app_process_main(argc, argv);
}
umask(0);
if (argv[0][0] == '\0') {

View File

@@ -6,40 +6,25 @@
#include <set>
#include <string>
#include <magisk.hpp>
#include <consts.hpp>
#include <db.hpp>
#include <base.hpp>
#include <daemon.hpp>
#include <core.hpp>
#include <selinux.hpp>
#include "core.hpp"
using namespace std;
// Boot stage state
enum : int {
FLAG_NONE = 0,
FLAG_POST_FS_DATA_DONE = (1 << 0),
FLAG_LATE_START_DONE = (1 << 1),
FLAG_BOOT_COMPLETE = (1 << 2),
FLAG_SAFE_MODE = (1 << 3),
};
static int boot_state = FLAG_NONE;
bool zygisk_enabled = false;
/*********
* Setup *
*********/
static bool mount_mirror(const std::string_view from, const std::string_view to) {
static bool rec_mount(const std::string_view from, const std::string_view to) {
return !xmkdirs(to.data(), 0755) &&
// recursively bind mount to mirror dir, rootfs will fail before 3.12 kernel
// because of MS_NOUSER
!mount(from.data(), to.data(), nullptr, MS_BIND | MS_REC, nullptr) &&
// make mirror dir as a private mount so that it won't be affected by magic mount
!xmount(nullptr, to.data(), nullptr, MS_PRIVATE | MS_REC, nullptr);
!mount(from.data(), to.data(), nullptr, MS_BIND | MS_REC, nullptr);
}
static void mount_mirrors() {
@@ -80,7 +65,7 @@ static void mount_mirrors() {
if (!rw) continue;
string preinit_dir = resolve_preinit_dir(info.target.data());
xmkdir(preinit_dir.data(), 0700);
if ((mounted = mount_mirror(preinit_dir, path))) {
if ((mounted = rec_mount(preinit_dir, path))) {
xmount(nullptr, path, nullptr, MS_UNBINDABLE, nullptr);
break;
}
@@ -96,10 +81,12 @@ static void mount_mirrors() {
ssprintf(path, sizeof(path), "%s/" WORKERDIR, get_magisk_tmp());
xmount("worker", path, "tmpfs", 0, "mode=755");
xmount(nullptr, path, nullptr, MS_PRIVATE, nullptr);
// Recursively bind mount / to mirror dir
if (auto mirror_dir = get_magisk_tmp() + "/"s MIRRDIR; !mount_mirror("/", mirror_dir)) {
// Keep mirror shared so that mounting during post-fs-data will be propagated
if (auto mirror_dir = get_magisk_tmp() + "/"s MIRRDIR; !rec_mount("/", mirror_dir)) {
LOGI("fallback to mount subtree\n");
// create new a bind mount for easy make private
xmount(mirror_dir.data(), mirror_dir.data(), nullptr, MS_BIND, nullptr);
// rootfs may fail, fallback to bind mount each mount point
set<string, greater<>> mounted_dirs {{ get_magisk_tmp() }};
for (const auto &info: self_mount_info) {
@@ -109,7 +96,7 @@ static void mount_mirrors() {
last_mount != mounted_dirs.end() && info.target.starts_with(*last_mount + '/')) {
continue;
}
if (mount_mirror(info.target, mirror_dir + info.target)) {
if (rec_mount(info.target, mirror_dir + info.target)) {
LOGD("%-8s: %s <- %s\n", "rbind", (mirror_dir + info.target).data(), info.target.data());
mounted_dirs.insert(info.target);
}
@@ -245,38 +232,6 @@ static bool magisk_env() {
return true;
}
void reboot() {
if (RECOVERY_MODE)
exec_command_sync("/system/bin/reboot", "recovery");
else
exec_command_sync("/system/bin/reboot");
}
static bool check_data() {
bool mnt = false;
file_readline("/proc/mounts", [&](string_view s) {
if (str_contains(s, " /data ") && !str_contains(s, "tmpfs")) {
mnt = true;
return false;
}
return true;
});
if (!mnt)
return false;
auto crypto = get_prop("ro.crypto.state");
if (!crypto.empty()) {
if (crypto != "encrypted") {
// Unencrypted, we can directly access data
return true;
} else {
// Encrypted, check whether vold is started
return !get_prop("init.svc.vold").empty();
}
}
// ro.crypto.state is not set, assume it's unencrypted
return true;
}
void unlock_blocks() {
int fd, dev, OFF = 0;
@@ -349,11 +304,8 @@ static bool check_key_combo() {
extern int disable_deny();
static void post_fs_data() {
if (!check_data())
return;
rust::get_magiskd().setup_logfile();
bool MagiskD::post_fs_data() const {
as_rust().setup_logfile();
LOGI("** post-fs-data mode running\n");
@@ -361,6 +313,8 @@ static void post_fs_data() {
mount_mirrors();
prune_su_access();
bool safe_mode = false;
if (access(SECURE_DIR, F_OK) != 0) {
LOGE(SECURE_DIR " is not present, abort\n");
goto early_abort;
@@ -373,7 +327,7 @@ static void post_fs_data() {
if (get_prop("persist.sys.safemode", true) == "1" ||
get_prop("ro.sys.safemode") == "1" || check_key_combo()) {
boot_state |= FLAG_SAFE_MODE;
safe_mode = true;
// Disable all modules and denylist so next boot will be clean
disable_modules();
disable_deny();
@@ -387,25 +341,29 @@ static void post_fs_data() {
}
early_abort:
auto mirror_dir = get_magisk_tmp() + "/"s MIRRDIR;
// make mirror dir as a private mount so that it won't be affected by magic mount
LOGD("make %s private\n", mirror_dir.data());
xmount(nullptr, mirror_dir.data(), nullptr, MS_PRIVATE | MS_REC, nullptr);
// We still do magic mount because root itself might need it
load_modules();
boot_state |= FLAG_POST_FS_DATA_DONE;
// make mirror dir as a shared mount to make magisk --stop work for other ns
xmount(nullptr, mirror_dir.data(), nullptr, MS_SHARED | MS_REC, nullptr);
LOGD("make %s shared\n", mirror_dir.data());
return safe_mode;
}
static void late_start() {
rust::get_magiskd().setup_logfile();
void MagiskD::late_start() const {
as_rust().setup_logfile();
LOGI("** late_start service mode running\n");
exec_common_scripts("service");
exec_module_scripts("service");
boot_state |= FLAG_LATE_START_DONE;
}
static void boot_complete() {
boot_state |= FLAG_BOOT_COMPLETE;
rust::get_magiskd().setup_logfile();
void MagiskD::boot_complete() const {
as_rust().setup_logfile();
LOGI("** boot-complete triggered\n");
@@ -416,30 +374,6 @@ static void boot_complete() {
// Ensure manager exists
check_pkg_refresh();
get_manager(0, nullptr, true);
}
void boot_stage_handler(int client, int code) {
// Make sure boot stage execution is always serialized
static pthread_mutex_t stage_lock = PTHREAD_MUTEX_INITIALIZER;
mutex_guard lock(stage_lock);
switch (code) {
case MainRequest::POST_FS_DATA:
if ((boot_state & FLAG_POST_FS_DATA_DONE) == 0)
post_fs_data();
close(client);
break;
case MainRequest::LATE_START:
close(client);
if ((boot_state & FLAG_POST_FS_DATA_DONE) && (boot_state & FLAG_SAFE_MODE) == 0)
late_start();
break;
case MainRequest::BOOT_COMPLETE:
close(client);
if ((boot_state & FLAG_SAFE_MODE) == 0)
boot_complete();
break;
default:
__builtin_unreachable();
}
reset_zygisk(true);
}

View File

@@ -1,30 +0,0 @@
#pragma once
#include <string>
#include <vector>
#include "core-rs.hpp"
#include "resetprop/resetprop.hpp"
extern bool RECOVERY_MODE;
extern std::atomic<ino_t> pkg_xml_ino;
std::string find_preinit_device();
void unlock_blocks();
void reboot();
// Module stuffs
void handle_modules();
void load_modules();
void disable_modules();
void remove_modules();
void exec_module_scripts(const char *stage);
// Scripting
void exec_script(const char *script);
void exec_common_scripts(const char *stage);
void exec_module_scripts(const char *stage, const std::vector<std::string_view> &modules);
void install_apk(const char *apk);
void uninstall_pkg(const char *pkg);
void clear_pkg(const char *pkg, int user_id);
[[noreturn]] void install_module(const char *file);

View File

@@ -3,21 +3,17 @@
#include <sys/un.h>
#include <sys/mount.h>
#include <magisk.hpp>
#include <consts.hpp>
#include <base.hpp>
#include <daemon.hpp>
#include <core.hpp>
#include <selinux.hpp>
#include <db.hpp>
#include <flags.h>
#include "core.hpp"
using namespace std;
int SDK_INT = -1;
bool RECOVERY_MODE = false;
static struct stat self_st;
static map<int, poll_callback> *poll_map;
@@ -132,33 +128,53 @@ static void poll_ctrl_handler(pollfd *pfd) {
}
}
const MagiskD &MagiskD::get() {
return *reinterpret_cast<const MagiskD*>(&rust::get_magiskd());
}
const rust::MagiskD *MagiskD::operator->() const {
return reinterpret_cast<const rust::MagiskD*>(this);
}
const rust::MagiskD &MagiskD::as_rust() const {
return *operator->();
}
void MagiskD::reboot() const {
if (as_rust().is_recovery())
exec_command_sync("/system/bin/reboot", "recovery");
else
exec_command_sync("/system/bin/reboot");
}
static void handle_request_async(int client, int code, const sock_cred &cred) {
switch (code) {
case MainRequest::DENYLIST:
case +RequestCode::DENYLIST:
denylist_handler(client, &cred);
break;
case MainRequest::SUPERUSER:
case +RequestCode::SUPERUSER:
su_daemon_handler(client, &cred);
break;
case MainRequest::ZYGOTE_RESTART:
close(client);
case +RequestCode::ZYGOTE_RESTART:
LOGI("** zygote restarted\n");
pkg_xml_ino = 0;
prune_su_access();
reset_zygisk(false);
close(client);
break;
case MainRequest::SQLITE_CMD:
case +RequestCode::SQLITE_CMD:
exec_sql(client);
break;
case MainRequest::REMOVE_MODULES: {
case +RequestCode::REMOVE_MODULES: {
int do_reboot = read_int(client);
remove_modules();
write_int(client, 0);
close(client);
if (do_reboot) reboot();
if (do_reboot) {
MagiskD::get().reboot();
}
break;
}
case MainRequest::ZYGISK:
case MainRequest::ZYGISK_PASSTHROUGH:
case +RequestCode::ZYGISK:
zygisk_handler(client, &cred);
break;
default:
@@ -168,24 +184,37 @@ static void handle_request_async(int client, int code, const sock_cred &cred) {
static void handle_request_sync(int client, int code) {
switch (code) {
case MainRequest::CHECK_VERSION:
case +RequestCode::CHECK_VERSION:
#if MAGISK_DEBUG
write_string(client, MAGISK_VERSION ":MAGISK:D");
#else
write_string(client, MAGISK_VERSION ":MAGISK:R");
#endif
break;
case MainRequest::CHECK_VERSION_CODE:
case +RequestCode::CHECK_VERSION_CODE:
write_int(client, MAGISK_VER_CODE);
break;
case MainRequest::START_DAEMON:
rust::get_magiskd().setup_logfile();
case +RequestCode::START_DAEMON:
MagiskD::get()->setup_logfile();
break;
case MainRequest::STOP_DAEMON:
case +RequestCode::STOP_DAEMON: {
// Unmount all overlays
denylist_handler(-1, nullptr);
// Restore native bridge property
auto nb = get_prop(NBPROP);
auto len = sizeof(ZYGISKLDR) - 1;
if (nb == ZYGISKLDR) {
set_prop(NBPROP, "0");
} else if (nb.size() > len) {
set_prop(NBPROP, nb.data() + len);
}
write_int(client, 0);
// Terminate the daemon!
exit(0);
}
default:
__builtin_unreachable();
}
@@ -200,7 +229,7 @@ static bool is_client(pid_t pid) {
}
static void handle_request(pollfd *pfd) {
int client = xaccept4(pfd->fd, nullptr, nullptr, SOCK_CLOEXEC);
owned_fd client = xaccept4(pfd->fd, nullptr, nullptr, SOCK_CLOEXEC);
// Verify client credentials
sock_cred cred;
@@ -210,70 +239,67 @@ static void handle_request(pollfd *pfd) {
if (!get_client_cred(client, &cred)) {
// Client died
goto done;
return;
}
is_root = cred.uid == AID_ROOT;
is_zygote = cred.context == "u:r:zygote:s0";
if (!is_root && !is_zygote && !is_client(cred.pid)) {
// Unsupported client state
write_int(client, MainResponse::ACCESS_DENIED);
goto done;
write_int(client, +RespondCode::ACCESS_DENIED);
return;
}
code = read_int(client);
if (code < 0 || code >= MainRequest::END ||
code == MainRequest::_SYNC_BARRIER_ ||
code == MainRequest::_STAGE_BARRIER_) {
if (code < 0 || code >= +RequestCode::END ||
code == +RequestCode::_SYNC_BARRIER_ ||
code == +RequestCode::_STAGE_BARRIER_) {
// Unknown request code
goto done;
return;
}
// Check client permissions
switch (code) {
case MainRequest::POST_FS_DATA:
case MainRequest::LATE_START:
case MainRequest::BOOT_COMPLETE:
case MainRequest::ZYGOTE_RESTART:
case MainRequest::SQLITE_CMD:
case MainRequest::DENYLIST:
case MainRequest::STOP_DAEMON:
case +RequestCode::POST_FS_DATA:
case +RequestCode::LATE_START:
case +RequestCode::BOOT_COMPLETE:
case +RequestCode::ZYGOTE_RESTART:
case +RequestCode::SQLITE_CMD:
case +RequestCode::DENYLIST:
case +RequestCode::STOP_DAEMON:
if (!is_root) {
write_int(client, MainResponse::ROOT_REQUIRED);
goto done;
write_int(client, +RespondCode::ROOT_REQUIRED);
return;
}
break;
case MainRequest::REMOVE_MODULES:
case +RequestCode::REMOVE_MODULES:
if (!is_root && cred.uid != AID_SHELL) {
write_int(client, MainResponse::ACCESS_DENIED);
goto done;
write_int(client, +RespondCode::ACCESS_DENIED);
return;
}
break;
case MainRequest::ZYGISK:
case +RequestCode::ZYGISK:
if (!is_zygote) {
// Invalid client context
write_int(client, MainResponse::ACCESS_DENIED);
goto done;
write_int(client, +RespondCode::ACCESS_DENIED);
return;
}
break;
default:
break;
}
write_int(client, MainResponse::OK);
write_int(client, +RespondCode::OK);
if (code < MainRequest::_SYNC_BARRIER_) {
if (code < +RequestCode::_SYNC_BARRIER_) {
handle_request_sync(client, code);
goto done;
} else if (code < MainRequest::_STAGE_BARRIER_) {
exec_task([=] { handle_request_async(client, code, cred); });
} else if (code < +RequestCode::_STAGE_BARRIER_) {
exec_task([=, fd = client.release()] { handle_request_async(fd, code, cred); });
} else {
exec_task([=] { boot_stage_handler(client, code); });
exec_task([=, fd = client.release()] {
MagiskD::get()->boot_stage_handler(fd, code);
});
}
return;
done:
close(client);
}
static void switch_cgroup(const char *cgroup, int pid) {
@@ -365,13 +391,12 @@ static void daemon_entry() {
ssprintf(path, sizeof(path), "%s/" ROOTOVL, tmp);
rm_rf(path);
// Load config status
ssprintf(path, sizeof(path), "%s/" MAIN_CONFIG, tmp);
parse_prop_file(path, [](auto key, auto val) -> bool {
if (key == "RECOVERYMODE" && val == "true")
RECOVERY_MODE = true;
return true;
});
// Unshare magiskd
xunshare(CLONE_NEWNS);
// Hide magisk internal mount point
xmount(nullptr, tmp, nullptr, MS_PRIVATE | MS_REC, nullptr);
// Fix sdcardfs bug on old kernel
xmount(nullptr, "/mnt", nullptr, MS_SLAVE | MS_REC, nullptr);
// Use isolated devpts if kernel support
if (access("/dev/pts/ptmx", F_OK) == 0) {
@@ -407,6 +432,7 @@ static void daemon_entry() {
register_poll(&main_socket_pfd, handle_request);
// Loop forever to listen for requests
init_thread_pool();
poll_loop();
}
@@ -454,20 +480,20 @@ int connect_daemon(int req, bool create) {
}
write_int(fd, req);
int res = read_int(fd);
if (res < MainResponse::ERROR || res >= MainResponse::END)
res = MainResponse::ERROR;
if (res < +RespondCode::ERROR || res >= +RespondCode::END)
res = +RespondCode::ERROR;
switch (res) {
case MainResponse::OK:
case +RespondCode::OK:
break;
case MainResponse::ERROR:
case +RespondCode::ERROR:
LOGE("Daemon error\n");
close(fd);
return -1;
case MainResponse::ROOT_REQUIRED:
case +RespondCode::ROOT_REQUIRED:
LOGE("Root is required for this operation\n");
close(fd);
return -1;
case MainResponse::ACCESS_DENIED:
case +RespondCode::ACCESS_DENIED:
LOGE("Access denied\n");
close(fd);
return -1;

View File

@@ -1,37 +1,100 @@
use std::fs::File;
use std::io;
use std::io::BufReader;
use std::sync::{Mutex, OnceLock};
use std::{io, mem};
use base::{cstr, Directory, ResultExt, Utf8CStr, Utf8CStrBuf, Utf8CStrBufRef, WalkResult};
use base::libc::{O_CLOEXEC, O_RDONLY};
use base::{
cstr, libc, open_fd, BufReadExt, Directory, FsPathBuf, ResultExt, Utf8CStr, Utf8CStrBuf,
Utf8CStrBufArr, Utf8CStrBufRef, WalkResult,
};
use crate::get_prop;
use crate::ffi::{get_magisk_tmp, CxxMagiskD, RequestCode};
use crate::logging::magisk_logging;
use crate::{get_prop, MAIN_CONFIG};
// Global magiskd singleton
pub static MAGISKD: OnceLock<MagiskD> = OnceLock::new();
#[repr(u32)]
enum BootState {
PostFsDataDone = (1 << 0),
LateStartDone = (1 << 1),
BootComplete = (1 << 2),
SafeMode = (1 << 3),
}
#[derive(Default)]
#[repr(transparent)]
struct BootStateFlags(u32);
impl BootStateFlags {
fn contains(&self, stage: BootState) -> bool {
(self.0 & stage as u32) != 0
}
fn set(&mut self, stage: BootState) {
self.0 |= stage as u32;
}
}
#[derive(Default)]
pub struct MagiskD {
pub logd: Mutex<Option<File>>,
boot_stage_lock: Mutex<BootStateFlags>,
is_emulator: bool,
is_recovery: bool,
}
impl MagiskD {
pub fn is_emulator(&self) -> bool {
self.is_emulator
}
}
mod cxx_extern {
use base::libc::c_char;
extern "C" {
pub fn get_magisk_tmp() -> *const c_char;
pub fn is_recovery(&self) -> bool {
self.is_recovery
}
}
pub fn get_magisk_tmp() -> &'static Utf8CStr {
unsafe { Utf8CStr::from_ptr(cxx_extern::get_magisk_tmp()).unwrap_unchecked() }
pub fn boot_stage_handler(&self, client: i32, code: i32) {
// Make sure boot stage execution is always serialized
let mut state = self.boot_stage_lock.lock().unwrap();
let code = RequestCode { repr: code };
match code {
RequestCode::POST_FS_DATA => {
if check_data() && !state.contains(BootState::PostFsDataDone) {
if self.as_cxx().post_fs_data() {
state.set(BootState::SafeMode);
}
state.set(BootState::PostFsDataDone);
}
unsafe { libc::close(client) };
}
RequestCode::LATE_START => {
unsafe { libc::close(client) };
if state.contains(BootState::PostFsDataDone) && !state.contains(BootState::SafeMode)
{
self.as_cxx().late_start();
state.set(BootState::LateStartDone);
}
}
RequestCode::BOOT_COMPLETE => {
unsafe { libc::close(client) };
if !state.contains(BootState::SafeMode) {
state.set(BootState::BootComplete);
self.as_cxx().boot_complete()
}
}
_ => {
unsafe { libc::close(client) };
}
}
}
#[inline(always)]
fn as_cxx(&self) -> &CxxMagiskD {
unsafe { mem::transmute(self) }
}
}
pub fn daemon_entry() {
@@ -41,26 +104,71 @@ pub fn daemon_entry() {
}
let is_emulator = qemu == "1";
// Load config status
let mut buf = Utf8CStrBufArr::<64>::new();
let path = FsPathBuf::new(&mut buf)
.join(get_magisk_tmp())
.join(MAIN_CONFIG!());
let mut is_recovery = false;
if let Ok(file) = path.open(O_RDONLY | O_CLOEXEC) {
let mut file = BufReader::new(file);
file.foreach_props(|key, val| {
if key == "RECOVERYMODE" {
is_recovery = val == "true";
return false;
}
true
});
}
let magiskd = MagiskD {
logd: Default::default(),
is_emulator,
is_recovery,
..Default::default()
};
magiskd.start_log_daemon();
MAGISKD.set(magiskd).ok();
magisk_logging();
}
fn check_data() -> bool {
if let Ok(fd) = open_fd!(cstr!("/proc/mounts"), O_RDONLY | O_CLOEXEC) {
let file = File::from(fd);
let mut mnt = false;
BufReader::new(file).foreach_lines(|line| {
if line.contains(" /data ") && !line.contains("tmpfs") {
mnt = true;
return false;
}
true
});
if !mnt {
return false;
}
let crypto = get_prop(cstr!("ro.crypto.state"), false);
return if !crypto.is_empty() {
if crypto != "encrypted" {
// Unencrypted, we can directly access data
true
} else {
// Encrypted, check whether vold is started
!get_prop(cstr!("init.svc.vold"), false).is_empty()
}
} else {
// ro.crypto.state is not set, assume it's unencrypted
true
};
}
false
}
pub fn get_magiskd() -> &'static MagiskD {
unsafe { MAGISKD.get().unwrap_unchecked() }
}
pub fn find_apk_path(pkg: &[u8], data: &mut [u8]) -> usize {
pub fn find_apk_path(pkg: &Utf8CStr, data: &mut [u8]) -> usize {
use WalkResult::*;
fn inner(pkg: &[u8], buf: &mut dyn Utf8CStrBuf) -> io::Result<usize> {
let pkg = match Utf8CStr::from_bytes(pkg) {
Ok(pkg) => pkg,
Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
};
fn inner(pkg: &Utf8CStr, buf: &mut dyn Utf8CStrBuf) -> io::Result<usize> {
Directory::open(cstr!("/data/app"))?.pre_order_walk(|e| {
if !e.is_dir() {
return Ok(Skip);

View File

@@ -2,12 +2,10 @@
#include <dlfcn.h>
#include <sys/stat.h>
#include <magisk.hpp>
#include <db.hpp>
#include <socket.hpp>
#include <consts.hpp>
#include <base.hpp>
#include "core.hpp"
#include <db.hpp>
#include <core.hpp>
#define DB_VERSION 12
@@ -118,7 +116,7 @@ db_settings::db_settings() {
data[SU_MULTIUSER_MODE] = MULTIUSER_MODE_OWNER_ONLY;
data[SU_MNT_NS] = NAMESPACE_MODE_REQUESTER;
data[DENYLIST_CONFIG] = false;
data[ZYGISK_CONFIG] = rust::get_magiskd().is_emulator();
data[ZYGISK_CONFIG] = MagiskD::get()->is_emulator();
}
int db_settings::get_idx(string_view key) const {

View File

@@ -1,7 +1,7 @@
#include <sys/wait.h>
#include <sys/mount.h>
#include <magisk.hpp>
#include <consts.hpp>
#include <base.hpp>
#include "deny.hpp"
@@ -92,7 +92,7 @@ int denylist_cli(int argc, char **argv) {
}
// Send request
int fd = connect_daemon(MainRequest::DENYLIST);
int fd = connect_daemon(+RequestCode::DENYLIST);
write_int(fd, req);
if (req == DenyRequest::ADD || req == DenyRequest::REMOVE) {
write_string(fd, argv[2]);

View File

@@ -6,7 +6,7 @@
#include <map>
#include <atomic>
#include <daemon.hpp>
#include <core.hpp>
#define ISOLATED_MAGIC "isolated"
@@ -44,9 +44,3 @@ int disable_deny();
int add_list(int client);
int rm_list(int client);
void ls_list(int client);
// Utility functions
bool is_deny_target(int uid, std::string_view process);
void revert_unmount();
extern std::atomic<bool> denylist_enforced;

View File

@@ -1,8 +1,9 @@
#include <set>
#include <sys/mount.h>
#include <magisk.hpp>
#include <consts.hpp>
#include <base.hpp>
#include <core.hpp>
#include "deny.hpp"

View File

@@ -6,9 +6,10 @@
#include <dirent.h>
#include <set>
#include <magisk.hpp>
#include <consts.hpp>
#include <base.hpp>
#include <db.hpp>
#include <core.hpp>
#include "deny.hpp"

View File

@@ -7,8 +7,8 @@
#include <atomic>
#include <functional>
#include <socket.hpp>
#include "../core/core-rs.hpp"
#include "socket.hpp"
#include "../core-rs.hpp"
#define AID_ROOT 0
#define AID_SHELL 2000
@@ -19,44 +19,14 @@
#define to_app_id(uid) (uid % AID_USER_OFFSET)
#define to_user_id(uid) (uid / AID_USER_OFFSET)
// Daemon command codes
namespace MainRequest {
enum : int {
START_DAEMON,
CHECK_VERSION,
CHECK_VERSION_CODE,
STOP_DAEMON,
_SYNC_BARRIER_,
SUPERUSER,
ZYGOTE_RESTART,
DENYLIST,
SQLITE_CMD,
REMOVE_MODULES,
ZYGISK,
ZYGISK_PASSTHROUGH,
_STAGE_BARRIER_,
POST_FS_DATA,
LATE_START,
BOOT_COMPLETE,
END,
};
}
// Return codes for daemon
namespace MainResponse {
enum : int {
enum class RespondCode : int {
ERROR = -1,
OK = 0,
ROOT_REQUIRED,
ACCESS_DENIED,
END
};
}
struct module_info {
std::string name;
@@ -67,12 +37,13 @@ struct module_info {
};
extern bool zygisk_enabled;
extern int app_process_32;
extern int app_process_64;
extern std::vector<module_info> *module_list;
extern std::string native_bridge;
extern "C" const char *get_magisk_tmp();
void reset_zygisk(bool restore);
int connect_daemon(int req, bool create = false);
std::string find_preinit_device();
void unlock_blocks();
// Poll control
using poll_callback = void(*)(pollfd*);
@@ -81,6 +52,7 @@ void unregister_poll(int fd, bool auto_close);
void clear_poll();
// Thread pool
void init_thread_pool();
void exec_task(std::function<void()> &&task);
// Daemon handlers
@@ -98,7 +70,26 @@ std::vector<bool> get_app_no_list();
int get_manager(int user_id = 0, std::string *pkg = nullptr, bool install = false);
void prune_su_access();
// Module stuffs
void handle_modules();
void load_modules();
void disable_modules();
void remove_modules();
void exec_module_scripts(const char *stage);
// Scripting
void exec_script(const char *script);
void exec_common_scripts(const char *stage);
void exec_module_scripts(const char *stage, const std::vector<std::string_view> &modules);
void install_apk(const char *apk);
void uninstall_pkg(const char *pkg);
void clear_pkg(const char *pkg, int user_id);
[[noreturn]] void install_module(const char *file);
// Denylist
extern std::atomic_flag skip_pkg_rescan;
void initialize_denylist();
extern std::atomic<bool> denylist_enforced;
int denylist_cli(int argc, char **argv);
void initialize_denylist();
bool is_deny_target(int uid, std::string_view process);
void revert_unmount();

View File

@@ -0,0 +1,29 @@
#pragma once
#include <base.hpp>
namespace rust {
struct MagiskD;
}
struct MagiskD {
// Make sure only references can exist
~MagiskD() = delete;
// Binding to Rust
static const MagiskD &get();
// C++ implementation
void reboot() const;
bool post_fs_data() const;
void late_start() const;
void boot_complete() const;
const rust::MagiskD *operator->() const;
private:
const rust::MagiskD &as_rust() const;
};
const char *get_magisk_tmp();
static inline rust::Utf8CStr get_magisk_tmp_rs() { return get_magisk_tmp(); }

View File

@@ -4,18 +4,15 @@
#include <map>
#include <cxx.h>
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <api/_system_properties.h>
struct prop_cb {
virtual void exec(const char *name, const char *value) = 0;
virtual void exec(const char *name, const char *value, uint32_t serial) = 0;
};
using prop_list = std::map<std::string, std::string>;
struct prop_collector : prop_cb {
explicit prop_collector(prop_list &list) : list(list) {}
void exec(const char *name, const char *value) override {
void exec(const char *name, const char *value, uint32_t) override {
list.insert({name, value});
}
private:
@@ -29,6 +26,6 @@ int delete_prop(const char *name, bool persist = false);
int set_prop(const char *name, const char *value, bool skip_svc = false);
void load_prop_file(const char *filename, bool skip_svc = false);
static inline void prop_cb_exec(prop_cb &cb, const char *name, const char *value) {
cb.exec(name, value);
static inline void prop_cb_exec(prop_cb &cb, const char *name, const char *value, uint32_t serial) {
cb.exec(name, value, serial);
}

View File

@@ -18,13 +18,60 @@ mod resetprop;
#[cxx::bridge]
pub mod ffi {
#[repr(i32)]
enum RequestCode {
START_DAEMON,
CHECK_VERSION,
CHECK_VERSION_CODE,
STOP_DAEMON,
_SYNC_BARRIER_,
SUPERUSER,
ZYGOTE_RESTART,
DENYLIST,
SQLITE_CMD,
REMOVE_MODULES,
ZYGISK,
_STAGE_BARRIER_,
POST_FS_DATA,
LATE_START,
BOOT_COMPLETE,
END,
}
extern "C++" {
include!("resetprop/resetprop.hpp");
include!("include/resetprop.hpp");
#[cxx_name = "prop_cb"]
type PropCb;
unsafe fn get_prop_rs(name: *const c_char, persist: bool) -> String;
unsafe fn prop_cb_exec(cb: Pin<&mut PropCb>, name: *const c_char, value: *const c_char);
unsafe fn prop_cb_exec(
cb: Pin<&mut PropCb>,
name: *const c_char,
value: *const c_char,
serial: u32,
);
}
unsafe extern "C++" {
#[namespace = "rust"]
#[cxx_name = "Utf8CStr"]
type Utf8CStrRef<'a> = base::ffi::Utf8CStrRef<'a>;
include!("include/daemon.hpp");
#[cxx_name = "get_magisk_tmp_rs"]
fn get_magisk_tmp() -> Utf8CStrRef<'static>;
#[cxx_name = "MagiskD"]
type CxxMagiskD;
fn post_fs_data(self: &CxxMagiskD) -> bool;
fn late_start(self: &CxxMagiskD);
fn boot_complete(self: &CxxMagiskD);
}
extern "Rust" {
@@ -34,12 +81,12 @@ pub mod ffi {
fn zygisk_logging();
fn zygisk_close_logd();
fn zygisk_get_logd() -> i32;
fn find_apk_path(pkg: &[u8], data: &mut [u8]) -> usize;
fn find_apk_path(pkg: Utf8CStrRef, data: &mut [u8]) -> usize;
fn read_certificate(fd: i32, version: i32) -> Vec<u8>;
unsafe fn persist_get_prop(name: *const c_char, prop_cb: Pin<&mut PropCb>);
unsafe fn persist_get_prop(name: Utf8CStrRef, prop_cb: Pin<&mut PropCb>);
unsafe fn persist_get_props(prop_cb: Pin<&mut PropCb>);
unsafe fn persist_delete_prop(name: *const c_char) -> bool;
unsafe fn persist_set_prop(name: *const c_char, value: *const c_char) -> bool;
unsafe fn persist_delete_prop(name: Utf8CStrRef) -> bool;
unsafe fn persist_set_prop(name: Utf8CStrRef, value: Utf8CStrRef) -> bool;
}
#[namespace = "rust"]
@@ -48,10 +95,10 @@ pub mod ffi {
type MagiskD;
fn get_magiskd() -> &'static MagiskD;
fn get_log_pipe(self: &MagiskD) -> i32;
fn close_log_pipe(self: &MagiskD);
fn setup_logfile(self: &MagiskD);
fn is_emulator(self: &MagiskD) -> bool;
fn is_recovery(self: &MagiskD) -> bool;
fn boot_stage_handler(self: &MagiskD, client: i32, code: i32);
}
}

View File

@@ -3,7 +3,7 @@ use std::ffi::{c_char, c_void};
use std::fmt::Write as FmtWrite;
use std::fs::File;
use std::io::{IoSlice, Read, Write};
use std::os::fd::{AsRawFd, FromRawFd, RawFd};
use std::os::fd::{FromRawFd, RawFd};
use std::ptr::null_mut;
use std::sync::atomic::{AtomicI32, Ordering};
use std::{fs, io};
@@ -19,7 +19,8 @@ use base::libc::{
};
use base::*;
use crate::daemon::{get_magisk_tmp, MagiskD, MAGISKD};
use crate::daemon::{MagiskD, MAGISKD};
use crate::ffi::get_magisk_tmp;
use crate::logging::LogFile::{Actual, Buffer};
use crate::{LOGFILE, LOG_PIPE};
@@ -382,14 +383,6 @@ impl MagiskD {
}
}
pub fn get_log_pipe(&self) -> RawFd {
self.logd
.lock()
.unwrap()
.as_ref()
.map_or(-1, |s| s.as_raw_fd())
}
pub fn close_log_pipe(&self) {
*self.logd.lock().unwrap() = None;
}

View File

@@ -2,13 +2,11 @@
#include <libgen.h>
#include <base.hpp>
#include <magisk.hpp>
#include <daemon.hpp>
#include <consts.hpp>
#include <core.hpp>
#include <selinux.hpp>
#include <flags.h>
#include "core.hpp"
using namespace std;
[[noreturn]] static void usage() {
@@ -60,12 +58,12 @@ int magisk_main(int argc, char *argv[]) {
#endif
return 0;
} else if (argv[1] == "-v"sv) {
int fd = connect_daemon(MainRequest::CHECK_VERSION);
int fd = connect_daemon(+RequestCode::CHECK_VERSION);
string v = read_string(fd);
printf("%s\n", v.data());
return 0;
} else if (argv[1] == "-V"sv) {
int fd = connect_daemon(MainRequest::CHECK_VERSION_CODE);
int fd = connect_daemon(+RequestCode::CHECK_VERSION_CODE);
printf("%d\n", read_int(fd));
return 0;
} else if (argv[1] == "--list"sv) {
@@ -85,29 +83,29 @@ int magisk_main(int argc, char *argv[]) {
cp_afc(argv[2], argv[3]);
return 0;
} else if (argv[1] == "--daemon"sv) {
close(connect_daemon(MainRequest::START_DAEMON, true));
close(connect_daemon(+RequestCode::START_DAEMON, true));
return 0;
} else if (argv[1] == "--stop"sv) {
int fd = connect_daemon(MainRequest::STOP_DAEMON);
int fd = connect_daemon(+RequestCode::STOP_DAEMON);
return read_int(fd);
} else if (argv[1] == "--post-fs-data"sv) {
int fd = connect_daemon(MainRequest::POST_FS_DATA, true);
int fd = connect_daemon(+RequestCode::POST_FS_DATA, true);
struct pollfd pfd = { fd, POLLIN, 0 };
poll(&pfd, 1, 1000 * POST_FS_DATA_WAIT_TIME);
return 0;
} else if (argv[1] == "--service"sv) {
close(connect_daemon(MainRequest::LATE_START, true));
close(connect_daemon(+RequestCode::LATE_START, true));
return 0;
} else if (argv[1] == "--boot-complete"sv) {
close(connect_daemon(MainRequest::BOOT_COMPLETE));
close(connect_daemon(+RequestCode::BOOT_COMPLETE));
return 0;
} else if (argv[1] == "--zygote-restart"sv) {
close(connect_daemon(MainRequest::ZYGOTE_RESTART));
close(connect_daemon(+RequestCode::ZYGOTE_RESTART));
return 0;
} else if (argv[1] == "--denylist"sv) {
return denylist_cli(argc - 1, argv + 1);
} else if (argc >= 3 && argv[1] == "--sqlite"sv) {
int fd = connect_daemon(MainRequest::SQLITE_CMD);
int fd = connect_daemon(+RequestCode::SQLITE_CMD);
write_string(fd, argv[2]);
string res;
for (;;) {
@@ -125,7 +123,7 @@ int magisk_main(int argc, char *argv[]) {
} else {
usage();
}
int fd = connect_daemon(MainRequest::REMOVE_MODULES);
int fd = connect_daemon(+RequestCode::REMOVE_MODULES);
write_int(fd, do_reboot);
return read_int(fd);
} else if (argv[1] == "--path"sv) {

View File

@@ -1,14 +1,14 @@
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/mount.h>
#include <map>
#include <utility>
#include <base.hpp>
#include <magisk.hpp>
#include <daemon.hpp>
#include <consts.hpp>
#include <core.hpp>
#include <selinux.hpp>
#include "core.hpp"
#include "node.hpp"
using namespace std;
@@ -22,9 +22,6 @@ static int bind_mount(const char *reason, const char *from, const char *to) {
return ret;
}
string node_entry::module_mnt;
string node_entry::mirror_dir;
/*************************
* Node Tree Construction
*************************/
@@ -125,8 +122,8 @@ void dir_node::collect_module_files(const char *module, int dfd) {
* Mount Implementations
************************/
void node_entry::create_and_mount(const char *reason, const string &src) {
const string &dest = node_path();
void node_entry::create_and_mount(const char *reason, const string &src, bool ro) {
const string dest = isa<tmpfs_node>(parent()) ? worker_path() : node_path();
if (is_lnk()) {
VLOGD("cp_link", src.data(), dest.data());
cp_afc(src.data(), dest.data());
@@ -138,6 +135,9 @@ void node_entry::create_and_mount(const char *reason, const string &src) {
else
return;
bind_mount(reason, src.data(), dest.data());
if (ro) {
xmount(nullptr, dest.data(), nullptr, MS_REMOUNT | MS_BIND | MS_RDONLY, nullptr);
}
}
}
@@ -163,22 +163,23 @@ void module_node::mount() {
void tmpfs_node::mount() {
string src = mirror_path();
const string &dest = node_path();
const char *src_path;
if (access(src.data(), F_OK) == 0)
src_path = src.data();
else
src_path = parent()->node_path().data();
const char *src_path = access(src.data(), F_OK) == 0 ? src.data() : nullptr;
if (!isa<tmpfs_node>(parent())) {
auto worker_dir = get_magisk_tmp() + "/"s WORKERDIR + dest;
const string &dest = node_path();
auto worker_dir = worker_path();
mkdirs(worker_dir.data(), 0);
create_and_mount(skip_mirror() ? "replace" : "tmpfs", worker_dir);
bind_mount("tmpfs", worker_dir.data(), worker_dir.data());
clone_attr(src_path ?: parent()->node_path().data(), worker_dir.data());
dir_node::mount();
VLOGD(skip_mirror() ? "replace" : "move", worker_dir.data(), dest.data());
xmount(worker_dir.data(), dest.data(), nullptr, MS_MOVE, nullptr);
} else {
const string dest = worker_path();
// We don't need another layer of tmpfs if parent is tmpfs
mkdir(dest.data(), 0);
clone_attr(src_path ?: parent()->worker_path().data(), dest.data());
dir_node::mount();
}
clone_attr(src_path, dest.data());
dir_node::mount();
}
/****************
@@ -194,7 +195,7 @@ public:
if (access(src.data(), F_OK))
return;
const string &dir_name = parent()->node_path();
const string dir_name = isa<tmpfs_node>(parent()) ? parent()->worker_path() : parent()->node_path();
if (name() == "magisk") {
for (int i = 0; applet_names[i]; ++i) {
string dest = dir_name + "/" + applet_names[i];
@@ -206,11 +207,24 @@ public:
VLOGD("create", "./magiskpolicy", dest.data());
xsymlink("./magiskpolicy", dest.data());
}
create_and_mount("magisk", src);
xmount(nullptr, node_path().data(), nullptr, MS_REMOUNT | MS_BIND | MS_RDONLY, nullptr);
create_and_mount("magisk", src, true);
}
};
class zygisk_node : public node_entry {
public:
explicit zygisk_node(const char *name, bool is64bit) : node_entry(name, DT_REG, this),
is64bit(is64bit) {}
void mount() override {
const string src = get_magisk_tmp() + "/magisk"s + (is64bit ? "64" : "32");
create_and_mount("zygisk", src, true);
}
private:
bool is64bit;
};
static void inject_magisk_bins(root_node *system) {
auto bin = system->get_child<inter_node>("bin");
if (!bin) {
@@ -228,24 +242,28 @@ static void inject_magisk_bins(root_node *system) {
delete bin->extract("supolicy");
}
vector<module_info> *module_list;
int app_process_32 = -1;
int app_process_64 = -1;
static void inject_zygisk_libs(root_node *system) {
if (access("/system/bin/linker", F_OK) == 0) {
auto lib = system->get_child<inter_node>("lib");
if (!lib) {
lib = new inter_node("lib");
system->insert(lib);
}
lib->insert(new zygisk_node(native_bridge.data(), false));
}
#define mount_zygisk(bit) \
if (access("/system/bin/app_process" #bit, F_OK) == 0) { \
app_process_##bit = xopen("/system/bin/app_process" #bit, O_RDONLY | O_CLOEXEC); \
string zbin = zygisk_bin + "/app_process" #bit; \
string mbin = get_magisk_tmp() + "/magisk"s #bit; \
int src = xopen(mbin.data(), O_RDONLY | O_CLOEXEC); \
int out = xopen(zbin.data(), O_CREAT | O_WRONLY | O_CLOEXEC, 0); \
xsendfile(out, src, nullptr, INT_MAX); \
close(out); \
close(src); \
clone_attr("/system/bin/app_process" #bit, zbin.data()); \
bind_mount("zygisk", zbin.data(), "/system/bin/app_process" #bit); \
if (access("/system/bin/linker64", F_OK) == 0) {
auto lib64 = system->get_child<inter_node>("lib64");
if (!lib64) {
lib64 = new inter_node("lib64");
system->insert(lib64);
}
lib64->insert(new zygisk_node(native_bridge.data(), true));
}
}
vector<module_info> *module_list;
void load_modules() {
node_entry::mirror_dir = get_magisk_tmp() + "/"s MIRRDIR;
node_entry::module_mnt = get_magisk_tmp() + "/"s MODULEMNT "/";
@@ -289,6 +307,22 @@ void load_modules() {
inject_magisk_bins(system);
}
if (zygisk_enabled) {
string native_bridge_orig = get_prop(NBPROP);
if (native_bridge_orig.empty()) {
native_bridge_orig = "0";
}
native_bridge = native_bridge_orig != "0" ? ZYGISKLDR + native_bridge_orig : ZYGISKLDR;
set_prop(NBPROP, native_bridge.data());
// Weather Huawei's Maple compiler is enabled.
// If so, system server will be created by a special Zygote which ignores the native bridge
// and make system server out of our control. Avoid it by disabling.
if (get_prop("ro.maple.enable") == "1") {
set_prop("ro.maple.enable", "0");
}
inject_zygisk_libs(system);
}
if (!system->is_empty()) {
// Handle special read-only partitions
for (const char *part : { "/vendor", "/product", "/system_ext" }) {
@@ -304,14 +338,6 @@ void load_modules() {
root->mount();
}
// Mount on top of modules to enable zygisk
if (zygisk_enabled) {
string zygisk_bin = get_magisk_tmp() + "/"s ZYGISKBIN;
mkdir(zygisk_bin.data(), 0);
mount_zygisk(32)
mount_zygisk(64)
}
ssprintf(buf, sizeof(buf), "%s/" WORKERDIR, get_magisk_tmp());
xmount(nullptr, buf, nullptr, MS_REMOUNT | MS_RDONLY, nullptr);
}

View File

@@ -45,12 +45,14 @@ public:
// Don't call the following two functions before prepare
const string &node_path();
const string worker_path();
string mirror_path() { return mirror_dir + node_path(); }
virtual void mount() = 0;
static string module_mnt;
static string mirror_dir;
inline static string module_mnt;
inline static string mirror_dir;
protected:
template<class T>
@@ -67,7 +69,7 @@ protected:
delete other;
}
void create_and_mount(const char *reason, const string &src);
void create_and_mount(const char *reason, const string &src, bool ro=false);
// Use bit 7 of _file_type for exist status
bool exist() const { return static_cast<bool>(_file_type & (1 << 7)); }
@@ -314,3 +316,7 @@ const string &node_entry::node_path() {
_node_path = _parent->node_path() + '/' + _name;
return _node_path;
}
const string node_entry::worker_path() {
return get_magisk_tmp() + "/"s WORKERDIR + node_path();
}

View File

@@ -1,11 +1,9 @@
#include <base.hpp>
#include <magisk.hpp>
#include <daemon.hpp>
#include <consts.hpp>
#include <core.hpp>
#include <db.hpp>
#include <flags.h>
#include "core.hpp"
using namespace std;
using rust::Vec;
@@ -15,12 +13,11 @@ using rust::Vec;
// so performance is absolutely critical. Most operations should either have its result cached
// or simply skipped unless necessary.
atomic<ino_t> pkg_xml_ino = 0;
static atomic_flag skip_mgr_check;
static pthread_mutex_t pkg_lock = PTHREAD_MUTEX_INITIALIZER;
// pkg_lock protects all following variables
static int mgr_app_id = -1;
static bool skip_mgr_check;
static timespec *app_ts;
static string *mgr_pkg;
static Vec<uint8_t> *mgr_cert;
static int stub_apk_fd = -1;
@@ -31,12 +28,17 @@ static bool operator==(const Vec<uint8_t> &a, const Vec<uint8_t> &b) {
}
void check_pkg_refresh() {
struct stat st{};
if (stat("/data/system/packages.xml", &st) == 0 &&
pkg_xml_ino.exchange(st.st_ino) != st.st_ino) {
skip_mgr_check.clear();
skip_pkg_rescan.clear();
mutex_guard g(pkg_lock);
if (app_ts == nullptr)
default_new(app_ts);
if (struct stat st{}; stat("/data/app", &st) == 0) {
if (memcmp(app_ts, &st.st_mtim, sizeof(timespec)) == 0) {
return;
}
memcpy(app_ts, &st.st_mtim, sizeof(timespec));
}
skip_mgr_check = false;
skip_pkg_rescan.clear();
}
// app_id = app_no + AID_APP_START
@@ -126,7 +128,7 @@ int get_manager(int user_id, string *pkg, bool install) {
return true;
};
if (skip_mgr_check.test_and_set()) {
if (skip_mgr_check) {
if (mgr_app_id >= 0) {
// Just need to check whether the app is installed in the user
const char *name = mgr_pkg->empty() ? JAVA_PACKAGE_NAME : mgr_pkg->data();
@@ -146,6 +148,8 @@ int get_manager(int user_id, string *pkg, bool install) {
// This means that we check all users, not just the requested user.
// Certificates are also verified to prevent manipulation.
skip_mgr_check = true;
db_strings str;
get_db_strings(str, SU_MANAGER);
@@ -178,7 +182,7 @@ int get_manager(int user_id, string *pkg, bool install) {
int app_id = to_app_id(st.st_uid);
byte_array<PATH_MAX> apk;
find_apk_path(byte_view(str[SU_MANAGER]), apk);
find_apk_path(str[SU_MANAGER], apk);
int fd = xopen((const char *) apk.buf(), O_RDONLY | O_CLOEXEC);
auto cert = read_certificate(fd, -1);
close(fd);
@@ -232,7 +236,7 @@ int get_manager(int user_id, string *pkg, bool install) {
if (stat(app_path, &st) == 0) {
#if ENFORCE_SIGNATURE
byte_array<PATH_MAX> apk;
find_apk_path(byte_view(JAVA_PACKAGE_NAME), apk);
find_apk_path(JAVA_PACKAGE_NAME, apk);
int fd = xopen((const char *) apk.buf(), O_RDONLY | O_CLOEXEC);
auto cert = read_certificate(fd, MAGISK_VER_CODE);
close(fd);

View File

@@ -1,4 +1,3 @@
use core::ffi::c_char;
use std::io::Read;
use std::{
fs::File,
@@ -39,7 +38,7 @@ trait PropCbExec {
impl PropCbExec for Pin<&mut PropCb> {
fn exec(&mut self, name: &Utf8CStr, value: &Utf8CStr) {
unsafe { prop_cb_exec(self.as_mut(), name.as_ptr(), value.as_ptr()) }
unsafe { prop_cb_exec(self.as_mut(), name.as_ptr(), value.as_ptr(), u32::MAX) }
}
}
@@ -142,9 +141,8 @@ fn proto_write_props(props: &PersistentProperties) -> LoggedResult<()> {
Ok(())
}
pub unsafe fn persist_get_prop(name: *const c_char, prop_cb: Pin<&mut PropCb>) {
fn inner(name: *const c_char, mut prop_cb: Pin<&mut PropCb>) -> LoggedResult<()> {
let name = unsafe { Utf8CStr::from_ptr(name)? };
pub unsafe fn persist_get_prop(name: &Utf8CStr, prop_cb: Pin<&mut PropCb>) {
fn inner(name: &Utf8CStr, mut prop_cb: Pin<&mut PropCb>) -> LoggedResult<()> {
if check_proto() {
let mut props = proto_read_props()?;
let prop = props.find(name)?;
@@ -197,9 +195,8 @@ pub unsafe fn persist_get_props(prop_cb: Pin<&mut PropCb>) {
inner(prop_cb).ok();
}
pub unsafe fn persist_delete_prop(name: *const c_char) -> bool {
fn inner(name: *const c_char) -> LoggedResult<()> {
let name = unsafe { Utf8CStr::from_ptr(name)? };
pub unsafe fn persist_delete_prop(name: &Utf8CStr) -> bool {
fn inner(name: &Utf8CStr) -> LoggedResult<()> {
if check_proto() {
let mut props = proto_read_props()?;
let idx = props.find_index(name).no_log()?;
@@ -212,10 +209,8 @@ pub unsafe fn persist_delete_prop(name: *const c_char) -> bool {
inner(name).is_ok()
}
pub unsafe fn persist_set_prop(name: *const c_char, value: *const c_char) -> bool {
unsafe fn inner(name: *const c_char, value: *const c_char) -> LoggedResult<()> {
let name = Utf8CStr::from_ptr(name)?;
let value = Utf8CStr::from_ptr(value)?;
pub unsafe fn persist_set_prop(name: &Utf8CStr, value: &Utf8CStr) -> bool {
unsafe fn inner(name: &Utf8CStr, value: &Utf8CStr) -> LoggedResult<()> {
if check_proto() {
let mut props = proto_read_props()?;
match props.find_index(name) {

View File

@@ -4,18 +4,22 @@
#include <map>
#include <base.hpp>
#include <core.hpp>
#include <resetprop.hpp>
#include "resetprop.hpp"
#include "../core-rs.hpp"
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <api/_system_properties.h>
#include <system_properties/prop_info.h>
using namespace std;
#ifdef APPLET_STUB_MAIN
#define system_property_set __system_property_set
#define system_property_read(...)
#define system_property_find __system_property_find
#define system_property_read_callback __system_property_read_callback
#define system_property_foreach __system_property_foreach
#define system_property_read(...)
#define system_property_wait __system_property_wait
#else
static int (*system_property_set)(const char*, const char*);
static int (*system_property_read)(const prop_info*, char*, char*);
@@ -23,6 +27,7 @@ static const prop_info *(*system_property_find)(const char*);
static void (*system_property_read_callback)(
const prop_info*, void (*)(void*, const char*, const char*, uint32_t), void*);
static int (*system_property_foreach)(void (*)(const prop_info*, void*), void*);
static bool (*system_property_wait)(const prop_info*, uint32_t, uint32_t*, const struct timespec*);
#endif
struct PropFlags {
@@ -30,10 +35,12 @@ struct PropFlags {
void setPersist() { flags |= (1 << 1); }
void setContext() { flags |= (1 << 2); }
void setPersistOnly() { flags |= (1 << 3); setPersist(); }
void setWait() { flags |= (1 << 4); }
bool isSkipSvc() const { return flags & 1; }
bool isPersist() const { return flags & (1 << 1); }
bool isContext() const { return flags & (1 << 2); }
bool isPersistOnly() const { return flags & (1 << 3); }
bool isWait() const { return flags & (1 << 4); }
private:
uint32_t flags = 0;
};
@@ -46,16 +53,22 @@ Usage: %s [flags] [arguments...]
Read mode arguments:
(no arguments) print all properties
NAME get property
NAME get property of NAME
Write mode arguments:
NAME VALUE set property NAME as VALUE
-f,--file FILE load and set properties from FILE
-d,--delete NAME delete property
Wait mode arguments (toggled with -w):
NAME wait until property NAME changes
NAME OLD_VALUE if value of property NAME is not OLD_VALUE, get value
or else wait until property NAME changes
General flags:
-h,--help show this message
-v print verbose output to stderr
-w switch to wait mode
Read mode flags:
-p also read persistent props from storage
@@ -101,8 +114,8 @@ illegal:
static void read_prop_with_cb(const prop_info *pi, void *cb) {
if (system_property_read_callback) {
auto callback = [](void *cb, const char *name, const char *value, uint32_t) {
static_cast<prop_cb*>(cb)->exec(name, value);
auto callback = [](void *cb, const char *name, const char *value, uint32_t serial) {
static_cast<prop_cb*>(cb)->exec(name, value, serial);
};
system_property_read_callback(pi, callback, cb);
} else {
@@ -111,39 +124,45 @@ static void read_prop_with_cb(const prop_info *pi, void *cb) {
name[0] = '\0';
value[0] = '\0';
system_property_read(pi, name, value);
static_cast<prop_cb*>(cb)->exec(name, value);
static_cast<prop_cb*>(cb)->exec(name, value, pi->serial);
}
}
template<class StringType>
struct prop_to_string : prop_cb {
void exec(const char *, const char *value) override {
void exec(const char *, const char *value, uint32_t s) override {
val = value;
serial = s;
}
StringType val;
uint32_t serial;
};
template<> void prop_to_string<rust::String>::exec(const char *, const char *value) {
template<> void prop_to_string<rust::String>::exec(const char *, const char *value, uint32_t s) {
// We do not want to crash when values are not UTF-8
val = rust::String::lossy(value);
serial = s;
}
static int set_prop(const char *name, const char *value, PropFlags flags) {
if (!check_legal_property_name(name))
return 1;
const char *msg = flags.isSkipSvc() ? "direct modification" : "property_service";
auto pi = const_cast<prop_info *>(__system_property_find(name));
// Always delete existing read-only properties, because they could be
// long properties and cannot directly go through __system_property_update
if (pi != nullptr && str_starts(name, "ro.")) {
// Skip pruning nodes as we will add it back ASAP
__system_property_delete(name, false);
pi = nullptr;
// Delete existing read-only properties if they are or will be long properties,
// which cannot directly go through __system_property_update
if (str_starts(name, "ro.")) {
if (pi != nullptr && (pi->is_long() || strlen(value) >= PROP_VALUE_MAX)) {
// Skip pruning nodes as we will add it back ASAP
__system_property_delete(name, false);
pi = nullptr;
}
flags.setSkipSvc();
}
const char *msg = flags.isSkipSvc() ? "direct modification" : "property_service";
int ret;
if (pi != nullptr) {
if (flags.isSkipSvc()) {
@@ -184,7 +203,7 @@ static StringType get_prop(const char *name, PropFlags flags) {
if (flags.isContext()) {
auto context = __system_property_get_context(name) ?: "";
LOGD("resetprop: prop context [%s]: [%s]\n", name, context);
cb.exec(name, context);
cb.exec(name, context, -1);
return cb.val;
}
@@ -203,6 +222,30 @@ static StringType get_prop(const char *name, PropFlags flags) {
return cb.val;
}
template<class StringType>
static StringType wait_prop(const char *name, const char *old_value) {
if (!check_legal_property_name(name))
return {};
auto pi = system_property_find(name);
if (!pi) {
LOGD("resetprop: prop [%s] does not exist\n", name);
return {};
}
prop_to_string<StringType> cb;
read_prop_with_cb(pi, &cb);
if (old_value == nullptr || cb.val == old_value) {
LOGD("resetprop: waiting for prop [%s]\n", name);
uint32_t new_serial;
system_property_wait(pi, cb.serial, &new_serial, nullptr);
read_prop_with_cb(pi, &cb);
}
LOGD("resetprop: get prop [%s]: [%s]\n", name, cb.val.c_str());
return cb.val;
}
static void print_props(PropFlags flags) {
prop_list list;
prop_collector collector(list);
@@ -250,7 +293,12 @@ struct Initialize {
DLOAD(system_property_find);
DLOAD(system_property_read_callback);
DLOAD(system_property_foreach);
DLOAD(system_property_wait);
#undef DLOAD
if (system_property_wait == nullptr) {
// The platform API only exist on API 26+
system_property_wait = __system_property_wait;
}
#endif
if (__system_properties_init()) {
LOGE("resetprop: __system_properties_init error\n");
@@ -313,6 +361,9 @@ int resetprop_main(int argc, char *argv[]) {
case 'Z':
flags.setContext();
continue;
case 'w':
flags.setWait();
continue;
case '\0':
break;
default:
@@ -337,6 +388,15 @@ int resetprop_main(int argc, char *argv[]) {
return 0;
}
if (flags.isWait()) {
if (argc == 0) usage(argv0);
auto val = wait_prop<string>(argv[0], argv[1]);
if (val.empty())
return 1;
printf("%s\n", val.data());
return 0;
}
switch (argc) {
case 0:
print_props(flags);

View File

@@ -2,12 +2,10 @@
#include <vector>
#include <sys/wait.h>
#include <magisk.hpp>
#include <consts.hpp>
#include <base.hpp>
#include <selinux.hpp>
#include <daemon.hpp>
#include "core.hpp"
#include <core.hpp>
using namespace std;
@@ -15,9 +13,10 @@ using namespace std;
static const char *bbpath() {
static string path;
if (path.empty()) {
path = get_magisk_tmp();
path += "/" BBPATH "/busybox";
path = get_magisk_tmp();
path += "/" BBPATH "/busybox";
if (access(path.data(), X_OK) != 0) {
path = DATABIN "/busybox";
}
return path.data();
}
@@ -162,12 +161,9 @@ rm -f $APK
void install_apk(const char *apk) {
setfilecon(apk, MAGISK_FILE_CON);
exec_t exec {
.fork = fork_no_orphan
};
char cmds[sizeof(install_script) + 4096];
ssprintf(cmds, sizeof(cmds), install_script, apk, JAVA_PACKAGE_NAME);
exec_command_sync(exec, "/system/bin/sh", "-c", cmds);
exec_command_async("/system/bin/sh", "-c", cmds);
}
constexpr char uninstall_script[] = R"EOF(
@@ -177,12 +173,9 @@ log -t Magisk "pm_uninstall: $(pm uninstall $PKG 2>&1)"
)EOF";
void uninstall_pkg(const char *pkg) {
exec_t exec {
.fork = fork_no_orphan
};
char cmds[sizeof(uninstall_script) + 256];
ssprintf(cmds, sizeof(cmds), uninstall_script, pkg);
exec_command_sync(exec, "/system/bin/sh", "-c", cmds);
exec_command_async("/system/bin/sh", "-c", cmds);
}
constexpr char clear_script[] = R"EOF(
@@ -193,12 +186,9 @@ log -t Magisk "pm_clear: $(pm clear --user $USER $PKG 2>&1)"
)EOF";
void clear_pkg(const char *pkg, int user_id) {
exec_t exec {
.fork = fork_no_orphan
};
char cmds[sizeof(clear_script) + 288];
ssprintf(cmds, sizeof(cmds), clear_script, pkg, user_id);
exec_command_sync(exec, "/system/bin/sh", "-c", cmds);
exec_command_async("/system/bin/sh", "-c", cmds);
}
[[noreturn]] __printflike(2, 3)
@@ -212,7 +202,7 @@ static void abort(FILE *fp, const char *fmt, ...) {
}
constexpr char install_module_script[] = R"EOF(
exec $(magisk --path)/.magisk/busybox/busybox sh -c '
exec %s sh -c '
. /data/adb/magisk/util_functions.sh
install_module
exit 0'
@@ -222,7 +212,7 @@ void install_module(const char *file) {
if (getuid() != 0)
abort(stderr, "Run this command with root");
if (access(DATABIN, F_OK) ||
access(DATABIN "/busybox", X_OK) ||
access(bbpath(), X_OK) ||
access(DATABIN "/util_functions.sh", F_OK))
abort(stderr, "Incomplete Magisk install");
if (access(file, F_OK))
@@ -238,7 +228,10 @@ void install_module(const char *file) {
xdup2(fd, STDERR_FILENO);
close(fd);
const char *argv[] = { "/system/bin/sh", "-c", install_module_script, nullptr };
char cmds[256];
ssprintf(cmds, sizeof(cmds), install_module_script, bbpath());
const char *argv[] = { "/system/bin/sh", "-c", cmds, nullptr };
execve(argv[0], (char **) argv, environ);
abort(stdout, "Failed to execute BusyBox shell");
}

View File

@@ -2,10 +2,10 @@
#include <sys/syscall.h>
#include <sys/xattr.h>
#include <magisk.hpp>
#include <consts.hpp>
#include <base.hpp>
#include <selinux.hpp>
#include <daemon.hpp>
#include <core.hpp>
#include <flags.h>
using namespace std;

View File

@@ -3,18 +3,18 @@
#include <base.hpp>
#include <selinux.hpp>
#include <magisk.hpp>
#include <consts.hpp>
#include "su.hpp"
using namespace std;
#define CALL_PROVIDER \
exe, "/system/bin", "com.android.commands.content.Content", \
"/system/bin/app_process", "/system/bin", "com.android.commands.content.Content", \
"call", "--uri", target, "--user", user, "--method", action
#define START_ACTIVITY \
exe, "/system/bin", "com.android.commands.am.Am", \
"/system/bin/app_process", "/system/bin", "com.android.commands.am.Am", \
"start", "-p", target, "--user", user, "-a", "android.intent.action.VIEW", \
"-f", "0x58800020", "--es", "action", action
@@ -130,21 +130,10 @@ static bool check_no_error(int fd) {
static void exec_cmd(const char *action, vector<Extra> &data,
const shared_ptr<su_info> &info, bool provider = true) {
char exe[128];
char target[128];
char user[4];
ssprintf(user, sizeof(user), "%d", to_user_id(info->eval_uid));
if (zygisk_enabled) {
#if defined(__LP64__)
ssprintf(exe, sizeof(exe), "/proc/self/fd/%d", app_process_64);
#else
ssprintf(exe, sizeof(exe), "/proc/self/fd/%d", app_process_32);
#endif
} else {
strscpy(exe, "/system/bin/app_process", sizeof(exe));
}
// First try content provider call method
if (provider) {
ssprintf(target, sizeof(target), "content://%s.provider", info->mgr_pkg.data());

View File

@@ -13,7 +13,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <magisk.hpp>
#include <consts.hpp>
#include <base.hpp>
#include <flags.h>
@@ -189,7 +189,7 @@ int su_client_main(int argc, char *argv[]) {
int ptmx, fd;
// Connect to client
fd = connect_daemon(MainRequest::SUPERUSER);
fd = connect_daemon(+RequestCode::SUPERUSER);
// Send su_request
xwrite(fd, &su_req, sizeof(su_req_base));

View File

@@ -5,7 +5,7 @@
#include <memory>
#include <db.hpp>
#include <daemon.hpp>
#include <core.hpp>
#define DEFAULT_SHELL "/system/bin/sh"

View File

@@ -5,7 +5,7 @@
#include <sys/wait.h>
#include <sys/mount.h>
#include <magisk.hpp>
#include <consts.hpp>
#include <base.hpp>
#include <selinux.hpp>

View File

@@ -2,7 +2,7 @@
#include <base.hpp>
#include <daemon.hpp>
#include <core.hpp>
using namespace std;
@@ -42,8 +42,6 @@ static void reset_pool() {
}
static void *thread_pool_loop(void * const is_core_pool) {
pthread_atfork(nullptr, nullptr, &reset_pool);
// Block all signals
sigset_t mask;
sigfillset(&mask);
@@ -83,6 +81,10 @@ static void *thread_pool_loop(void * const is_core_pool) {
}
}
void init_thread_pool() {
pthread_atfork(nullptr, nullptr, &reset_pool);
}
void exec_task(function<void()> &&task) {
mutex_guard g(lock);
pending_task.swap(task);

View File

@@ -23,7 +23,7 @@
#include <jni.h>
#define ZYGISK_API_VERSION 4
#define ZYGISK_API_VERSION 5
/*
@@ -161,6 +161,7 @@ struct AppSpecializeArgs {
jobjectArray *const whitelisted_data_info_list;
jboolean *const mount_data_dirs;
jboolean *const mount_storage_dirs;
jboolean *const mount_sysprop_overrides;
AppSpecializeArgs() = delete;
};

View File

@@ -6,57 +6,28 @@
#include <android/dlext.h>
#include <base.hpp>
#include <daemon.hpp>
#include <magisk.hpp>
#include <selinux.hpp>
#include <consts.hpp>
#include "zygisk.hpp"
#include "module.hpp"
#include "deny/deny.hpp"
using namespace std;
void *self_handle = nullptr;
string native_bridge = "0";
// Make sure /proc/self/environ is sanitized
// Filter env and reset MM_ENV_END
static void sanitize_environ() {
char *cur = environ[0];
for (int i = 0; environ[i]; ++i) {
// Copy all env onto the original stack
size_t len = strlen(environ[i]);
memmove(cur, environ[i], len + 1);
environ[i] = cur;
cur += len + 1;
}
prctl(PR_SET_MM, PR_SET_MM_ENV_END, cur, 0, 0);
}
extern "C" void unload_first_stage() {
ZLOGD("unloading first stage\n");
unmap_all(HIJACK_BIN);
xumount2(HIJACK_BIN, MNT_DETACH);
}
extern "C" void zygisk_inject_entry(void *handle) {
static bool is_compatible_with(uint32_t) {
zygisk_logging();
ZLOGD("load success\n");
char *ld = getenv("LD_PRELOAD");
if (char *c = strrchr(ld, ':')) {
*c = '\0';
setenv("LD_PRELOAD", ld, 1); // Restore original LD_PRELOAD
} else {
unsetenv("LD_PRELOAD");
}
self_handle = handle;
sanitize_environ();
hook_functions();
ZLOGD("load success\n");
return false;
}
extern "C" [[maybe_unused]] NativeBridgeCallbacks NativeBridgeItf{
.version = 2,
.padding = {},
.isCompatibleWith = &is_compatible_with,
};
// The following code runs in zygote/app process
static inline bool should_load_modules(uint32_t flags) {
@@ -146,88 +117,6 @@ static void connect_companion(int client, bool is_64_bit) {
send_fd(zygiskd_socket, client);
}
static timespec last_zygote_start;
static int zygote_start_counts[] = { 0, 0 };
#define zygote_start_count zygote_start_counts[is_64_bit]
#define zygote_started (zygote_start_counts[0] + zygote_start_counts[1])
#define zygote_start_reset(val) { zygote_start_counts[0] = val; zygote_start_counts[1] = val; }
static void setup_files(int client, const sock_cred *cred) {
LOGD("zygisk: setup files for pid=[%d]\n", cred->pid);
char buf[4096];
if (!get_exe(cred->pid, buf, sizeof(buf))) {
write_int(client, 1);
return;
}
// Hijack some binary in /system/bin to host loader
const char *hbin;
string mbin;
int app_fd;
bool is_64_bit = str_ends(buf, "64");
if (is_64_bit) {
hbin = HIJACK_BIN64;
mbin = get_magisk_tmp() + "/"s ZYGISKBIN "/loader64.so";
app_fd = app_process_64;
} else {
hbin = HIJACK_BIN32;
mbin = get_magisk_tmp() + "/"s ZYGISKBIN "/loader32.so";
app_fd = app_process_32;
}
if (!zygote_started) {
// First zygote launch, record time
clock_gettime(CLOCK_MONOTONIC, &last_zygote_start);
}
if (zygote_start_count) {
// This zygote ABI had started before, kill existing zygiskd
close(zygiskd_sockets[0]);
close(zygiskd_sockets[1]);
zygiskd_sockets[0] = -1;
zygiskd_sockets[1] = -1;
xumount2(hbin, MNT_DETACH);
}
++zygote_start_count;
if (zygote_start_count >= 5) {
// Bootloop prevention
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
if (ts.tv_sec - last_zygote_start.tv_sec > 60) {
// This is very likely manual soft reboot
memcpy(&last_zygote_start, &ts, sizeof(ts));
zygote_start_reset(1);
} else {
// If any zygote relaunched more than 5 times within a minute,
// don't do any setups further to prevent bootloop.
zygote_start_reset(999);
write_int(client, 1);
return;
}
}
// Ack
write_int(client, 0);
// Receive and bind mount loader
int ld_fd = xopen(mbin.data(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0755);
string ld_data = read_string(client);
xwrite(ld_fd, ld_data.data(), ld_data.size());
close(ld_fd);
setfilecon(mbin.data(), MAGISK_FILE_CON);
xmount(mbin.data(), hbin, nullptr, MS_BIND, nullptr);
send_fd(client, app_fd);
}
static void magiskd_passthrough(int client) {
bool is_64_bit = read_int(client);
write_int(client, 0);
send_fd(client, is_64_bit ? app_process_64 : app_process_32);
}
extern bool uid_granted_root(int uid);
static void get_process_info(int client, const sock_cred *cred) {
int uid = read_int(client);
@@ -301,12 +190,6 @@ void zygisk_handler(int client, const sock_cred *cred) {
int code = read_int(client);
char buf[256];
switch (code) {
case ZygiskRequest::SETUP:
setup_files(client, cred);
break;
case ZygiskRequest::PASSTHROUGH:
magiskd_passthrough(client);
break;
case ZygiskRequest::GET_INFO:
get_process_info(client, cred);
break;
@@ -326,3 +209,28 @@ void zygisk_handler(int client, const sock_cred *cred) {
}
close(client);
}
void reset_zygisk(bool restore) {
if (!zygisk_enabled) return;
static atomic_uint zygote_start_count{1};
if (!restore) {
close(zygiskd_sockets[0]);
close(zygiskd_sockets[1]);
zygiskd_sockets[0] = zygiskd_sockets[1] = -1;
}
if (restore) {
zygote_start_count = 1;
} else if (zygote_start_count.fetch_add(1) > 3) {
LOGW("zygote crashes too many times, rolling-back\n");
restore = true;
}
if (restore) {
string native_bridge_orig = "0";
if (native_bridge.length() > strlen(ZYGISKLDR)) {
native_bridge_orig = native_bridge.substr(strlen(ZYGISKLDR));
}
set_prop(NBPROP, native_bridge_orig.data());
} else {
set_prop(NBPROP, native_bridge.data());
}
}

View File

@@ -87,7 +87,7 @@ class ForkAndSpec(JNIHook):
return 'nativeForkAndSpecialize'
def init_args(self):
return 'AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);'
return 'AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);'
def body(self):
decl = ''
@@ -95,7 +95,7 @@ class ForkAndSpec(JNIHook):
for a in self.args:
if a.set_arg:
decl += ind(1) + f'args.{a.name} = &{a.name};'
decl += ind(1) + 'HookContext ctx(env, &args);'
decl += ind(1) + 'ZygiskContext ctx(env, &args);'
decl += ind(1) + f'ctx.{self.base_name()}_pre();'
decl += ind(1) + self.orig_method() + '('
decl += ind(2) + f'env, clazz, {self.name_list()}'
@@ -146,6 +146,9 @@ whitelisted_data_info_list = Argument('whitelisted_data_info_list', JArray(jstri
mount_data_dirs = Argument('mount_data_dirs', jboolean, True)
mount_storage_dirs = Argument('mount_storage_dirs', jboolean, True)
# u
mount_sysprop_overrides = Argument('mount_sysprop_overrides', jboolean, True)
# server
permitted_capabilities = Argument('permitted_capabilities', jlong)
effective_capabilities = Argument('effective_capabilities', jlong)
@@ -167,6 +170,10 @@ fas_r = ForkAndSpec('r', [uid, gid, gids, runtime_flags, rlimits, mount_external
nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir, is_top_app,
pkg_data_info_list, whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs])
fas_u = ForkAndSpec('u', [uid, gid, gids, runtime_flags, rlimits, mount_external, se_info,
nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir, is_top_app,
pkg_data_info_list, whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs, mount_sysprop_overrides])
fas_samsung_m = ForkAndSpec('samsung_m', [uid, gid, gids, runtime_flags, rlimits, mount_external,
se_info, Anon(jint), Anon(jint), nice_name, fds_to_close, instruction_set, app_data_dir])
@@ -190,6 +197,10 @@ spec_r = SpecApp('r', [uid, gid, gids, runtime_flags, rlimits, mount_external, s
is_child_zygote, instruction_set, app_data_dir, is_top_app, pkg_data_info_list,
whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs])
spec_u = SpecApp('u', [uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name,
is_child_zygote, instruction_set, app_data_dir, is_top_app, pkg_data_info_list,
whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs, mount_sysprop_overrides])
spec_samsung_q = SpecApp('samsung_q', [uid, gid, gids, runtime_flags, rlimits, mount_external,
se_info, Anon(jint), Anon(jint), nice_name, is_child_zygote, instruction_set, app_data_dir])
@@ -213,76 +224,34 @@ def gen_jni_def(clz, methods):
decl += ind(1) + f'return {m.ret.value};'
decl += ind(0) + '}'
decl += ind(0) + f'const JNINativeMethod {m.base_name()}_methods[] = {{'
decl += ind(0) + f'std::array {m.base_name()}_methods = {{'
for m in methods:
decl += ind(1) + '{'
decl += ind(1) + 'JNINativeMethod {'
decl += ind(2) + f'"{m.base_name()}",'
decl += ind(2) + f'"{m.jni()}",'
decl += ind(2) + f'(void *) &{m.name}'
decl += ind(1) + '},'
decl += ind(0) + '};'
decl = ind(0) + f'void *{m.base_name()}_orig = nullptr;' + decl
decl += ind(0) + f'constexpr int {m.base_name()}_methods_num = std::size({m.base_name()}_methods);'
decl += ind(0)
hook_map[clz].append(m.base_name())
return decl
def gen_jni_hook():
decl = ''
decl += ind(0) + 'static JNINativeMethod *hookAndSaveJNIMethods(const char *className, const JNINativeMethod *methods, int numMethods) {'
decl += ind(1) + 'JNINativeMethod *newMethods = nullptr;'
decl += ind(1) + 'int clz_id = -1;'
decl += ind(1) + 'int hook_cnt = 0;'
decl += ind(1) + 'do {'
for index, (clz, methods) in enumerate(hook_map.items()):
decl += ind(2) + f'if (className == "{clz}"sv) {{'
decl += ind(3) + f'clz_id = {index};'
decl += ind(3) + f'hook_cnt = {len(methods)};'
decl += ind(3) + 'break;'
decl += ind(2) + '}'
decl += ind(1) + '} while (false);'
decl += ind(1) + 'if (hook_cnt) {'
decl += ind(2) + 'newMethods = new JNINativeMethod[numMethods];'
decl += ind(2) + 'memcpy(newMethods, methods, sizeof(JNINativeMethod) * numMethods);'
decl += ind(1) + '}'
decl += ind(1) + 'auto &class_map = (*jni_method_map)[className];'
decl += ind(1) + 'for (int i = 0; i < numMethods; ++i) {'
for index, methods in enumerate(hook_map.values()):
decl += ind(2) + f'if (hook_cnt && clz_id == {index}) {{'
for m in methods:
decl += ind(3) + f'HOOK_JNI({m})'
decl += ind(2) + '}'
decl += ind(2) + 'class_map[methods[i].name][methods[i].signature] = methods[i].fnPtr;'
decl += ind(1) + '}'
decl += ind(1) + 'return newMethods;'
decl += ind(0) + '}'
return decl
with open('jni_hooks.hpp', 'w') as f:
f.write('// Generated by gen_jni_hooks.py\n')
f.write('\nnamespace {\n')
zygote = 'com/android/internal/os/Zygote'
methods = [fas_l, fas_o, fas_p, fas_q_alt, fas_r, fas_samsung_m, fas_samsung_n, fas_samsung_o, fas_samsung_p]
methods = [fas_l, fas_o, fas_p, fas_q_alt, fas_r, fas_u, fas_samsung_m, fas_samsung_n, fas_samsung_o, fas_samsung_p]
f.write(gen_jni_def(zygote, methods))
methods = [spec_q, spec_q_alt, spec_r, spec_samsung_q]
methods = [spec_q, spec_q_alt, spec_r, spec_u, spec_samsung_q]
f.write(gen_jni_def(zygote, methods))
methods = [server_l, server_samsung_q]
f.write(gen_jni_def(zygote, methods))
f.write('\n} // namespace\n')
f.write(gen_jni_hook())
f.write('\n')

View File

@@ -0,0 +1,592 @@
#include <sys/mount.h>
#include <dlfcn.h>
#include <unwind.h>
#include <lsplt.hpp>
#include <base.hpp>
#include <consts.hpp>
#include "zygisk.hpp"
#include "module.hpp"
#include "jni_hooks.hpp"
using namespace std;
// *********************
// Zygisk Bootstrapping
// *********************
//
// Zygisk's lifecycle is driven by several PLT function hooks in libandroid_runtime, libart, and
// libnative_bridge. As Zygote is starting up, these carefully selected functions will call into
// the respective lifecycle callbacks in Zygisk to drive the progress forward.
//
// The entire bootstrap process is shown in the graph below.
// Arrows represent control flow, and the blocks are sorted chronologically from top to bottom.
//
// libnative_bridge libandroid_runtime zygisk libart
//
// ┌───────┐
// │ start │
// └───┬─┬─┘
// │ │ ┌────────────────┐
// │ └────────────────────────────────────────►│LoadNativeBridge│
// │ └───────┬────────┘
// ┌────────────────┐ │ │
// │LoadNativeBridge│◄────────────┼───────────────────────────────────────────────────┘
// └───────┬────┬───┘ │
// │ │ │ ┌───────────────┐
// │ └─────────────────┼────────────────────►│NativeBridgeItf│
// │ │ └──────┬────────┘
// │ │ │
// │ │ ▼
// │ │ ┌────────┐
// │ │ │hook_plt│
// ▼ │ └────────┘
// ┌───────┐ │
// │dlclose│ │
// └───┬───┘ │
// │ │
// │ │ ┌───────────────────────┐
// └──────────────────────┼────────────────►│post_native_bridge_load│
// │ └───────────────────────┘
// ▼
// ┌──────────────────────────┐
// │androidSetCreateThreadFunc│
// └─────────────┬────┬───────┘
// │ │ ┌────────────┐
// │ └────────────────►│hook_jni_env│
// ▼ └────────────┘
// ┌──────────────────┐
// │register_jni_procs│
// └────────┬────┬────┘
// │ │ ┌───────────────────┐
// │ └─────────────►│replace_jni_methods│
// │ └───────────────────┘ ┌─────────┐
// │ │ │
// └────────────────────────────────────────────►│ JVM │
// │ │
// └──┬─┬────┘
// ┌───────────────────┐ │ │
// │nativeXXXSpecialize│◄─────────────────────────────────────┘ │
// └─────────────┬─────┘ │
// │ ┌─────────────┐ │
// └────────────────►│ZygiskContext│ │
// └─────────────┘ ▼
// ┌────────────────────┐
// │pthread_attr_destroy│
// └─────────┬──────────┘
// ┌────────────────┐ │
// │restore_plt_hook│◄───────────┘
// └────────────────┘
//
// Some notes regarding the important functions/symbols during bootstrap:
//
// * NativeBridgeItf: this symbol is the entry point for android::LoadNativeBridge
// * HookContext::hook_plt(): hook functions like |dlclose| and |androidSetCreateThreadFunc|
// * dlclose: the final step before android::LoadNativeBridge returns
// * androidSetCreateThreadFunc: called in AndroidRuntime::startReg before
// |register_jni_procs|, which is when most native JNI methods are registered.
// * HookContext::hook_jni_env(): replace the |RegisterNatives| function pointer in JNIEnv.
// * replace_jni_methods: called in the replaced |RegisterNatives| function to filter and replace
// the function pointers registered in register_jni_procs, most importantly the process
// specialization routines, which are our main targets. This marks the final step
// of the code injection bootstrap process.
// * pthread_attr_destroy: called whenever the JVM tries to setup threads for itself. We use
// this method to cleanup and unload Zygisk from the process.
struct HookContext {
vector<tuple<dev_t, ino_t, const char *, void **>> plt_backup;
map<string, vector<JNINativeMethod>, StringCmp> jni_backup;
JNINativeInterface new_env{};
const JNINativeInterface *old_env = nullptr;
const NativeBridgeRuntimeCallbacks *runtime_callbacks = nullptr;
void hook_plt();
void hook_unloader();
void restore_plt_hook();
void hook_jni_env();
void restore_jni_hook(JNIEnv *env);
void post_native_bridge_load();
private:
void register_hook(dev_t dev, ino_t inode, const char *symbol, void *new_func, void **old_func);
};
// Global contexts:
//
// HookContext lives as long as Zygisk is loaded in memory. It tracks the process's function
// hooking state and bootstraps code injection until we replace the process specialization methods.
//
// ZygiskContext lives during the process specialization process. It implements Zygisk
// features, such as loading modules and customizing process fork/specialization.
ZygiskContext *g_ctx;
static HookContext *g_hook;
static bool should_unmap_zygisk = false;
static void *self_handle = nullptr;
// -----------------------------------------------------------------
#define DCL_HOOK_FUNC(ret, func, ...) \
ret (*old_##func)(__VA_ARGS__); \
ret new_##func(__VA_ARGS__)
DCL_HOOK_FUNC(static void, androidSetCreateThreadFunc, void *func) {
ZLOGD("androidSetCreateThreadFunc\n");
g_hook->hook_jni_env();
old_androidSetCreateThreadFunc(func);
}
// Skip actual fork and return cached result if applicable
DCL_HOOK_FUNC(int, fork) {
return (g_ctx && g_ctx->pid >= 0) ? g_ctx->pid : old_fork();
}
// Unmount stuffs in the process's private mount namespace
DCL_HOOK_FUNC(static int, unshare, int flags) {
int res = old_unshare(flags);
if (g_ctx && (flags & CLONE_NEWNS) != 0 && res == 0) {
if (g_ctx->flags & DO_REVERT_UNMOUNT) {
revert_unmount();
}
// Restore errno back to 0
errno = 0;
}
return res;
}
// This is the last moment before the secontext of the process changes
DCL_HOOK_FUNC(static int, selinux_android_setcontext,
uid_t uid, bool isSystemServer, const char *seinfo, const char *pkgname) {
// Pre-fetch logd before secontext transition
zygisk_get_logd();
return old_selinux_android_setcontext(uid, isSystemServer, seinfo, pkgname);
}
// Close file descriptors to prevent crashing
DCL_HOOK_FUNC(static void, android_log_close) {
if (g_ctx == nullptr || !(g_ctx->flags & SKIP_CLOSE_LOG_PIPE)) {
// This happens during forks like nativeForkApp, nativeForkUsap,
// nativeForkSystemServer, and nativeForkAndSpecialize.
zygisk_close_logd();
}
old_android_log_close();
}
// It should be safe to assume all dlclose's in libnativebridge are for zygisk_loader
DCL_HOOK_FUNC(static int, dlclose, void *handle) {
if (!self_handle) {
ZLOGV("dlclose zygisk_loader\n");
self_handle = handle;
g_hook->post_native_bridge_load();
}
return 0;
}
// We cannot directly call `dlclose` to unload ourselves, otherwise when `dlclose` returns,
// it will return to our code which has been unmapped, causing segmentation fault.
// Instead, we hook `pthread_attr_destroy` which will be called when VM daemon threads start.
DCL_HOOK_FUNC(static int, pthread_attr_destroy, void *target) {
int res = old_pthread_attr_destroy((pthread_attr_t *)target);
// Only perform unloading on the main thread
if (gettid() != getpid())
return res;
ZLOGV("pthread_attr_destroy\n");
if (should_unmap_zygisk) {
g_hook->restore_plt_hook();
if (should_unmap_zygisk) {
ZLOGV("dlclosing self\n");
delete g_hook;
// Because both `pthread_attr_destroy` and `dlclose` have the same function signature,
// we can use `musttail` to let the compiler reuse our stack frame and thus
// `dlclose` will directly return to the caller of `pthread_attr_destroy`.
[[clang::musttail]] return dlclose(self_handle);
}
}
delete g_hook;
return res;
}
#undef DCL_HOOK_FUNC
// -----------------------------------------------------------------
ZygiskContext::ZygiskContext(JNIEnv *env, void *args) :
env(env), args{args}, process(nullptr), pid(-1), flags(0), info_flags(0),
hook_info_lock(PTHREAD_MUTEX_INITIALIZER) { g_ctx = this; }
ZygiskContext::~ZygiskContext() {
// This global pointer points to a variable on the stack.
// Set this to nullptr to prevent leaking local variable.
// This also disables most plt hooked functions.
g_ctx = nullptr;
if (!is_child())
return;
zygisk_close_logd();
android_logging();
// Strip out all API function pointers
for (auto &m : modules) {
m.clearApi();
}
// Cleanup
should_unmap_zygisk = true;
g_hook->restore_jni_hook(env);
g_hook->hook_unloader();
}
// -----------------------------------------------------------------
inline void *unwind_get_region_start(_Unwind_Context *ctx) {
auto fp = _Unwind_GetRegionStart(ctx);
#if defined(__arm__)
// On arm32, we need to check if the pc is in thumb mode,
// if so, we need to set the lowest bit of fp to 1
auto pc = _Unwind_GetGR(ctx, 15); // r15 is pc
if (pc & 1) {
// Thumb mode
fp |= 1;
}
#endif
return reinterpret_cast<void *>(fp);
}
// As we use NativeBridgeRuntimeCallbacks to reload native bridge and to hook jni functions,
// we need to find it by the native bridge's unwind context.
// For abis that use registers to pass arguments, i.e. arm32, arm64, x86_64, the registers are
// caller-saved, and they are not preserved in the unwind context. However, they will be saved
// into the callee-saved registers, so we will search the callee-saved registers for the second
// argument, which is the pointer to NativeBridgeRuntimeCallbacks.
// For x86, whose abi uses stack to pass arguments, we can directly get the pointer to
// NativeBridgeRuntimeCallbacks from the stack.
static const NativeBridgeRuntimeCallbacks* find_runtime_callbacks(struct _Unwind_Context *ctx) {
// Find the writable memory region of libart.so, where the NativeBridgeRuntimeCallbacks is located.
auto [start, end] = []()-> tuple<uintptr_t, uintptr_t> {
for (const auto &map : lsplt::MapInfo::Scan()) {
if (map.path.ends_with("/libart.so") && map.perms == (PROT_WRITE | PROT_READ)) {
ZLOGV("libart.so: start=%p, end=%p\n",
reinterpret_cast<void *>(map.start), reinterpret_cast<void *>(map.end));
return {map.start, map.end};
}
}
return {0, 0};
}();
#if defined(__aarch64__)
// r19-r28 are callee-saved registers
for (int i = 19; i <= 28; ++i) {
auto val = static_cast<uintptr_t>(_Unwind_GetGR(ctx, i));
ZLOGV("r%d = %p\n", i, reinterpret_cast<void *>(val));
if (val >= start && val < end)
return reinterpret_cast<const NativeBridgeRuntimeCallbacks*>(val);
}
#elif defined(__arm__)
// r4-r10 are callee-saved registers
for (int i = 4; i <= 10; ++i) {
auto val = static_cast<uintptr_t>(_Unwind_GetGR(ctx, i));
ZLOGV("r%d = %p\n", i, reinterpret_cast<void *>(val));
if (val >= start && val < end)
return reinterpret_cast<const NativeBridgeRuntimeCallbacks*>(val);
}
#elif defined(__i386__)
// get ebp, which points to the bottom of the stack frame
auto ebp = static_cast<uintptr_t>(_Unwind_GetGR(ctx, 5));
// 1 pointer size above ebp is the old ebp
// 2 pointer sizes above ebp is the return address
// 3 pointer sizes above ebp is the 2nd arg
auto val = *reinterpret_cast<uintptr_t *>(ebp + 3 * sizeof(void *));
ZLOGV("ebp + 3 * ptr_size = %p\n", reinterpret_cast<void *>(val));
if (val >= start && val < end)
return reinterpret_cast<const NativeBridgeRuntimeCallbacks*>(val);
#elif defined(__x86_64__)
// r12-r15 and rbx are callee-saved registers, but the compiler is likely to use them reversely
for (int i : {3, 15, 14, 13, 12}) {
auto val = static_cast<uintptr_t>(_Unwind_GetGR(ctx, i));
ZLOGV("r%d = %p\n", i, reinterpret_cast<void *>(val));
if (val >= start && val < end)
return reinterpret_cast<const NativeBridgeRuntimeCallbacks*>(val);
}
#else
#error "Unsupported architecture"
#endif
return nullptr;
}
void HookContext::post_native_bridge_load() {
using method_sig = const bool (*)(const char *, const NativeBridgeRuntimeCallbacks *);
struct trace_arg {
method_sig load_native_bridge;
const NativeBridgeRuntimeCallbacks *callbacks;
};
trace_arg arg{};
// Unwind to find the address of android::LoadNativeBridge and NativeBridgeRuntimeCallbacks
_Unwind_Backtrace(+[](_Unwind_Context *ctx, void *arg) -> _Unwind_Reason_Code {
void *fp = unwind_get_region_start(ctx);
Dl_info info{};
dladdr(fp, &info);
ZLOGV("backtrace: %p %s\n", fp, info.dli_fname ?: "???");
if (info.dli_fname && std::string_view(info.dli_fname).ends_with("/libnativebridge.so")) {
auto payload = reinterpret_cast<trace_arg *>(arg);
payload->load_native_bridge = reinterpret_cast<method_sig>(fp);
payload->callbacks = find_runtime_callbacks(ctx);
ZLOGV("NativeBridgeRuntimeCallbacks: %p\n", payload->callbacks);
return _URC_END_OF_STACK;
}
return _URC_NO_REASON;
}, &arg);
if (!arg.load_native_bridge || !arg.callbacks)
return;
// Reload the real native bridge if necessary
auto nb = get_prop(NBPROP);
auto len = sizeof(ZYGISKLDR) - 1;
if (nb.size() > len) {
arg.load_native_bridge(nb.data() + len, arg.callbacks);
}
runtime_callbacks = arg.callbacks;
}
// -----------------------------------------------------------------
void HookContext::register_hook(
dev_t dev, ino_t inode, const char *symbol, void *new_func, void **old_func) {
if (!lsplt::RegisterHook(dev, inode, symbol, new_func, old_func)) {
ZLOGE("Failed to register plt_hook \"%s\"\n", symbol);
return;
}
plt_backup.emplace_back(dev, inode, symbol, old_func);
}
#define PLT_HOOK_REGISTER_SYM(DEV, INODE, SYM, NAME) \
register_hook(DEV, INODE, SYM, \
reinterpret_cast<void *>(new_##NAME), reinterpret_cast<void **>(&old_##NAME))
#define PLT_HOOK_REGISTER(DEV, INODE, NAME) \
PLT_HOOK_REGISTER_SYM(DEV, INODE, #NAME, NAME)
void HookContext::hook_plt() {
ino_t android_runtime_inode = 0;
dev_t android_runtime_dev = 0;
ino_t native_bridge_inode = 0;
dev_t native_bridge_dev = 0;
for (auto &map : lsplt::MapInfo::Scan()) {
if (map.path.ends_with("/libandroid_runtime.so")) {
android_runtime_inode = map.inode;
android_runtime_dev = map.dev;
} else if (map.path.ends_with("/libnativebridge.so")) {
native_bridge_inode = map.inode;
native_bridge_dev = map.dev;
}
}
PLT_HOOK_REGISTER(native_bridge_dev, native_bridge_inode, dlclose);
PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, fork);
PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, unshare);
PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, androidSetCreateThreadFunc);
PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, selinux_android_setcontext);
PLT_HOOK_REGISTER_SYM(android_runtime_dev, android_runtime_inode, "__android_log_close", android_log_close);
if (!lsplt::CommitHook())
ZLOGE("plt_hook failed\n");
// Remove unhooked methods
plt_backup.erase(
std::remove_if(plt_backup.begin(), plt_backup.end(),
[](auto &t) { return *std::get<3>(t) == nullptr;}),
g_hook->plt_backup.end());
}
void HookContext::hook_unloader() {
ino_t art_inode = 0;
dev_t art_dev = 0;
for (auto &map : lsplt::MapInfo::Scan()) {
if (map.path.ends_with("/libart.so")) {
art_inode = map.inode;
art_dev = map.dev;
break;
}
}
PLT_HOOK_REGISTER(art_dev, art_inode, pthread_attr_destroy);
if (!lsplt::CommitHook())
ZLOGE("plt_hook failed\n");
}
void HookContext::restore_plt_hook() {
// Unhook plt_hook
for (const auto &[dev, inode, sym, old_func] : plt_backup) {
if (!lsplt::RegisterHook(dev, inode, sym, *old_func, nullptr)) {
ZLOGE("Failed to register plt_hook [%s]\n", sym);
should_unmap_zygisk = false;
}
}
if (!lsplt::CommitHook()) {
ZLOGE("Failed to restore plt_hook\n");
should_unmap_zygisk = false;
}
}
// -----------------------------------------------------------------
static string get_class_name(JNIEnv *env, jclass clazz) {
static auto class_getName = env->GetMethodID(
env->FindClass("java/lang/Class"), "getName", "()Ljava/lang/String;");
auto nameRef = (jstring) env->CallObjectMethod(clazz, class_getName);
const char *name = env->GetStringUTFChars(nameRef, nullptr);
string className(name);
env->ReleaseStringUTFChars(nameRef, name);
std::replace(className.begin(), className.end(), '.', '/');
return className;
}
static void replace_jni_methods(
vector<JNINativeMethod> &methods, vector<JNINativeMethod> &backup,
const JNINativeMethod *hook_methods, size_t hook_methods_size,
void **orig_function) {
for (auto &method : methods) {
if (strcmp(method.name, hook_methods[0].name) == 0) {
for (auto i = 0; i < hook_methods_size; ++i) {
const auto &hook = hook_methods[i];
if (strcmp(method.signature, hook.signature) == 0) {
backup.push_back(method);
*orig_function = method.fnPtr;
method.fnPtr = hook.fnPtr;
ZLOGI("replace %s\n", method.name);
return;
}
}
ZLOGE("unknown signature of %s%s\n", method.name, method.signature);
}
}
}
#define HOOK_JNI(method) \
replace_jni_methods(newMethods, backup, method##_methods.data(), method##_methods.size(), &method##_orig)
static jint env_RegisterNatives(
JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint numMethods) {
auto className = get_class_name(env, clazz);
if (className == "com/android/internal/os/Zygote") {
// Restore JNIEnv as we no longer need to replace anything
env->functions = g_hook->old_env;
vector<JNINativeMethod> newMethods(methods, methods + numMethods);
vector<JNINativeMethod> &backup = g_hook->jni_backup[className];
HOOK_JNI(nativeForkAndSpecialize);
HOOK_JNI(nativeSpecializeAppProcess);
HOOK_JNI(nativeForkSystemServer);
return g_hook->old_env->RegisterNatives(env, clazz, newMethods.data(), numMethods);
} else {
return g_hook->old_env->RegisterNatives(env, clazz, methods, numMethods);
}
}
void HookContext::hook_jni_env() {
using method_sig = jint(*)(JavaVM **, jsize, jsize *);
auto get_created_vms = reinterpret_cast<method_sig>(
dlsym(RTLD_DEFAULT, "JNI_GetCreatedJavaVMs"));
if (!get_created_vms) {
for (auto &map: lsplt::MapInfo::Scan()) {
if (!map.path.ends_with("/libnativehelper.so")) continue;
void *h = dlopen(map.path.data(), RTLD_LAZY);
if (!h) {
ZLOGW("Cannot dlopen libnativehelper.so: %s\n", dlerror());
break;
}
get_created_vms = reinterpret_cast<method_sig>(dlsym(h, "JNI_GetCreatedJavaVMs"));
dlclose(h);
break;
}
if (!get_created_vms) {
ZLOGW("JNI_GetCreatedJavaVMs not found\n");
return;
}
}
JavaVM *vm = nullptr;
jsize num = 0;
jint res = get_created_vms(&vm, 1, &num);
if (res != JNI_OK || vm == nullptr) {
ZLOGW("JavaVM not found\n");
return;
}
JNIEnv *env = nullptr;
res = vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
if (res != JNI_OK || env == nullptr) {
ZLOGW("JNIEnv not found\n");
return;
}
// Replace the function table in JNIEnv to hook RegisterNatives
memcpy(&new_env, env->functions, sizeof(*env->functions));
new_env.RegisterNatives = &env_RegisterNatives;
old_env = env->functions;
env->functions = &new_env;
}
void HookContext::restore_jni_hook(JNIEnv *env) {
for (const auto &[clz, methods] : jni_backup) {
if (!methods.empty() && env->RegisterNatives(
env->FindClass(clz.data()), methods.data(),
static_cast<int>(methods.size())) != 0) {
ZLOGE("Failed to restore JNI hook of class [%s]\n", clz.data());
should_unmap_zygisk = false;
}
}
}
// -----------------------------------------------------------------
void hook_functions() {
default_new(g_hook);
g_hook->hook_plt();
}
void hookJniNativeMethods(JNIEnv *env, const char *clz, JNINativeMethod *methods, int numMethods) {
jclass clazz;
if (!g_hook || !g_hook->runtime_callbacks || !env || !clz || !(clazz = env->FindClass(clz))) {
for (auto i = 0; i < numMethods; ++i) {
methods[i].fnPtr = nullptr;
}
return;
}
// Backup existing methods
auto total = g_hook->runtime_callbacks->getNativeMethodCount(env, clazz);
vector<JNINativeMethod> old_methods(total);
g_hook->runtime_callbacks->getNativeMethods(env, clazz, old_methods.data(), total);
// Replace the method
for (auto i = 0; i < numMethods; ++i) {
auto &method = methods[i];
auto res = env->RegisterNatives(clazz, &method, 1);
// It's normal that the method is not found
if (res == JNI_ERR || env->ExceptionCheck()) {
auto exception = env->ExceptionOccurred();
if (exception) env->DeleteLocalRef(exception);
env->ExceptionClear();
method.fnPtr = nullptr;
} else {
// Find the old function pointer and return to caller
for (const auto &old_method : old_methods) {
if (strcmp(method.name, old_method.name) == 0 &&
strcmp(method.signature, old_method.signature) == 0) {
ZLOGD("replace %s#%s%s %p -> %p\n", clz,
method.name, method.signature, old_method.fnPtr, method.fnPtr);
method.fnPtr = old_method.fnPtr;
}
}
}
}
}

View File

@@ -4,8 +4,8 @@ namespace {
void *nativeForkAndSpecialize_orig = nullptr;
[[clang::no_stack_protector]] jint nativeForkAndSpecialize_l(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jstring instruction_set, jstring app_data_dir) {
AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
HookContext ctx(env, &args);
AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
ZygiskContext ctx(env, &args);
ctx.nativeForkAndSpecialize_pre();
reinterpret_cast<decltype(&nativeForkAndSpecialize_l)>(nativeForkAndSpecialize_orig)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, instruction_set, app_data_dir
@@ -14,9 +14,9 @@ void *nativeForkAndSpecialize_orig = nullptr;
return ctx.pid;
}
[[clang::no_stack_protector]] jint nativeForkAndSpecialize_o(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jstring instruction_set, jstring app_data_dir) {
AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
args.fds_to_ignore = &fds_to_ignore;
HookContext ctx(env, &args);
ZygiskContext ctx(env, &args);
ctx.nativeForkAndSpecialize_pre();
reinterpret_cast<decltype(&nativeForkAndSpecialize_o)>(nativeForkAndSpecialize_orig)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, fds_to_ignore, instruction_set, app_data_dir
@@ -25,10 +25,10 @@ void *nativeForkAndSpecialize_orig = nullptr;
return ctx.pid;
}
[[clang::no_stack_protector]] jint nativeForkAndSpecialize_p(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir) {
AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
args.fds_to_ignore = &fds_to_ignore;
args.is_child_zygote = &is_child_zygote;
HookContext ctx(env, &args);
ZygiskContext ctx(env, &args);
ctx.nativeForkAndSpecialize_pre();
reinterpret_cast<decltype(&nativeForkAndSpecialize_p)>(nativeForkAndSpecialize_orig)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir
@@ -37,11 +37,11 @@ void *nativeForkAndSpecialize_orig = nullptr;
return ctx.pid;
}
[[clang::no_stack_protector]] jint nativeForkAndSpecialize_q_alt(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app) {
AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
args.fds_to_ignore = &fds_to_ignore;
args.is_child_zygote = &is_child_zygote;
args.is_top_app = &is_top_app;
HookContext ctx(env, &args);
ZygiskContext ctx(env, &args);
ctx.nativeForkAndSpecialize_pre();
reinterpret_cast<decltype(&nativeForkAndSpecialize_q_alt)>(nativeForkAndSpecialize_orig)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir, is_top_app
@@ -50,7 +50,7 @@ void *nativeForkAndSpecialize_orig = nullptr;
return ctx.pid;
}
[[clang::no_stack_protector]] jint nativeForkAndSpecialize_r(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app, jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list, jboolean mount_data_dirs, jboolean mount_storage_dirs) {
AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
args.fds_to_ignore = &fds_to_ignore;
args.is_child_zygote = &is_child_zygote;
args.is_top_app = &is_top_app;
@@ -58,7 +58,7 @@ void *nativeForkAndSpecialize_orig = nullptr;
args.whitelisted_data_info_list = &whitelisted_data_info_list;
args.mount_data_dirs = &mount_data_dirs;
args.mount_storage_dirs = &mount_storage_dirs;
HookContext ctx(env, &args);
ZygiskContext ctx(env, &args);
ctx.nativeForkAndSpecialize_pre();
reinterpret_cast<decltype(&nativeForkAndSpecialize_r)>(nativeForkAndSpecialize_orig)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir, is_top_app, pkg_data_info_list, whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs
@@ -66,9 +66,27 @@ void *nativeForkAndSpecialize_orig = nullptr;
ctx.nativeForkAndSpecialize_post();
return ctx.pid;
}
[[clang::no_stack_protector]] jint nativeForkAndSpecialize_u(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app, jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list, jboolean mount_data_dirs, jboolean mount_storage_dirs, jboolean mount_sysprop_overrides) {
AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
args.fds_to_ignore = &fds_to_ignore;
args.is_child_zygote = &is_child_zygote;
args.is_top_app = &is_top_app;
args.pkg_data_info_list = &pkg_data_info_list;
args.whitelisted_data_info_list = &whitelisted_data_info_list;
args.mount_data_dirs = &mount_data_dirs;
args.mount_storage_dirs = &mount_storage_dirs;
args.mount_sysprop_overrides = &mount_sysprop_overrides;
ZygiskContext ctx(env, &args);
ctx.nativeForkAndSpecialize_pre();
reinterpret_cast<decltype(&nativeForkAndSpecialize_u)>(nativeForkAndSpecialize_orig)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir, is_top_app, pkg_data_info_list, whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs, mount_sysprop_overrides
);
ctx.nativeForkAndSpecialize_post();
return ctx.pid;
}
[[clang::no_stack_protector]] jint nativeForkAndSpecialize_samsung_m(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jint _0, jint _1, jstring nice_name, jintArray fds_to_close, jstring instruction_set, jstring app_data_dir) {
AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
HookContext ctx(env, &args);
AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
ZygiskContext ctx(env, &args);
ctx.nativeForkAndSpecialize_pre();
reinterpret_cast<decltype(&nativeForkAndSpecialize_samsung_m)>(nativeForkAndSpecialize_orig)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, _0, _1, nice_name, fds_to_close, instruction_set, app_data_dir
@@ -77,8 +95,8 @@ void *nativeForkAndSpecialize_orig = nullptr;
return ctx.pid;
}
[[clang::no_stack_protector]] jint nativeForkAndSpecialize_samsung_n(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jint _2, jint _3, jstring nice_name, jintArray fds_to_close, jstring instruction_set, jstring app_data_dir, jint _4) {
AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
HookContext ctx(env, &args);
AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
ZygiskContext ctx(env, &args);
ctx.nativeForkAndSpecialize_pre();
reinterpret_cast<decltype(&nativeForkAndSpecialize_samsung_n)>(nativeForkAndSpecialize_orig)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, _2, _3, nice_name, fds_to_close, instruction_set, app_data_dir, _4
@@ -87,9 +105,9 @@ void *nativeForkAndSpecialize_orig = nullptr;
return ctx.pid;
}
[[clang::no_stack_protector]] jint nativeForkAndSpecialize_samsung_o(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jint _5, jint _6, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jstring instruction_set, jstring app_data_dir) {
AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
args.fds_to_ignore = &fds_to_ignore;
HookContext ctx(env, &args);
ZygiskContext ctx(env, &args);
ctx.nativeForkAndSpecialize_pre();
reinterpret_cast<decltype(&nativeForkAndSpecialize_samsung_o)>(nativeForkAndSpecialize_orig)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, _5, _6, nice_name, fds_to_close, fds_to_ignore, instruction_set, app_data_dir
@@ -98,10 +116,10 @@ void *nativeForkAndSpecialize_orig = nullptr;
return ctx.pid;
}
[[clang::no_stack_protector]] jint nativeForkAndSpecialize_samsung_p(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jint _7, jint _8, jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir) {
AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
args.fds_to_ignore = &fds_to_ignore;
args.is_child_zygote = &is_child_zygote;
HookContext ctx(env, &args);
ZygiskContext ctx(env, &args);
ctx.nativeForkAndSpecialize_pre();
reinterpret_cast<decltype(&nativeForkAndSpecialize_samsung_p)>(nativeForkAndSpecialize_orig)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, _7, _8, nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir
@@ -109,60 +127,64 @@ void *nativeForkAndSpecialize_orig = nullptr;
ctx.nativeForkAndSpecialize_post();
return ctx.pid;
}
const JNINativeMethod nativeForkAndSpecialize_methods[] = {
{
std::array nativeForkAndSpecialize_methods = {
JNINativeMethod {
"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I",
(void *) &nativeForkAndSpecialize_l
},
{
JNINativeMethod {
"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[ILjava/lang/String;Ljava/lang/String;)I",
(void *) &nativeForkAndSpecialize_o
},
{
JNINativeMethod {
"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I",
(void *) &nativeForkAndSpecialize_p
},
{
JNINativeMethod {
"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Z)I",
(void *) &nativeForkAndSpecialize_q_alt
},
{
JNINativeMethod {
"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)I",
(void *) &nativeForkAndSpecialize_r
},
{
JNINativeMethod {
"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;[Ljava/lang/String;ZZZ)I",
(void *) &nativeForkAndSpecialize_u
},
JNINativeMethod {
"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;IILjava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I",
(void *) &nativeForkAndSpecialize_samsung_m
},
{
JNINativeMethod {
"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;IILjava/lang/String;[ILjava/lang/String;Ljava/lang/String;I)I",
(void *) &nativeForkAndSpecialize_samsung_n
},
{
JNINativeMethod {
"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;IILjava/lang/String;[I[ILjava/lang/String;Ljava/lang/String;)I",
(void *) &nativeForkAndSpecialize_samsung_o
},
{
JNINativeMethod {
"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;IILjava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I",
(void *) &nativeForkAndSpecialize_samsung_p
},
};
constexpr int nativeForkAndSpecialize_methods_num = std::size(nativeForkAndSpecialize_methods);
void *nativeSpecializeAppProcess_orig = nullptr;
[[clang::no_stack_protector]] void nativeSpecializeAppProcess_q(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir) {
AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
args.is_child_zygote = &is_child_zygote;
HookContext ctx(env, &args);
ZygiskContext ctx(env, &args);
ctx.nativeSpecializeAppProcess_pre();
reinterpret_cast<decltype(&nativeSpecializeAppProcess_q)>(nativeSpecializeAppProcess_orig)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, is_child_zygote, instruction_set, app_data_dir
@@ -170,10 +192,10 @@ void *nativeSpecializeAppProcess_orig = nullptr;
ctx.nativeSpecializeAppProcess_post();
}
[[clang::no_stack_protector]] void nativeSpecializeAppProcess_q_alt(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app) {
AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
args.is_child_zygote = &is_child_zygote;
args.is_top_app = &is_top_app;
HookContext ctx(env, &args);
ZygiskContext ctx(env, &args);
ctx.nativeSpecializeAppProcess_pre();
reinterpret_cast<decltype(&nativeSpecializeAppProcess_q_alt)>(nativeSpecializeAppProcess_orig)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, is_child_zygote, instruction_set, app_data_dir, is_top_app
@@ -181,58 +203,78 @@ void *nativeSpecializeAppProcess_orig = nullptr;
ctx.nativeSpecializeAppProcess_post();
}
[[clang::no_stack_protector]] void nativeSpecializeAppProcess_r(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app, jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list, jboolean mount_data_dirs, jboolean mount_storage_dirs) {
AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
args.is_child_zygote = &is_child_zygote;
args.is_top_app = &is_top_app;
args.pkg_data_info_list = &pkg_data_info_list;
args.whitelisted_data_info_list = &whitelisted_data_info_list;
args.mount_data_dirs = &mount_data_dirs;
args.mount_storage_dirs = &mount_storage_dirs;
HookContext ctx(env, &args);
ZygiskContext ctx(env, &args);
ctx.nativeSpecializeAppProcess_pre();
reinterpret_cast<decltype(&nativeSpecializeAppProcess_r)>(nativeSpecializeAppProcess_orig)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, is_child_zygote, instruction_set, app_data_dir, is_top_app, pkg_data_info_list, whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs
);
ctx.nativeSpecializeAppProcess_post();
}
[[clang::no_stack_protector]] void nativeSpecializeAppProcess_samsung_q(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jint _9, jint _10, jstring nice_name, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir) {
AppSpecializeArgs_v3 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
[[clang::no_stack_protector]] void nativeSpecializeAppProcess_u(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app, jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list, jboolean mount_data_dirs, jboolean mount_storage_dirs, jboolean mount_sysprop_overrides) {
AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
args.is_child_zygote = &is_child_zygote;
HookContext ctx(env, &args);
args.is_top_app = &is_top_app;
args.pkg_data_info_list = &pkg_data_info_list;
args.whitelisted_data_info_list = &whitelisted_data_info_list;
args.mount_data_dirs = &mount_data_dirs;
args.mount_storage_dirs = &mount_storage_dirs;
args.mount_sysprop_overrides = &mount_sysprop_overrides;
ZygiskContext ctx(env, &args);
ctx.nativeSpecializeAppProcess_pre();
reinterpret_cast<decltype(&nativeSpecializeAppProcess_u)>(nativeSpecializeAppProcess_orig)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, is_child_zygote, instruction_set, app_data_dir, is_top_app, pkg_data_info_list, whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs, mount_sysprop_overrides
);
ctx.nativeSpecializeAppProcess_post();
}
[[clang::no_stack_protector]] void nativeSpecializeAppProcess_samsung_q(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jint _9, jint _10, jstring nice_name, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir) {
AppSpecializeArgs_v5 args(uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, nice_name, instruction_set, app_data_dir);
args.is_child_zygote = &is_child_zygote;
ZygiskContext ctx(env, &args);
ctx.nativeSpecializeAppProcess_pre();
reinterpret_cast<decltype(&nativeSpecializeAppProcess_samsung_q)>(nativeSpecializeAppProcess_orig)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info, _9, _10, nice_name, is_child_zygote, instruction_set, app_data_dir
);
ctx.nativeSpecializeAppProcess_post();
}
const JNINativeMethod nativeSpecializeAppProcess_methods[] = {
{
std::array nativeSpecializeAppProcess_methods = {
JNINativeMethod {
"nativeSpecializeAppProcess",
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V",
(void *) &nativeSpecializeAppProcess_q
},
{
JNINativeMethod {
"nativeSpecializeAppProcess",
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Z)V",
(void *) &nativeSpecializeAppProcess_q_alt
},
{
JNINativeMethod {
"nativeSpecializeAppProcess",
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)V",
(void *) &nativeSpecializeAppProcess_r
},
{
JNINativeMethod {
"nativeSpecializeAppProcess",
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;[Ljava/lang/String;ZZZ)V",
(void *) &nativeSpecializeAppProcess_u
},
JNINativeMethod {
"nativeSpecializeAppProcess",
"(II[II[[IILjava/lang/String;IILjava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V",
(void *) &nativeSpecializeAppProcess_samsung_q
},
};
constexpr int nativeSpecializeAppProcess_methods_num = std::size(nativeSpecializeAppProcess_methods);
void *nativeForkSystemServer_orig = nullptr;
[[clang::no_stack_protector]] jint nativeForkSystemServer_l(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities, jlong effective_capabilities) {
ServerSpecializeArgs_v1 args(uid, gid, gids, runtime_flags, permitted_capabilities, effective_capabilities);
HookContext ctx(env, &args);
ZygiskContext ctx(env, &args);
ctx.nativeForkSystemServer_pre();
reinterpret_cast<decltype(&nativeForkSystemServer_l)>(nativeForkSystemServer_orig)(
env, clazz, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities, effective_capabilities
@@ -242,7 +284,7 @@ void *nativeForkSystemServer_orig = nullptr;
}
[[clang::no_stack_protector]] jint nativeForkSystemServer_samsung_q(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jint _11, jint _12, jobjectArray rlimits, jlong permitted_capabilities, jlong effective_capabilities) {
ServerSpecializeArgs_v1 args(uid, gid, gids, runtime_flags, permitted_capabilities, effective_capabilities);
HookContext ctx(env, &args);
ZygiskContext ctx(env, &args);
ctx.nativeForkSystemServer_pre();
reinterpret_cast<decltype(&nativeForkSystemServer_samsung_q)>(nativeForkSystemServer_orig)(
env, clazz, uid, gid, gids, runtime_flags, _11, _12, rlimits, permitted_capabilities, effective_capabilities
@@ -250,45 +292,17 @@ void *nativeForkSystemServer_orig = nullptr;
ctx.nativeForkSystemServer_post();
return ctx.pid;
}
const JNINativeMethod nativeForkSystemServer_methods[] = {
{
std::array nativeForkSystemServer_methods = {
JNINativeMethod {
"nativeForkSystemServer",
"(II[II[[IJJ)I",
(void *) &nativeForkSystemServer_l
},
{
JNINativeMethod {
"nativeForkSystemServer",
"(II[IIII[[IJJ)I",
(void *) &nativeForkSystemServer_samsung_q
},
};
constexpr int nativeForkSystemServer_methods_num = std::size(nativeForkSystemServer_methods);
} // namespace
static JNINativeMethod *hookAndSaveJNIMethods(const char *className, const JNINativeMethod *methods, int numMethods) {
JNINativeMethod *newMethods = nullptr;
int clz_id = -1;
int hook_cnt = 0;
do {
if (className == "com/android/internal/os/Zygote"sv) {
clz_id = 0;
hook_cnt = 3;
break;
}
} while (false);
if (hook_cnt) {
newMethods = new JNINativeMethod[numMethods];
memcpy(newMethods, methods, sizeof(JNINativeMethod) * numMethods);
}
auto &class_map = (*jni_method_map)[className];
for (int i = 0; i < numMethods; ++i) {
if (hook_cnt && clz_id == 0) {
HOOK_JNI(nativeForkAndSpecialize)
HOOK_JNI(nativeSpecializeAppProcess)
HOOK_JNI(nativeForkSystemServer)
}
class_map[methods[i].name][methods[i].signature] = methods[i].fnPtr;
}
return newMethods;
}

View File

@@ -0,0 +1,98 @@
#include <sys/mount.h>
#include <android/dlext.h>
#include <dlfcn.h>
#include <consts.hpp>
#include <base.hpp>
#include <core.hpp>
#include <selinux.hpp>
#include "zygisk.hpp"
using namespace std;
static void zygiskd(int socket) {
if (getuid() != 0 || fcntl(socket, F_GETFD) < 0)
exit(-1);
init_thread_pool();
#if defined(__LP64__)
set_nice_name("zygiskd64");
LOGI("* Launching zygiskd64\n");
#else
set_nice_name("zygiskd32");
LOGI("* Launching zygiskd32\n");
#endif
// Load modules
using comp_entry = void(*)(int);
vector<comp_entry> modules;
{
vector<int> module_fds = recv_fds(socket);
for (int fd : module_fds) {
comp_entry entry = nullptr;
struct stat s{};
if (fstat(fd, &s) == 0 && S_ISREG(s.st_mode)) {
android_dlextinfo info {
.flags = ANDROID_DLEXT_USE_LIBRARY_FD,
.library_fd = fd,
};
if (void *h = android_dlopen_ext("/jit-cache", RTLD_LAZY, &info)) {
*(void **) &entry = dlsym(h, "zygisk_companion_entry");
} else {
LOGW("Failed to dlopen zygisk module: %s\n", dlerror());
}
}
modules.push_back(entry);
close(fd);
}
}
// ack
write_int(socket, 0);
// Start accepting requests
pollfd pfd = { socket, POLLIN, 0 };
for (;;) {
poll(&pfd, 1, -1);
if (pfd.revents && !(pfd.revents & POLLIN)) {
// Something bad happened in magiskd, terminate zygiskd
exit(0);
}
int client = recv_fd(socket);
if (client < 0) {
// Something bad happened in magiskd, terminate zygiskd
exit(0);
}
int module_id = read_int(client);
if (module_id >= 0 && module_id < modules.size() && modules[module_id]) {
exec_task([=, entry = modules[module_id]] {
struct stat s1;
fstat(client, &s1);
entry(client);
// Only close client if it is the same file so we don't
// accidentally close a re-used file descriptor.
// This check is required because the module companion
// handler could've closed the file descriptor already.
if (struct stat s2; fstat(client, &s2) == 0) {
if (s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino) {
close(client);
}
}
});
} else {
close(client);
}
}
}
// Entrypoint where we need to re-exec ourselves
// This should only ever be called internally
int zygisk_main(int argc, char *argv[]) {
android_logging();
if (argc == 3 && argv[1] == "companion"sv) {
zygiskd(parse_int(argv[2]));
}
return 0;
}

View File

@@ -0,0 +1,466 @@
#include <android/dlext.h>
#include <dlfcn.h>
#include <lsplt.hpp>
#include <base.hpp>
#include "zygisk.hpp"
#include "module.hpp"
using namespace std;
ZygiskModule::ZygiskModule(int id, void *handle, void *entry)
: id(id), handle(handle), entry{entry}, api{}, mod{nullptr} {
// Make sure all pointers are null
memset(&api, 0, sizeof(api));
api.base.impl = this;
api.base.registerModule = &ZygiskModule::RegisterModuleImpl;
}
bool ZygiskModule::RegisterModuleImpl(ApiTable *api, long *module) {
if (api == nullptr || module == nullptr)
return false;
long api_version = *module;
// Unsupported version
if (api_version > ZYGISK_API_VERSION)
return false;
// Set the actual module_abi*
api->base.impl->mod = { module };
// Fill in API accordingly with module API version
if (api_version >= 1) {
api->v1.hookJniNativeMethods = hookJniNativeMethods;
api->v1.pltHookRegister = [](auto a, auto b, auto c, auto d) {
if (g_ctx) g_ctx->plt_hook_register(a, b, c, d);
};
api->v1.pltHookExclude = [](auto a, auto b) {
if (g_ctx) g_ctx->plt_hook_exclude(a, b);
};
api->v1.pltHookCommit = []() { return g_ctx && g_ctx->plt_hook_commit(); };
api->v1.connectCompanion = [](ZygiskModule *m) { return m->connectCompanion(); };
api->v1.setOption = [](ZygiskModule *m, auto opt) { m->setOption(opt); };
}
if (api_version >= 2) {
api->v2.getModuleDir = [](ZygiskModule *m) { return m->getModuleDir(); };
api->v2.getFlags = [](auto) { return ZygiskModule::getFlags(); };
}
if (api_version >= 4) {
api->v4.pltHookCommit = lsplt::CommitHook;
api->v4.pltHookRegister = [](dev_t dev, ino_t inode, const char *symbol, void *fn, void **backup) {
if (dev == 0 || inode == 0 || symbol == nullptr || fn == nullptr)
return;
lsplt::RegisterHook(dev, inode, symbol, fn, backup);
};
api->v4.exemptFd = [](int fd) { return g_ctx && g_ctx->exempt_fd(fd); };
}
return true;
}
bool ZygiskModule::valid() const {
if (mod.api_version == nullptr)
return false;
switch (*mod.api_version) {
case 4:
case 3:
case 2:
case 1:
return mod.v1->impl && mod.v1->preAppSpecialize && mod.v1->postAppSpecialize &&
mod.v1->preServerSpecialize && mod.v1->postServerSpecialize;
default:
return false;
}
}
int ZygiskModule::connectCompanion() const {
if (int fd = zygisk_request(ZygiskRequest::CONNECT_COMPANION); fd >= 0) {
write_int(fd, id);
return fd;
}
return -1;
}
int ZygiskModule::getModuleDir() const {
if (int fd = zygisk_request(ZygiskRequest::GET_MODDIR); fd >= 0) {
write_int(fd, id);
int dfd = recv_fd(fd);
close(fd);
return dfd;
}
return -1;
}
void ZygiskModule::setOption(zygisk::Option opt) {
if (g_ctx == nullptr)
return;
switch (opt) {
case zygisk::FORCE_DENYLIST_UNMOUNT:
g_ctx->flags |= DO_REVERT_UNMOUNT;
break;
case zygisk::DLCLOSE_MODULE_LIBRARY:
unload = true;
break;
}
}
uint32_t ZygiskModule::getFlags() {
return g_ctx ? (g_ctx->info_flags & ~PRIVATE_MASK) : 0;
}
void ZygiskModule::tryUnload() const {
if (unload) dlclose(handle);
}
// -----------------------------------------------------------------
#define call_app(method) \
switch (*mod.api_version) { \
case 1: \
case 2: { \
AppSpecializeArgs_v1 a(args); \
mod.v1->method(mod.v1->impl, &a); \
break; \
} \
case 3: \
case 4: \
case 5: \
mod.v1->method(mod.v1->impl, args);\
break; \
}
void ZygiskModule::preAppSpecialize(AppSpecializeArgs_v5 *args) const {
call_app(preAppSpecialize)
}
void ZygiskModule::postAppSpecialize(const AppSpecializeArgs_v5 *args) const {
call_app(postAppSpecialize)
}
void ZygiskModule::preServerSpecialize(ServerSpecializeArgs_v1 *args) const {
mod.v1->preServerSpecialize(mod.v1->impl, args);
}
void ZygiskModule::postServerSpecialize(const ServerSpecializeArgs_v1 *args) const {
mod.v1->postServerSpecialize(mod.v1->impl, args);
}
// -----------------------------------------------------------------
void ZygiskContext::plt_hook_register(const char *regex, const char *symbol, void *fn, void **backup) {
if (regex == nullptr || symbol == nullptr || fn == nullptr)
return;
regex_t re;
if (regcomp(&re, regex, REG_NOSUB) != 0)
return;
mutex_guard lock(hook_info_lock);
register_info.emplace_back(RegisterInfo{re, symbol, fn, backup});
}
void ZygiskContext::plt_hook_exclude(const char *regex, const char *symbol) {
if (!regex) return;
regex_t re;
if (regcomp(&re, regex, REG_NOSUB) != 0)
return;
mutex_guard lock(hook_info_lock);
ignore_info.emplace_back(IgnoreInfo{re, symbol ?: ""});
}
void ZygiskContext::plt_hook_process_regex() {
if (register_info.empty())
return;
for (auto &map : lsplt::MapInfo::Scan()) {
if (map.offset != 0 || !map.is_private || !(map.perms & PROT_READ)) continue;
for (auto &reg: register_info) {
if (regexec(&reg.regex, map.path.data(), 0, nullptr, 0) != 0)
continue;
bool ignored = false;
for (auto &ign: ignore_info) {
if (regexec(&ign.regex, map.path.data(), 0, nullptr, 0) != 0)
continue;
if (ign.symbol.empty() || ign.symbol == reg.symbol) {
ignored = true;
break;
}
}
if (!ignored) {
lsplt::RegisterHook(map.dev, map.inode, reg.symbol, reg.callback, reg.backup);
}
}
}
}
bool ZygiskContext::plt_hook_commit() {
{
mutex_guard lock(hook_info_lock);
plt_hook_process_regex();
register_info.clear();
ignore_info.clear();
}
return lsplt::CommitHook();
}
// -----------------------------------------------------------------
void ZygiskContext::sanitize_fds() {
zygisk_close_logd();
if (!is_child()) {
return;
}
if (can_exempt_fd() && !exempted_fds.empty()) {
auto update_fd_array = [&](int old_len) -> jintArray {
jintArray array = env->NewIntArray(static_cast<int>(old_len + exempted_fds.size()));
if (array == nullptr)
return nullptr;
env->SetIntArrayRegion(
array, old_len, static_cast<int>(exempted_fds.size()), exempted_fds.data());
for (int fd : exempted_fds) {
if (fd >= 0 && fd < MAX_FD_SIZE) {
allowed_fds[fd] = true;
}
}
*args.app->fds_to_ignore = array;
return array;
};
if (jintArray fdsToIgnore = *args.app->fds_to_ignore) {
int *arr = env->GetIntArrayElements(fdsToIgnore, nullptr);
int len = env->GetArrayLength(fdsToIgnore);
for (int i = 0; i < len; ++i) {
int fd = arr[i];
if (fd >= 0 && fd < MAX_FD_SIZE) {
allowed_fds[fd] = true;
}
}
if (jintArray newFdList = update_fd_array(len)) {
env->SetIntArrayRegion(newFdList, 0, len, arr);
}
env->ReleaseIntArrayElements(fdsToIgnore, arr, JNI_ABORT);
} else {
update_fd_array(0);
}
}
// Close all forbidden fds to prevent crashing
auto dir = xopen_dir("/proc/self/fd");
int dfd = dirfd(dir.get());
for (dirent *entry; (entry = xreaddir(dir.get()));) {
int fd = parse_int(entry->d_name);
if ((fd < 0 || fd >= MAX_FD_SIZE || !allowed_fds[fd]) && fd != dfd) {
close(fd);
}
}
}
bool ZygiskContext::exempt_fd(int fd) {
if ((flags & POST_SPECIALIZE) || (flags & SKIP_CLOSE_LOG_PIPE))
return true;
if (!can_exempt_fd())
return false;
exempted_fds.push_back(fd);
return true;
}
bool ZygiskContext::can_exempt_fd() const {
return (flags & APP_FORK_AND_SPECIALIZE) && args.app->fds_to_ignore;
}
static int sigmask(int how, int signum) {
sigset_t set;
sigemptyset(&set);
sigaddset(&set, signum);
return sigprocmask(how, &set, nullptr);
}
void ZygiskContext::fork_pre() {
// Do our own fork before loading any 3rd party code
// First block SIGCHLD, unblock after original fork is done
sigmask(SIG_BLOCK, SIGCHLD);
pid = old_fork();
if (!is_child())
return;
// Record all open fds
auto dir = xopen_dir("/proc/self/fd");
for (dirent *entry; (entry = xreaddir(dir.get()));) {
int fd = parse_int(entry->d_name);
if (fd < 0 || fd >= MAX_FD_SIZE) {
close(fd);
continue;
}
allowed_fds[fd] = true;
}
// The dirfd will be closed once out of scope
allowed_fds[dirfd(dir.get())] = false;
// logd_fd should be handled separately
if (int fd = zygisk_get_logd(); fd >= 0) {
allowed_fds[fd] = false;
}
}
void ZygiskContext::fork_post() {
// Unblock SIGCHLD in case the original method didn't
sigmask(SIG_UNBLOCK, SIGCHLD);
}
void ZygiskContext::run_modules_pre(const vector<int> &fds) {
for (int i = 0; i < fds.size(); ++i) {
struct stat s{};
if (fstat(fds[i], &s) != 0 || !S_ISREG(s.st_mode)) {
close(fds[i]);
continue;
}
android_dlextinfo info {
.flags = ANDROID_DLEXT_USE_LIBRARY_FD,
.library_fd = fds[i],
};
if (void *h = android_dlopen_ext("/jit-cache", RTLD_LAZY, &info)) {
if (void *e = dlsym(h, "zygisk_module_entry")) {
modules.emplace_back(i, h, e);
}
} else if (flags & SERVER_FORK_AND_SPECIALIZE) {
ZLOGW("Failed to dlopen zygisk module: %s\n", dlerror());
}
close(fds[i]);
}
for (auto it = modules.begin(); it != modules.end();) {
it->onLoad(env);
if (it->valid()) {
++it;
} else {
it = modules.erase(it);
}
}
for (auto &m : modules) {
if (flags & APP_SPECIALIZE) {
m.preAppSpecialize(args.app);
} else if (flags & SERVER_FORK_AND_SPECIALIZE) {
m.preServerSpecialize(args.server);
}
}
}
void ZygiskContext::run_modules_post() {
flags |= POST_SPECIALIZE;
for (const auto &m : modules) {
if (flags & APP_SPECIALIZE) {
m.postAppSpecialize(args.app);
} else if (flags & SERVER_FORK_AND_SPECIALIZE) {
m.postServerSpecialize(args.server);
}
m.tryUnload();
}
}
void ZygiskContext::app_specialize_pre() {
flags |= APP_SPECIALIZE;
vector<int> module_fds;
int fd = remote_get_info(args.app->uid, process, &info_flags, module_fds);
if ((info_flags & UNMOUNT_MASK) == UNMOUNT_MASK) {
ZLOGI("[%s] is on the denylist\n", process);
flags |= DO_REVERT_UNMOUNT;
} else if (fd >= 0) {
run_modules_pre(module_fds);
}
close(fd);
}
void ZygiskContext::app_specialize_post() {
run_modules_post();
if (info_flags & PROCESS_IS_MAGISK_APP) {
setenv("ZYGISK_ENABLED", "1", 1);
}
// Cleanups
env->ReleaseStringUTFChars(args.app->nice_name, process);
}
void ZygiskContext::server_specialize_pre() {
vector<int> module_fds;
int fd = remote_get_info(1000, "system_server", &info_flags, module_fds);
if (fd >= 0) {
if (module_fds.empty()) {
write_int(fd, 0);
} else {
run_modules_pre(module_fds);
// Send the bitset of module status back to magiskd from system_server
dynamic_bitset bits;
for (const auto &m : modules)
bits[m.getId()] = true;
write_int(fd, static_cast<int>(bits.slots()));
for (int i = 0; i < bits.slots(); ++i) {
auto l = bits.get_slot(i);
xwrite(fd, &l, sizeof(l));
}
}
close(fd);
}
}
void ZygiskContext::server_specialize_post() {
run_modules_post();
}
// -----------------------------------------------------------------
void ZygiskContext::nativeSpecializeAppProcess_pre() {
process = env->GetStringUTFChars(args.app->nice_name, nullptr);
ZLOGV("pre specialize [%s]\n", process);
// App specialize does not check FD
flags |= SKIP_CLOSE_LOG_PIPE;
app_specialize_pre();
}
void ZygiskContext::nativeSpecializeAppProcess_post() {
ZLOGV("post specialize [%s]\n", process);
app_specialize_post();
}
void ZygiskContext::nativeForkSystemServer_pre() {
ZLOGV("pre forkSystemServer\n");
flags |= SERVER_FORK_AND_SPECIALIZE;
fork_pre();
if (is_child()) {
server_specialize_pre();
}
sanitize_fds();
}
void ZygiskContext::nativeForkSystemServer_post() {
if (is_child()) {
ZLOGV("post forkSystemServer\n");
server_specialize_post();
}
fork_post();
}
void ZygiskContext::nativeForkAndSpecialize_pre() {
process = env->GetStringUTFChars(args.app->nice_name, nullptr);
ZLOGV("pre forkAndSpecialize [%s]\n", process);
flags |= APP_FORK_AND_SPECIALIZE;
fork_pre();
if (is_child()) {
app_specialize_pre();
}
sanitize_fds();
}
void ZygiskContext::nativeForkAndSpecialize_post() {
if (is_child()) {
ZLOGV("post forkAndSpecialize [%s]\n", process);
app_specialize_post();
}
fork_post();
}

View File

@@ -1,26 +1,31 @@
#pragma once
#include <regex.h>
#include <bitset>
#include <list>
#include "api.hpp"
namespace {
struct HookContext;
struct ZygiskContext;
struct ZygiskModule;
struct AppSpecializeArgs_v1;
using AppSpecializeArgs_v2 = AppSpecializeArgs_v1;
struct AppSpecializeArgs_v3;
using AppSpecializeArgs_v4 = AppSpecializeArgs_v3;
struct AppSpecializeArgs_v5;
struct module_abi_v1;
using module_abi_v2 = module_abi_v1;
using module_abi_v3 = module_abi_v1;
using module_abi_v4 = module_abi_v1;
using module_abi_v5 = module_abi_v1;
struct api_abi_v1;
struct api_abi_v2;
using api_abi_v3 = api_abi_v2;
struct api_abi_v4;
using api_abi_v5 = api_abi_v4;
union ApiTable;
@@ -53,6 +58,17 @@ struct AppSpecializeArgs_v3 {
instruction_set(instruction_set), app_data_dir(app_data_dir) {}
};
struct AppSpecializeArgs_v5 : public AppSpecializeArgs_v3 {
jboolean *mount_sysprop_overrides = nullptr;
AppSpecializeArgs_v5(
jint &uid, jint &gid, jintArray &gids, jint &runtime_flags,
jobjectArray &rlimits, jint &mount_external, jstring &se_info, jstring &nice_name,
jstring &instruction_set, jstring &app_data_dir) : AppSpecializeArgs_v3(
uid, gid, gids, runtime_flags, rlimits, mount_external,
se_info, nice_name, instruction_set, app_data_dir) {}
};
struct AppSpecializeArgs_v1 {
jint &uid;
jint &gid;
@@ -71,14 +87,14 @@ struct AppSpecializeArgs_v1 {
jboolean *const mount_data_dirs;
jboolean *const mount_storage_dirs;
AppSpecializeArgs_v1(const AppSpecializeArgs_v3 *v3) :
uid(v3->uid), gid(v3->gid), gids(v3->gids), runtime_flags(v3->runtime_flags),
mount_external(v3->mount_external), se_info(v3->se_info), nice_name(v3->nice_name),
instruction_set(v3->instruction_set), app_data_dir(v3->app_data_dir),
is_child_zygote(v3->is_child_zygote), is_top_app(v3->is_top_app),
pkg_data_info_list(v3->pkg_data_info_list),
whitelisted_data_info_list(v3->whitelisted_data_info_list),
mount_data_dirs(v3->mount_data_dirs), mount_storage_dirs(v3->mount_storage_dirs) {}
AppSpecializeArgs_v1(const AppSpecializeArgs_v5 *a) :
uid(a->uid), gid(a->gid), gids(a->gids), runtime_flags(a->runtime_flags),
mount_external(a->mount_external), se_info(a->se_info), nice_name(a->nice_name),
instruction_set(a->instruction_set), app_data_dir(a->app_data_dir),
is_child_zygote(a->is_child_zygote), is_top_app(a->is_top_app),
pkg_data_info_list(a->pkg_data_info_list),
whitelisted_data_info_list(a->whitelisted_data_info_list),
mount_data_dirs(a->mount_data_dirs), mount_storage_dirs(a->mount_storage_dirs) {}
};
struct ServerSpecializeArgs_v1 {
@@ -110,12 +126,11 @@ enum : uint32_t {
PROCESS_GRANTED_ROOT = zygisk::StateFlag::PROCESS_GRANTED_ROOT,
PROCESS_ON_DENYLIST = zygisk::StateFlag::PROCESS_ON_DENYLIST,
PROCESS_IS_SYS_UI = (1u << 29),
DENYLIST_ENFORCING = (1u << 30),
PROCESS_IS_MAGISK_APP = (1u << 31),
UNMOUNT_MASK = (PROCESS_ON_DENYLIST | DENYLIST_ENFORCING),
PRIVATE_MASK = (PROCESS_IS_SYS_UI | DENYLIST_ENFORCING | PROCESS_IS_MAGISK_APP)
PRIVATE_MASK = (DENYLIST_ENFORCING | PROCESS_IS_MAGISK_APP)
};
struct api_abi_base {
@@ -155,44 +170,23 @@ union ApiTable {
api_abi_v4 v4;
};
#define call_app(method) \
switch (*mod.api_version) { \
case 1: \
case 2: { \
AppSpecializeArgs_v1 a(args); \
mod.v1->method(mod.v1->impl, &a); \
break; \
} \
case 3: \
case 4: \
mod.v1->method(mod.v1->impl, args);\
break; \
}
struct ZygiskModule {
void onLoad(void *env) {
entry.fn(&api, env);
}
void preAppSpecialize(AppSpecializeArgs_v3 *args) const {
call_app(preAppSpecialize)
}
void postAppSpecialize(const AppSpecializeArgs_v3 *args) const {
call_app(postAppSpecialize)
}
void preServerSpecialize(ServerSpecializeArgs_v1 *args) const {
mod.v1->preServerSpecialize(mod.v1->impl, args);
}
void postServerSpecialize(const ServerSpecializeArgs_v1 *args) const {
mod.v1->postServerSpecialize(mod.v1->impl, args);
}
void preAppSpecialize(AppSpecializeArgs_v5 *args) const;
void postAppSpecialize(const AppSpecializeArgs_v5 *args) const;
void preServerSpecialize(ServerSpecializeArgs_v1 *args) const;
void postServerSpecialize(const ServerSpecializeArgs_v1 *args) const;
bool valid() const;
int connectCompanion() const;
int getModuleDir() const;
void setOption(zygisk::Option opt);
static uint32_t getFlags();
void tryUnload() const { if (unload) dlclose(handle); }
void tryUnload() const;
void clearApi() { memset(&api, 0, sizeof(api)); }
int getId() const { return id; }
@@ -218,4 +212,80 @@ private:
} mod;
};
} // namespace
extern ZygiskContext *g_ctx;
extern int (*old_fork)(void);
enum : uint32_t {
POST_SPECIALIZE = (1u << 0),
APP_FORK_AND_SPECIALIZE = (1u << 1),
APP_SPECIALIZE = (1u << 2),
SERVER_FORK_AND_SPECIALIZE = (1u << 3),
DO_REVERT_UNMOUNT = (1u << 4),
SKIP_CLOSE_LOG_PIPE = (1u << 5),
};
#define MAX_FD_SIZE 1024
#define DCL_PRE_POST(name) \
void name##_pre(); \
void name##_post();
struct ZygiskContext {
JNIEnv *env;
union {
void *ptr;
AppSpecializeArgs_v5 *app;
ServerSpecializeArgs_v1 *server;
} args;
const char *process;
std::list<ZygiskModule> modules;
int pid;
uint32_t flags;
uint32_t info_flags;
std::bitset<MAX_FD_SIZE> allowed_fds;
std::vector<int> exempted_fds;
struct RegisterInfo {
regex_t regex;
std::string symbol;
void *callback;
void **backup;
};
struct IgnoreInfo {
regex_t regex;
std::string symbol;
};
pthread_mutex_t hook_info_lock;
std::vector<RegisterInfo> register_info;
std::vector<IgnoreInfo> ignore_info;
ZygiskContext(JNIEnv *env, void *args);
~ZygiskContext();
void run_modules_pre(const std::vector<int> &fds);
void run_modules_post();
DCL_PRE_POST(fork)
DCL_PRE_POST(app_specialize)
DCL_PRE_POST(server_specialize)
DCL_PRE_POST(nativeForkAndSpecialize)
DCL_PRE_POST(nativeSpecializeAppProcess)
DCL_PRE_POST(nativeForkSystemServer)
void sanitize_fds();
bool exempt_fd(int fd);
bool can_exempt_fd() const;
bool is_child() const { return pid <= 0; }
// Compatibility shim
void plt_hook_register(const char *regex, const char *symbol, void *fn, void **backup);
void plt_hook_exclude(const char *regex, const char *symbol);
void plt_hook_process_regex();
bool plt_hook_commit();
};
#undef DCL_PRE_POST

View File

@@ -0,0 +1,60 @@
#pragma once
#include <sys/mman.h>
#include <stdint.h>
#include <jni.h>
#include <vector>
#include <core.hpp>
namespace ZygiskRequest {
enum : int {
GET_INFO,
CONNECT_COMPANION,
GET_MODDIR,
END
};
}
#if defined(__LP64__)
#define ZLOGD(...) LOGD("zygisk64: " __VA_ARGS__)
#define ZLOGE(...) LOGE("zygisk64: " __VA_ARGS__)
#define ZLOGI(...) LOGI("zygisk64: " __VA_ARGS__)
#define ZLOGW(...) LOGW("zygisk64: " __VA_ARGS__)
#else
#define ZLOGD(...) LOGD("zygisk32: " __VA_ARGS__)
#define ZLOGE(...) LOGE("zygisk32: " __VA_ARGS__)
#define ZLOGI(...) LOGI("zygisk32: " __VA_ARGS__)
#define ZLOGW(...) LOGW("zygisk32: " __VA_ARGS__)
#endif
// Extreme verbose logging
#define ZLOGV(...) ZLOGD(__VA_ARGS__)
//#define ZLOGV(...) (void*)0
void hook_functions();
void hookJniNativeMethods(JNIEnv *env, const char *clz, JNINativeMethod *methods, int numMethods);
int remote_get_info(int uid, const char *process, uint32_t *flags, std::vector<int> &fds);
inline int zygisk_request(int req) {
int fd = connect_daemon(+RequestCode::ZYGISK);
if (fd < 0) return fd;
write_int(fd, req);
return fd;
}
// The reference of the following structs
// https://cs.android.com/android/platform/superproject/main/+/main:art/libnativebridge/include/nativebridge/native_bridge.h
struct NativeBridgeRuntimeCallbacks {
const char* (*getMethodShorty)(JNIEnv* env, jmethodID mid);
uint32_t (*getNativeMethodCount)(JNIEnv* env, jclass clazz);
uint32_t (*getNativeMethods)(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
uint32_t method_count);
};
struct NativeBridgeCallbacks {
uint32_t version;
void *padding[5];
bool (*isCompatibleWith)(uint32_t);
};

View File

@@ -1,4 +1,3 @@
{
zygisk_inject_entry;
unload_first_stage;
NativeBridgeItf;
};

View File

@@ -1,11 +1,5 @@
LOCAL_PATH := $(call my-dir)
# Header only library
include $(CLEAR_VARS)
LOCAL_MODULE:= libphmap
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/parallel-hashmap
include $(BUILD_STATIC_LIBRARY)
# libxz.a
include $(CLEAR_VARS)
LOCAL_MODULE:= libxz

View File

@@ -1,8 +1,8 @@
#pragma once
#include <string>
#define JAVA_PACKAGE_NAME "com.topjohnwu.magisk"
#define ZYGISKLDR "libzygisk.so"
#define NBPROP "ro.dalvik.vm.native.bridge"
#define SECURE_DIR "/data/adb"
#define MODULEROOT SECURE_DIR "/modules"
#define MODULEUPGRADE SECURE_DIR "/modules_update"
@@ -21,7 +21,6 @@
#define ROOTOVL INTLROOT "/rootdir"
#define SHELLPTS INTLROOT "/pts"
#define ROOTMNT ROOTOVL "/.mount_list"
#define ZYGISKBIN INTLROOT "/zygisk"
#define SELINUXMOCK INTLROOT "/selinux"
#define MAIN_CONFIG INTLROOT "/config"
#define MAIN_SOCKET INTLROOT "/socket"
@@ -49,5 +48,4 @@ extern int SDK_INT;
int magisk_main(int argc, char *argv[]);
int su_client_main(int argc, char *argv[]);
int resetprop_main(int argc, char *argv[]);
int app_process_main(int argc, char *argv[]);
int zygisk_main(int argc, char *argv[]);

View File

@@ -20,3 +20,10 @@ macro_rules! LOG_PIPE {
concat!($crate::INTLROOT!(), "/log")
};
}
#[macro_export]
macro_rules! MAIN_CONFIG {
() => {
concat!($crate::INTLROOT!(), "/config")
};
}

View File

@@ -217,8 +217,24 @@ bool check_two_stage() {
return init.contains("selinux_setup");
}
void unxz_init(const char *init_xz, const char *init) {
LOGD("unxz %s -> %s\n", init_xz, init);
int fd = xopen(init, O_WRONLY | O_CREAT, 0777);
fd_channel ch(fd);
unxz(ch, mmap_data{init_xz});
close(fd);
clone_attr(init_xz, init);
unlink(init_xz);
}
const char *backup_init() {
if (access("/.backup/init.real", F_OK) == 0)
return "/.backup/init.real";
if (access("/.backup/init.real.xz", F_OK) == 0) {
unxz_init("/.backup/init.real.xz", "/.backup/init.real");
return "/.backup/init.real";
}
if (access("/.backup/init.xz", F_OK) == 0)
unxz_init("/.backup/init.xz", "/.backup/init");
return "/.backup/init";
}

View File

@@ -5,7 +5,7 @@
#include <base.hpp>
#include <flags.h>
#include <magisk.hpp>
#include <consts.hpp>
#include "init.hpp"

View File

@@ -3,7 +3,7 @@
#include <sys/sysmacros.h>
#include <sepolicy.hpp>
#include <magisk.hpp>
#include <consts.hpp>
#include <base.hpp>
#include <flags.h>
@@ -13,48 +13,72 @@ using namespace std;
static vector<string> rc_list;
static void patch_init_rc(const char *src, const char *dest, const char *tmp_dir) {
FILE *rc = xfopen(dest, "we");
if (!rc) {
PLOGE("%s: open %s failed", __PRETTY_FUNCTION__, src);
return;
}
file_readline(src, [=](string_view line) -> bool {
// Do not start vaultkeeper
if (str_contains(line, "start vaultkeeper")) {
LOGD("Remove vaultkeeper\n");
return true;
}
// Do not run flash_recovery
if (str_starts(line, "service flash_recovery")) {
LOGD("Remove flash_recovery\n");
fprintf(rc, "service flash_recovery /system/bin/xxxxx\n");
return true;
}
// Samsung's persist.sys.zygote.early will cause Zygote to start before post-fs-data
if (str_starts(line, "on property:persist.sys.zygote.early=")) {
LOGD("Invalidate persist.sys.zygote.early\n");
fprintf(rc, "on property:persist.sys.zygote.early.xxxxx=true\n");
return true;
}
// Else just write the line
fprintf(rc, "%s", line.data());
return true;
});
#define ROOTMIR MIRRDIR "/system_root"
#define NEW_INITRC_DIR "/system/etc/init/hw"
#define INIT_RC "init.rc"
fprintf(rc, "\n");
static void patch_rc_scripts(const char *src_path, const char *tmp_path, bool writable) {
auto src_dir = xopen_dir(src_path);
if (!src_dir) return;
int src_fd = dirfd(src_dir.get());
// Inject custom rc scripts
for (auto &script : rc_list) {
// Replace template arguments of rc scripts with dynamic paths
replace_all(script, "${MAGISKTMP}", tmp_dir);
fprintf(rc, "\n%s\n", script.data());
}
rc_list.clear();
// If writable, directly modify the file in src_path, or else add to rootfs overlay
auto dest_dir = writable ? [&] {
return xopen_dir(src_path);
}() : [&] {
char buf[PATH_MAX] = {};
ssprintf(buf, sizeof(buf), ROOTOVL "%s", src_path);
xmkdirs(buf, 0755);
return xopen_dir(buf);
}();
if (!dest_dir) return;
int dest_fd = dirfd(dest_dir.get());
// Inject Magisk rc scripts
LOGD("Inject magisk rc\n");
fprintf(rc, R"EOF(
// First patch init.rc
{
auto src = xopen_file(xopenat(src_fd, INIT_RC, O_RDONLY | O_CLOEXEC, 0), "re");
if (!src) return;
if (writable) unlinkat(src_fd, INIT_RC, 0);
auto dest = xopen_file(
xopenat(dest_fd, INIT_RC, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0), "we");
if (!dest) return;
LOGD("Patching " INIT_RC " in %s\n", src_path);
file_readline(false, src.get(), [&dest](string_view line) -> bool {
// Do not start vaultkeeper
if (str_contains(line, "start vaultkeeper")) {
LOGD("Remove vaultkeeper\n");
return true;
}
// Do not run flash_recovery
if (line.starts_with("service flash_recovery")) {
LOGD("Remove flash_recovery\n");
fprintf(dest.get(), "service flash_recovery /system/bin/true\n");
return true;
}
// Samsung's persist.sys.zygote.early will cause Zygote to start before post-fs-data
if (line.starts_with("on property:persist.sys.zygote.early=")) {
LOGD("Invalidate persist.sys.zygote.early\n");
fprintf(dest.get(), "on property:persist.sys.zygote.early.xxxxx=true\n");
return true;
}
// Else just write the line
fprintf(dest.get(), "%s", line.data());
return true;
});
fprintf(dest.get(), "\n");
// Inject custom rc scripts
for (auto &script : rc_list) {
// Replace template arguments of rc scripts with dynamic paths
replace_all(script, "${MAGISKTMP}", tmp_path);
fprintf(dest.get(), "\n%s\n", script.data());
}
rc_list.clear();
// Inject Magisk rc scripts
LOGD("Inject magisk rc\n");
fprintf(dest.get(), R"EOF(
on post-fs-data
start logd
exec %2$s 0 0 -- %1$s/magisk --post-fs-data
@@ -68,15 +92,37 @@ on nonencrypted
on property:sys.boot_completed=1
exec %2$s 0 0 -- %1$s/magisk --boot-complete
on property:init.svc.zygote=restarting
exec %2$s 0 0 -- %1$s/magisk --zygote-restart
on property:init.svc.zygote=stopped
exec %2$s 0 0 -- %1$s/magisk --zygote-restart
)EOF", tmp_dir, MAGISK_PROC_CON);
)EOF", tmp_path, MAGISK_PROC_CON);
fclose(rc);
clone_attr(src, dest);
fclone_attr(fileno(src.get()), fileno(dest.get()));
}
// Then patch init.zygote*.rc
for (dirent *entry; (entry = readdir(src_dir.get()));) {
auto name = std::string_view(entry->d_name);
if (!name.starts_with("init.zygote") || !name.ends_with(".rc")) continue;
auto src = xopen_file(xopenat(src_fd, name.data(), O_RDONLY | O_CLOEXEC, 0), "re");
if (!src) continue;
if (writable) unlinkat(src_fd, name.data(), 0);
auto dest = xopen_file(
xopenat(dest_fd, name.data(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0), "we");
if (!dest) continue;
LOGD("Patching %s in %s\n", name.data(), src_path);
file_readline(false, src.get(), [&dest, &tmp_path](string_view line) -> bool {
if (line.starts_with("service zygote ")) {
LOGD("Inject zygote restart\n");
fprintf(dest.get(), "%s", line.data());
fprintf(dest.get(), " onrestart exec %2$s 0 0 -- %1$s/magisk --zygote-restart\n",
tmp_path, MAGISK_PROC_CON);
return true;
}
fprintf(dest.get(), "%s", line.data());
return true;
});
fclone_attr(fileno(src.get()), fileno(dest.get()));
}
}
static void load_overlay_rc(const char *overlay) {
@@ -85,7 +131,7 @@ static void load_overlay_rc(const char *overlay) {
int dfd = dirfd(dir.get());
// Do not allow overwrite init.rc
unlinkat(dfd, "init.rc", 0);
unlinkat(dfd, INIT_RC, 0);
// '/' + name + '\0'
char buf[NAME_MAX + 2];
@@ -202,9 +248,6 @@ void MagiskInit::parse_config_file() {
});
}
#define ROOTMIR MIRRDIR "/system_root"
#define NEW_INITRC "/system/etc/init/hw/init.rc"
void MagiskInit::patch_ro_root() {
mount_list.emplace_back("/data");
parse_config_file();
@@ -259,12 +302,11 @@ void MagiskInit::patch_ro_root() {
}
// Patch init.rc
if (access(NEW_INITRC, F_OK) == 0) {
if (access(NEW_INITRC_DIR "/" INIT_RC, F_OK) == 0) {
// Android 11's new init.rc
xmkdirs(dirname(ROOTOVL NEW_INITRC), 0755);
patch_init_rc(NEW_INITRC, ROOTOVL NEW_INITRC, tmp_dir.data());
patch_rc_scripts(NEW_INITRC_DIR, tmp_dir.data(), false);
} else {
patch_init_rc("/init.rc", ROOTOVL "/init.rc", tmp_dir.data());
patch_rc_scripts("/", tmp_dir.data(), false);
}
// Extract magisk
@@ -312,8 +354,7 @@ void MagiskInit::patch_rw_root() {
rm_rf("/.backup");
// Patch init.rc
patch_init_rc("/init.rc", "/init.p.rc", "/sbin");
rename("/init.p.rc", "/init.rc");
patch_rc_scripts("/", "/sbin", true);
bool treble;
{

Some files were not shown because too many files have changed in this diff Show More