mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-08-14 08:07:25 +00:00
Compare commits
98 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2c6adbc69b | ||
![]() |
5280982363 | ||
![]() |
18c45ae289 | ||
![]() |
41fbd2a7be | ||
![]() |
5e45884af4 | ||
![]() |
d78ee171bc | ||
![]() |
356ee1febd | ||
![]() |
cc044ccc4c | ||
![]() |
9c638cc463 | ||
![]() |
df786eb2b6 | ||
![]() |
8e7186eebb | ||
![]() |
74b7b84561 | ||
![]() |
308c9999fa | ||
![]() |
930bb8687f | ||
![]() |
f2c4288d2d | ||
![]() |
b44141ae39 | ||
![]() |
86e0020964 | ||
![]() |
94d3daeadf | ||
![]() |
79334b7702 | ||
![]() |
df66458db6 | ||
![]() |
97705704e2 | ||
![]() |
1206179580 | ||
![]() |
a0b8aa4da6 | ||
![]() |
65207f96c8 | ||
![]() |
062e498bdd | ||
![]() |
1057cb3e3c | ||
![]() |
2dd23b2518 | ||
![]() |
8cab12998c | ||
![]() |
48b1c26dc8 | ||
![]() |
f1e0bc3e4a | ||
![]() |
38527cd58f | ||
![]() |
e94d65b4b2 | ||
![]() |
27ece3c7df | ||
![]() |
06687abffc | ||
![]() |
deedb462a0 | ||
![]() |
c48962bdf7 | ||
![]() |
1ef3f6e13b | ||
![]() |
83a34a9004 | ||
![]() |
e30bda6c8d | ||
![]() |
00e9d76a5a | ||
![]() |
6cda6c2fae | ||
![]() |
6dfda6dc39 | ||
![]() |
f41994cb52 | ||
![]() |
a003336497 | ||
![]() |
401090d6fe | ||
![]() |
90dcc1cd30 | ||
![]() |
2ac464b186 | ||
![]() |
8b7fae278b | ||
![]() |
d73c2daf6d | ||
![]() |
ca25935de3 | ||
![]() |
d7750b7220 | ||
![]() |
98861f0b5a | ||
![]() |
e35925d520 | ||
![]() |
685a2d2101 | ||
![]() |
f7e471616d | ||
![]() |
c013a349af | ||
![]() |
61ea59a27b | ||
![]() |
e55f338367 | ||
![]() |
1425cf4105 | ||
![]() |
b493a985b0 | ||
![]() |
1fe9ede940 | ||
![]() |
1fd49e4987 | ||
![]() |
d49b02b274 | ||
![]() |
d47e70cfaa | ||
![]() |
40cb031af5 | ||
![]() |
1dcf325547 | ||
![]() |
4e99997013 | ||
![]() |
334554697d | ||
![]() |
e77cbd0c15 | ||
![]() |
46ba008b9d | ||
![]() |
58aded31c2 | ||
![]() |
6f6b0ade06 | ||
![]() |
d9b67a207b | ||
![]() |
c7083659aa | ||
![]() |
a6d1803105 | ||
![]() |
66eef75673 | ||
![]() |
367f5f7b44 | ||
![]() |
0edcb03c45 | ||
![]() |
63eef153de | ||
![]() |
68442f38ac | ||
![]() |
8d5b9e5329 | ||
![]() |
6c0966b795 | ||
![]() |
7c2e93d266 | ||
![]() |
1ff7b9055f | ||
![]() |
49f241b77c | ||
![]() |
cfb20b0f86 | ||
![]() |
6d6f14fcb3 | ||
![]() |
977c981265 | ||
![]() |
ef48abf19d | ||
![]() |
65c18f9c09 | ||
![]() |
ecb31eed40 | ||
![]() |
a80cadf587 | ||
![]() |
fce1bf2365 | ||
![]() |
cbc6d40b2c | ||
![]() |
9fbd079560 | ||
![]() |
42eb928054 | ||
![]() |
577483fde1 | ||
![]() |
aa6c7c15cc |
44
.github/actions/setup/action.yml
vendored
Normal file
44
.github/actions/setup/action.yml
vendored
Normal 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
|
111
.github/workflows/build.yml
vendored
111
.github/workflows/build.yml
vendored
@@ -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
3
.gitmodules
vendored
@@ -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
|
||||
|
@@ -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://github.com/topjohnwu/Magisk/releases/tag/v26.3)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v26.3)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v26.4)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v26.4)
|
||||
[](https://raw.githubusercontent.com/topjohnwu/magisk-files/canary/app-release.apk)
|
||||
[](https://raw.githubusercontent.com/topjohnwu/magisk-files/canary/app-debug.apk)
|
||||
|
||||
|
@@ -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")
|
||||
}
|
||||
|
@@ -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>
|
||||
|
@@ -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>
|
||||
|
@@ -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>
|
||||
|
@@ -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>
|
||||
|
@@ -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>
|
||||
|
@@ -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>
|
||||
|
18
build.py
18
build.py
@@ -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"
|
||||
|
||||
|
@@ -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")
|
||||
}
|
||||
|
@@ -72,6 +72,7 @@ fun Project.setupCommon() {
|
||||
compileSdkVersion(34)
|
||||
buildToolsVersion = "34.0.0"
|
||||
ndkPath = "$sdkDirectory/ndk/magisk"
|
||||
ndkVersion = "26.1.10909125"
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 23
|
||||
|
@@ -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
|
||||
|
@@ -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`.
|
||||
|
@@ -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:
|
||||
|
||||
|
@@ -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
9
docs/releases/27000.md
Normal 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)
|
@@ -1,5 +1,6 @@
|
||||
# Release Notes
|
||||
|
||||
- [v27.0](27000.md)
|
||||
- [v26.4](26400.md)
|
||||
- [v26.3](26300.md)
|
||||
- [v26.2](26200.md)
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -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
20
gradlew.bat
vendored
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
194
native/src/Cargo.lock
generated
@@ -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",
|
||||
]
|
||||
|
@@ -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)]
|
||||
|
@@ -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()
|
||||
}
|
||||
|
@@ -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();
|
||||
|
@@ -4,7 +4,6 @@
|
||||
#include "../files.hpp"
|
||||
#include "../misc.hpp"
|
||||
#include "../logging.hpp"
|
||||
#include "../missing.hpp"
|
||||
#include "../base-rs.hpp"
|
||||
|
||||
using rust::xpipe2;
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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));
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
@@ -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);
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <poll.h>
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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> {
|
||||
|
@@ -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
|
||||
|
@@ -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"]
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <magisk.hpp>
|
||||
#include <consts.hpp>
|
||||
#include <selinux.hpp>
|
||||
#include <base.hpp>
|
||||
|
||||
|
@@ -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') {
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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);
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -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 {
|
||||
|
@@ -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]);
|
@@ -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;
|
@@ -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"
|
||||
|
@@ -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"
|
||||
|
@@ -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();
|
29
native/src/core/include/daemon.hpp
Normal file
29
native/src/core/include/daemon.hpp
Normal 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(); }
|
@@ -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);
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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) {
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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();
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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) {
|
||||
|
@@ -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);
|
||||
|
@@ -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");
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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());
|
||||
|
@@ -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));
|
||||
|
@@ -5,7 +5,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include <db.hpp>
|
||||
#include <daemon.hpp>
|
||||
#include <core.hpp>
|
||||
|
||||
#define DEFAULT_SHELL "/system/bin/sh"
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
#include <sys/wait.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <magisk.hpp>
|
||||
#include <consts.hpp>
|
||||
#include <base.hpp>
|
||||
#include <selinux.hpp>
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
};
|
@@ -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());
|
||||
}
|
||||
}
|
@@ -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')
|
592
native/src/core/zygisk/hook.cpp
Normal file
592
native/src/core/zygisk/hook.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
98
native/src/core/zygisk/main.cpp
Normal file
98
native/src/core/zygisk/main.cpp
Normal 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;
|
||||
}
|
466
native/src/core/zygisk/module.cpp
Normal file
466
native/src/core/zygisk/module.cpp
Normal 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 ®: register_info) {
|
||||
if (regexec(®.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();
|
||||
}
|
@@ -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
|
60
native/src/core/zygisk/zygisk.hpp
Normal file
60
native/src/core/zygisk/zygisk.hpp
Normal 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);
|
||||
};
|
@@ -1,4 +1,3 @@
|
||||
{
|
||||
zygisk_inject_entry;
|
||||
unload_first_stage;
|
||||
NativeBridgeItf;
|
||||
};
|
||||
|
6
native/src/external/Android.mk
vendored
6
native/src/external/Android.mk
vendored
@@ -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
|
||||
|
2
native/src/external/cxx-rs
vendored
2
native/src/external/cxx-rs
vendored
Submodule native/src/external/cxx-rs updated: ce439b25bf...16abd4d2b4
1
native/src/external/parallel-hashmap
vendored
1
native/src/external/parallel-hashmap
vendored
Submodule native/src/external/parallel-hashmap deleted from 7684faf186
2
native/src/external/selinux
vendored
2
native/src/external/selinux
vendored
Submodule native/src/external/selinux updated: 9786b2ebe6...8c6acc0d77
2
native/src/external/system_properties
vendored
2
native/src/external/system_properties
vendored
Submodule native/src/external/system_properties updated: 3b4b3f0c64...049ceb6791
@@ -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[]);
|
@@ -20,3 +20,10 @@ macro_rules! LOG_PIPE {
|
||||
concat!($crate::INTLROOT!(), "/log")
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! MAIN_CONFIG {
|
||||
() => {
|
||||
concat!($crate::INTLROOT!(), "/config")
|
||||
};
|
||||
}
|
||||
|
@@ -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";
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <base.hpp>
|
||||
#include <flags.h>
|
||||
#include <magisk.hpp>
|
||||
#include <consts.hpp>
|
||||
|
||||
#include "init.hpp"
|
||||
|
||||
|
@@ -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
Reference in New Issue
Block a user