Compare commits

..

112 Commits
v26.2 ... v26.4

Author SHA1 Message Date
topjohnwu
6c807d35b2 Release Magisk v26.4 2023-11-05 23:31:15 -08:00
topjohnwu
8ca8cdae97 Add v26.4 release notes 2023-11-05 23:07:53 -08:00
topjohnwu
75e37be6f3 Do not need to check pkg in magisk_env 2023-11-05 23:02:40 -08:00
WindowsFan9600
4985314ca6 Update language "tr" on main application 2023-11-05 22:37:39 -08:00
topjohnwu
ac5ceb18c8 Guard log FIFO with SELinux 2023-11-04 23:59:11 -07:00
topjohnwu
72b39594d3 Always close logd_fd during fork 2023-11-04 02:36:14 -07:00
topjohnwu
16ae4aedf1 Remove usage of MAGISKTMP 2023-11-02 15:50:36 -07:00
topjohnwu
3ba00858e6 Allow avd_magisk on API 28 2023-11-01 09:15:17 -07:00
topjohnwu
489100c755 Fix fd sanitization 2023-11-01 02:01:29 -07:00
topjohnwu
da766f2a4e Do not go through magiskd for getting the log pipe 2023-11-01 02:01:18 -07:00
topjohnwu
c81d7ff76c Remove unnecessary RefCell usage 2023-10-31 18:22:48 -07:00
topjohnwu
a6e50d3648 Make log pipe a FIFO instead of anonymous pipe 2023-10-31 18:05:22 -07:00
topjohnwu
a177846044 Better logging in recv_fds 2023-10-31 17:40:59 -07:00
topjohnwu
19a4e11645 Make tmpfs path static strings 2023-10-29 00:47:28 -07:00
topjohnwu
67cc36268e Simplify zygisk log pipe 2023-10-26 18:13:56 -07:00
topjohnwu
28770b9a32 Support baseline profiles 2023-10-26 15:56:51 -07:00
WindowsFan9600
9f92e1bf15 [STRINGS] Improve Turkish (tr) language 2023-10-26 15:23:35 -07:00
topjohnwu
23fe5d5a19 Update build.yml 2023-10-26 14:50:42 -07:00
LoveSy
9088b584f6 Use official argh 2023-10-25 15:14:16 -07:00
vvb2060
beaf636415 Use ccache for C code 2023-10-25 15:05:41 -07:00
vvb2060
09bb2fe8dc Update dependencies 2023-10-25 14:58:02 -07:00
tzagim
1d6747d90e Update Hebrew translation 2023-10-24 21:06:15 -07:00
南宫雪珊
efadd94de3 Update strings.xml 2023-10-24 21:02:32 -07:00
vvb2060
8c0b4e444a Update zh-rCN translation 2023-10-24 21:02:32 -07:00
Rom
32c7106e40 Update French translation 2023-10-24 21:01:53 -07:00
topjohnwu
d2f2a9e4c8 Make avd_test less flaky 2023-10-24 16:45:24 -07:00
topjohnwu
985454afd4 Better logging 2023-10-24 16:41:49 -07:00
topjohnwu
9e1322de25 Make sure the shared preference is committed 2023-10-24 16:41:38 -07:00
topjohnwu
4e4ec73d94 Make gradle.properties optional 2023-10-19 15:44:34 -07:00
topjohnwu
bb39a524d0 Switch to default images for faster boot time 2023-10-19 05:31:03 -07:00
topjohnwu
196d9af099 Add application and Zygisk tests to avd_test.sh 2023-10-19 05:15:53 -07:00
topjohnwu
1eeb2a34a1 Don't support alternative binary paths
The Magisk app will guide users through repair setup
2023-10-19 05:11:43 -07:00
Arbri çoçka
cf43c56218 Update strings.xml sq 2023-10-18 14:29:55 -07:00
kubalav
e6c1aec443 Update Slovak translation 2023-10-18 14:29:38 -07:00
topjohnwu
43fd1c4c1b Update stub version 2023-10-17 19:22:53 -07:00
topjohnwu
022caca979 Release new canary build 2023-10-17 19:13:16 -07:00
topjohnwu
0352ea2cca Rename biometrics to user authentication 2023-10-17 18:43:27 -07:00
topjohnwu
e483d6befe Do not go through a fragment for auth 2023-10-17 17:39:31 -07:00
vvb2060
678c07fff5 suBiometric: remove biometric
use device credential to support more devices and second user
2023-10-17 17:39:05 -07:00
topjohnwu
91c92051f1 Simplify C++ SELinux routines 2023-10-17 16:04:59 -07:00
topjohnwu
4b8a0388e7 Make SELinux support a feature 2023-10-17 13:29:15 -07:00
topjohnwu
66788dc58c Cleanup SELinux support 2023-10-16 17:38:44 -07:00
topjohnwu
dd8c28b1cb Upgrade AGP 2023-10-16 17:25:57 -07:00
残页
32c5153e8e Increase boot timeout to 600s 2023-10-16 01:20:25 -07:00
topjohnwu
36de62873a Fix error logging on the C++ side 2023-10-13 16:59:54 -07:00
topjohnwu
51e37880c6 Add repr(transparent) to guarantee soundness 2023-10-12 18:59:16 -07:00
topjohnwu
4b83c1e76c Cleanup messy error messages 2023-10-12 18:54:09 -07:00
topjohnwu
b0b04690d5 Use newer bash version for avd_test.sh 2023-10-12 00:45:53 -07:00
topjohnwu
6d1e8d86cb Cleaner cstr code 2023-10-11 23:53:55 -07:00
topjohnwu
eda8c70a80 Borrow value instead of moving in FsPath::from()
When accepting a value of AsRef<Utf8CStr> in FsPath::from(), the
existing code will move a value of Utf8CStrBufArr, creating a reference
that lives longer than the borrowing value, causing undefined behavior.

The issue is only visible on release builds, as more advanced
optimizations will be more aggressive re-using the stack of variables
that no longer lives.

Fix #7408
2023-10-11 23:48:54 -07:00
topjohnwu
587b6cfd41 Update avd_test.sh 2023-10-11 22:42:45 -07:00
topjohnwu
e774408782 Allow AVD hacks on release builds 2023-10-11 14:17:31 -07:00
canyie
187f583c95 Fix $RECOVERYMODE from config being incorrectly overridden
Move legacy SAR checking logic into mount_partitions, and avoid calling get_flags before check_boot_ramdisk
Fix #7346
2023-10-10 15:53:18 -07:00
topjohnwu
f5d3a71478 Update ONDK to r26.1 2023-10-10 15:52:59 -07:00
残页
d868ff3080 AVD test release builds as well 2023-10-10 15:52:41 -07:00
nkh0472
f80198a669 typo fix 2023-10-09 17:22:48 -07:00
topjohnwu
6076b52c48 Update libcxx 2023-10-03 17:22:25 -07:00
topjohnwu
79a1c39b30 Simplify fd sanitization 2023-09-28 20:38:16 -07:00
topjohnwu
5c92d39498 Enable Zygisk by default in emulators
Make sure CI tests Zygisk
2023-09-28 20:25:26 -07:00
topjohnwu
6e7a995716 Introduce UtfCString 2023-09-27 15:21:24 -07:00
topjohnwu
a55d570213 Move more I/O operations into Rust 2023-09-27 02:28:43 -07:00
topjohnwu
5d07d0b964 Do not support systems without SELinux 2023-09-27 02:28:43 -07:00
Wang Han
ec115cd7e3 Don't skip fd sanitization if fds_to_ignore does not exist 2023-09-25 09:45:03 -07:00
osm0sis
9b3896fd3d Retain PREINITDEVICE during A-only addon.d 2023-09-23 23:51:36 -07:00
topjohnwu
a3f5918d25 Fix bug in libsepol
Fix #7308
2023-09-23 22:34:51 -07:00
topjohnwu
b28326198c Use crates for cpio code 2023-09-22 01:39:21 -07:00
topjohnwu
46275b90c2 Generalize unxz 2023-09-21 05:47:21 -07:00
topjohnwu
15e13a8d8b Organize logging code 2023-09-19 03:02:30 -07:00
topjohnwu
b750c89c87 Address clippy warnings 2023-09-19 01:11:50 -07:00
LoveSy
8d7c7c3dfb Refactor dtb in rust 2023-09-19 00:41:42 -07:00
topjohnwu
8e1a91509c Remove readlink_unsafe 2023-09-19 00:06:21 -07:00
LoveSy
927cd571f8 Fix read_cert crash when receive fd = -1 2023-09-18 22:32:32 -07:00
LoveSy
5fbd3e5c65 Fix buf len update of read_link to Utf8CStrBuf 2023-09-18 22:31:12 -07:00
LoveSy
877aeb66cb Upgrade to Gradle 8.3 2023-09-14 13:16:59 -07:00
topjohnwu
8a88d8465a Prevent OOM
Fix #7341
2023-09-14 13:14:30 -07:00
topjohnwu
dda8cc85c9 Use bytemuck 2023-09-14 13:10:09 -07:00
topjohnwu
6a59939d9a Remove for_all_file 2023-09-13 18:09:16 -07:00
topjohnwu
4745e86c1b Fix #7301 2023-09-13 14:44:20 -07:00
topjohnwu
9aa466c773 Fix genfscon and filename_trans
Fix #7329
2023-09-12 21:31:31 -07:00
LoveSy
0243610c09 No trailing zeros if the signed boot img is larger 2023-09-12 18:09:20 -07:00
topjohnwu
0a2a590ab7 Use Utf8CStr for logging 2023-09-12 17:35:20 -07:00
topjohnwu
89aee6ffa7 Add more to the Utf8CStr family
Better C strings with path operations
2023-09-12 17:35:01 -07:00
topjohnwu
4eaf701cb7 Address clippy warnings 2023-09-06 21:45:12 -07:00
topjohnwu
4fff2aa7d8 Fix proto read and write 2023-09-06 20:45:59 -07:00
topjohnwu
35b3c8ba5c Cleanup persist props code 2023-09-06 15:52:14 -07:00
topjohnwu
1d7cff7703 Update Cargo dependencies 2023-09-06 13:57:43 -07:00
LoveSy
8d81bd0e33 resetprop: replace nanopb with quick-protobuf for persist 2023-09-05 22:20:57 -07:00
topjohnwu
7826d7527f Release new canary build 2023-09-04 00:35:17 -07:00
topjohnwu
d4e552d08b Update README 2023-09-04 00:26:48 -07:00
topjohnwu
5a16418543 Release Magisk v26.3 2023-09-04 00:01:46 -07:00
topjohnwu
7297aba15a Add v26.3 release notes 2023-09-03 23:54:45 -07:00
Ylarod
bc5d5f9502 Update details.md
The `MAGISKTMP` changed to `/debug_ramdisk` since https://github.com/topjohnwu/Magisk/pull/6931
2023-09-03 23:46:25 -07:00
vvb2060
1761986c1b Update zh-rCN translation 2023-09-03 23:43:07 -07:00
topjohnwu
1e034e3e0e Update libsu 2023-09-03 23:41:17 -07:00
topjohnwu
bbf9756bfa Release new canary build 2023-09-02 06:20:10 -07:00
topjohnwu
96e559fb0e Skip cargo build if possible 2023-09-02 06:03:39 -07:00
topjohnwu
4c45775131 Update BusyBox 2023-09-02 05:45:18 -07:00
LoveSy
c072b4254d Wrap rename and renameat 2023-09-02 04:24:24 -07:00
topjohnwu
2dbb812126 Disable stack protector on x86 static executables
Close #7274
2023-09-01 23:04:19 -07:00
topjohnwu
be50f17f55 Update to ONDK r26.0
Close #7264
2023-09-01 23:01:49 -07:00
残页
6f77f190f2 Fix processPayload 2023-08-31 20:30:10 -07:00
topjohnwu
6bdc57cbe4 Release new canary build 2023-08-30 01:22:02 -07:00
残页
de00f1d5a9 Always check mounts to detect legacy SAR on bootmode 2023-08-30 01:02:19 -07:00
残页
e9b9bf987b Fix syntax error in util_functions.sh 2023-08-29 15:33:03 -07:00
topjohnwu
f4b6385f9f Disable boot vbmeta patch when found vbmeta.img 2023-08-28 22:54:55 -07:00
topjohnwu
75d905a56d Fix device detection scripts and logic 2023-08-28 22:13:36 -07:00
topjohnwu
b1363ee479 Do not allow user to configure boot vbmeta patching 2023-08-28 22:13:36 -07:00
topjohnwu
51afe43a30 Cleanup util_functions 2023-08-28 22:13:36 -07:00
残页
189c03c047 Add canyie to developer list 2023-08-28 13:21:58 -07:00
topjohnwu
ae9d270a32 Release new canary build 2023-08-28 01:25:07 -07:00
topjohnwu
e47e869f6b Update full changelog 2023-08-28 01:15:14 -07:00
topjohnwu
c39038a439 Update README 2023-08-28 01:13:25 -07:00
176 changed files with 3567 additions and 3012 deletions

View File

@@ -22,10 +22,10 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
os: [ubuntu-latest, windows-latest, macos-13]
steps:
- name: Check out
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: "recursive"
fetch-depth: 0
@@ -98,7 +98,7 @@ jobs:
test:
name: Test on ${{ matrix.api }}
runs-on: macos-latest
runs-on: macos-13
needs: build
strategy:
fail-fast: false
@@ -111,12 +111,6 @@ jobs:
with:
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:
@@ -130,5 +124,5 @@ jobs:
- name: AVD test
run: |
brew install coreutils
brew install coreutils bash
scripts/avd_test.sh ${{ matrix.api }}

6
.gitmodules vendored
View File

@@ -4,9 +4,6 @@
[submodule "busybox"]
path = native/src/external/busybox
url = https://github.com/topjohnwu/ndk-busybox.git
[submodule "dtc"]
path = native/src/external/dtc
url = https://github.com/dgibson/dtc.git
[submodule "lz4"]
path = native/src/external/lz4
url = https://github.com/lz4/lz4.git
@@ -16,9 +13,6 @@
[submodule "xz"]
path = native/src/external/xz
url = https://github.com/xz-mirror/xz.git
[submodule "nanopb"]
path = native/src/external/nanopb
url = https://github.com/nanopb/nanopb.git
[submodule "pcre"]
path = native/src/external/pcre
url = https://android.googlesource.com/platform/external/pcre

View File

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

View File

@@ -80,7 +80,7 @@ dependencies {
implementation("dev.rikka.rikkax.recyclerview:recyclerview-ktx:1.3.2")
implementation("io.noties.markwon:core:4.6.2")
val vLibsu = "5.2.0"
val vLibsu = "5.2.1"
implementation("com.github.topjohnwu.libsu:core:${vLibsu}")
implementation("com.github.topjohnwu.libsu:service:${vLibsu}")
implementation("com.github.topjohnwu.libsu:nio:${vLibsu}")
@@ -90,7 +90,7 @@ dependencies {
implementation("com.squareup.retrofit2:converter-moshi:${vRetrofit}")
implementation("com.squareup.retrofit2:converter-scalars:${vRetrofit}")
val vOkHttp = "4.11.0"
val vOkHttp = "4.12.0"
implementation("com.squareup.okhttp3:okhttp:${vOkHttp}")
implementation("com.squareup.okhttp3:logging-interceptor:${vOkHttp}")
implementation("com.squareup.okhttp3:okhttp-dnsoverhttps:${vOkHttp}")
@@ -99,23 +99,23 @@ dependencies {
implementation("com.squareup.moshi:moshi:${vMoshi}")
kapt("com.squareup.moshi:moshi-kotlin-codegen:${vMoshi}")
val vRoom = "2.6.0-beta01"
val vRoom = "2.6.0"
implementation("androidx.room:room-runtime:${vRoom}")
implementation("androidx.room:room-ktx:${vRoom}")
kapt("androidx.room:room-compiler:${vRoom}")
val vNav = "2.7.1"
val vNav = "2.7.4"
implementation("androidx.navigation:navigation-fragment-ktx:${vNav}")
implementation("androidx.navigation:navigation-ui-ktx:${vNav}")
implementation("androidx.biometric:biometric:1.1.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.recyclerview:recyclerview:1.3.1")
implementation("androidx.recyclerview:recyclerview:1.3.2")
implementation("androidx.fragment:fragment-ktx:1.6.1")
implementation("androidx.transition:transition:1.4.1")
implementation("androidx.core:core-ktx:1.10.1")
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.core:core-splashscreen:1.0.1")
implementation("com.google.android.material:material:1.9.0")
implementation("androidx.profileinstaller:profileinstaller:1.3.1")
implementation("com.google.android.material:material:1.10.0")
}

View File

@@ -82,11 +82,15 @@
android:name="androidx.room.MultiInstanceInvalidationService"
tools:node="remove" />
<!-- We don't need emoji compat -->
<!-- We handle initialization ourselves -->
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="remove" />
<!-- We handle profile installation ourselves -->
<receiver
android:name="androidx.profileinstaller.ProfileInstallReceiver"
tools:node="remove" />
</application>

View File

@@ -5,9 +5,12 @@ import android.app.Application
import android.content.Context
import android.content.res.Configuration
import android.os.Bundle
import androidx.profileinstaller.ProfileInstaller
import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.StubApk
import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.core.utils.DispatcherExecutor
import com.topjohnwu.magisk.core.utils.NetworkObserver
import com.topjohnwu.magisk.core.utils.ProcessLifecycle
import com.topjohnwu.magisk.core.utils.RootUtils
import com.topjohnwu.magisk.core.utils.ShellInit
@@ -19,6 +22,8 @@ import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.internal.UiThreadHandler
import com.topjohnwu.superuser.ipc.RootService
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import timber.log.Timber
import java.lang.ref.WeakReference
import kotlin.system.exitProcess
@@ -82,6 +87,12 @@ open class App() : Application() {
override fun onCreate() {
super.onCreate()
ProcessLifecycle.init(this)
NetworkObserver.init(this)
if (!BuildConfig.DEBUG && !isRunningAsStub) {
GlobalScope.launch(Dispatchers.IO) {
ProfileInstaller.writeProfile(this@App)
}
}
}
override fun onConfigurationChanged(newConfig: Configuration) {

View File

@@ -114,7 +114,6 @@ object Config : PreferenceConfig, DBConfig {
@JvmField var keepVerity = false
@JvmField var keepEnc = false
@JvmField var patchVbmeta = false
@JvmField var recovery = false
var bootId by preference(Key.BOOT_ID, "")
@@ -157,7 +156,12 @@ object Config : PreferenceConfig, DBConfig {
var rootMode by dbSettings(Key.ROOT_ACCESS, Value.ROOT_ACCESS_APPS_AND_ADB)
var suMntNamespaceMode by dbSettings(Key.SU_MNT_NS, Value.NAMESPACE_MODE_REQUESTER)
var suMultiuserMode by dbSettings(Key.SU_MULTIUSER_MODE, Value.MULTIUSER_MODE_OWNER_ONLY)
var suBiometric by dbSettings(Key.SU_BIOMETRIC, false)
private var suBiometric by dbSettings(Key.SU_BIOMETRIC, false)
var userAuth
get() = Info.isDeviceSecure && suBiometric
set(value) {
suBiometric = value
}
var zygisk by dbSettings(Key.ZYGISK, false)
var denyList by BoolDBPropertyNoWrite(Key.DENYLIST, false)
var suManager by dbStrings(Key.SU_MANAGER, "", true)

View File

@@ -1,14 +1,12 @@
package com.topjohnwu.magisk.core
import android.os.Build
import androidx.lifecycle.LiveData
import android.app.KeyguardManager
import androidx.lifecycle.MutableLiveData
import com.topjohnwu.magisk.StubApk
import com.topjohnwu.magisk.core.di.AppContext
import com.topjohnwu.magisk.core.ktx.getProperty
import com.topjohnwu.magisk.core.model.UpdateInfo
import com.topjohnwu.magisk.core.repository.NetworkService
import com.topjohnwu.magisk.core.utils.NetworkObserver
import com.topjohnwu.superuser.ShellUtils.fastCmd
val isRunningAsStub get() = Info.stub != null
@@ -33,31 +31,26 @@ object Info {
@JvmField val isZygiskEnabled = System.getenv("ZYGISK_ENABLED") == "1"
@JvmStatic val isFDE get() = crypto == "block"
@JvmField var ramdisk = false
@JvmField var vbmeta = false
var patchBootVbmeta = false
var crypto = ""
var noDataExec = false
var isRooted = false
@JvmField var hasGMS = true
val isSamsung = Build.MANUFACTURER.equals("samsung", ignoreCase = true)
@JvmField val isEmulator =
getProperty("ro.kernel.qemu", "0") == "1" ||
getProperty("ro.boot.qemu", "0") == "1"
val isConnected: LiveData<Boolean> by lazy {
MutableLiveData(false).also { field ->
NetworkObserver.observe(AppContext) {
remote = EMPTY_REMOTE
field.postValue(it)
}
}
}
val isConnected = MutableLiveData(false)
val showSuperUser: Boolean get() {
return env.isActive && (Const.USER_ID == 0
|| Config.suMultiuserMode == Config.Value.MULTIUSER_MODE_USER)
}
val isDeviceSecure get() =
AppContext.getSystemService(KeyguardManager::class.java).isDeviceSecure
private fun loadState(): Env {
val v = fastCmd("magisk -v").split(":".toRegex())
return Env(

View File

@@ -6,12 +6,18 @@ import android.os.ParcelFileDescriptor
import android.os.ParcelFileDescriptor.MODE_READ_ONLY
import com.topjohnwu.magisk.core.base.BaseProvider
import com.topjohnwu.magisk.core.su.SuCallbackHandler
import com.topjohnwu.magisk.core.su.TestHandler
class Provider : BaseProvider() {
override fun call(method: String, arg: String?, extras: Bundle?): Bundle? {
SuCallbackHandler.run(context!!, method, extras)
return Bundle.EMPTY
return when (method) {
SuCallbackHandler.LOG, SuCallbackHandler.NOTIFY -> {
SuCallbackHandler.run(context!!, method, extras)
Bundle.EMPTY
}
else -> TestHandler.run(method)
}
}
override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor? {

View File

@@ -20,6 +20,7 @@ import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.isRunningAsStub
import com.topjohnwu.magisk.core.ktx.reflectField
import com.topjohnwu.magisk.core.ktx.toast
import com.topjohnwu.magisk.core.utils.RequestAuthentication
import com.topjohnwu.magisk.core.utils.RequestInstall
import com.topjohnwu.magisk.core.wrap
@@ -43,6 +44,12 @@ abstract class BaseActivity : AppCompatActivity() {
installCallback = null
}
var authenticateCallback: ((Boolean) -> Unit)? = null
val requestAuthenticate = registerForActivityResult(RequestAuthentication()) {
authenticateCallback?.invoke(it)
authenticateCallback = null
}
private var contentCallback: ContentResultCallback? = null
private val getContent = registerForActivityResult(GetContent()) {
if (it != null) contentCallback?.onActivityResult(it)

View File

@@ -12,7 +12,6 @@ import com.topjohnwu.magisk.core.data.magiskdb.StringDao
import com.topjohnwu.magisk.core.ktx.deviceProtectedContext
import com.topjohnwu.magisk.core.repository.LogRepository
import com.topjohnwu.magisk.core.repository.NetworkService
import com.topjohnwu.magisk.core.utils.BiometricHelper
import io.noties.markwon.Markwon
import io.noties.markwon.utils.NoCopySpannableFactory
@@ -24,7 +23,6 @@ object ServiceLocator {
lateinit var context: Context
val deContext by lazy { context.deviceProtectedContext }
val timeoutPrefs by lazy { deContext.getSharedPreferences("su_timeout", 0) }
val biometrics by lazy { BiometricHelper(context) }
// Database
val policyDB = PolicyDao()

View File

@@ -58,6 +58,7 @@ class SuRequestHandler(
val pid = intent.getIntExtra("pid", -1)
val fifo = intent.getStringExtra("fifo")
if (uid <= 0 || pid <= 0 || fifo == null) {
Timber.e("Unexpected extras: uid=[${uid}], pid=[${pid}], fifo=[${fifo}]")
return false
}
output = File(fifo)
@@ -73,7 +74,11 @@ class SuRequestHandler(
respond(SuPolicy.DENY, -1)
return false
}
return output.canWrite()
if (!output.canWrite()) {
Timber.e("Cannot write to $output")
return false
}
return true
}
suspend fun respond(action: Int, time: Int) {

View File

@@ -0,0 +1,68 @@
package com.topjohnwu.magisk.core.su
import android.os.Bundle
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.core.tasks.MagiskInstaller
import com.topjohnwu.magisk.core.utils.RootUtils
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.internal.NOPList
import kotlinx.coroutines.runBlocking
object TestHandler {
fun run(method: String): Bundle {
val r = Bundle()
fun setup(): Boolean {
val nop = NOPList.getInstance()
return runBlocking {
MagiskInstaller.Emulator(nop, nop).exec()
}
}
fun test(): Boolean {
// Make sure Zygisk works correctly
if (!Info.isZygiskEnabled) {
r.putString("reason", "zygisk not enabled")
return false
}
// Make sure the Magisk app can get root
val shell = Shell.getShell()
if (!shell.isRoot) {
r.putString("reason", "shell not root")
return false
}
// Make sure the root service is running
RootUtils.Connection.await()
// Clear existing grant for ADB shell
runBlocking {
ServiceLocator.policyDB.delete(2000)
Config.suAutoResponse = Config.Value.SU_AUTO_ALLOW
Config.prefs.edit().commit()
}
return true
}
val b = runCatching {
when (method) {
"setup" -> setup()
"test" -> test()
else -> {
r.putString("reason", "unknown method")
false
}
}
}.getOrElse {
r.putString("reason", it.stackTraceToString())
false
}
r.putBoolean("result", b)
return r
}
}

View File

@@ -181,8 +181,10 @@ abstract class MagiskInstallImpl protected constructor(
return TarEntry(TarHeader.createHeader(name, size, 0, false, 420 /* 0644 */))
}
private class LZ4InputStream(s: InputStream) : LZ4FrameInputStream(s) {
// Workaround bug in LZ4FrameInputStream
private class NoAvailableStream(s: InputStream) : FilterInputStream(s) {
// Make sure available is never called on the actual stream and always return 0
// 1. Workaround bug in LZ4FrameInputStream
// 2. Reduce max buffer size to prevent OOM
override fun available() = 0
}
@@ -194,7 +196,8 @@ abstract class MagiskInstallImpl protected constructor(
lateinit var entry: TarEntry
fun decompressedStream(): InputStream {
return if (entry.name.endsWith(".lz4")) LZ4InputStream(tarIn) else tarIn
val stream = if (entry.name.endsWith(".lz4")) LZ4FrameInputStream(tarIn) else tarIn
return NoAvailableStream(stream)
}
while (tarIn.nextEntry?.let { entry = it } != null) {
@@ -218,6 +221,8 @@ abstract class MagiskInstallImpl protected constructor(
ByteBuffer.wrap(rawData).putInt(120, 3)
tarOut.putNextEntry(newTarEntry("vbmeta.img", rawData.size.toLong()))
tarOut.write(rawData)
// vbmeta partition exist, disable boot vbmeta patch
Info.patchBootVbmeta = false
} else if (entry.name.contains("userdata.img")) {
continue
} else {
@@ -320,7 +325,8 @@ abstract class MagiskInstallImpl protected constructor(
val fd = Os.open(fifo.path, O_WRONLY, 0)
try {
val buf = ByteBuffer.allocate(1024 * 1024)
val bufSize = 1024 * 1024
val buf = ByteBuffer.allocate(bufSize)
buf.position(input.read(buf.array()).coerceAtLeast(0)).flip()
while (buf.hasRemaining()) {
try {
@@ -332,6 +338,7 @@ abstract class MagiskInstallImpl protected constructor(
break
}
if (!buf.hasRemaining()) {
buf.limit(bufSize)
buf.position(input.read(buf.array()).coerceAtLeast(0)).flip()
}
}
@@ -490,7 +497,7 @@ abstract class MagiskInstallImpl protected constructor(
"cd $installDir",
"KEEPFORCEENCRYPT=${Config.keepEnc} " +
"KEEPVERITY=${Config.keepVerity} " +
"PATCHVBMETAFLAG=${Config.patchVbmeta} " +
"PATCHVBMETAFLAG=${Info.patchBootVbmeta} " +
"RECOVERYMODE=${Config.recovery} " +
"LEGACYSAR=${Info.legacySAR} " +
"sh boot_patch.sh $srcBoot")

View File

@@ -1,53 +0,0 @@
package com.topjohnwu.magisk.core.utils
import android.content.Context
import androidx.biometric.BiometricManager
import androidx.biometric.BiometricManager.Authenticators
import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentActivity
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Config
class BiometricHelper(context: Context) {
private val mgr = BiometricManager.from(context)
val isSupported get() = when (mgr.canAuthenticate(Authenticators.BIOMETRIC_WEAK)) {
BiometricManager.BIOMETRIC_SUCCESS -> true
else -> false
}
val isEnabled get() = isSupported && Config.suBiometric
fun authenticate(
activity: FragmentActivity,
onError: () -> Unit = {},
onSuccess: () -> Unit): BiometricPrompt {
val prompt = BiometricPrompt(activity,
ContextCompat.getMainExecutor(activity),
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
onError()
}
override fun onAuthenticationFailed() {
onError()
}
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
onSuccess()
}
}
)
val info = BiometricPrompt.PromptInfo.Builder()
.setConfirmationRequired(true)
.setAllowedAuthenticators(Authenticators.BIOMETRIC_WEAK)
.setTitle(activity.getString(R.string.authenticate))
.setNegativeButtonText(activity.getString(android.R.string.cancel))
.build()
prompt.authenticate(info)
return prompt
}
}

View File

@@ -14,14 +14,10 @@ import androidx.core.content.getSystemService
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ProcessLifecycleOwner
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.ktx.registerRuntimeReceiver
typealias ConnectionCallback = (Boolean) -> Unit
class NetworkObserver(
context: Context,
private val callback: ConnectionCallback
): DefaultLifecycleObserver {
class NetworkObserver(context: Context): DefaultLifecycleObserver {
private val manager = context.getSystemService<ConnectivityManager>()!!
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
@@ -29,11 +25,11 @@ class NetworkObserver(
override fun onAvailable(network: Network) {
activeList.add(network)
callback(true)
postValue(true)
}
override fun onLost(network: Network) {
activeList.remove(network)
callback(!activeList.isEmpty())
postValue(!activeList.isEmpty())
}
}
@@ -45,7 +41,7 @@ class NetworkObserver(
}
override fun onReceive(context: Context, intent: Intent) {
if (context.isIdleMode()) {
callback(false)
postValue(false)
} else {
postCurrentState()
}
@@ -67,13 +63,18 @@ class NetworkObserver(
}
private fun postCurrentState() {
callback(manager.getNetworkCapabilities(manager.activeNetwork)
postValue(manager.getNetworkCapabilities(manager.activeNetwork)
?.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) ?: false)
}
private fun postValue(b: Boolean) {
Info.remote = Info.EMPTY_REMOTE
Info.isConnected.postValue(b)
}
companion object {
fun observe(context: Context, callback: ConnectionCallback): NetworkObserver {
return NetworkObserver(context, callback).apply { postCurrentState() }
fun init(context: Context): NetworkObserver {
return NetworkObserver(context).apply { postCurrentState() }
}
}
}

View File

@@ -0,0 +1,17 @@
package com.topjohnwu.magisk.core.utils
import android.app.Activity
import android.app.KeyguardManager
import android.content.Context
import android.content.Intent
import androidx.activity.result.contract.ActivityResultContract
class RequestAuthentication: ActivityResultContract<Unit, Boolean>() {
override fun createIntent(context: Context, input: Unit) =
context.getSystemService(KeyguardManager::class.java)
.createConfirmDeviceCredentialIntent(null, null)
override fun parseResult(resultCode: Int, intent: Intent?) =
resultCode == Activity.RESULT_OK
}

View File

@@ -73,18 +73,17 @@ class ShellInit : Shell.Initializer() {
fun getVar(name: String) = fastCmd("echo \$$name")
fun getBool(name: String) = getVar(name).toBoolean()
Info.isSAR = getBool("SYSTEM_ROOT")
Info.isSAR = getBool("SYSTEM_AS_ROOT")
Info.ramdisk = getBool("RAMDISKEXIST")
Info.vbmeta = getBool("VBMETAEXIST")
Info.isAB = getBool("ISAB")
Info.crypto = getVar("CRYPTOTYPE")
Info.patchBootVbmeta = getBool("PATCHVBMETAFLAG")
Info.legacySAR = getBool("LEGACYSAR")
// Default presets
Config.recovery = getBool("RECOVERYMODE")
Config.keepVerity = getBool("KEEPVERITY")
Config.keepEnc = getBool("KEEPFORCEENCRYPT")
Config.patchVbmeta = getBool("PATCHVBMETAFLAG")
return true
}

View File

@@ -1,38 +0,0 @@
package com.topjohnwu.magisk.events
import com.topjohnwu.magisk.arch.ActivityExecutor
import com.topjohnwu.magisk.arch.UIActivity
import com.topjohnwu.magisk.arch.ViewEvent
import com.topjohnwu.magisk.core.di.ServiceLocator
class BiometricEvent(
builder: Builder.() -> Unit
) : ViewEvent(), ActivityExecutor {
private var listenerOnFailure: () -> Unit = {}
private var listenerOnSuccess: () -> Unit = {}
init {
builder(Builder())
}
override fun invoke(activity: UIActivity<*>) {
ServiceLocator.biometrics.authenticate(
activity,
onError = listenerOnFailure,
onSuccess = listenerOnSuccess
)
}
inner class Builder internal constructor() {
fun onFailure(listener: () -> Unit) {
listenerOnFailure = listener
}
fun onSuccess(listener: () -> Unit) {
listenerOnSuccess = listener
}
}
}

View File

@@ -51,6 +51,16 @@ class RecreateEvent : ViewEvent(), ActivityExecutor {
}
}
class AuthEvent(
private val callback: () -> Unit
) : ViewEvent(), ActivityExecutor {
override fun invoke(activity: UIActivity<*>) {
activity.authenticateCallback = { if (it) callback() }
activity.requestAuthenticate.launch(Unit)
}
}
class GetContentEvent(
private val type: String,
private val callback: ContentResultCallback

View File

@@ -24,6 +24,10 @@ private interface RikkaImpl : Dev {
override val name get() = "RikkaW"
}
private interface CanyieImpl : Dev {
override val name get() = "canyie"
}
sealed class DeveloperItem : Dev {
abstract val items: List<IconLink>
@@ -61,6 +65,14 @@ sealed class DeveloperItem : Dev {
object : IconLink.Github.User(), RikkaImpl {}
)
}
object Canyie : DeveloperItem(), CanyieImpl {
override val items =
listOf<IconLink>(
object : IconLink.Twitter() { override val name = "canyie2977" },
object : IconLink.Github.User(), CanyieImpl {}
)
}
}
sealed class IconLink : RvItem() {

View File

@@ -37,8 +37,7 @@ import java.io.IOException
class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel() {
val isRooted get() = Info.isRooted
val hideVbmeta = Info.vbmeta || Info.isSamsung || Info.isAB
val skipOptions = Info.isEmulator || (Info.isSAR && !Info.isFDE && hideVbmeta && Info.ramdisk)
val skipOptions = Info.isEmulator || (Info.isSAR && !Info.isFDE && Info.ramdisk)
val noSecondSlot = !isRooted || !Info.isAB || Info.isEmulator
@get:Bindable
@@ -105,7 +104,6 @@ class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel()
step,
Config.keepVerity,
Config.keepEnc,
Config.patchVbmeta,
Config.recovery
))
}
@@ -116,7 +114,6 @@ class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel()
step = it.step
Config.keepVerity = it.keepVerity
Config.keepEnc = it.keepEnc
Config.patchVbmeta = it.patchVbmeta
Config.recovery = it.recovery
}
}
@@ -137,7 +134,6 @@ class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel()
val step: Int,
val keepVerity: Boolean,
val keepEnc: Boolean,
val patchVbmeta: Boolean,
val recovery: Boolean,
) : Parcelable

View File

@@ -12,7 +12,6 @@ import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.core.ktx.activity
import com.topjohnwu.magisk.core.tasks.HideAPK
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
@@ -283,19 +282,15 @@ object Tapjack : BaseSettingsItem.Toggle() {
override var value by Config::suTapjack
}
object Biometrics : BaseSettingsItem.Toggle() {
override val title = R.string.settings_su_biometric_title.asText()
override var description = R.string.settings_su_biometric_summary.asText()
override var value
get() = ServiceLocator.biometrics.isEnabled
set(value) {
Config.suBiometric = value
}
object Authentication : BaseSettingsItem.Toggle() {
override val title = R.string.settings_su_auth_title.asText()
override var description = R.string.settings_su_auth_summary.asText()
override var value by Config::userAuth
override fun refresh() {
isEnabled = ServiceLocator.biometrics.isSupported
isEnabled = Info.isDeviceSecure
if (!isEnabled) {
description = R.string.no_biometric.asText()
description = R.string.settings_su_auth_insecure.asText()
}
}
}

View File

@@ -18,7 +18,7 @@ import com.topjohnwu.magisk.core.ktx.toast
import com.topjohnwu.magisk.core.tasks.HideAPK
import com.topjohnwu.magisk.databinding.bindExtra
import com.topjohnwu.magisk.events.AddHomeIconEvent
import com.topjohnwu.magisk.events.BiometricEvent
import com.topjohnwu.magisk.events.AuthEvent
import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.launch
@@ -72,7 +72,7 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
if (Info.showSuperUser) {
list.addAll(listOf(
Superuser,
Tapjack, Biometrics, AccessMode, MultiuserMode, MountNamespaceMode,
Tapjack, Authentication, AccessMode, MultiuserMode, MountNamespaceMode,
AutomaticResponse, RequestTimeout, SUNotification
))
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
@@ -92,7 +92,7 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
when (item) {
DownloadPath -> withExternalRW(andThen)
UpdateChecker -> withPostNotificationPermission(andThen)
Biometrics -> authenticate(andThen)
Authentication -> AuthEvent(andThen).publish()
Theme -> SettingsFragmentDirections.actionSettingsFragmentToThemeFragment().navigate()
DenyListConfig -> SettingsFragmentDirections.actionSettingsFragmentToDenyFragment().navigate()
SystemlessHosts -> createHosts()
@@ -119,13 +119,6 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
}
}
private fun authenticate(callback: () -> Unit) {
BiometricEvent {
// allow the change on success
onSuccess { callback() }
}.publish()
}
private fun createHosts() {
Shell.cmd("add_hosts_module").submit {
AppContext.toast(R.string.settings_hosts_toast, Toast.LENGTH_SHORT)

View File

@@ -10,16 +10,20 @@ import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.data.magiskdb.PolicyDao
import com.topjohnwu.magisk.core.di.AppContext
import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.core.ktx.getLabel
import com.topjohnwu.magisk.core.model.su.SuPolicy
import com.topjohnwu.magisk.core.utils.currentLocale
import com.topjohnwu.magisk.databinding.*
import com.topjohnwu.magisk.databinding.MergeObservableList
import com.topjohnwu.magisk.databinding.RvItem
import com.topjohnwu.magisk.databinding.bindExtra
import com.topjohnwu.magisk.databinding.diffList
import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.dialog.SuperuserRevokeDialog
import com.topjohnwu.magisk.events.BiometricEvent
import com.topjohnwu.magisk.events.AuthEvent
import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.utils.asText
import com.topjohnwu.magisk.view.TextItem
@@ -113,10 +117,8 @@ class SuperuserViewModel(
}
}
if (ServiceLocator.biometrics.isEnabled) {
BiometricEvent {
onSuccess { updateState() }
}.publish()
if (Config.userAuth) {
AuthEvent { updateState() }.publish()
} else {
SuperuserRevokeDialog(item.title) { updateState() }.show()
}
@@ -168,10 +170,8 @@ class SuperuserViewModel(
}
}
if (ServiceLocator.biometrics.isEnabled) {
BiometricEvent {
onSuccess { updateState() }
}.publish()
if (Config.userAuth) {
AuthEvent { updateState() }.publish()
} else {
updateState()
}

View File

@@ -22,14 +22,13 @@ import com.topjohnwu.magisk.arch.BaseViewModel
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.data.magiskdb.PolicyDao
import com.topjohnwu.magisk.core.di.AppContext
import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.core.ktx.getLabel
import com.topjohnwu.magisk.core.ktx.toast
import com.topjohnwu.magisk.core.model.su.SuPolicy.Companion.ALLOW
import com.topjohnwu.magisk.core.model.su.SuPolicy.Companion.DENY
import com.topjohnwu.magisk.core.su.SuRequestHandler
import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.events.BiometricEvent
import com.topjohnwu.magisk.events.AuthEvent
import com.topjohnwu.magisk.events.DieEvent
import com.topjohnwu.magisk.events.ShowUIEvent
import com.topjohnwu.magisk.utils.TextHolder
@@ -77,12 +76,8 @@ class SuRequestViewModel(
fun grantPressed() {
cancelTimer()
if (ServiceLocator.biometrics.isEnabled) {
BiometricEvent {
onSuccess {
respond(ALLOW)
}
}.publish()
if (Config.userAuth) {
AuthEvent { respond(ALLOW) }.publish()
} else {
respond(ALLOW)
}

View File

@@ -242,6 +242,14 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/l_50" />
<include
item="@{DeveloperItem.Canyie.INSTANCE}"
layout="@layout/item_developer"
viewModel="@{viewModel}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/l_50" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>

View File

@@ -108,15 +108,6 @@
android:text="@string/keep_force_encryption"
app:tint="?colorPrimary" />
<CheckBox
style="@style/WidgetFoundation.Checkbox"
gone="@{viewModel.hideVbmeta}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checked="@={Config.patchVbmeta}"
android:text="@string/patch_vbmeta"
app:tint="?colorPrimary" />
<CheckBox
style="@style/WidgetFoundation.Checkbox"
gone="@{Info.ramdisk}"

View File

@@ -193,30 +193,26 @@ check_encryption() {
mount_partitions() {
[ "$(getprop ro.build.ab_update)" = "true" ] && SLOT=$(getprop ro.boot.slot_suffix)
# Check whether non rootfs root dir exists
SYSTEM_ROOT=false
grep ' / ' /proc/mounts | grep -qv 'rootfs' && SYSTEM_ROOT=true
SYSTEM_AS_ROOT=false
grep ' / ' /proc/mounts | grep -qv 'rootfs' && SYSTEM_AS_ROOT=true
LEGACYSAR=false
grep ' / ' /proc/mounts | grep -q '/dev/root' && LEGACYSAR=true
}
get_flags() {
KEEPVERITY=$SYSTEM_ROOT
KEEPVERITY=$SYSTEM_AS_ROOT
ISENCRYPTED=false
[ "$(getprop ro.crypto.state)" = "encrypted" ] && ISENCRYPTED=true
KEEPFORCEENCRYPT=$ISENCRYPTED
VBMETAEXIST=false
if [ -n "$(getprop ro.boot.vbmeta.device)" -o -n "$(getprop ro.boot.vbmeta.size)" ]; then
VBMETAEXIST=true
PATCHVBMETAFLAG=false
elif getprop ro.product.ab_ota_partitions | grep -wq vbmeta; then
VBMETAEXIST=true
fi
# Preset PATCHVBMETAFLAG to false in the non-root case
PATCHVBMETAFLAG=false
# Make sure RECOVERYMODE has value
[ -z $RECOVERYMODE ] && RECOVERYMODE=false
if grep ' / ' /proc/mounts | grep -q '/dev/root'; then
LEGACYSAR=true
PATCHVBMETAFLAG=false
else
LEGACYSAR=false
PATCHVBMETAFLAG=true
fi
[ -z $RECOVERYMODE ] && RECOVERYMODE=false
}
run_migrations() { return; }
@@ -229,9 +225,9 @@ grep_prop() { return; }
app_init() {
mount_partitions
get_flags
RAMDISKEXIST=false
check_boot_ramdisk && RAMDISKEXIST=true
get_flags
run_migrations
SHA1=$(grep_prop SHA1 $MAGISKTMP/.magisk/config)
check_encryption

View File

@@ -142,9 +142,6 @@
<string name="superuser_notification">إشعارات طلبات الروت</string>
<string name="settings_su_reauth_title">إعادة المصادقة بعد الترقية</string>
<string name="settings_su_reauth_summary">أعد مصادقة صلاحيات الروت بعد إجراء ترقيات للتطبيق</string>
<string name="settings_su_biometric_title">تفعيل التحقق بالبصمة</string>
<string name="settings_su_biometric_summary">تحقق إضافي بالبصمة لطلبات الروت </string>
<string name="no_biometric">جهازك غير مدعوم، أو أنك لم تضبّط البصماتَ بجهازك</string>
<string name="settings_customization">تخصيص</string>
<string name="multiuser_mode">نمط مستخدمين متعددين</string>

View File

@@ -155,9 +155,6 @@
<string name="settings_su_reauth_summary">Vuelve pidir los permisos de superusuariu dempués d\'anovar les aplicaciones</string>
<string name="settings_su_tapjack_title">Proteición escontra\'l tapjacking</string>
<string name="settings_su_tapjack_summary">El diálogu de concesión de permisos de superusuariu nun respuende a la entrada mentanto lu torgue otra ventana o superposición</string>
<string name="settings_su_biometric_title">Autenticación biométrica</string>
<string name="settings_su_biometric_summary">Usa l\'autenticación biométrica pa permitir les solicitúes de superusuariu</string>
<string name="no_biometric">El preséu nun ye compatible o nun s\'activaron los axustes biométricos</string>
<string name="settings_customization">Personalización</string>
<string name="setting_add_shortcut_summary">Amiesta un atayu a la pantalla d\'aniciu en casu de que\'l nome y l\'iconu seyan difíciles de reconocer darréu d\'anubrir l\'aplicación</string>
<string name="settings_doh_title">DNS per HTTPS</string>

View File

@@ -165,9 +165,6 @@
<string name="settings_su_reauth_summary">Tətbiqləri yüksəltdikdən sonra Superuser icazəsi istə</string>
<string name="settings_su_tapjack_title">Tapjack Qoruması</string>
<string name="settings_su_tapjack_summary">Superuser icazə pəncərəsi digər pəncərələr tərəfindən əngəlləndikdə heçbir girişə cavab verməyəcək</string>
<string name="settings_su_biometric_title">Biometrik İcazə</string>
<string name="settings_su_biometric_summary">Superuser istəkləri üçün biometrik icazədən istifadə et</string>
<string name="no_biometric">Cihaz ya dəstəklənmir ya da biometrik ayarlar yoxdur</string>
<string name="settings_customization">Özəlləşdirmə</string>
<string name="setting_add_shortcut_summary">Tətbiqi gizlətdikdən sonra tapmaq çətin olmasın deyə ana ekrana qısayol əlavə et</string>
<string name="settings_doh_title">HTTPS əvəzinə DNS</string>

View File

@@ -142,9 +142,6 @@
<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_biometric_title">Уключыць біяметрычную аўтэнтыфікацыю</string>
<string name="settings_su_biometric_summary">Выкарыстанне біяметрычнай аўтэнтыфікацыі для запытаў правоў суперкарыстальніка</string>
<string name="no_biometric">Не падтрымліваецца прыладай альбо не ўключана ў наладах</string>
<string name="settings_customization">Персаналізацыя</string>
<string name="setting_add_shortcut_summary">Дадаць на хатні экран прыгожы цэтлік на той выпадак, калі пасля хавання праграмы будзе цяжка разглядзець значок і назву</string>
<string name="settings_doh_title">DNS паверх HTTPS</string>

View File

@@ -167,9 +167,6 @@
<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_biometric_title">Биометрично удостоверяване</string>
<string name="settings_su_biometric_summary">За получаване на достъп до суперпотребителя е необходимо биометрично удостоверяване</string>
<string name="no_biometric">Устройството не се поддръжа или липсват биометрични настройки</string>
<string name="settings_customization">Приспособяване</string>
<string name="setting_add_shortcut_summary">Добавя красив пряк път на началния екран ако името или текущата икона на скритото приложение са трудни за разпознаване</string>
<string name="settings_doh_title">DNS през HTTPS</string>

View File

@@ -164,9 +164,6 @@
<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_biometric_title">বায়োমেট্রিক প্রমাণীকরণ</string>
<string name="settings_su_biometric_summary">সুপার ইউজার অনুরোধের অনুমতি দিতে বায়োমেট্রিক প্রমাণীকরণ ব্যবহার করুন</string>
<string name="no_biometric">অসমর্থিত ডিভাইস বা কোনো বায়োমেট্রিক সেটিংস সক্ষম করা নেই৷</string>
<string name="settings_customization">কাস্টমাইজেশন</string>
<string name="setting_add_shortcut_summary">অ্যাপটি লুকানোর পরে নাম এবং আইকন সনাক্ত করা কঠিন হলে হোম স্ক্রিনে একটি সুন্দর শর্টকাট যোগ করুন</string>
<string name="settings_doh_title">HTTPS এর উপর ডিএনএস</string>

View File

@@ -152,9 +152,6 @@
<string name="settings_su_reauth_summary">Demanar permisos de superusuari novament si una aplicació és actualitzada o reinstal·lada</string>
<string name="settings_su_tapjack_title">Activa la protecció contra \'TapJacking\'</string>
<string name="settings_su_tapjack_summary">El diàleg per donar permisos de superusuari no respondrà mentre estigui ofuscat per alguna altra finestra o superposició</string>
<string name="settings_su_biometric_title">Activar autenticació biomètrica</string>
<string name="settings_su_biometric_summary">Utilitza l\'autenticació biomètrica per permetre sol·licituds de superusuari</string>
<string name="no_biometric">El dispositiu no suporta o no té establerta configuració biomètrica</string>
<string name="settings_customization">Personalització</string>
<string name="setting_add_shortcut_summary">Afegeix una bonica drecera a la pantalla d\'inici en cas que el nom i la icona siguin difícils de reconèixer després d\'amagar l\'aplicació.</string>
<string name="settings_doh_title">DNS sobre HTTPS</string>

View File

@@ -170,9 +170,6 @@
<string name="settings_su_reauth_summary">Opětovné ověření oprávnění SuperUser po aktualizaci aplikace.</string>
<string name="settings_su_tapjack_title">Povolit ochranu před TapJack</string>
<string name="settings_su_tapjack_summary">Okno dialogu SuperUser nebude reagovat na kliknutí v případě, že je zavřené nebo překryté jiným oknem</string>
<string name="settings_su_biometric_title">Povolit biometrické ověření</string>
<string name="settings_su_biometric_summary">Použije biometrické ověření pro povolení požadavků SuperUser</string>
<string name="no_biometric">Nepodporované zařízení, nebo není povolené biometrické ověření</string>
<string name="settings_customization">Přizpůsobit</string>
<string name="setting_add_shortcut_summary">Přidá odkaz na domovskou obrazovku v případě, že se po skrytí aplikace její název a ikona těžko rozpoznávají.</string>
<string name="settings_doh_title">DNS přes HTTPS</string>

View File

@@ -167,9 +167,6 @@
<string name="settings_su_reauth_summary">Superuser-Berechtigungen nach App-Aktualisierung erneut authentifizieren</string>
<string name="settings_su_tapjack_title">Tapjacking-Schutz aktivieren</string>
<string name="settings_su_tapjack_summary">Das Dialogfeld der Superuser-Eingabeaufforderung reagiert nicht auf Eingaben, wenn es durch ein anderes Fenster oder Überlagerung verdeckt wird</string>
<string name="settings_su_biometric_title">Biometrische Authentifizierung aktivieren</string>
<string name="settings_su_biometric_summary">Biometrie verwenden, um Superuser-Anfragen zuzulassen</string>
<string name="no_biometric">Gerät unterstützt keine biometrischen Daten oder ist nicht mit diesen konfiguriert</string>
<string name="settings_customization">Personalisierung</string>
<string name="setting_add_shortcut_summary">Hinzufügen einer hübschen Startbildschirm-Verknüpfung, falls der Name und das Symbol nach dem Ausblenden der App schwer zu erkennen sind</string>
<string name="settings_doh_title">DNS über HTTPS</string>

View File

@@ -165,9 +165,6 @@
<string name="settings_su_reauth_summary">Επαναπιστοποίηση αδειών υπερχρήστη μετά την αναβάθμιση μίας εφαρμογής</string>
<string name="settings_su_tapjack_title">Ενεργοποίηση προστασίας Tapjacking</string>
<string name="settings_su_tapjack_summary">Το παράθυρο διαλόγου προτροπής του υπερχρήστη δεν αποκρίνεται στην είσοδο ενώ κρύβεται από οποιοδήποτε άλλο παράθυρο</string>
<string name="settings_su_biometric_title">Ενεργοποίηση βιομετρικού ελέγχου ταυτότητας</string>
<string name="settings_su_biometric_summary">Χρησιμοποιήστε βιομετρικό έλεγχο ταυτότητας για να επιτρέψετε αιτήματα υπερχρηστών</string>
<string name="no_biometric">Δεν υποστηρίζεται η συσκευή ή δεν υπάρχει καμία βιομετρική ρύθμιση</string>
<string name="settings_customization">Προσαρμογή</string>
<string name="setting_add_shortcut_summary">Προσθέστε μια όμορφη συντόμευση στην αρχική οθόνη σε περίπτωση που το όνομα και το εικονίδιο είναι δύσκολο να αναγνωριστούν αφού κρύψετε την εφαρμογή</string>
<string name="settings_doh_title">DNS μέσω HTTPS</string>

View File

@@ -167,9 +167,6 @@
<string name="settings_su_reauth_summary">Las apps volverán a solicitar privilegios de superusuario tras actualizarse</string>
<string name="settings_su_tapjack_title">Protección contra tapjacking</string>
<string name="settings_su_tapjack_summary">No podrás interactuar con las solicitudes de superusuario mientras estén tapadas por cualquier otra ventana o superposición</string>
<string name="settings_su_biometric_title">Autenticación biométrica</string>
<string name="settings_su_biometric_summary">Usa tu rostro, iris o huella digital para conceder privilegios de superusuario</string>
<string name="no_biometric">El dispositivo no está soportado o no has configurado ningún dato biométrico</string>
<string name="settings_customization">Personalización</string>
<string name="setting_add_shortcut_summary">Añade un atajo a la app con el ícono de Magisk a la pantalla de inicio en caso de que te resulte difícil reconocerla tras haberle cambiado el nombre y el ícono</string>
<string name="settings_doh_title">DNS sobre HTTPS</string>

View File

@@ -163,9 +163,6 @@
<string name="settings_su_reauth_summary">Pärast rakenduste uuendamist küsi superkasutaja luba uuesti</string>
<string name="settings_su_tapjack_title">Nupu varjamise kaitse</string>
<string name="settings_su_tapjack_summary">Superkasutaja taotluse hüpik ei reageeri vajutusele, kui seda katab mõni teine aken või ülekate</string>
<string name="settings_su_biometric_title">Luba biomeetriaga autentimine</string>
<string name="settings_su_biometric_summary">Kasuta superkasutaja taotluste kinnitamiseks biomeetrilist autentimist</string>
<string name="no_biometric">Mittetoetatud seade või ükski biomeetriaseadistus pole lubatud</string>
<string name="settings_customization">Kohandamine</string>
<string name="setting_add_shortcut_summary">Lisa avakuvale ilus otsetee juhuks, kui nime ja ikooni on pärast rakenduse peitmist raske tuvastada</string>
<string name="settings_doh_title">DNS üle HTTPSi</string>

View File

@@ -138,9 +138,6 @@
<string name="superuser_notification">اعلان روت</string>
<string name="settings_su_reauth_title">احراز هویت دوباره پس از بروز رسانی</string>
<string name="settings_su_reauth_summary">تأیید کردندوباره مجوزهای روت پس از ارتقاء برنامه</string>
<string name="settings_su_biometric_title">فعال کردن احراز هویت بیومتریک</string>
<string name="settings_su_biometric_summary">استفاده کردن از احراز هویت بیومتریک برای تأیید درخواست های روت</string>
<string name="no_biometric">دستگاه پشتیبانی نمی شود یا تنظیمات بیومتریک فعال نیست</string>
<string name="settings_customization">سفارشی سازی</string>
<string name="setting_add_shortcut_summary">اضافه کردن یک میانبر زیبا را در صفحه اصلی در صورت شناسایی نام و نماد پس از پنهان کردن برنامه</string>

View File

@@ -88,6 +88,9 @@
<string name="logs_cleared">Le journal a été effacé.</string>
<string name="pid">PID : %1$d</string>
<string name="target_uid">UID cible : %1$d</string>
<string name="target_pid">Montage ns PID cible: %s</string>
<string name="selinux_context">Contexte SELinux: %s</string>
<string name="supp_group">Groupe supplémentaire: %s</string>
<!--SafetyNet-->
@@ -167,9 +170,9 @@
<string name="settings_su_reauth_summary">Redemander une authentification pour autoriser laccès en superutilisateur après une mise à jour de lapplication</string>
<string name="settings_su_tapjack_title">Activer la protection contre le détournement du tapotement</string>
<string name="settings_su_tapjack_summary">Le dialogue dinvite du superutilisateur ne répondra pas à la saisie lorsquil est masqué par une autre fenêtre ou une surcouche</string>
<string name="settings_su_biometric_title">Activer lauthentification biométrique</string>
<string name="settings_su_biometric_summary">Utiliser lauthentification biométrique pour autoriser les accès en superutilisateur</string>
<string name="no_biometric">Lappareil nest pas pris en charge ou alors aucun paramètre biométrique nest activé</string>
<string name="settings_su_auth_title">Authentification utilisateur</string>
<string name="settings_su_auth_summary">Demander lauthentification utilisateur lors de la requête super-utilisateur</string>
<string name="settings_su_auth_insecure">Aucun méthode dauthentification utilisateur nest configurée sur le périphérique</string>
<string name="settings_customization">Personnalisation</string>
<string name="setting_add_shortcut_summary">Ajouter un joli raccourci dans lécran daccueil au cas où le nom et licône seraient difficiles à reconnaître après avoir masqué lapplication</string>
<string name="settings_doh_title">DNS sur HTTPS</string>

View File

@@ -165,9 +165,6 @@
<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_biometric_title">बायोमेट्रिक प्रमाणीकरण सक्षम करें</string>
<string name="settings_su_biometric_summary">सुपरयूज़र अनुरोधों की अनुमति देने के लिए बायोमेट्रिक प्रमाणीकरण का उपयोग करें</string>
<string name="no_biometric">असमर्थित डिवाइस या कोई बायोमेट्रिक सेटिंग सक्षम नहीं हैं</string>
<string name="settings_customization">कस्टमाईजेशन</string>
<string name="setting_add_shortcut_summary">ऐप को छिपाने के बाद नाम और आइकन को पहचानना मुश्किल है, तो होम स्क्रीन में एक सुंदर शॉर्टकट जोड़ें</string>
<string name="settings_doh_title">HTTPS पर DNS</string>

View File

@@ -142,9 +142,6 @@
<string name="superuser_notification">Superuser obavijest</string>
<string name="settings_su_reauth_title">Ponovno provjerite autentičnost nakon ažuriranja</string>
<string name="settings_su_reauth_summary">Ponovno provjerite autentičnost Superuser-a dopuštenja nakon ažuriranja aplikacije</string>
<string name="settings_su_biometric_title">Omogući biometrijsku provjeru autentičnosti</string>
<string name="settings_su_biometric_summary">Koristi biometrijsku provjeru autentičnosti da biste omogućili zahtjeve Superuser-a</string>
<string name="no_biometric">Nepodržani uređaj ili nije omogućena biometrijska provjera autentičnosti</string>
<string name="settings_customization">Prilagodba</string>
<string name="setting_add_shortcut_summary">Dodajte lijepi prečac na početni zaslon u slučaju da je naziv i ikonu teško prepoznati nakon skrivanja aplikacije</string>
<string name="settings_doh_title">DNS preko HTTPS-a</string>

View File

@@ -165,9 +165,6 @@
<string name="settings_su_reauth_summary">Az appok frissítés után kérjenek ismét Superuser engedélyeket</string>
<string name="settings_su_tapjack_title">Tapjacking védelem</string>
<string name="settings_su_tapjack_summary">A Superuser kérés párbeszédpanel nem válaszol a bevitelre, ha más ablak vagy átfedés eltakarja</string>
<string name="settings_su_biometric_title">Biometrikus azonosítás</string>
<string name="settings_su_biometric_summary">Használjon biometrikus hitelesítést a Superuser kérések engedélyezéséhez</string>
<string name="no_biometric">Nem támogatott eszköz, vagy nincsenek engedélyezve a biometrikus beállítások</string>
<string name="settings_customization">Testreszabás</string>
<string name="setting_add_shortcut_summary">Adjon hozzá egy szép parancsikont a kezdőképernyőhöz arra az esetre, ha a nevet és az ikont nehéz felismerni az alkalmazás elrejtése után</string>
<string name="settings_doh_title">DNS HTTPS-en keresztül</string>

View File

@@ -167,9 +167,6 @@
<string name="settings_su_reauth_summary">Autentikasi ulang izin akses superuser setelah aplikasi ditingkatkan</string>
<string name="settings_su_tapjack_title">Aktifkan perlindungan tapjacking</string>
<string name="settings_su_tapjack_summary">Dialog permintaan superuser tidak akan menanggapi masukan saat terhalangi oleh lapisan atau jendela lainnya</string>
<string name="settings_su_biometric_title">Aktifkan autentikasi biometrik</string>
<string name="settings_su_biometric_summary">Gunakan autentikasi biometrik untuk mengizinkan permintaan superuser</string>
<string name="no_biometric">Perangkat tidak mendukung atau setelan biometrik tidak diaktifkan</string>
<string name="settings_customization">Personalisasi</string>
<string name="setting_add_shortcut_summary">Tambahkan pintasan yang menarik pada layar utama seandainya nama dan ikon sulit untuk dikenali setelah menyembunyikan aplikasi</string>
<string name="settings_doh_title">DNS melalui HTTPS</string>

View File

@@ -165,9 +165,6 @@
<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_biometric_title">Autenticazione biometrica</string>
<string name="settings_su_biometric_summary">Utilizza l\'autenticazione biometrica per accettare le richieste di accesso root</string>
<string name="no_biometric">Il dispositivo non è supportato o le impostazioni biometriche sono disattivate</string>
<string name="settings_customization">Personalizzazione</string>
<string name="setting_add_shortcut_summary">Aggiungi un collegamento alla schermata iniziale se il nome e l\'icona sono difficili da riconoscere dopo aver nascosto l\'app</string>
<string name="settings_doh_title">DNS over HTTPS</string>

View File

@@ -8,6 +8,8 @@
<string name="install">התקנה</string>
<string name="section_home">בית</string>
<string name="section_theme">עיצוב</string>
<string name="denylist">רשימת דחייה</string>
<!--Home-->
<string name="no_connection">אין חיבור זמין</string>
@@ -18,10 +20,11 @@
<string name="hide">הסתרה</string>
<string name="home_package">חבילה</string>
<string name="home_app_title">יישום</string>
<string name="home_notice_content">הורד את Magisk רק מהדף הרשמי של GitHub. קבצים ממקורות לא ידועים יכולים להיות זדוניים!</string>
<string name="home_support_title">תמיכה בנו</string>
<string name="home_notice_content">יש להוריד את Magisk רק מהדף הרשמי של GitHub. קבצים ממקורות לא ידועים יכולים להיות זדוניים!</string>
<string name="home_support_title">תמיכה בנו</string>
<string name="home_follow_title">עקבו אחרינו</string>
<string name="home_item_source">מקור</string>
<string name="home_support_content">Magisk היה ותמיד יהיה בעל קוד מקור פתוח. עם זאת אתה יכול להראות לנו שאכפת לך על ידי שליחת תרומה קטנה.</string>
<string name="home_support_content">Magisk היה ותמיד יהיה בעל קוד מקור פתוח. עם זאת באפשרותך להראות לנו שאכפת לך על ידי שליחת תרומה קטנה.</string>
<string name="home_installed_version">מותקנת</string>
<string name="home_latest_version">אחרונה</string>
<string name="invalid_update_channel">ערוץ עדכון לא חוקי</string>
@@ -31,18 +34,19 @@
<!--Install-->
<string name="keep_force_encryption">שמירה על הצפנה בכח</string>
<string name="keep_dm_verity">שמירה על AVB 2.0/dm-verity</string>
<string name="patch_vbmeta">תיקון vbmeta בתמונת האתחול</string>
<string name="recovery_mode">מצב שחזור</string>
<string name="install_options_title">אפשרויות</string>
<string name="install_method_title">שיטה</string>
<string name="install_next">הבא</string>
<string name="install_start">צא לדרך</string>
<string name="manager_download_install">לחץ להורדה והתקנה</string>
<string name="manager_download_install">לחיצה להורדה והתקנה</string>
<string name="direct_install">התקנה ישירה (מומלץ)</string>
<string name="install_inactive_slot">התקן לחריץ לא פעיל (לאחר OTA)</string>
<string name="install_inactive_slot">התקנה לחריץ לא פעיל (לאחר OTA)</string>
<string name="install_inactive_slot_msg">ההתקן שלך ייאלץ אתחול לחריץ הלא פעיל הנוכחי שלך לאחר הפעלה מחדש!\nיש להשתמש באפשרות זו רק לאחר ביצוע OTA בלבד.\nלהמשיך?</string>
<string name="setup_title">התקנה נוספת</string>
<string name="select_patch_file">בחר והתקן קובץ</string>
<string name="patch_file_msg">בחר תמונה גולמית (*.img) או ODIN קובץ tar (*.tar)</string>
<string name="select_patch_file">בחירה והתקנת קובץ</string>
<string name="patch_file_msg">בחירת תמונה גולמית (*.img) או ODIN קובץ tar (*.tar)</string>
<string name="reboot_delay_toast">מאתחל בעוד 5 שניות…</string>
<string name="flash_screen_title">התקנה</string>
@@ -52,7 +56,7 @@
<string name="deny">דחה</string>
<string name="prompt">מיידי</string>
<string name="grant">הענק</string>
<string name="su_warning">מעניק גישה מלאה להתקן שלך.\nדחה באם אינך בטוח!</string>
<string name="su_warning">מעניק גישה מלאה להתקן שלך.\nיש לדחות באי וודאות!</string>
<string name="forever">לצמיתות</string>
<string name="once">פעם אחת</string>
<string name="tenmin">10 דקות</string>
@@ -76,13 +80,16 @@
<string name="superuser_policy_none">לא נתבקשו הרשאות משתמש על על ידי שום יישום</string>
<!--Logs-->
<string name="log_data_none">הינך ללא יומן רישום, נסה להשתמש ביישומים מותאמים יותר למשתמש העל שלך</string>
<string name="log_data_none">הינך ללא יומן רישום, יש לנסות להשתמש ביישומים מותאמים יותר למשתמש העל שלך</string>
<string name="log_data_magisk_none">יומני רישום Magisk ריקים, זה מוזר</string>
<string name="menuSaveLog">שמור יומן רישום</string>
<string name="menuClearLog">נקה יומן רישום כעת</string>
<string name="menuSaveLog">שמירת יומן רישום</string>
<string name="menuClearLog">ניקוי יומן רישום כעת</string>
<string name="logs_cleared">יומני רישום נוקו בהצלחה</string>
<string name="pid">PID: %1$d</string>
<string name="target_uid">יעד UID: %1$d</string>
<string name="target_pid">מציב ns יעד PID: %s</string>
<string name="selinux_context">הקשר SELinux: %s</string>
<string name="supp_group">קבוצה משלימה: %s</string>
<!--SafetyNet-->
@@ -100,35 +107,47 @@
<string name="reboot_download">אתחול מצב הורדה</string>
<string name="reboot_edl">אתחול למצב EDL</string>
<string name="module_version_author">%1$s מאת %2$s</string>
<string name="module_state_remove">הסר</string>
<string name="module_state_restore">שחזר</string>
<string name="module_action_install_external">התקן מהאחסון</string>
<string name="module_state_remove">הסרה</string>
<string name="module_state_restore">שיחזור</string>
<string name="module_action_install_external">התקנה מהאחסון</string>
<string name="update_available">עדכונים זמינים</string>
<string name="suspend_text_riru">מודול מושעה כי %1$s מופעל</string>
<string name="suspend_text_zygisk">המודול הושעה כי %1$s אינו מופעל</string>
<string name="zygisk_module_unloaded">מודול Zygisk לא נטען עקב חוסר תאימות</string>
<string name="module_empty">לא מותקן מודול</string>
<string name="confirm_install">להתקין מודול %1$s?</string>
<string name="confirm_install_title">אישור התקנה</string>
<!--Settings -->
<string name="settings_dark_mode_title">מצב עיצוב</string>
<string name="settings_dark_mode_message">בחר מצב המתאים ביותר לסגנון שלך!</string>
<string name="settings_dark_mode_message">נא לבחור מצב המתאים ביותר לסגנון שלך!</string>
<string name="settings_dark_mode_light">תמיד בהיר</string>
<string name="settings_dark_mode_system">בהתאם למערכת</string>
<string name="settings_dark_mode_dark">תמיד כהה</string>
<string name="settings_download_path_title">נתיב הורדה</string>
<string name="settings_download_path_message">הקבצים ישמרו אל %1$s</string>
<string name="settings_hide_app_title">הסתר את היישום Magisk</string>
<string name="settings_hide_app_summary">התקן יישום מתווך עם מזהה חבילה אקראי ותווית שם מותאמת אישית</string>
<string name="settings_restore_app_title">שחזר את יישום Magisk</string>
<string name="settings_restore_app_summary">בטל את הסתרת היישום ושחזר אותה ל-APK המקורי</string>
<string name="language">שפה</string>
<string name="settings_hide_app_title">הסתרת היישום Magisk</string>
<string name="settings_hide_app_summary">התקנת יישום מתווך עם מזהה חבילה אקראי ותווית שם מותאמת אישית</string>
<string name="settings_restore_app_title">שיחזור היישום Magisk</string>
<string name="settings_restore_app_summary">יש לבטל את הסתרת היישום ולשחזור אותו ל-APK המקורי</string>
<string name="language">שפה</string>
<string name="system_default">(ברירת מחדל מערכת)</string>
<string name="settings_check_update_title">בדוק עדכונים</string>
<string name="settings_check_update_title">בדיקת עדכונים</string>
<string name="settings_check_update_summary">בדוק מעת לעת ברקע אם יש עדכונים</string>
<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">הזן כתובת מותאמת אישית</string>
<string name="settings_update_custom">מותאם אישית</string>
<string name="settings_update_custom_msg">הזנת כתובת מותאמת אישית</string>
<string name="settings_zygisk_summary">הפעל חלקים של Magisk בדמון zygote</string>
<string name="settings_denylist_title">אכיפת רשימת דחייה</string>
<string name="settings_denylist_summary">כל השינויים של Magisk יוחזרו לתהליכים ברשימת הדחייה</string>
<string name="settings_denylist_error">תכונה זו דורשת הפעלה של %1$s</string>
<string name="settings_denylist_config_title">הגדרת רשימת הדחייה</string>
<string name="settings_denylist_config_summary">בחירת התהליכים שייכללו ברשימת הדחייה</string>
<string name="settings_hosts_title">מארחים חסרי מערכת</string>
<string name="settings_hosts_summary">מארחים חסרי מערכת תומכים ביישומים חוסמי פרסומות</string>
<string name="settings_hosts_toast">הוסף מודול מארחים חסרי מערכת</string>
<string name="settings_hosts_toast">הוספת מודול מארחים חסרי מערכת</string>
<string name="settings_app_name_hint">שם חדש</string>
<string name="settings_app_name_helper">היישום יארז מחדש בשם זה</string>
<string name="settings_app_name_error">פורמט לא חוקי</string>
@@ -146,15 +165,15 @@
<string name="auto_response">תגובה אוטומטית</string>
<string name="request_timeout">בקש פסק זמן</string>
<string name="superuser_notification">התראות משתמש על</string>
<string name="settings_su_reauth_title">אמת מחדש לאחר שדרוג</string>
<string name="settings_su_reauth_title">אימות מחדש לאחר שדרוג</string>
<string name="settings_su_reauth_summary">אימות מחדש הרשאות של משתמש על לאחר שדרוג יישום</string>
<string name="settings_su_tapjack_title">הפעלת הגנת Tapjacking</string>
<string name="settings_su_tapjack_summary">תיבת הדו שיח של משתמש העל לא תגיב לקלט כשהיא מוסתרת על ידי חלון או כיסוי אחר</string>
<string name="settings_su_biometric_title">אפשר אימות ביומטרי</string>
<string name="settings_su_biometric_summary">השתמש באימות ביומטרי כדי לאפשר בקשות לשימוש במשתמש על</string>
<string name="no_biometric">התקן לא נתמך או הגדרות ביומטריות אינן מאופשרות</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="setting_add_shortcut_summary">הוספת קיצור דרך יפה במסך הבית למקרה שקשה לזהות את השם ואת הסמל לאחר הסתרת היישום</string>
<string name="settings_doh_title">DNS על HTTPS</string>
<string name="settings_doh_description">עקיפת DNS מורעל במדינות מסוימות</string>
<string name="multiuser_mode">מצב מרובה משתמשים</string>
@@ -175,13 +194,17 @@
<!--Notifications-->
<string name="update_channel">עדכוני Magisk</string>
<string name="progress_channel">התראות התקדמות</string>
<string name="updated_channel">העדכון הושלם</string>
<string name="download_complete">ההורדה הושלמה</string>
<string name="download_file_error">שגיאה בהורדת קובץ</string>
<string name="magisk_update_title">עדכון Magisk זמין!</string>
<string name="updated_title">עדכון Magisk</string>
<string name="updated_text">הקשה כדי לפתוח יישום</string>
<!--Toasts, Dialogs-->
<string name="yes">כן</string>
<string name="no">לא</string>
<string name="repo_install_title">מתקין %1$s %2$s(%3$d)</string>
<string name="download">הורדה</string>
<string name="reboot">הפעלה מחדש</string>
<string name="release_notes">הערות שחרור</string>
@@ -189,7 +212,7 @@
<string name="done">בוצע!</string>
<string name="failure">נכשל</string>
<string name="hide_app_title">מסתיר את יישום Magisk…</string>
<string name="open_link_failed_toast">לא נמצאו יישומים לפתיחת קישור זה</string>
<string name="open_link_failed_toast">לא נמצאו יישומים לפתיחת קישור זה</string>
<string name="complete_uninstall">הסרה מלאה</string>
<string name="restore_img">שיחזור תמונות</string>
<string name="restore_img_msg">משחזר…</string>
@@ -197,8 +220,9 @@
<string name="restore_fail">גיבוי מקורי אינו קיים!</string>
<string name="setup_fail">ההתקנה כשלה</string>
<string name="env_fix_title">דורש התקנה נוספת</string>
<string name="env_fix_msg">המכשיר שלך זקוק להתקנה נוספת כדי ש-Magisk יפעל כראוי. האם ברצונך להמשיך ולהפעיל מחדש?</string>
<string name="setup_msg">הגדרת סביבת ריצה…</string>
<string name="env_fix_msg">ההתקן שלך זקוק להתקנה נוספת כדי ש-Magisk יפעל כראוי. האם ברצונך להמשיך ולהפעיל מחדש?</string>
<string name="env_full_fix_msg">ההתקן שלך זקוק לצריבה מחדש של Magisk כדי לעבוד כראוי. נא להתקין מחדש את Magisk בתוך היישום, מצב השחזור אינו יכול לקבל מידע נכון על ההתקן.</string>
<string name="setup_msg">הגדרת סביבת ריצה…</string>
<string name="authenticate">אימות</string>
<string name="unsupport_magisk_title">גרסת Magisk אינה נתמכת</string>
<string name="unsupport_magisk_msg">גרסה זו של היישום אינה תומכת ביישום Magisk הנמוך מ- %1$s.\n\nהיישום יתנהג כאילו Magisk אינו מותקן,יש לשדרג את Magisk במהירות האפשריות.</string>
@@ -208,8 +232,12 @@
<string name="unsupport_external_storage_msg">Magisk מותקן באחסון החיצוני. נא להעביר את היישום לאחסון הפנימי.</string>
<string name="unsupport_nonroot_stub_msg">היישום אינו יכול להמשיך לעבוד במצב הנסתר מכיוון שגישת השורש אבדה. נא לשחזר אותו חזרה ל-APK המקורי.</string>
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">הענק הרשאת אחסון להפעלת פונקציונליות זו</string>
<string name="add_shortcut_title">הוסף קיצור דרך למסך הבית</string>
<string name="external_rw_permission_denied">הענת הרשאת אחסון להפעלת פונקציה זו</string>
<string name="post_notifications_denied">הענקת הרשאה להתראות כדי להפעיל פונקציה זו</string>
<string name="install_unknown_denied">יש לאפשר "התקנה ממקורות לא ידועים" בכדי להפעיל פונקציה זו</string>
<string name="add_shortcut_title">הוספת קיצור דרך למסך הבית</string>
<string name="add_shortcut_msg">לאחר הסתרת היישום הזה, השם והסמליל שלה עשויים להיות קשים לזיהוי. האם ברצונך להוסיף קיצור דרך יפה למסך הבית?</string>
<string name="app_not_found">לא נמצא יישום לטיפול בפעולה זו</string>
<string name="app_not_found">לא נמצא יישום לטיפול בפעולה זו</string>
<string name="reboot_apply_change">ייש להפעיל מחדש כדי להחיל שינויים</string>
<string name="restore_app_confirmation">פעולה זו תשחזר את היישום המוסתר חזרה ליישום המקורי. האם בוודאות ברצונך לעשות את זה?</string>
</resources>

View File

@@ -165,9 +165,6 @@
<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_biometric_title">生体認証の有効化</string>
<string name="settings_su_biometric_summary">スーパーユーザー権限の要求時に生体認証を使用します</string>
<string name="no_biometric">生体認証に対応していないか、有効化されていません</string>
<string name="settings_customization">カスタマイズ</string>
<string name="setting_add_shortcut_summary">アプリを隠した後に見つけられなくなったときは、ここでホーム画面にショートカットを追加できます</string>
<string name="settings_doh_title">DNS over HTTPS</string>

View File

@@ -152,9 +152,6 @@
<string name="settings_su_reauth_summary">სუპერმომხმარებლის ნებართვის რეაუტენთიფიკაცია აპის განახლების შემდეგ</string>
<string name="settings_su_tapjack_title">Tapjacking-სგან თავის დაცვა</string> <!-- TODO: tapjacking has no direct translation; must make something up later -->
<string name="settings_su_tapjack_summary">superuser-ის დიალოგის ღილაკებზე დაჭერა არ იქნება შესაძლებელი თუ სხვა აპი არის მასზე გადახურული</string>
<string name="settings_su_biometric_title">ბიომეტრიკული აუტენთიფიკაციის ჩართვა</string>
<string name="settings_su_biometric_summary">ბიომეტრიკული აუტენთიფიკაციის გამოყენება სუპერმომხმარებლის ნებართვის გასაცემად</string>
<string name="no_biometric">შეუთავსებელი მოწყობილობა ან არასწორად დაყენებული ბიომეტრიკული პარამეტრები</string>
<string name="settings_customization">პერსონალიზაცია</string>
<string name="setting_add_shortcut_summary">ლამაზი ხატულის დამატება საწყისს ეკრანზე, იმ შემთხვევაში თუ აპის ამოცნობა არის რთული დამალვის შემდეგ</string>
<string name="settings_doh_title">DNS HTTPS-ზე</string>

View File

@@ -163,9 +163,6 @@
<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_biometric_title">생체 인증 활성화</string>
<string name="settings_su_biometric_summary">슈퍼유저 요청 허용에 생체 인증을 사용합니다.</string>
<string name="no_biometric">지원되지 않는 기기이거나 등록된 생체 정보가 없습니다.</string>
<string name="settings_customization">커스터마이즈</string>
<string name="setting_add_shortcut_summary">앱을 숨긴 후 아이콘과 이름을 알아보기 힘들 경우를 위해 알아보기 쉬운 바로가기를 홈 화면에 추가합니다.</string>
<string name="settings_doh_title">DNS over HTTPS</string>

View File

@@ -167,9 +167,6 @@
<string name="settings_su_reauth_summary">Iš naujo prašyti supernaudotojo teisių po programėlių naujinimo</string>
<string name="settings_su_tapjack_title">Bakstelėjimų perėmimo apsauga</string>
<string name="settings_su_tapjack_summary">Supernaudotojo užklausos langas bus neaktyvus, kol jis yra užstotas kito lango</string>
<string name="settings_su_biometric_title">Biometrinis autentifikavimas</string>
<string name="settings_su_biometric_summary">Naudoti biometrinį autentifikavimą supernaudotojo užklausų patvirtinimui</string>
<string name="no_biometric">Nepalaikomas įrenginys arba biometriniai nustatymai neįjungti</string>
<string name="settings_customization">Tinkinimas</string>
<string name="setting_add_shortcut_summary">Pridėti nuorodą į pagrindinį ekraną, jei po programėlės paslėpimo yra sunku atpažinti jos pavadinimą ir piktogramą</string>
<string name="settings_doh_title">DNS virš HTTPS</string>

View File

@@ -165,10 +165,7 @@
<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_biometric_title">ബയോമെട്രിക് പ്രാമാണീകരണം</string>
<string name="settings_su_biometric_summary">സൂപ്പർയൂസർ അഭ്യർത്ഥനകൾ അനുവദിക്കുന്നതിന് ബയോമെട്രിക് പ്രാമാണീകരണം ഉപയോഗിക്കുക</string>
<string name="settings_customization">Customization</string>
<string name="no_biometric">പിന്തുണയ്‌ക്കാത്ത ഉപകരണം അല്ലെങ്കിൽ ബയോമെട്രിക് ഒന്നും പ്രവർത്തനക്ഷമമാക്കിയിട്ടില്ല</string>
<string name="setting_add_shortcut_summary">ആപ്പ് മറച്ചതിന് ശേഷം പേരും ഐക്കണും തിരിച്ചറിയാൻ പ്രയാസമാണെങ്കിൽ ഹോം സ്‌ക്രീനിലേക്ക് മനോഹരമായ ഒരു ഷോർട്ട്ക്കട് ചേർക്കുക</string>
<string name="settings_doh_title">DNS ഓവർ HTTPS</string>
<string name="settings_doh_description">ചില രാജ്യങ്ങളിൽ DNS പോയ്സണിങിന് പരിഹാരം</string>

View File

@@ -152,9 +152,6 @@
<string name="settings_su_reauth_summary">Identitetsbekreft superbrukertilganger etter programoppgraderinger</string>
<string name="settings_su_tapjack_title">Trykkstjelingsbeskyttelse</string>
<string name="settings_su_tapjack_summary">Superbrukings-forespørselsdialogen vil ikke svare på inndata mens den dekkes av et annet vindu eller lag</string>
<string name="settings_su_biometric_title">Biometrisk identitetsbekreftelse</string>
<string name="settings_su_biometric_summary">Bruk biometrisk identitetsbekreftelse for å tillate superbruker-forespørsler</string>
<string name="no_biometric">Ustøttet enhet, eller mangel på biometrisk oppsett</string>
<string name="settings_customization">Tilpasning</string>
<string name="setting_add_shortcut_summary">Legg til fin snarvei på hjemmeskjermen i fall navnet og ikonet er vanskelig å gjenkjenne etter skjuling av programmet</string>
<string name="settings_doh_title">DNS over HTTPS</string>

View File

@@ -141,9 +141,6 @@
<string name="superuser_notification">Superusermelding</string>
<string name="settings_su_reauth_title">Opnieuw goedkeuren na update</string>
<string name="settings_su_reauth_summary">Superuserrechten opnieuw goedkeuren na app-updates.</string>
<string name="settings_su_biometric_title">Biometrische authenticatie gebruiken</string>
<string name="settings_su_biometric_summary">Gebruik biometrische authenticatie om superuserverzoeken goed te keuren.</string>
<string name="no_biometric">Niet-ondersteund apparaat of geen biometrische authenticatie ingesteld</string>
<string name="settings_customization">Aanpassingen</string>
<string name="multiuser_mode">Meerdere gebruikers</string>

View File

@@ -143,9 +143,6 @@
<string name="superuser_notification">ਸੁਪਰਯੂਜ਼ਰ ਸੂਚਨਾ</string>
<string name="settings_su_reauth_title">ਅਪਗ੍ਰੇਡ ਹੋਣ ਤੋਂ ਬਾਅਦ ਪ੍ਰਮਾਣਿਕਤਾ</string>
<string name="settings_su_reauth_summary">ਇੱਕ ਐਪ ਦੇ ਅਪਡੇਟ ਹੋਣ ਤੋਂ ਬਾਅਦ ਸੁਪਰਯੂਜ਼ਰ ਆਗਿਆ ਪ੍ਰਮਾਣਿਤ ਕਰੋ</string>
<string name="settings_su_biometric_title">ਬਾਇਓਮੈਟ੍ਰਿਕ ਪ੍ਰਮਾਣਿਕਤਾ ਦਾ ਯੋਗ ਕਰੋ</string>
<string name="settings_su_biometric_summary">ਸੁਪਰਯੂਜ਼ਰ ਦੀ ਆਗਿਆ ਦੇਣ ਲਈ ਬਾਇਓਮੈਟ੍ਰਿਕ ਪ੍ਰਮਾਣੀਕਰਣ ਦੀ ਵਰਤੋਂ ਕਰੋ</string>
<string name="no_biometric">ਅਸਮਰਥਿਤ ਡਿਵਾਈਸ ਜਾਂ ਕੋਈ ਬਾਇਓਮੈਟ੍ਰਿਕ ਸੈਟਿੰਗ ਸਮਰਥਿਤ ਨਹੀਂ ਹੈ</string>
<string name="settings_customization">ਕਸਟਮਾਈਜੇਸ਼ਨ</string>
<string name="setting_add_shortcut_summary">ਐਪ ਨੂੰ ਲੁਕਾਉਣ ਤੋਂ ਬਾਅਦ ਨਾਮ ਅਤੇ ਆਈਕਾਨ ਨੂੰ ਪਛਾਣਨਾ ਮੁਸ਼ਕਲ ਹੈ, ਤਾਂ ਹੋਮ ਸਕ੍ਰੀਨ ਵਿਚ ਇਕ ਸੁੰਦਰ ਸ਼ਾਰਟਕੱਟ ਸ਼ਾਮਲ ਕਰੋ</string>
<string name="settings_doh_title">DNS ਉੱਤੇ HTTPS</string>

View File

@@ -167,9 +167,6 @@
<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_biometric_title">Uwierzytelnianie biometryczne</string>
<string name="settings_su_biometric_summary">Używaj uwierzytelniania biometrycznego (np. odcisku palca) aby przyznać uprawnienia Superusera</string>
<string name="no_biometric">Urządzenie jest nieobsługiwane lub ustawienia biometryczne nie są włączone</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="settings_doh_title">DNS over HTTPS</string>

View File

@@ -166,9 +166,6 @@
<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_biometric_title">Ativar Autenticação Biométrica</string>
<string name="settings_su_biometric_summary">Use a autenticação biométrica para permitir solicitações de SuperUsuário</string>
<string name="no_biometric">Dispositivo não suportado ou nenhuma configuração biométrica está ativada</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>

View File

@@ -166,9 +166,6 @@
<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_biometric_title">Ativar Autenticação Biométrica</string>
<string name="settings_su_biometric_summary">Use a autenticação biométrica para permitir solicitações de SuperUsuário</string>
<string name="no_biometric">Dispositivo não suportado ou nenhuma configuração biométrica está ativada</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>

View File

@@ -167,9 +167,6 @@
<string name="settings_su_reauth_summary">Cere din nou permisiunile de superutilizator după actualizarea aplicațiilor</string>
<string name="settings_su_tapjack_title">Protecție față de tapjacking</string>
<string name="settings_su_tapjack_summary">Caseta de dialog pentru solicitarea permisiunilor de superutilizator nu va răspunde la input cât timp este ascunsă de orice altă fereastră sau suprapunere</string>
<string name="settings_su_biometric_title">Autentificare biometrică</string>
<string name="settings_su_biometric_summary">Folosește autentificarea biometrică pentru a permite cereri de superutilizator</string>
<string name="no_biometric">Dispozitiv nesuportat sau nu sunt activate setări biometrice</string>
<string name="settings_customization">Personalizare</string>
<string name="setting_add_shortcut_summary">Adaugă o comandă rapidă frumoasă în ecranul de pornire în cazul în care numele și pictograma sunt dificil de recunoscut după ascunderea aplicației</string>
<string name="settings_doh_title">DNS prin HTTPS</string>

View File

@@ -167,9 +167,6 @@
<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_biometric_title">Биометрическая аутентификация</string>
<string name="settings_su_biometric_summary">Принимать запросы прав суперпользователя только после биометрической аутентификации</string>
<string name="no_biometric">Функция не поддерживается устройством или не заданы настройки блокировки экрана</string>
<string name="settings_customization">Персонализация</string>
<string name="setting_add_shortcut_summary">Добавить ярлык на рабочий стол для удобного восприятия приложения после его скрытия</string>
<string name="settings_doh_title">DNS поверх HTTPS</string>

View File

@@ -170,9 +170,9 @@
<string name="settings_su_reauth_summary">Opätovne vyzve na udelenie oprávnení Superužívateľa po upgrade aplikácie</string>
<string name="settings_su_tapjack_title">Ochrana pred tapjackingom</string>
<string name="settings_su_tapjack_summary">Dialógové okno superužívateľa nebude reagovať na zadanie, ak je zakryté alebo prekryté iným oknom</string>
<string name="settings_su_biometric_title">Biometrické overenie</string>
<string name="settings_su_biometric_summary">Použije biometrickú autentifikáciu na povolenie žiadostí superužívateľa</string>
<string name="no_biometric">Nepodporované zariadenie alebo žiadne biometrické nastavenia nie sú povolené</string>
<string name="settings_su_auth_title">Overenie používateľa</string>
<string name="settings_su_auth_summary">Žiadosť o overenie používateľa počas požiadaviek Superužívateľa</string>
<string name="settings_su_auth_insecure">V zariadení nie je nakonfigurovaná žiadna metóda overovania</string>
<string name="settings_customization">Prispôsobenie</string>
<string name="setting_add_shortcut_summary">V prípade, že sa po skrytí apky názov a ikona ťažko rozpoznávajú, pridať na domovskú obrazovku odkaz</string>
<string name="settings_doh_title">DNS over HTTPS</string>

View File

@@ -170,9 +170,6 @@
<string name="settings_su_reauth_summary">Ri-vërtetoni lejet e super-përdoruesit pas azhurnimit të aplikacionit</string>
<string name="settings_su_tapjack_title">Aktivizo mbrojtjen tapjacking</string>
<string name="settings_su_tapjack_summary">Dialogu i menjëhershëm i super-përdoruesit nuk do ti përgjigjet hyrjes ndërsa është i errësuar nga ndonjë dritare ose mbivendosje tjetër</string>
<string name="settings_su_biometric_title">Aktivizo vërtetimin biometrik</string>
<string name="settings_su_biometric_summary">Përdorni vërtetimin biometrik për të lejuar kërkesat e super-përdoruesit</string>
<string name="no_biometric">Pajisja e pambështetur ose cilësimet biometrike nuk janë të aktivizuara</string>
<string name="settings_customization">Personalizimi</string>
<string name="setting_add_shortcut_summary">Shtoni një shkurtore mjaft të mirë në ekranin fillestar në rast se emri dhe ikona janë të vështira për tu njohur pasi keni fshehur aplikacionin</string>
<string name="settings_doh_title">DNS mbi HTTPS</string>
@@ -191,6 +188,9 @@
<string name="global_summary">Të gjitha sesionet rrënjë përdorin hapësirën globale të emrave të montimit</string>
<string name="requester_summary">Seancat rrënjësore do të trashëgojnë hapësirën e emrave të kërkuesit të tyre</string>
<string name="isolate_summary">Çdo sesion rrënjë do të ketë hapësirën e vet të izoluar të emrave</string>
<string name="settings_su_auth_title">Vërtetimi i përdoruesit</string>
<string name="settings_su_auth_summary">Kërkoni vërtetimin e përdoruesit gjatë kërkesave të Superpërdoruesit</string>
<string name="settings_su_auth_insecure">Asnjë metodë vërtetimi nuk është konfiguruar në pajisje</string>
<!--Notifications-->
<string name="update_channel">Përditësimet e magisk</string>

View File

@@ -151,9 +151,6 @@
<string name="settings_su_reauth_summary">Återautentisera superuser-rättigheter efter en applikationsuppdatering</string>
<string name="settings_su_tapjack_title">Aktivera Tapjacking-skydd</string>
<string name="settings_su_tapjack_summary">Superuser-dialogrutan kommer inte att lyssna på någon input om den är dold eller övertäckt utav något annat fönster.</string>
<string name="settings_su_biometric_title">Aktivera biometriskt autentisering</string>
<string name="settings_su_biometric_summary">Använd biometriskt autentisering för att tillåta förfrågan om superuser-tillgång</string>
<string name="no_biometric">Denna enhet stöds ej eller så är inte biometrisk autentisering aktiverad</string>
<string name="settings_customization">Anpassning</string>
<string name="setting_add_shortcut_summary">Lägg till en snygg genväg på startskärmen om namnet och ikonen är svåra att känna igen efter att appen har döljts</string>
<string name="settings_doh_title">DNS över HTTPS</string>

View File

@@ -163,9 +163,6 @@
<string name="settings_su_reauth_summary">Ask for Superuser permissions again after upgrading apps</string>
<string name="settings_su_tapjack_title">Tapjacking Protection</string>
<string name="settings_su_tapjack_summary">The Superuser prompt dialog will not respond to input while obscured by any other window or overlay</string>
<string name="settings_su_biometric_title">Biometric Authentication</string>
<string name="settings_su_biometric_summary">Use biometric authentication to allow Superuser requests</string>
<string name="no_biometric">Unsupported device or no biometric settings are enabled</string>
<string name="settings_customization">Customization</string>
<string name="setting_add_shortcut_summary">Add a pretty shortcut to the home screen in case the name and icon are difficult to recognize after hiding the app</string>
<string name="settings_doh_title">DNS over HTTPS</string>

View File

@@ -152,9 +152,6 @@
<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_biometric_title">பயோமெட்ரிக் அங்கீகாரத்தை இயக்கு</string>
<string name="settings_su_biometric_summary">சூப்பர் யூசர் கோரிக்கைகளை அனுமதிக்க பயோமெட்ரிக் அங்கீகாரத்தைப் பயன்படுத்தவும்</string>
<string name="no_biometric">ஆதரிக்கப்படாத சாதனம் அல்லது பயோமெட்ரிக் அமைப்புகள் எதுவும் செயல்படுத்தப்படவில்லை</string>
<string name="settings_customization">தனிப்பயனாக்கம்</string>
<string name="setting_add_shortcut_summary">பயன்பாட்டை மறைத்தபின் பெயர் மற்றும் ஐகான் அடையாளம் காண கடினமாக இருந்தால் முகப்புத் திரையில் அழகான குறுக்குவழியைச் சேர்க்கவும்</string>
<string name="settings_doh_title">HTTPS வழியாக டி.என்.எஸ்</string>

View File

@@ -34,7 +34,7 @@
<!--Install-->
<string name="keep_force_encryption">Zorla şifrelemeyi koru</string>
<string name="keep_dm_verity">AVB 2.0/dm-verity\'yi koruyun</string>
<string name="patch_vbmeta">Önyükleme görüntüsünde vbmeta yaması</string>
<string name="patch_vbmeta">Önyükleme görüntüsünde vbmeta yamasını uygula</string>
<string name="recovery_mode">Kurtarma Modu</string>
<string name="install_options_title">Seçenekler</string>
<string name="install_method_title">Yöntem</string>
@@ -55,24 +55,24 @@
<string name="touch_filtered_warning">Bir uygulama bir Süper Kullanıcı isteğini engellediği için Magisk yanıtınızı doğrulayamıyor</string>
<string name="deny">Reddet</string>
<string name="prompt">Hemen</string>
<string name="grant">İzin</string>
<string name="su_warning">Cihazınıza tam erişim sağlar.\nEmin değilseniz reddedin!</string>
<string name="grant">İzin ver</string>
<string name="su_warning">Cihazınıza tam erişim sağlar.\nEğer emin değilseniz reddedin!</string>
<string name="forever">Daima</string>
<string name="once">Bir kere</string>
<string name="tenmin">10 dakika</string>
<string name="twentymin">20 dakika</string>
<string name="thirtymin">30 dakika</string>
<string name="sixtymin">60 dakika</string>
<string name="su_allow_toast">%1$s Süper Kullanıcı hakları verildi</string>
<string name="su_deny_toast">%1$s Süper Kullanıcı hakları reddedildi</string>
<string name="su_snack_grant">%1$s Süper Kullanıcı hakları verildi</string>
<string name="su_snack_deny">%1$s Süper Kullanıcı hakları reddedildi</string>
<string name="su_snack_notif_on">%1$s bildirimleri etkinleştirildi</string>
<string name="su_snack_notif_off">%1$s bildirimleri devre dışı bırakıldı</string>
<string name="su_snack_log_on">%1$s günlüğü etkinleştirildi</string>
<string name="su_snack_log_off">%1$s günlüğü devre dışı bırakıldı</string>
<string name="su_allow_toast">%1$s uygulamasının Süper Kullanıcı izni verildi</string>
<string name="su_deny_toast">%1$s uygulamasının Süper Kullanıcı izni reddedildi</string>
<string name="su_snack_grant">%1$s uygulamasının Süper Kullanıcı izni verildi</string>
<string name="su_snack_deny">%1$s uygulamasının Süper Kullanıcı izni reddedildi</string>
<string name="su_snack_notif_on">%1$s uygulamasının bildirimleri etkinleştirildi</string>
<string name="su_snack_notif_off">%1$s uygulamasının bildirimleri devre dışı bırakıldı</string>
<string name="su_snack_log_on">%1$s uygulamasının günlüğü etkinleştirildi</string>
<string name="su_snack_log_off">%1$s uygulamasının günlüğü devre dışı bırakıldı</string>
<string name="su_revoke_title">İptal et?</string>
<string name="su_revoke_msg">%1$s Süper Kullanıcı haklarını iptal etmeyi onaylayın</string>
<string name="su_revoke_msg">%1$s uygulamasının Süper Kullanıcı haklarını iptal etmeyi onaylayın</string>
<string name="toast">Tost</string>
<string name="none">Hiçbiri</string>
@@ -99,11 +99,11 @@
<!--Module-->
<string name="no_info_provided">(Bilgi verilmedi)</string>
<string name="reboot_userspace">Yumuşak yeniden başlatma</string>
<string name="reboot_recovery">Kurtarma için Yeniden Başlatın</string>
<string name="reboot_bootloader">Bootloader için Yeniden Başlatın</string>
<string name="reboot_download">İndirmek için Yeniden Başlatın</string>
<string name="reboot_edl">EDL için Yeniden Başlatın</string>
<string name="reboot_userspace">Yazılımsal olarak yeniden başlat</string>
<string name="reboot_recovery">Kurtarma modunda Yeniden Başlat</string>
<string name="reboot_bootloader">Önyükleyici modunda Yeniden Başlat</string>
<string name="reboot_download">Download modu için Yeniden Başlat</string>
<string name="reboot_edl">EDL modunda Yeniden Başlat</string>
<string name="module_version_author">%1$s / %2$s</string>
<string name="module_state_remove">Kaldır</string>
<string name="module_state_restore">Geri yükle</string>
@@ -119,9 +119,9 @@
<!--Settings-->
<string name="settings_dark_mode_title">Tema Modu</string>
<string name="settings_dark_mode_message">Tarzınıza en uygun modu seçin!</string>
<string name="settings_dark_mode_light">Daima Açık</string>
<string name="settings_dark_mode_light">Her zamanık</string>
<string name="settings_dark_mode_system">Sistemi Takip Et</string>
<string name="settings_dark_mode_dark">Daima Koyu</string>
<string name="settings_dark_mode_dark">Her zaman Koyu</string>
<string name="settings_download_path_title">İndirme yolu</string>
<string name="settings_download_path_message">Dosyalar %1$s konumuna kaydedilecek</string>
<string name="settings_hide_app_title">Magisk uygulamasını gizleyin</string>
@@ -131,7 +131,7 @@
<string name="language">Dil</string>
<string name="system_default">(Sistem Varsayılanı)</string>
<string name="settings_check_update_title">Güncellemeleri Kontrol Et</string>
<string name="settings_check_update_summary">Arka planda güncellemeleri periyodik olarak kontrol edin</string>
<string name="settings_check_update_summary">Arka planda güncellemeleri düzenli olarak kontrol edin</string>
<string name="settings_update_channel_title">Güncelleme Kanalı</string>
<string name="settings_update_stable">Stabil</string>
<string name="settings_update_beta">Beta</string>
@@ -165,11 +165,8 @@
<string name="superuser_notification">Süper Kullanıcı Bildirimi</string>
<string name="settings_su_reauth_title">Yükseltmeden sonra yeniden kimlik doğrulaması yapın</string>
<string name="settings_su_reauth_summary">Uygulamaları yükselttikten sonra Süper Kullanıcı izinlerini tekrar isteyin</string>
<string name="settings_su_tapjack_title">Sahte Ekran Koruması</string>
<string name="settings_su_tapjack_title">Sahte Ekran (Tapjacking) Koruması</string>
<string name="settings_su_tapjack_summary">Süper Kullanıcı bilgi istemi iletişim kutusu, herhangi bir başka pencere veya yer paylaşımı tarafından engellendiğinde girişe yanıt vermeyecektir.</string>
<string name="settings_su_biometric_title">Biyometrik Kimlik Doğrulama</string>
<string name="settings_su_biometric_summary">Süper Kullanıcı isteklerine izin vermek için biyometrik kimlik doğrulamayı kullanın</string>
<string name="no_biometric">Desteklenmeyen cihaz veya hiçbir biyometrik ayar etkin değil</string>
<string name="settings_customization">Özelleştir</string>
<string name="setting_add_shortcut_summary">Uygulamayı gizledikten sonra adın ve simgenin tanınmasının zor olması durumunda ana ekrana güzel bir kısayol ekleyin</string>
<string name="settings_doh_title">HTTPS üzerinden DNS</string>
@@ -219,7 +216,7 @@
<string name="restore_done">Geri yükleme tamamlandı!</string>
<string name="restore_fail">Stok yedeği mevcut değil!</string>
<string name="setup_fail">Kurulum başarısız oldu</string>
<string name="env_fix_title">Ek Kurulum Gerektirir</string>
<string name="env_fix_title">Ek Kurulum Gerekiyor</string>
<string name="env_fix_msg">Magisk\'in düzgün çalışması için cihazınızın ek kuruluma ihtiyacı var. Devam etmek ve yeniden başlatmak istiyor musunuz?</string>
<string name="env_full_fix_msg">Cihazınızın düzgün çalışması için Magisk\'in yeniden yüklenmeye ihtiyacı var. Lütfen Magisk\'i uygulama içinde yeniden yükleyin, kurtarma modu doğru cihaz bilgilerini alamıyor.</string>
<string name="setup_msg">Ortam kurulumu çalıştırılıyor…</string>
@@ -227,18 +224,18 @@
<string name="unsupport_magisk_title">Desteklenmeyen Magisk Sürümü</string>
<string name="unsupport_magisk_msg">Uygulamanın bu sürümü, %1$s\'den daha düşük Magisk sürümlerini desteklemiyor.\n\nUygulama, Magisk kurulu değilmiş gibi davranacak, lütfen Magisk\'i mümkün olan en kısa sürede yükseltin.</string>
<string name="unsupport_general_title">Anormal Durum</string>
<string name="unsupport_system_app_msg">Bu uygulamayı bir sistem uygulaması olarak çalıştırmak desteklenmiyor. Lütfen uygulamayı bir kullanıcı uygulamasına geri döndürün.</string>
<string name="unsupport_other_su_msg">Magisk\'ten olmayan bir \"su\" ikili dosyası algılandı. Lütfen rakip kök çözümlerini kaldırın ve/veya Magisk\'i yeniden yükleyin.</string>
<string name="unsupport_system_app_msg">Bu uygulamayı bir sistem uygulaması olarak çalıştırma desteklenmiyor. Lütfen uygulamayı bir kullanıcı uygulamasına geri döndürün.</string>
<string name="unsupport_other_su_msg">Magisk\'ten olmayan bir \"su\" ikili dosyası algılandı. Lütfen başka kök çözümlerini kaldırın ve/veya Magisk\'i yeniden yükleyin.</string>
<string name="unsupport_external_storage_msg">Magisk, harici depolama birimine kurulur. Lütfen uygulamayı dahili depolamaya taşıyın.</string>
<string name="unsupport_nonroot_stub_msg">Kök kaybolduğu için gizli Magisk uygulaması çalışmaya devam edemiyor. Lütfen orijinal APK\'yı geri yükleyin.</string>
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">Bu işlevi etkinleştirmek için depolama izni verin</string>
<string name="post_notifications_denied">Bu işlevi etkinleştirmek için bildirim izni verin</string>
<string name="install_unknown_denied">Bu işlevi etkinleştirmek için "bilinmeyen uygulamaları yükle"ye izin verin</string>
<string name="external_rw_permission_denied">Bu işlevi etkinleştirmek için depolama izni veriniz.</string>
<string name="post_notifications_denied">Bu işlevi etkinleştirmek için bildirim izni veriniz.</string>
<string name="install_unknown_denied">Bu işlevi etkinleştirmek için "Bilinmeyen uygulamaları yükle" ayarına izin veriniz.</string>
<string name="add_shortcut_title">Ana ekrana kısayol ekle</string>
<string name="add_shortcut_msg">Bu uygulamayı gizledikten sonra adını ve simgesini tanımak zorlaşabilir. Ana ekrana hoş bir kısayol eklemek ister misiniz?</string>
<string name="app_not_found">Bu eylemi gerçekleştirecek uygulama bulunamadı</string>
<string name="reboot_apply_change">Değişiklikleri uygulamak için yeniden başlatın</string>
<string name="restore_app_confirmation">Bu, gizli uygulamayı orijinal uygulamaya geri yükleyecektir. Gerçekten bunu yapmak istiyor musun?</string>
<string name="restore_app_confirmation">Bu işlem, gizli uygulamayı orijinal uygulama ile değiştirecektir. Bu işlemi yapmak istediğinizden emin misiniz?</string>
</resources>

View File

@@ -159,9 +159,6 @@
<string name="settings_su_reauth_summary">Перевидача прав суперкористувача після оновлення застосунку</string>
<string name="settings_su_tapjack_title">Увімкнути захист від Tapjack</string>
<string name="settings_su_tapjack_summary">Діалогове вікно суперкористувача не буде отримувати ввід від користувача, коли вікно перекрито іншим застосунком чи вікном</string>
<string name="settings_su_biometric_title">Біометрична автентифікація</string>
<string name="settings_su_biometric_summary">Використовувати біометричну автентифікацію, щоб підтверджувати запити суперкористувача</string>
<string name="no_biometric">Пристрій не підтримується, або не налаштовано біометрику</string>
<string name="settings_customization">Оформлення</string>
<string name="setting_add_shortcut_summary">Додати ярлик на домашній екран для зручного сприйняття застосунку після його приховування</string>
<string name="settings_doh_title">DNS поверх HTTPS</string>

View File

@@ -165,9 +165,6 @@
<string name="settings_su_reauth_summary">Xác thực lại quyền Superuser sau khi nâng cấp ứng dụng</string>
<string name="settings_su_tapjack_title">Bảo vệ khỏi Tapjacking</string>
<string name="settings_su_tapjack_summary">Hộp thoại nhắc Superuser sẽ không trả lời đầu vào khi bị che khuất bởi bất kỳ cửa sổ hoặc lớp phủ nào khác</string>
<string name="settings_su_biometric_title">Bật xác thực sinh trắc học</string>
<string name="settings_su_biometric_summary">Sử dụng xác thực sinh trắc học để xác nhận yêu cầu Superuser</string>
<string name="no_biometric">Thiết bị của bạn không được hỗ trợ hoặc không có phương pháp xác thực sinh trắc học nào được kích hoạt</string>
<string name="settings_customization">Tùy biến</string>
<string name="setting_add_shortcut_summary">Thêm một phím tắt đẹp vào màn hình trong trường hợp khó tìm ra tên và biểu tượng sau khi ẩn ứng dụng</string>
<string name="settings_doh_title">DNS over HTTPS</string>

View File

@@ -88,6 +88,9 @@
<string name="logs_cleared">日志已清空</string>
<string name="pid">PID: %1$d</string>
<string name="target_uid">目标 UID: %1$d</string>
<string name="target_pid">挂载命名空间目标 PID: %s</string>
<string name="selinux_context">SELinux 上下文: %s</string>
<string name="supp_group">补充组: %s</string>
<!--SafetyNet-->
@@ -167,9 +170,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_biometric_title">生物识别验证</string>
<string name="settings_su_biometric_summary">使用生物识别来允许超级用户请求</string>
<string name="no_biometric">设备不支持或未配置生物识别功能</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">安全 DNSDoH</string>

View File

@@ -167,9 +167,6 @@
<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_biometric_title">生物特徵辨識驗證</string>
<string name="settings_su_biometric_summary">使用生物特徵辨識驗證來允許超級使用者的要求</string>
<string name="no_biometric">不支援的裝置或是未啟用生物特徵辨識設定</string>
<string name="settings_customization">客製化</string>
<string name="setting_add_shortcut_summary">在主螢幕中新增一個精緻的捷徑。防止隱藏 Magisk 以後,其名稱與圖示將難以辨識</string>
<string name="settings_doh_title">安全化的網域解析(DoH)</string>

View File

@@ -170,9 +170,9 @@
<string name="settings_su_reauth_summary">Ask for Superuser permissions again after upgrading apps</string>
<string name="settings_su_tapjack_title">Tapjacking Protection</string>
<string name="settings_su_tapjack_summary">The Superuser prompt dialog will not respond to input while obscured by any other window or overlay</string>
<string name="settings_su_biometric_title">Biometric Authentication</string>
<string name="settings_su_biometric_summary">Use biometric authentication to allow Superuser requests</string>
<string name="no_biometric">Unsupported device or no biometric settings are enabled</string>
<string name="settings_su_auth_title">User Authentication</string>
<string name="settings_su_auth_summary">Ask for user authentication during Superuser requests</string>
<string name="settings_su_auth_insecure">No authentication method is configured on the device</string>
<string name="settings_customization">Customization</string>
<string name="setting_add_shortcut_summary">Add a pretty shortcut to the home screen in case the name and icon are difficult to recognize after hiding the app</string>
<string name="settings_doh_title">DNS over HTTPS</string>

View File

@@ -3,5 +3,5 @@ plugins {
}
tasks.register("clean", Delete::class) {
delete(rootProject.buildDir)
delete(rootProject.layout.buildDirectory)
}

View File

@@ -62,6 +62,8 @@ if shutil.which("sccache") is not None:
os.environ["RUSTC_WRAPPER"] = "sccache"
os.environ["NDK_CCACHE"] = "sccache"
os.environ["CARGO_INCREMENTAL"] = "0"
if shutil.which("ccache") is not None:
os.environ["NDK_CCACHE"] = "ccache"
cpu_count = multiprocessing.cpu_count()
os_name = platform.system().lower()
@@ -187,15 +189,17 @@ def load_config(args):
# Default values
config["version"] = commit_hash
config["versionCode"] = 1000000
config["outdir"] = "out"
# Load prop files
if op.exists(args.config):
config.update(parse_props(args.config))
for key, value in parse_props("gradle.properties").items():
if key.startswith("magisk."):
config[key[7:]] = value
if op.exists("gradle.properties"):
for key, value in parse_props("gradle.properties").items():
if key.startswith("magisk."):
config[key[7:]] = value
try:
config["versionCode"] = int(config["versionCode"])
@@ -259,7 +263,6 @@ def run_cargo(cmds, triple="aarch64-linux-android"):
def run_cargo_build(args):
os.chdir(op.join("native", "src"))
native_out = op.join("..", "out")
mkdir(native_out)
@@ -267,11 +270,11 @@ def run_cargo_build(args):
if "resetprop" in args.target:
targets.add("magisk")
if len(targets) == 0:
return
# Start building the actual build commands
cmds = ["build"]
for target in targets:
cmds.append("-p")
cmds.append(target)
cmds = ["build", "-p", ""]
rust_out = "debug"
if args.release:
cmds.append("-r")
@@ -287,9 +290,12 @@ def run_cargo_build(args):
"thumbv7neon-linux-androideabi" if triple.startswith("armv7") else triple
)
cmds[-1] = rust_triple
proc = run_cargo(cmds, triple)
if proc.returncode != 0:
error("Build binary failed!")
for target in targets:
cmds[2] = target
proc = run_cargo(cmds, triple)
if proc.returncode != 0:
error("Build binary failed!")
arch_out = op.join(native_out, arch)
mkdir(arch_out)
@@ -298,8 +304,6 @@ def run_cargo_build(args):
target = op.join(arch_out, f"lib{tgt}-rs.a")
mv(source, target)
os.chdir(op.join("..", ".."))
def run_cargo_cmd(args):
global STDOUT
@@ -382,7 +386,9 @@ def build_binary(args):
header("* Building binaries: " + " ".join(args.target))
os.chdir(op.join("native", "src"))
run_cargo_build(args)
os.chdir(op.join("..", ".."))
dump_flag_header()

View File

@@ -16,9 +16,9 @@ gradlePlugin {
}
dependencies {
implementation(kotlin("gradle-plugin", "1.9.0"))
implementation("com.android.tools.build:gradle:8.1.1")
implementation("androidx.navigation:navigation-safe-args-gradle-plugin:2.7.1")
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("org.lsposed.lsparanoid:gradle-plugin:0.5.2")
implementation("org.eclipse.jgit:org.eclipse.jgit:6.5.0.202303070854-r")
implementation("org.eclipse.jgit:org.eclipse.jgit:6.7.0.202309050840-r")
}

View File

@@ -213,7 +213,7 @@ private fun Project.setupAppCommon() {
this.comment.set("version=${Config.version}\n" +
"versionCode=${Config.versionCode}\n" +
"stubVersion=${Config.stubVersion}\n")
this.outFolder.set(File(buildDir, "outputs/apk/${variant.name}"))
this.outFolder.set(layout.buildDirectory.dir("outputs/apk/${variant.name}"))
}
}
}
@@ -318,8 +318,8 @@ fun Project.setupStub() {
project.tasks.register("${variantName}ManifestProducer", ManifestUpdater::class.java) {
dependsOn("generate${variantCapped}ObfuscatedClass")
applicationId.set(variant.applicationId)
appClassDir.set(File(buildDir, "generated/source/app/$variantName"))
factoryClassDir.set(File(buildDir, "generated/source/factory/$variantName"))
appClassDir.set(layout.buildDirectory.dir("generated/source/app/$variantName"))
factoryClassDir.set(layout.buildDirectory.dir("generated/source/factory/$variantName"))
}
variant.artifacts.use(manifestUpdater)
.wiredWithFiles(
@@ -331,12 +331,12 @@ fun Project.setupStub() {
android.applicationVariants.all {
val variantCapped = name.replaceFirstChar { it.uppercase() }
val variantLowered = name.lowercase()
val outFactoryClassDir = File(buildDir, "generated/source/factory/${variantLowered}")
val outAppClassDir = File(buildDir, "generated/source/app/${variantLowered}")
val outResDir = File(buildDir, "generated/source/res/${variantLowered}")
val outFactoryClassDir = layout.buildDirectory.file("generated/source/factory/${variantLowered}").get().asFile
val outAppClassDir = layout.buildDirectory.file("generated/source/app/${variantLowered}").get().asFile
val outResDir = layout.buildDirectory.dir("generated/source/res/${variantLowered}").get().asFile
val aapt = File(android.sdkDirectory, "build-tools/${android.buildToolsVersion}/aapt2")
val apk = File(buildDir, "intermediates/processed_res/" +
"${variantLowered}/out/resources-${variantLowered}.ap_")
val apk = layout.buildDirectory.file("intermediates/processed_res/" +
"${variantLowered}/out/resources-${variantLowered}.ap_").get().asFile
val genManifestTask = tasks.register("generate${variantCapped}ObfuscatedClass") {
inputs.property("seed", RAND_SEED)
@@ -377,10 +377,10 @@ fun Project.setupStub() {
registerJavaGeneratingTask(processResourcesTask, outResDir)
}
// Override optimizeReleaseResources task
val apk = File(buildDir, "intermediates/processed_res/" +
"release/out/resources-release.ap_")
val optRes = File(buildDir, "intermediates/optimized_processed_res/" +
"release/resources-release-optimize.ap_")
val apk = layout.buildDirectory.file("intermediates/processed_res/" +
"release/out/resources-release.ap_").get().asFile
val optRes = layout.buildDirectory.file("intermediates/optimized_processed_res/" +
"release/resources-release-optimize.ap_").get().asFile
afterEvaluate {
tasks.named("optimizeReleaseResources") {
doLast { apk.copyTo(optRes, true) }

View File

@@ -10,7 +10,7 @@
- Windows only: Enable [developer mode](https://learn.microsoft.com/en-us/windows/apps/get-started/enable-your-device-for-development). This is required because we need symbolic link support.
- Install Python 3.8+:
- On Unix, install python3 using your favorite package manager
- On Windows, download and install the latest Python version on the [offical website](https://www.python.org/downloads/windows/).<br>
- On Windows, download and install the latest Python version on the [official website](https://www.python.org/downloads/windows/).<br>
Make sure to select **"Add Python to PATH"** during installation.
- (Optional on Windows): Run `pip install colorama` to install the `colorama` python package
- Install Git:
@@ -40,7 +40,7 @@
### Developing Rust in Android Studio
Because the Magisk NDK package, [ONDK](https://github.com/topjohnwu/ondk) (the one installed with `./build.py ndk`), contains a fully self contained Clang + Rust toolchain, building the Magisk project alone does not require configuring toolchains. However, due to the way how the Intellij Rust plugin works, you'll have to go through some additional setup to make Android Studio work with Magisk's Rust codebase:
Because the Magisk NDK package, [ONDK](https://github.com/topjohnwu/ondk) (the one installed with `./build.py ndk`), contains a fully self contained Clang + Rust toolchain, building the Magisk project alone does not require configuring toolchains. However, due to the way the IntelliJ Rust plugin works, you'll have to go through some additional setup to make Android Studio work with Magisk's Rust codebase:
- Install [rustup](https://rustup.rs/), the official Rust toolchain manager
- Link the ONDK Rust toolchain and set it as default:

View File

@@ -1,5 +1,41 @@
# Magisk Changelog
### v26.4
- [MagiskBoot] Don't pad zeros if signed boot image is larger
- [MagiskPolicy] Fix `genfscon` and `filename_trans`
- [MagiskPolicy] Fix bug in `libsepol`
- [Zygisk] Fix and simplify file descriptor sanitization logic
- [App] Prevent OOM when patching AP tarfiles
- [App] Fix bug in device configuration detection
- [Daemon] Fix certificate parsing of APKs
- [General] Fix logging errors from C++ code being ignored
### v26.3
- [General] Fix device information detection script
- [General] Update BusyBox to 1.36.1
- [General] Update toolchain that produces broken arm32 executables
- [App] Fix root service unable to bind on OnePlus devices
### v26.2
- [MagiskBoot] Support extracting boot image from `payload.bin`
- [MagiskBoot] Support cpio files containing character files
- [MagiskBoot] Support listing cpio content
- [MagiskBoot] Directly handle AVB 1.0 signing and verification without going through Java implementation
- [Daemon] Make daemon socket a fixed path in MAGISKTMP
- [resetprop] Support printing property context
- [resetprop] Support only printing persistent properties from storage
- [resetprop] Properly support setting persistent properties bypassing property_service
- [MagiskSU] Support `-g` and `-G` options
- [MagiskSU] Support switching mount namespace to PID with `-t`
- [MagiskPolicy] Fix patching extended permissions
- [MagiskPolicy] Support more syntax for extended permissions
- [MagiskPolicy] Support printing out the loaded sepolicy rules
- [App] Support patching boot image from ROM zips
- [App] Properly preserve `boot.img` when patching Samsung firmware with `init_boot.img`
### v26.1
- [App] Fix crashing when revoking root permissions

View File

@@ -4,7 +4,7 @@
### Paths in "Magisk tmpfs directory"
Magisk will mount a `tmpfs` directory to store some temporary data. For devices with the `/sbin` folder, it will be chosen as it will also act as an overlay to inject binaries into `PATH`. From Android 11 onwards, the `/sbin` folder might not exist, so Magisk will randomly create a folder under `/dev` and use it as the base folder.
Magisk will mount a `tmpfs` directory to store some temporary data. For devices with the `/sbin` folder, it will be chosen as it will also act as an overlay to inject binaries into `PATH`. From Android 11 onwards, the `/sbin` folder might not exist, so Magisk will use `/debug_ramdisk` as the base folder.
```
# In order to get the current base folder Magisk is using,

View File

@@ -107,7 +107,7 @@ To unlock your bootloader, follow the instructions below. If no OEM Lock value i
Possible KnoxGuard values are the following:
- `Active`, `Locked`: your device has been remotely locked by your telecom operator or your insurance company.
- `Prenormal`: your device is temporarely locked, reaching 168h of uptime should trigger unlock.
- `Prenormal`: your device is temporarily locked, reaching 168h of uptime should trigger unlock.
- `Checking`, `Completed`, `Broken`: your device is unlocked.
Having KnoxGuard active will prevent you from installing/running Magisk regardless of your bootloader lock state.

28
docs/releases/26300.md Normal file
View File

@@ -0,0 +1,28 @@
## 2023.9.4 Magisk v26.3
### v26.3
- [General] Fix device information detection script
- [General] Update BusyBox to 1.36.1
- [General] Update toolchain that produces broken arm32 executables
- [App] Fix root service unable to bind on OnePlus devices
### v26.2
- [MagiskBoot] Support extracting boot image from `payload.bin`
- [MagiskBoot] Support cpio files containing character files
- [MagiskBoot] Support listing cpio content
- [MagiskBoot] Directly handle AVB 1.0 signing and verification without going through Java implementation
- [Daemon] Make daemon socket a fixed path in MAGISKTMP
- [resetprop] Support printing property context
- [resetprop] Support only printing persistent properties from storage
- [resetprop] Properly support setting persistent properties bypassing property_service
- [MagiskSU] Support `-g` and `-G` options
- [MagiskSU] Support switching mount namespace to PID with `-t`
- [MagiskPolicy] Fix patching extended permissions
- [MagiskPolicy] Support more syntax for extended permissions
- [MagiskPolicy] Support printing out the loaded sepolicy rules
- [App] Support patching boot image from ROM zips
- [App] Properly preserve `boot.img` when patching Samsung firmware with `init_boot.img`
### Full Changelog: [here](https://topjohnwu.github.io/Magisk/changes.html)

12
docs/releases/26400.md Normal file
View File

@@ -0,0 +1,12 @@
## 2023.11.5 Magisk v26.4
- [MagiskBoot] Don't pad zeros if signed boot image is larger
- [MagiskPolicy] Fix `genfscon` and `filename_trans`
- [MagiskPolicy] Fix bug in `libsepol`
- [Zygisk] Fix and simplify file descriptor sanitization logic
- [App] Prevent OOM when patching AP tarfiles
- [App] Fix bug in device configuration detection
- [Daemon] Fix certificate parsing of APKs
- [General] Fix logging errors from C++ code being ignored
### Full Changelog: [here](https://topjohnwu.github.io/Magisk/changes.html)

View File

@@ -1,5 +1,7 @@
# Release Notes
- [v26.4](26400.md)
- [v26.3](26300.md)
- [v26.2](26200.md)
- [v26.1](26100.md)
- [v26.0](26000.md)

View File

@@ -26,6 +26,6 @@ android.injected.testOnly=false
android.nonFinalResIds=false
# Magisk
magisk.stubVersion=37
magisk.versionCode=26200
magisk.ondkVersion=r25.7
magisk.stubVersion=38
magisk.versionCode=26400
magisk.ondkVersion=r26.1

Binary file not shown.

View File

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

22
gradlew vendored
View File

@@ -83,7 +83,8 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -130,10 +131,13 @@ location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
@@ -141,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
@@ -149,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -198,11 +202,11 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \

View File

@@ -10,7 +10,6 @@ include $(CLEAR_VARS)
LOCAL_MODULE := magisk
LOCAL_STATIC_LIBRARIES := \
libbase \
libnanopb \
libsystemproperties \
libphmap \
liblsplt \
@@ -25,10 +24,9 @@ LOCAL_SRC_FILES := \
core/db.cpp \
core/package.cpp \
core/scripting.cpp \
core/restorecon.cpp \
core/selinux.cpp \
core/module.cpp \
core/thread.cpp \
core/resetprop/persist.cpp \
core/resetprop/resetprop.cpp \
core/core-rs.cpp \
core/su/su.cpp \
@@ -101,7 +99,6 @@ LOCAL_STATIC_LIBRARIES := \
liblzma \
liblz4 \
libbz2 \
libfdt \
libz \
libzopfli \
libboot-rs
@@ -111,7 +108,6 @@ LOCAL_SRC_FILES := \
boot/bootimg.cpp \
boot/compress.cpp \
boot/format.cpp \
boot/dtb.cpp \
boot/boot-rs.cpp
include $(BUILD_EXECUTABLE)
@@ -139,14 +135,13 @@ include $(CLEAR_VARS)
LOCAL_MODULE := resetprop
LOCAL_STATIC_LIBRARIES := \
libbase \
libnanopb \
libsystemproperties \
libmagisk-rs
LOCAL_SRC_FILES := \
core/applet_stub.cpp \
core/resetprop/resetprop.cpp \
core/resetprop/persist.cpp
core/core-rs.cpp
LOCAL_CFLAGS := -DAPPLET_STUB_MAIN=resetprop_main
include $(BUILD_EXECUTABLE)

142
native/src/Cargo.lock generated
View File

@@ -4,9 +4,9 @@ version = 3
[[package]]
name = "aho-corasick"
version = "1.0.4"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a"
checksum = "0f2135563fb5c609d2b2b87c1e8ce7bc41b0b45430fa9661f457981503dd5bf0"
dependencies = [
"memchr",
]
@@ -23,7 +23,7 @@ dependencies = [
[[package]]
name = "argh"
version = "0.1.12"
source = "git+https://github.com/topjohnwu/argh.git?rev=f0ca7d9d7f66b4ff56fbbd44ce19a96c625bffd8#f0ca7d9d7f66b4ff56fbbd44ce19a96c625bffd8"
source = "git+https://github.com/google/argh.git?rev=1c632b046d084e7bde86b82dfc969b30b4647c8c#1c632b046d084e7bde86b82dfc969b30b4647c8c"
dependencies = [
"argh_derive",
"argh_shared",
@@ -32,18 +32,18 @@ dependencies = [
[[package]]
name = "argh_derive"
version = "0.1.12"
source = "git+https://github.com/topjohnwu/argh.git?rev=f0ca7d9d7f66b4ff56fbbd44ce19a96c625bffd8#f0ca7d9d7f66b4ff56fbbd44ce19a96c625bffd8"
source = "git+https://github.com/google/argh.git?rev=1c632b046d084e7bde86b82dfc969b30b4647c8c#1c632b046d084e7bde86b82dfc969b30b4647c8c"
dependencies = [
"argh_shared",
"proc-macro2",
"quote",
"syn 2.0.29",
"syn",
]
[[package]]
name = "argh_shared"
version = "0.1.12"
source = "git+https://github.com/topjohnwu/argh.git?rev=f0ca7d9d7f66b4ff56fbbd44ce19a96c625bffd8#f0ca7d9d7f66b4ff56fbbd44ce19a96c625bffd8"
source = "git+https://github.com/google/argh.git?rev=1c632b046d084e7bde86b82dfc969b30b4647c8c#1c632b046d084e7bde86b82dfc969b30b4647c8c"
dependencies = [
"serde",
]
@@ -70,10 +70,13 @@ name = "base"
version = "0.0.0"
dependencies = [
"argh",
"bytemuck",
"cfg-if",
"cxx",
"cxx-gen",
"libc",
"num-derive",
"num-traits",
"thiserror",
]
@@ -104,6 +107,26 @@ dependencies = [
"generic-array",
]
[[package]]
name = "bytemuck"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6"
dependencies = [
"bytemuck_derive",
]
[[package]]
name = "bytemuck_derive"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "byteorder"
version = "1.4.3"
@@ -112,9 +135,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.82"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"libc",
]
@@ -167,9 +190,9 @@ dependencies = [
[[package]]
name = "crypto-bigint"
version = "0.5.2"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15"
checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124"
dependencies = [
"generic-array",
"rand_core",
@@ -203,7 +226,7 @@ dependencies = [
"codespan-reporting",
"proc-macro2",
"quote",
"syn 2.0.29",
"syn",
]
[[package]]
@@ -216,7 +239,7 @@ version = "1.0.105"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.29",
"syn",
]
[[package]]
@@ -240,7 +263,7 @@ checksum = "5fe87ce4529967e0ba1dcf8450bab64d97dfd5010a6256187ffe2e43e6f0e049"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.29",
"syn",
]
[[package]]
@@ -303,6 +326,12 @@ dependencies = [
"termcolor",
]
[[package]]
name = "fdt"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67"
[[package]]
name = "ff"
version = "0.13.0"
@@ -315,9 +344,9 @@ dependencies = [
[[package]]
name = "flagset"
version = "0.4.3"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda653ca797810c02f7ca4b804b40b8b95ae046eb989d356bce17919a8c25499"
checksum = "d52a7e408202050813e6f1d9addadcaafef3dca7530c7ddfb005d4081cce6779"
[[package]]
name = "generic-array"
@@ -399,9 +428,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.147"
version = "0.2.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
[[package]]
name = "libm"
@@ -420,10 +449,13 @@ name = "magisk"
version = "0.0.0"
dependencies = [
"base",
"bytemuck",
"cxx",
"cxx-gen",
"num-derive",
"num-traits",
"pb-rs",
"quick-protobuf",
]
[[package]]
@@ -432,11 +464,14 @@ version = "0.0.0"
dependencies = [
"argh",
"base",
"bytemuck",
"byteorder",
"cxx",
"cxx-gen",
"der",
"digest",
"fdt",
"num-traits",
"p256",
"p384",
"pb-rs",
@@ -469,9 +504,9 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.5.0"
version = "2.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
[[package]]
name = "minimal-lexical"
@@ -508,13 +543,13 @@ dependencies = [
[[package]]
name = "num-derive"
version = "0.3.3"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
"syn",
]
[[package]]
@@ -630,9 +665,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.66"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
dependencies = [
"unicode-ident",
]
@@ -691,9 +726,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.9.3"
version = "1.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a"
checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47"
dependencies = [
"aho-corasick",
"memchr",
@@ -703,9 +738,9 @@ dependencies = [
[[package]]
name = "regex-automata"
version = "0.3.6"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69"
checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795"
dependencies = [
"aho-corasick",
"memchr",
@@ -714,9 +749,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.7.4"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
[[package]]
name = "rfc6979"
@@ -767,22 +802,22 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.183"
version = "1.0.188"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c"
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.183"
version = "1.0.188"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816"
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.29",
"syn",
]
[[package]]
@@ -859,20 +894,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "syn"
version = "1.0.109"
version = "2.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
dependencies = [
"proc-macro2",
"quote",
@@ -881,9 +905,9 @@ dependencies = [
[[package]]
name = "termcolor"
version = "1.2.0"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64"
dependencies = [
"winapi-util",
]
@@ -899,35 +923,35 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.47"
version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f"
checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.47"
version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b"
checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.29",
"syn",
]
[[package]]
name = "typenum"
version = "1.16.0"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicode-ident"
version = "1.0.11"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-width"

View File

@@ -9,7 +9,7 @@ cxx-gen = { path = "external/cxx-rs/gen/lib" }
libc = "0.2"
cfg-if = "1.0"
num-traits = "0.2"
num-derive = "0.3"
num-derive = "0.4"
thiserror = "1.0"
byteorder = "1"
size = "0.4"
@@ -21,10 +21,13 @@ p384 = "0.13"
rsa = "0.9"
x509-cert = "0.2"
der = "0.7"
bytemuck = "1.14"
fdt = "0.1"
[workspace.dependencies.argh]
git = "https://github.com/topjohnwu/argh.git"
rev = "f0ca7d9d7f66b4ff56fbbd44ce19a96c625bffd8"
git = "https://github.com/google/argh.git"
rev = "1c632b046d084e7bde86b82dfc969b30b4647c8c"
default-features = false
[workspace.dependencies.pb-rs]
git = "https://github.com/tafia/quick-protobuf.git"

View File

@@ -17,7 +17,6 @@ LOCAL_SRC_FILES := \
new.cpp \
files.cpp \
misc.cpp \
selinux.cpp \
logging.cpp \
stream.cpp \
base-rs.cpp \
@@ -28,10 +27,13 @@ include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libcompat
# Add "hacky" libc.a missing symbols back
# All symbols in this library are weak, so a vanilla NDK should still link properly
LOCAL_SRC_FILES := compat/compat.cpp
# Fix static variables' ctor/dtor when using LTO
# See: https://github.com/android/ndk/issues/1461
LOCAL_EXPORT_LDFLAGS := -static -T src/lto_fix.lds
LOCAL_EXPORT_LDFLAGS := -static -T src/lto_fix.lds -Wl,--wrap=rename -Wl,--wrap=renameat
# For some reason, using the hacky libc.a with x86 will trigger stack protection violation
# when mixing Rust and C++ code. Disable stack protector to bypass this issue.
ifeq ($(TARGET_ARCH), x86)
LOCAL_EXPORT_CFLAGS := -fno-stack-protector
endif
include $(BUILD_STATIC_LIBRARY)

View File

@@ -6,6 +6,10 @@ edition = "2021"
[lib]
path = "lib.rs"
[features]
selinux = []
dyn_selinux = []
[build-dependencies]
cxx-gen = { workspace = true }
@@ -15,3 +19,6 @@ libc = { workspace = true }
cfg-if = { workspace = true }
thiserror = { workspace = true }
argh = { workspace = true }
bytemuck = { workspace = true }
num-traits = { workspace = true }
num-derive = { workspace = true }

View File

@@ -1,17 +1,21 @@
// This file implements all missing symbols that should exist in normal API 23
// libc.a but missing in our extremely lean libc.a replacements.
#if !defined(__LP64__)
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <sys/xattr.h>
extern "C" {
#if !defined(__LP64__)
// Add "hacky" libc.a missing symbols back
// All symbols in this file are weak, so a vanilla NDK should still link properly
#include "fortify.hpp"
// Original source: https://github.com/freebsd/freebsd/blob/master/contrib/file/src/getline.c
@@ -87,6 +91,16 @@ int mkfifo(const char *path, mode_t mode) {
return mknod(path, (mode & ~S_IFMT) | S_IFIFO, 0);
}
[[gnu::weak]]
int fsetxattr(int fd, const char *name, const void *value, size_t size, int flags) {
return syscall(__NR_fsetxattr, fd, name, value, size, flags);
}
[[gnu::weak]]
int lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags) {
return syscall(__NR_lsetxattr, path, name, value, size, flags);
}
#define SPLIT_64(v) (unsigned)((v) & 0xFFFFFFFF), (unsigned)((v) >> 32)
#if defined(__arm__)
@@ -111,5 +125,20 @@ extern FILE __sF[];
[[gnu::weak]] FILE* stdout = &__sF[1];
[[gnu::weak]] FILE* stderr = &__sF[2];
#endif // !defined(__LP64__)
[[maybe_unused]]
int __wrap_renameat(int old_dir_fd, const char *old_path, int new_dir_fd, const char *new_path) {
long out = syscall(__NR_renameat, old_dir_fd, old_path, new_dir_fd, new_path);
if (out == -1 && errno == ENOSYS) {
out = syscall(__NR_renameat2, old_dir_fd, old_path, new_dir_fd, new_path, 0);
}
return static_cast<int>(out);
}
[[maybe_unused]]
int __wrap_rename(const char *old_path, const char *new_path) {
return __wrap_renameat(AT_FDCWD, old_path, AT_FDCWD, new_path);
}
} // extern "C"
#endif

635
native/src/base/cstr.rs Normal file
View File

@@ -0,0 +1,635 @@
use std::cmp::min;
use std::ffi::{CStr, FromBytesWithNulError, OsStr};
use std::fmt::{Arguments, Debug, Display, Formatter, Write};
use std::ops::{Deref, DerefMut};
use std::path::Path;
use std::str::{Utf8Chunks, Utf8Error};
use std::{fmt, mem, slice, str};
use crate::slice_from_ptr_mut;
use libc::c_char;
use thiserror::Error;
// Utf8CStr types are UTF-8 validated and null terminated strings.
//
// Several Utf8CStr types:
//
// Utf8CStr: can only exist as reference, similar to &str
// Utf8CString: dynamically sized buffer allocated on the heap
// Utf8CStrBufRef: reference to a fixed sized buffer
// Utf8CStrBufArr<N>: fixed sized buffer allocated on the stack
//
// In most cases, these are the types being used
//
// &Utf8CStr: whenever a printable null terminated string is needed
// &mut dyn Utf8CStrWrite: whenever we need a buffer that only needs to support appending
// strings to the end, and has to be null terminated
// &mut dyn Utf8CStrBuf: whenever we need a pre-allocated buffer that is large enough to fit
// in the result, and has to be null terminated
//
// All types dereferences to &Utf8CStr.
// Utf8CString, Utf8CStrBufRef, and Utf8CStrBufArr<N> implements Utf8CStrWrite.
// Utf8CStrBufRef and Utf8CStrBufArr<N> implements Utf8CStrBuf.
pub fn copy_cstr<T: AsRef<CStr> + ?Sized>(dest: &mut [u8], src: &T) -> usize {
let src = src.as_ref().to_bytes_with_nul();
let len = min(src.len(), dest.len());
dest[..len].copy_from_slice(&src[..len]);
len - 1
}
fn utf8_cstr_buf_append(buf: &mut dyn Utf8CStrBuf, s: &[u8]) -> usize {
let mut used = buf.len();
if used >= buf.capacity() - 1 {
// Truncate
return 0;
}
let dest = unsafe { &mut buf.mut_buf()[used..] };
let len = min(s.len(), dest.len() - 1);
dest[..len].copy_from_slice(&s[..len]);
dest[len] = b'\0';
used += len;
unsafe { buf.set_len(used) };
len
}
fn utf8_cstr_append_lossy(buf: &mut dyn Utf8CStrWrite, s: &[u8]) -> usize {
let chunks = Utf8Chunks::new(s);
let mut len = 0_usize;
for chunk in chunks {
len += buf.push_str(chunk.valid());
if !chunk.invalid().is_empty() {
len += buf.push_str(char::REPLACEMENT_CHARACTER.encode_utf8(&mut [0; 4]));
}
}
len
}
// Trait definitions
pub trait Utf8CStrWrite:
Write + AsRef<Utf8CStr> + AsMut<Utf8CStr> + Deref<Target = Utf8CStr> + DerefMut
{
fn len(&self) -> usize;
#[inline(always)]
fn is_empty(&self) -> bool {
self.len() == 0
}
fn push_str(&mut self, s: &str) -> usize;
fn push_lossy(&mut self, s: &[u8]) -> usize;
fn clear(&mut self);
}
pub trait Utf8CStrBuf: Utf8CStrWrite {
fn buf(&self) -> &[u8];
// Modifying the underlying buffer or length is unsafe because it can either:
// 1. Break null termination
// 2. Break UTF-8 validation
// 3. Introduce inner null byte in the string
unsafe fn mut_buf(&mut self) -> &mut [u8];
unsafe fn set_len(&mut self, len: usize);
#[inline(always)]
fn capacity(&self) -> usize {
self.buf().len()
}
}
trait AsUtf8CStr {
fn as_utf8_cstr(&self) -> &Utf8CStr;
fn as_utf8_cstr_mut(&mut self) -> &mut Utf8CStr;
}
// Implementation for Utf8CString
trait StringExt {
fn nul_terminate(&mut self) -> &mut [u8];
}
impl StringExt for String {
fn nul_terminate(&mut self) -> &mut [u8] {
self.reserve(1);
// SAFETY: the string is reserved to have enough capacity to fit in the null byte
// SAFETY: the null byte is explicitly added outside of the string's length
unsafe {
let buf = slice::from_raw_parts_mut(self.as_mut_ptr(), self.len() + 1);
*buf.get_unchecked_mut(self.len()) = b'\0';
buf
}
}
}
#[derive(Default)]
pub struct Utf8CString(String);
impl Utf8CString {
#[inline(always)]
pub fn new() -> Self {
Self::default()
}
}
impl AsUtf8CStr for Utf8CString {
#[inline(always)]
fn as_utf8_cstr(&self) -> &Utf8CStr {
// SAFETY: the internal string is always null terminated
unsafe { mem::transmute(slice::from_raw_parts(self.0.as_ptr(), self.0.len() + 1)) }
}
#[inline(always)]
fn as_utf8_cstr_mut(&mut self) -> &mut Utf8CStr {
Utf8CStr::from_string(&mut self.0)
}
}
impl Utf8CStrWrite for Utf8CString {
#[inline(always)]
fn len(&self) -> usize {
self.0.len()
}
fn push_str(&mut self, s: &str) -> usize {
self.0.push_str(s);
self.0.nul_terminate();
s.len()
}
#[inline(always)]
fn push_lossy(&mut self, s: &[u8]) -> usize {
utf8_cstr_append_lossy(self, s)
}
fn clear(&mut self) {
self.0.clear();
self.0.nul_terminate();
}
}
impl From<String> for Utf8CString {
fn from(mut value: String) -> Self {
value.nul_terminate();
Utf8CString(value)
}
}
// Implementations for Utf8CStrBuf
impl<T: Utf8CStrBuf> AsUtf8CStr for T {
#[inline(always)]
fn as_utf8_cstr(&self) -> &Utf8CStr {
// SAFETY: the internal buffer is always UTF-8 checked
// SAFETY: self.used is guaranteed to always <= SIZE - 1
unsafe { Utf8CStr::from_bytes_unchecked(self.buf().get_unchecked(..(self.len() + 1))) }
}
#[inline(always)]
fn as_utf8_cstr_mut(&mut self) -> &mut Utf8CStr {
// SAFETY: the internal buffer is always UTF-8 checked
// SAFETY: self.used is guaranteed to always <= SIZE - 1
unsafe {
let len = self.len() + 1;
Utf8CStr::from_bytes_unchecked_mut(self.mut_buf().get_unchecked_mut(..len))
}
}
}
// UTF-8 validated + null terminated reference to buffer
pub struct Utf8CStrBufRef<'a> {
used: usize,
buf: &'a mut [u8],
}
impl<'a> Utf8CStrBufRef<'a> {
pub unsafe fn from_ptr(buf: *mut u8, len: usize) -> Utf8CStrBufRef<'a> {
Self::from(slice_from_ptr_mut(buf, len))
}
}
impl<'a> From<&'a mut [u8]> for Utf8CStrBufRef<'a> {
fn from(buf: &'a mut [u8]) -> Utf8CStrBufRef<'a> {
buf[0] = b'\0';
Utf8CStrBufRef { used: 0, buf }
}
}
impl Utf8CStrBuf for Utf8CStrBufRef<'_> {
#[inline(always)]
fn buf(&self) -> &[u8] {
self.buf
}
#[inline(always)]
unsafe fn mut_buf(&mut self) -> &mut [u8] {
self.buf
}
#[inline(always)]
unsafe fn set_len(&mut self, len: usize) {
self.used = len;
}
}
// UTF-8 validated + null terminated buffer on the stack
pub struct Utf8CStrBufArr<const N: usize> {
used: usize,
buf: [u8; N],
}
impl<const N: usize> Utf8CStrBufArr<N> {
pub fn new() -> Self {
Utf8CStrBufArr {
used: 0,
buf: [0; N],
}
}
}
impl<const N: usize> Utf8CStrBuf for Utf8CStrBufArr<N> {
#[inline(always)]
fn buf(&self) -> &[u8] {
&self.buf
}
#[inline(always)]
unsafe fn mut_buf(&mut self) -> &mut [u8] {
&mut self.buf
}
#[inline(always)]
unsafe fn set_len(&mut self, len: usize) {
self.used = len;
}
#[inline(always)]
fn capacity(&self) -> usize {
N
}
}
impl Default for Utf8CStrBufArr<4096> {
fn default() -> Self {
Utf8CStrBufArr::<4096>::new()
}
}
#[derive(Debug, Error)]
pub enum StrErr {
#[error(transparent)]
Utf8Error(#[from] Utf8Error),
#[error(transparent)]
CStrError(#[from] FromBytesWithNulError),
#[error("argument is null")]
NullPointerError,
}
// UTF-8 validated + null terminated string slice
#[repr(transparent)]
pub struct Utf8CStr([u8]);
impl Utf8CStr {
pub fn from_cstr(cstr: &CStr) -> Result<&Utf8CStr, StrErr> {
// Validate the buffer during construction
str::from_utf8(cstr.to_bytes())?;
Ok(unsafe { Self::from_bytes_unchecked(cstr.to_bytes_with_nul()) })
}
pub fn from_bytes(buf: &[u8]) -> Result<&Utf8CStr, StrErr> {
Self::from_cstr(CStr::from_bytes_with_nul(buf)?)
}
pub fn from_bytes_mut(buf: &mut [u8]) -> Result<&mut Utf8CStr, StrErr> {
CStr::from_bytes_with_nul(buf)?;
str::from_utf8(buf)?;
// Both condition checked
unsafe { Ok(mem::transmute(buf)) }
}
pub fn from_string(s: &mut String) -> &mut Utf8CStr {
let buf = s.nul_terminate();
// SAFETY: the null byte is explicitly added to the buffer
unsafe { mem::transmute(buf) }
}
#[inline(always)]
pub unsafe fn from_bytes_unchecked(buf: &[u8]) -> &Utf8CStr {
mem::transmute(buf)
}
#[inline(always)]
pub unsafe fn from_bytes_unchecked_mut(buf: &mut [u8]) -> &mut Utf8CStr {
mem::transmute(buf)
}
pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> Result<&'a Utf8CStr, StrErr> {
if ptr.is_null() {
return Err(StrErr::NullPointerError);
}
Self::from_cstr(unsafe { CStr::from_ptr(ptr) })
}
#[inline(always)]
pub fn as_bytes_with_nul(&self) -> &[u8] {
&self.0
}
#[inline(always)]
pub fn as_ptr(&self) -> *const c_char {
self.0.as_ptr().cast()
}
#[inline(always)]
pub fn as_mut_ptr(&mut self) -> *mut c_char {
self.0.as_mut_ptr().cast()
}
#[inline(always)]
pub fn as_cstr(&self) -> &CStr {
// SAFETY: Already validated as null terminated during construction
unsafe { CStr::from_bytes_with_nul_unchecked(&self.0) }
}
#[inline(always)]
pub fn as_str(&self) -> &str {
// SAFETY: Already UTF-8 validated during construction
// SAFETY: The length of the slice is at least 1 due to null termination check
unsafe { str::from_utf8_unchecked(self.0.get_unchecked(..self.0.len() - 1)) }
}
#[inline(always)]
pub fn as_str_mut(&mut self) -> &mut str {
// SAFETY: Already UTF-8 validated during construction
// SAFETY: The length of the slice is at least 1 due to null termination check
unsafe { str::from_utf8_unchecked_mut(self.0.get_unchecked_mut(..self.0.len() - 1)) }
}
}
impl Deref for Utf8CStr {
type Target = str;
#[inline(always)]
fn deref(&self) -> &str {
self.as_str()
}
}
impl DerefMut for Utf8CStr {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_str_mut()
}
}
// File system path extensions types
#[repr(transparent)]
pub struct FsPath(Utf8CStr);
impl FsPath {
#[inline(always)]
pub fn from<T: AsRef<Utf8CStr> + ?Sized>(value: &T) -> &FsPath {
unsafe { mem::transmute(value.as_ref()) }
}
#[inline(always)]
pub fn from_mut<T: AsMut<Utf8CStr> + ?Sized>(value: &mut T) -> &mut FsPath {
unsafe { mem::transmute(value.as_mut()) }
}
}
impl Deref for FsPath {
type Target = Utf8CStr;
#[inline(always)]
fn deref(&self) -> &Utf8CStr {
&self.0
}
}
impl DerefMut for FsPath {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Utf8CStr {
&mut self.0
}
}
pub struct FsPathBuf<'a>(&'a mut dyn Utf8CStrWrite);
impl<'a> FsPathBuf<'a> {
pub fn new(value: &'a mut dyn Utf8CStrWrite) -> Self {
FsPathBuf(value)
}
pub fn join<T: AsRef<str>>(self, path: T) -> Self {
fn inner(buf: &mut dyn Utf8CStrWrite, path: &str) {
if path.starts_with('/') {
buf.clear();
} else {
buf.push_str("/");
}
buf.push_str(path);
}
inner(self.0, path.as_ref());
self
}
pub fn join_fmt<T: Display>(self, name: T) -> Self {
fn inner(buf: &mut dyn Utf8CStrWrite, path: Arguments) {
buf.write_fmt(path).ok();
}
inner(self.0, format_args!("/{}", name));
self
}
}
impl<'a> Deref for FsPathBuf<'a> {
type Target = FsPath;
fn deref(&self) -> &FsPath {
FsPath::from(&self.0)
}
}
impl<'a> DerefMut for FsPathBuf<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
FsPath::from_mut(&mut self.0)
}
}
// Boilerplate trait implementations
macro_rules! impl_str {
($( ($t:ty, $($g:tt)*) )*) => {$(
impl<$($g)*> AsRef<Utf8CStr> for $t {
#[inline(always)]
fn as_ref(&self) -> &Utf8CStr {
self
}
}
impl<$($g)*> AsRef<str> for $t {
#[inline(always)]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl<$($g)*> AsRef<CStr> for $t {
#[inline(always)]
fn as_ref(&self) -> &CStr {
self.as_cstr()
}
}
impl<$($g)*> AsRef<OsStr> for $t {
#[inline(always)]
fn as_ref(&self) -> &OsStr {
OsStr::new(self.as_str())
}
}
impl<$($g)*> AsRef<Path> for $t {
#[inline(always)]
fn as_ref(&self) -> &Path {
Path::new(self.as_str())
}
}
impl<$($g)*> Display for $t {
#[inline(always)]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(self.as_str(), f)
}
}
impl<$($g)*> Debug for $t {
#[inline(always)]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Debug::fmt(self.as_str(), f)
}
}
impl<$($g)*> PartialEq<str> for $t {
#[inline(always)]
fn eq(&self, other: &str) -> bool {
self.as_str() == other
}
}
impl<$($g)*> PartialEq<$t> for str {
#[inline(always)]
fn eq(&self, other: &$t) -> bool {
self == other.as_str()
}
}
impl<$($g)*> PartialEq<CStr> for $t {
#[inline(always)]
fn eq(&self, other: &CStr) -> bool {
self.as_cstr() == other
}
}
impl<$($g)*> PartialEq<$t> for CStr {
#[inline(always)]
fn eq(&self, other: &$t) -> bool {
self == other.as_cstr()
}
}
impl<T: AsRef<Utf8CStr>, $($g)*> PartialEq<T> for $t {
#[inline(always)]
fn eq(&self, other: &T) -> bool {
self.as_bytes_with_nul() == other.as_ref().as_bytes_with_nul()
}
}
)*}
}
impl_str!(
(Utf8CStr,)
(FsPath,)
(FsPathBuf<'_>,)
(Utf8CStrBufRef<'_>,)
(Utf8CStrBufArr<N>, const N: usize)
(Utf8CString,)
);
macro_rules! impl_str_write {
($( ($t:ty, $($g:tt)*) )*) => {$(
impl<$($g)*> Write for $t {
#[inline(always)]
fn write_str(&mut self, s: &str) -> fmt::Result {
self.push_str(s);
Ok(())
}
}
impl<$($g)*> Deref for $t {
type Target = Utf8CStr;
#[inline(always)]
fn deref(&self) -> &Utf8CStr {
self.as_utf8_cstr()
}
}
impl<$($g)*> DerefMut for $t {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Utf8CStr {
self.as_utf8_cstr_mut()
}
}
impl<$($g)*> AsMut<Utf8CStr> for $t {
#[inline(always)]
fn as_mut(&mut self) -> &mut Utf8CStr {
self.as_utf8_cstr_mut()
}
}
)*}
}
impl_str_write!(
(Utf8CStrBufRef<'_>,)
(Utf8CStrBufArr<N>, const N: usize)
(Utf8CString,)
);
macro_rules! impl_str_buf {
($( ($t:ty, $($g:tt)*) )*) => {$(
impl<$($g)*> Utf8CStrWrite for $t {
#[inline(always)]
fn len(&self) -> usize {
self.used
}
#[inline(always)]
fn push_str(&mut self, s: &str) -> usize {
utf8_cstr_buf_append(self, s.as_bytes())
}
#[inline(always)]
fn push_lossy(&mut self, s: &[u8]) -> usize {
utf8_cstr_append_lossy(self, s)
}
#[inline(always)]
fn clear(&mut self) {
self.buf[0] = b'\0';
self.used = 0;
}
}
)*}
}
impl_str_buf!(
(Utf8CStrBufRef<'_>,)
(Utf8CStrBufArr<N>, const N: usize)
);
// The cstr! macro is copied from https://github.com/bytecodealliance/rustix/blob/main/src/cstr.rs
#[macro_export]
macro_rules! cstr {
($($str:tt)*) => {{
assert!(
!($($str)*).bytes().any(|b| b == b'\0'),
"cstr argument contains embedded NUL bytes",
);
#[allow(unused_unsafe)]
unsafe {
$crate::Utf8CStr::from_bytes_unchecked(concat!($($str)*, "\0").as_bytes())
}
}};
}
#[macro_export]
macro_rules! raw_cstr {
($($str:tt)*) => {{
cstr!($($str)*).as_ptr()
}};
}

View File

@@ -1,28 +1,34 @@
// Functions in this file are only for exporting to C++, DO NOT USE IN RUST
use std::fmt::Write;
use std::io;
use std::os::fd::{BorrowedFd, OwnedFd, RawFd};
use cfg_if::cfg_if;
use cxx::private::c_char;
use libc::mode_t;
use crate::logging::CxxResultExt;
pub(crate) use crate::xwrap::*;
use crate::{
fd_path, map_fd, map_file, mkdirs, realpath, rm_rf, slice_from_ptr_mut, Directory, ResultExt,
Utf8CStr,
clone_attr, fclone_attr, fd_path, map_fd, map_file, Directory, FsPath, Utf8CStr, Utf8CStrBufRef,
};
pub(crate) fn fd_path_for_cxx(fd: RawFd, buf: &mut [u8]) -> isize {
fd_path(fd, buf)
let mut buf = Utf8CStrBufRef::from(buf);
fd_path(fd, &mut buf)
.log_cxx_with_msg(|w| w.write_str("fd_path failed"))
.map_or(-1_isize, |v| v as isize)
.map_or(-1_isize, |_| buf.len() as isize)
}
#[no_mangle]
unsafe extern "C" fn canonical_path(path: *const c_char, buf: *mut u8, bufsz: usize) -> isize {
match Utf8CStr::from_ptr(path) {
Ok(p) => realpath(p, slice_from_ptr_mut(buf, bufsz)).map_or(-1, |v| v as isize),
Ok(p) => {
let mut buf = Utf8CStrBufRef::from_ptr(buf, bufsz);
FsPath::from(p)
.realpath(&mut buf)
.map_or(-1, |_| buf.len() as isize)
}
Err(_) => -1,
}
}
@@ -30,7 +36,7 @@ unsafe extern "C" fn canonical_path(path: *const c_char, buf: *mut u8, bufsz: us
#[export_name = "mkdirs"]
unsafe extern "C" fn mkdirs_for_cxx(path: *const c_char, mode: mode_t) -> i32 {
match Utf8CStr::from_ptr(path) {
Ok(p) => mkdirs(p, mode).map_or(-1, |_| 0),
Ok(p) => FsPath::from(p).mkdirs(mode).map_or(-1, |_| 0),
Err(_) => -1,
}
}
@@ -38,7 +44,7 @@ unsafe extern "C" fn mkdirs_for_cxx(path: *const c_char, mode: mode_t) -> i32 {
#[export_name = "rm_rf"]
unsafe extern "C" fn rm_rf_for_cxx(path: *const c_char) -> bool {
match Utf8CStr::from_ptr(path) {
Ok(p) => rm_rf(p).map_or(false, |_| true),
Ok(p) => FsPath::from(p).remove_all().is_ok(),
Err(_) => false,
}
}
@@ -48,7 +54,7 @@ unsafe extern "C" fn frm_rf(fd: OwnedFd) -> bool {
fn inner(fd: OwnedFd) -> io::Result<()> {
Directory::try_from(fd)?.remove_all()
}
inner(fd).map_or(false, |_| true)
inner(fd).is_ok()
}
pub(crate) fn map_file_for_cxx(path: &[u8], rw: bool) -> &'static mut [u8] {
@@ -66,3 +72,102 @@ pub(crate) fn map_fd_for_cxx(fd: RawFd, sz: usize, rw: bool) -> &'static mut [u8
.unwrap_or(&mut [])
}
}
pub(crate) unsafe fn readlinkat_for_cxx(
dirfd: RawFd,
path: *const c_char,
buf: *mut u8,
bufsz: usize,
) -> isize {
// readlinkat() may fail on x86 platform, returning random value
// instead of number of bytes placed in buf (length of link)
cfg_if! {
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
libc::memset(buf.cast(), 0, bufsz);
let mut r = libc::readlinkat(dirfd, path, buf.cast(), bufsz - 1);
if r > 0 {
r = libc::strlen(buf.cast()) as isize;
}
} else {
let r = libc::readlinkat(dirfd, path, buf.cast(), bufsz - 1);
if r >= 0 {
*buf.offset(r) = b'\0';
}
}
}
r
}
#[export_name = "cp_afc"]
unsafe extern "C" fn cp_afc_for_cxx(src: *const c_char, dest: *const c_char) -> bool {
if let Ok(src) = Utf8CStr::from_ptr(src) {
if let Ok(dest) = Utf8CStr::from_ptr(dest) {
let src = FsPath::from(src);
let dest = FsPath::from(dest);
return src
.copy_to(dest)
.log_cxx_with_msg(|w| {
w.write_fmt(format_args!("cp_afc {} -> {} failed", src, dest))
})
.is_ok();
}
}
false
}
#[export_name = "mv_path"]
unsafe extern "C" fn mv_path_for_cxx(src: *const c_char, dest: *const c_char) -> bool {
if let Ok(src) = Utf8CStr::from_ptr(src) {
if let Ok(dest) = Utf8CStr::from_ptr(dest) {
let src = FsPath::from(src);
let dest = FsPath::from(dest);
return src
.move_to(dest)
.log_cxx_with_msg(|w| {
w.write_fmt(format_args!("mv_path {} -> {} failed", src, dest))
})
.is_ok();
}
}
false
}
#[export_name = "link_path"]
unsafe extern "C" fn link_path_for_cxx(src: *const c_char, dest: *const c_char) -> bool {
if let Ok(src) = Utf8CStr::from_ptr(src) {
if let Ok(dest) = Utf8CStr::from_ptr(dest) {
let src = FsPath::from(src);
let dest = FsPath::from(dest);
return src
.link_to(dest)
.log_cxx_with_msg(|w| {
w.write_fmt(format_args!("link_path {} -> {} failed", src, dest))
})
.is_ok();
}
}
false
}
#[export_name = "clone_attr"]
unsafe extern "C" fn clone_attr_for_cxx(src: *const c_char, dest: *const c_char) -> bool {
if let Ok(src) = Utf8CStr::from_ptr(src) {
if let Ok(dest) = Utf8CStr::from_ptr(dest) {
let src = FsPath::from(src);
let dest = FsPath::from(dest);
return clone_attr(src, dest)
.log_cxx_with_msg(|w| {
w.write_fmt(format_args!("clone_attr {} -> {} failed", src, dest))
})
.is_ok();
}
}
false
}
#[export_name = "fclone_attr"]
unsafe extern "C" fn fclone_attr_for_cxx(a: RawFd, b: RawFd) -> bool {
fclone_attr(a, b)
.log_cxx_with_msg(|w| w.write_str("fclone_attr failed"))
.is_ok()
}

View File

@@ -7,7 +7,6 @@
#include <libgen.h>
#include <base.hpp>
#include <selinux.hpp>
using namespace std;
@@ -20,191 +19,6 @@ int fd_pathat(int dirfd, const char *name, char *path, size_t size) {
return 0;
}
void mv_path(const char *src, const char *dest) {
file_attr attr;
getattr(src, &attr);
if (S_ISDIR(attr.st.st_mode)) {
if (access(dest, F_OK) != 0) {
xmkdirs(dest, 0);
setattr(dest, &attr);
}
mv_dir(xopen(src, O_RDONLY | O_CLOEXEC), xopen(dest, O_RDONLY | O_CLOEXEC));
} else{
xrename(src, dest);
}
rmdir(src);
}
void mv_dir(int src, int dest) {
auto dir = xopen_dir(src);
run_finally f([=]{ close(dest); });
for (dirent *entry; (entry = xreaddir(dir.get()));) {
switch (entry->d_type) {
case DT_DIR:
if (xfaccessat(dest, entry->d_name, F_OK, 0) == 0) {
// Destination folder exists, needs recursive move
int newsrc = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
int newdest = xopenat(dest, entry->d_name, O_RDONLY | O_CLOEXEC);
mv_dir(newsrc, newdest);
unlinkat(src, entry->d_name, AT_REMOVEDIR);
break;
}
// Else fall through
case DT_LNK:
case DT_REG:
renameat(src, entry->d_name, dest, entry->d_name);
break;
}
}
}
void cp_afc(const char *src, const char *dest) {
file_attr a;
getattr(src, &a);
if (S_ISDIR(a.st.st_mode)) {
xmkdirs(dest, 0);
clone_dir(xopen(src, O_RDONLY | O_CLOEXEC), xopen(dest, O_RDONLY | O_CLOEXEC));
} else{
unlink(dest);
if (S_ISREG(a.st.st_mode)) {
int sfd = xopen(src, O_RDONLY | O_CLOEXEC);
int dfd = xopen(dest, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0);
xsendfile(dfd, sfd, nullptr, a.st.st_size);
close(sfd);
close(dfd);
} else if (S_ISLNK(a.st.st_mode)) {
char buf[4096];
xreadlink(src, buf, sizeof(buf));
xsymlink(buf, dest);
}
}
setattr(dest, &a);
}
void clone_dir(int src, int dest) {
auto dir = xopen_dir(src);
run_finally f([&]{ close(dest); });
for (dirent *entry; (entry = xreaddir(dir.get()));) {
file_attr a;
getattrat(src, entry->d_name, &a);
switch (entry->d_type) {
case DT_DIR: {
xmkdirat(dest, entry->d_name, 0);
setattrat(dest, entry->d_name, &a);
int sfd = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
int dst = xopenat(dest, entry->d_name, O_RDONLY | O_CLOEXEC);
clone_dir(sfd, dst);
break;
}
case DT_REG: {
int sfd = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
int dfd = xopenat(dest, entry->d_name, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0);
xsendfile(dfd, sfd, nullptr, a.st.st_size);
fsetattr(dfd, &a);
close(dfd);
close(sfd);
break;
}
case DT_LNK: {
char buf[4096];
xreadlinkat(src, entry->d_name, buf, sizeof(buf));
xsymlinkat(buf, dest, entry->d_name);
setattrat(dest, entry->d_name, &a);
break;
}
}
}
}
void link_path(const char *src, const char *dest) {
link_dir(xopen(src, O_RDONLY | O_CLOEXEC), xopen(dest, O_RDONLY | O_CLOEXEC));
}
void link_dir(int src, int dest) {
auto dir = xopen_dir(src);
run_finally f([&]{ close(dest); });
for (dirent *entry; (entry = xreaddir(dir.get()));) {
if (entry->d_type == DT_DIR) {
file_attr a;
getattrat(src, entry->d_name, &a);
xmkdirat(dest, entry->d_name, 0);
setattrat(dest, entry->d_name, &a);
int sfd = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
int dfd = xopenat(dest, entry->d_name, O_RDONLY | O_CLOEXEC);
link_dir(sfd, dfd);
} else {
xlinkat(src, entry->d_name, dest, entry->d_name, 0);
}
}
}
int getattr(const char *path, file_attr *a) {
if (xlstat(path, &a->st) == -1)
return -1;
char *con;
if (lgetfilecon(path, &con) == -1)
return -1;
strcpy(a->con, con);
freecon(con);
return 0;
}
int getattrat(int dirfd, const char *name, file_attr *a) {
char path[4096];
fd_pathat(dirfd, name, path, sizeof(path));
return getattr(path, a);
}
int fgetattr(int fd, file_attr *a) {
if (xfstat(fd, &a->st) < 0)
return -1;
char *con;
if (fgetfilecon(fd, &con) < 0)
return -1;
strcpy(a->con, con);
freecon(con);
return 0;
}
int setattr(const char *path, file_attr *a) {
if (chmod(path, a->st.st_mode & 0777) < 0)
return -1;
if (chown(path, a->st.st_uid, a->st.st_gid) < 0)
return -1;
if (a->con[0] && lsetfilecon(path, a->con) < 0)
return -1;
return 0;
}
int setattrat(int dirfd, const char *name, file_attr *a) {
char path[4096];
fd_pathat(dirfd, name, path, sizeof(path));
return setattr(path, a);
}
int fsetattr(int fd, file_attr *a) {
if (fchmod(fd, a->st.st_mode & 0777) < 0)
return -1;
if (fchown(fd, a->st.st_uid, a->st.st_gid) < 0)
return -1;
if (a->con[0] && fsetfilecon(fd, a->con) < 0)
return -1;
return 0;
}
void clone_attr(const char *src, const char *dest) {
file_attr a;
getattr(src, &a);
setattr(dest, &a);
}
void fclone_attr(int src, int dest) {
file_attr a;
fgetattr(src, &a);
fsetattr(dest, &a);
}
void full_read(int fd, string &str) {
char buf[4096];
for (ssize_t len; (len = xread(fd, buf, sizeof(buf))) > 0;)

View File

@@ -20,11 +20,6 @@ static inline T align_padding(T v, int a) {
return align_to(v, a) - v;
}
struct file_attr {
struct stat st;
char con[128];
};
struct mount_info {
unsigned int id;
unsigned int parent;
@@ -58,27 +53,19 @@ int mkdirs(const char *path, mode_t mode);
ssize_t canonical_path(const char * __restrict__ path, char * __restrict__ buf, size_t bufsiz);
bool rm_rf(const char *path);
bool frm_rf(int dirfd);
void cp_afc(const char *src, const char *dest);
void mv_path(const char *src, const char *dest);
void link_path(const char *src, const char *dest);
void clone_attr(const char *src, const char *dest);
void fclone_attr(int src, int dest);
} // extern "C"
int fd_pathat(int dirfd, const char *name, char *path, size_t size);
void mv_path(const char *src, const char *dest);
void mv_dir(int src, int dest);
void cp_afc(const char *src, const char *dest);
void link_path(const char *src, const char *dest);
void link_dir(int src, int dest);
static inline ssize_t realpath(
const char * __restrict__ path, char * __restrict__ buf, size_t bufsiz) {
return canonical_path(path, buf, bufsiz);
}
int getattr(const char *path, file_attr *a);
int getattrat(int dirfd, const char *name, file_attr *a);
int fgetattr(int fd, file_attr *a);
int setattr(const char *path, file_attr *a);
int setattrat(int dirfd, const char *name, file_attr *a);
int fsetattr(int fd, file_attr *a);
void fclone_attr(int src, int dest);
void clone_attr(const char *src, const char *dest);
void full_read(int fd, std::string &str);
void full_read(const char *filename, std::string &str);
std::string full_read(int fd);
@@ -90,7 +77,6 @@ void file_readline(const char *file, const std::function<bool(std::string_view)>
void parse_prop_file(FILE *fp, const std::function<bool(std::string_view, std::string_view)> &fn);
void parse_prop_file(const char *file,
const std::function<bool(std::string_view, std::string_view)> &fn);
void clone_dir(int src, int dest);
std::vector<mount_info> parse_mount_info(const char *pid);
std::string resolve_preinit_dir(const char *base_dir);

View File

@@ -10,9 +10,18 @@ use std::os::unix::fs::FileTypeExt;
use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd, RawFd};
use std::{io, mem, ptr, slice};
use libc::{c_char, c_uint, dirent, mode_t, EEXIST, ENOENT, O_CLOEXEC, O_PATH, O_RDONLY, O_RDWR};
use bytemuck::{bytes_of_mut, Pod};
use libc::{
c_uint, dirent, mode_t, EEXIST, ENOENT, F_OK, O_CLOEXEC, O_CREAT, O_PATH, O_RDONLY, O_RDWR,
O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFREG,
};
use num_traits::AsPrimitive;
use crate::{bfmt_cstr, copy_cstr, cstr, errno, error, FlatData, LibcReturn, Utf8CStr};
use crate::cxx_extern::readlinkat_for_cxx;
use crate::{
copy_cstr, cstr, errno, error, FsPath, FsPathBuf, LibcReturn, Utf8CStr, Utf8CStrBuf,
Utf8CStrBufArr,
};
pub fn __open_fd_impl(path: &Utf8CStr, flags: i32, mode: mode_t) -> io::Result<OwnedFd> {
unsafe {
@@ -31,77 +40,15 @@ macro_rules! open_fd {
};
}
pub(crate) unsafe fn readlink_unsafe(path: *const c_char, buf: *mut u8, bufsz: usize) -> isize {
let r = libc::readlink(path, buf.cast(), bufsz - 1);
if r >= 0 {
*buf.offset(r) = b'\0';
}
r
}
pub fn readlink(path: &Utf8CStr, data: &mut [u8]) -> io::Result<usize> {
let r =
unsafe { readlink_unsafe(path.as_ptr(), data.as_mut_ptr(), data.len()) }.check_os_err()?;
Ok(r as usize)
}
pub fn fd_path(fd: RawFd, buf: &mut [u8]) -> io::Result<usize> {
let mut fd_buf = [0_u8; 40];
let fd_path = bfmt_cstr!(&mut fd_buf, "/proc/self/fd/{}", fd);
readlink(fd_path, buf)
}
// Inspired by https://android.googlesource.com/platform/bionic/+/master/libc/bionic/realpath.cpp
pub fn realpath(path: &Utf8CStr, buf: &mut [u8]) -> io::Result<usize> {
let fd = open_fd!(path, O_PATH | O_CLOEXEC)?;
let mut st1: libc::stat;
let mut st2: libc::stat;
let mut skip_check = false;
unsafe {
st1 = mem::zeroed();
if libc::fstat(fd.as_raw_fd(), &mut st1) < 0 {
// This shall only fail on Linux < 3.6
skip_check = true;
}
}
let len = fd_path(fd.as_raw_fd(), buf)?;
unsafe {
st2 = mem::zeroed();
if libc::stat(buf.as_ptr().cast(), &mut st2) < 0
|| (!skip_check && (st2.st_dev != st1.st_dev || st2.st_ino != st1.st_ino))
{
*errno() = ENOENT;
return Err(io::Error::last_os_error());
}
}
Ok(len)
}
pub fn mkdirs(path: &Utf8CStr, mode: mode_t) -> io::Result<()> {
let mut buf = [0_u8; 4096];
let len = copy_cstr(&mut buf, path);
let buf = &mut buf[..len];
let mut off = 1;
unsafe {
while let Some(p) = buf[off..].iter().position(|c| *c == b'/') {
buf[off + p] = b'\0';
if libc::mkdir(buf.as_ptr().cast(), mode) < 0 && *errno() != EEXIST {
return Err(io::Error::last_os_error());
}
buf[off + p] = b'/';
off += p + 1;
}
if libc::mkdir(buf.as_ptr().cast(), mode) < 0 && *errno() != EEXIST {
return Err(io::Error::last_os_error());
}
}
*errno() = 0;
Ok(())
pub fn fd_path(fd: RawFd, buf: &mut dyn Utf8CStrBuf) -> io::Result<()> {
let mut arr = Utf8CStrBufArr::<40>::new();
let path = FsPathBuf::new(&mut arr).join("/proc/self/fd").join_fmt(fd);
path.read_link(buf)
}
pub trait ReadExt {
fn skip(&mut self, len: usize) -> io::Result<()>;
fn read_flat_data<F: FlatData>(&mut self, data: &mut F) -> io::Result<()>;
fn read_pod<F: Pod>(&mut self, data: &mut F) -> io::Result<()>;
}
impl<T: Read> ReadExt for T {
@@ -116,8 +63,8 @@ impl<T: Read> ReadExt for T {
Ok(())
}
fn read_flat_data<F: FlatData>(&mut self, data: &mut F) -> io::Result<()> {
self.read_exact(data.as_raw_bytes_mut())
fn read_pod<F: Pod>(&mut self, data: &mut F) -> io::Result<()> {
self.read_exact(bytes_of_mut(data))
}
}
@@ -190,6 +137,25 @@ impl<T: Write> WriteExt for T {
}
}
pub struct FileAttr {
pub st: libc::stat,
#[cfg(feature = "selinux")]
pub con: Utf8CStrBufArr<128>,
}
impl FileAttr {
fn new() -> Self {
FileAttr {
st: unsafe { mem::zeroed() },
#[cfg(feature = "selinux")]
con: Utf8CStrBufArr::new(),
}
}
}
#[cfg(feature = "selinux")]
const XATTR_NAME_SELINUX: &[u8] = b"security.selinux\0";
pub struct DirEntry<'a> {
dir: &'a Directory,
entry: &'a dirent,
@@ -206,12 +172,11 @@ impl DirEntry<'_> {
}
}
pub fn path(&self, buf: &mut [u8]) -> io::Result<usize> {
let mut len = self.dir.path(buf)?;
buf[len] = b'/';
len += 1;
len += copy_cstr(&mut buf[len..], self.d_name());
Ok(len)
pub fn path(&self, buf: &mut dyn Utf8CStrBuf) -> io::Result<()> {
self.dir.path(buf)?;
buf.push_str("/");
buf.push_lossy(self.d_name().to_bytes());
Ok(())
}
pub fn is_dir(&self) -> bool {
@@ -234,34 +199,49 @@ impl DirEntry<'_> {
Ok(())
}
pub fn read_link(&self, buf: &mut dyn Utf8CStrBuf) -> io::Result<()> {
buf.clear();
unsafe {
let r = readlinkat_for_cxx(
self.dir.as_raw_fd(),
self.d_name.as_ptr(),
buf.as_mut_ptr().cast(),
buf.capacity(),
)
.check_os_err()? as usize;
buf.set_len(r);
}
Ok(())
}
unsafe fn open_fd(&self, flags: i32) -> io::Result<RawFd> {
self.dir.open_fd(self.d_name(), flags, 0)
}
pub fn open_as_dir(&self) -> io::Result<Directory> {
if !self.is_dir() {
return Err(io::Error::from(io::ErrorKind::NotADirectory));
}
unsafe {
let fd = libc::openat(
self.dir.as_raw_fd(),
self.d_name.as_ptr(),
O_RDONLY | O_CLOEXEC,
)
.check_os_err()?;
Directory::try_from(OwnedFd::from_raw_fd(fd))
}
unsafe { Directory::try_from(OwnedFd::from_raw_fd(self.open_fd(O_RDONLY)?)) }
}
pub fn open_as_file(&self, flags: i32) -> io::Result<File> {
if self.is_dir() {
return Err(io::Error::from(io::ErrorKind::IsADirectory));
}
unsafe {
let fd = libc::openat(
self.dir.as_raw_fd(),
self.d_name.as_ptr(),
flags | O_CLOEXEC,
)
.check_os_err()?;
Ok(File::from_raw_fd(fd))
}
unsafe { Ok(File::from_raw_fd(self.open_fd(flags)?)) }
}
pub fn get_attr(&self) -> io::Result<FileAttr> {
let mut path = Utf8CStrBufArr::default();
self.path(&mut path)?;
FsPath::from(&path).get_attr()
}
pub fn set_attr(&self, attr: &FileAttr) -> io::Result<()> {
let mut path = Utf8CStrBufArr::default();
self.path(&mut path)?;
FsPath::from(&path).set_attr(attr)
}
}
@@ -320,7 +300,26 @@ impl Directory {
unsafe { libc::rewinddir(self.dirp) }
}
pub fn path(&self, buf: &mut [u8]) -> io::Result<usize> {
unsafe fn open_fd(&self, name: &CStr, flags: i32, mode: i32) -> io::Result<RawFd> {
libc::openat(self.as_raw_fd(), name.as_ptr(), flags | O_CLOEXEC, mode).check_os_err()
}
pub fn contains_path(&self, path: &CStr) -> bool {
// WARNING: Using faccessat is incorrect, because the raw linux kernel syscall
// does not support the flag AT_SYMLINK_NOFOLLOW until 5.8 with faccessat2.
// Use fstatat to check the existence of a file instead.
unsafe {
let mut st: libc::stat = mem::zeroed();
libc::fstatat(
self.as_raw_fd(),
path.as_ptr(),
&mut st,
libc::AT_SYMLINK_NOFOLLOW,
) == 0
}
}
pub fn path(&self, buf: &mut dyn Utf8CStrBuf) -> io::Result<()> {
fd_path(self.as_raw_fd(), buf)
}
@@ -345,6 +344,108 @@ impl Directory {
})?;
Ok(())
}
pub fn copy_into(&mut self, dir: &Directory) -> io::Result<()> {
while let Some(ref e) = self.read()? {
let attr = e.get_attr()?;
let new_entry = DirEntry {
dir,
entry: e.entry,
d_name_len: e.d_name_len,
};
if e.is_dir() {
unsafe {
libc::mkdirat(dir.as_raw_fd(), e.d_name.as_ptr(), 0o777).as_os_err()?;
}
let mut src = e.open_as_dir()?;
let dest = new_entry.open_as_dir()?;
src.copy_into(&dest)?;
fd_set_attr(dest.as_raw_fd(), &attr)?;
} else if e.is_file() {
let mut src = e.open_as_file(O_RDONLY)?;
let mut dest = unsafe {
File::from_raw_fd(dir.open_fd(
e.d_name(),
O_WRONLY | O_CREAT | O_TRUNC,
0o777,
)?)
};
std::io::copy(&mut src, &mut dest)?;
fd_set_attr(dest.as_raw_fd(), &attr)?;
} else if e.is_lnk() {
let mut path = Utf8CStrBufArr::default();
e.read_link(&mut path)?;
unsafe {
libc::symlinkat(path.as_ptr(), dir.as_raw_fd(), e.d_name.as_ptr())
.as_os_err()?;
}
new_entry.set_attr(&attr)?;
}
}
Ok(())
}
pub fn move_into(&mut self, dir: &Directory) -> io::Result<()> {
let dir_fd = self.as_raw_fd();
while let Some(ref e) = self.read()? {
if e.is_dir() && dir.contains_path(e.d_name()) {
// Destination folder exists, needs recursive move
let mut src = e.open_as_dir()?;
let new_entry = DirEntry {
dir,
entry: e.entry,
d_name_len: e.d_name_len,
};
let dest = new_entry.open_as_dir()?;
src.move_into(&dest)?;
return e.unlink();
}
unsafe {
libc::renameat(
dir_fd,
e.d_name.as_ptr(),
dir.as_raw_fd(),
e.d_name.as_ptr(),
)
.as_os_err()?;
}
}
Ok(())
}
pub fn link_into(&mut self, dir: &Directory) -> io::Result<()> {
let dir_fd = self.as_raw_fd();
while let Some(ref e) = self.read()? {
if e.is_dir() {
unsafe {
libc::mkdirat(dir.as_raw_fd(), e.d_name.as_ptr(), 0o777).as_os_err()?;
}
let attr = e.get_attr()?;
let new_entry = DirEntry {
dir,
entry: e.entry,
d_name_len: e.d_name_len,
};
let mut src = e.open_as_dir()?;
let dest = new_entry.open_as_dir()?;
src.link_into(&dest)?;
fd_set_attr(dest.as_raw_fd(), &attr)?;
} else {
unsafe {
libc::linkat(
dir_fd,
e.d_name.as_ptr(),
dir.as_raw_fd(),
e.d_name.as_ptr(),
0,
)
.as_os_err()?;
}
}
}
Ok(())
}
}
impl Directory {
@@ -427,19 +528,254 @@ impl Drop for Directory {
}
}
pub fn rm_rf(path: &Utf8CStr) -> io::Result<()> {
unsafe {
let f = File::from(open_fd!(path, O_RDONLY | O_CLOEXEC)?);
impl FsPath {
pub fn open(&self, flags: i32) -> io::Result<File> {
Ok(File::from(open_fd!(self, flags)?))
}
pub fn create(&self, flags: i32, mode: mode_t) -> io::Result<File> {
Ok(File::from(open_fd!(self, flags, mode)?))
}
pub fn exists(&self) -> bool {
unsafe { libc::access(self.as_ptr(), F_OK) == 0 }
}
pub fn rename_to<T: AsRef<Utf8CStr>>(&self, name: T) -> io::Result<()> {
unsafe { libc::rename(self.as_ptr(), name.as_ref().as_ptr()).as_os_err() }
}
pub fn remove(&self) -> io::Result<()> {
unsafe { libc::remove(self.as_ptr()).as_os_err() }
}
pub fn remove_all(&self) -> io::Result<()> {
let f = self.open(O_RDONLY | O_CLOEXEC)?;
let st = f.metadata()?;
if st.is_dir() {
let mut dir = Directory::try_from(OwnedFd::from(f))?;
dir.remove_all()?;
}
libc::remove(path.as_ptr()).check_os_err()?;
self.remove()
}
pub fn read_link(&self, buf: &mut dyn Utf8CStrBuf) -> io::Result<()> {
buf.clear();
unsafe {
let r = libc::readlink(self.as_ptr(), buf.as_mut_ptr().cast(), buf.capacity() - 1)
.check_os_err()? as usize;
*buf.mut_buf().get_unchecked_mut(r) = b'\0';
buf.set_len(r);
}
Ok(())
}
pub fn mkdir(&self, mode: mode_t) -> io::Result<()> {
unsafe {
if libc::mkdir(self.as_ptr(), mode) < 0 {
if *errno() == EEXIST {
libc::chmod(self.as_ptr(), mode).as_os_err()?;
} else {
return Err(io::Error::last_os_error());
}
}
}
Ok(())
}
pub fn mkdirs(&self, mode: mode_t) -> io::Result<()> {
let mut buf = [0_u8; 4096];
let len = copy_cstr(&mut buf, self);
let buf = &mut buf[..len];
let mut off = 1;
unsafe {
while let Some(p) = buf[off..].iter().position(|c| *c == b'/') {
buf[off + p] = b'\0';
if libc::mkdir(buf.as_ptr().cast(), mode) < 0 && *errno() != EEXIST {
return Err(io::Error::last_os_error());
}
buf[off + p] = b'/';
off += p + 1;
}
if libc::mkdir(buf.as_ptr().cast(), mode) < 0 && *errno() != EEXIST {
return Err(io::Error::last_os_error());
}
}
*errno() = 0;
Ok(())
}
// Inspired by https://android.googlesource.com/platform/bionic/+/master/libc/bionic/realpath.cpp
pub fn realpath(&self, buf: &mut dyn Utf8CStrBuf) -> io::Result<()> {
let fd = open_fd!(self, O_PATH | O_CLOEXEC)?;
let mut st1: libc::stat;
let mut st2: libc::stat;
let mut skip_check = false;
unsafe {
st1 = mem::zeroed();
if libc::fstat(fd.as_raw_fd(), &mut st1) < 0 {
// This will only fail on Linux < 3.6
skip_check = true;
}
}
fd_path(fd.as_raw_fd(), buf)?;
unsafe {
st2 = mem::zeroed();
libc::stat(buf.as_ptr(), &mut st2).as_os_err()?;
if !skip_check && (st2.st_dev != st1.st_dev || st2.st_ino != st1.st_ino) {
*errno() = ENOENT;
return Err(io::Error::last_os_error());
}
}
Ok(())
}
pub fn get_attr(&self) -> io::Result<FileAttr> {
let mut attr = FileAttr::new();
unsafe {
libc::lstat(self.as_ptr(), &mut attr.st).as_os_err()?;
#[cfg(feature = "selinux")]
{
let sz = libc::lgetxattr(
self.as_ptr(),
XATTR_NAME_SELINUX.as_ptr().cast(),
attr.con.as_mut_ptr().cast(),
attr.con.capacity(),
)
.check_os_err()?;
attr.con.set_len((sz - 1) as usize);
}
}
Ok(attr)
}
pub fn set_attr(&self, attr: &FileAttr) -> io::Result<()> {
unsafe {
if (attr.st.st_mode & libc::S_IFMT as c_uint) != S_IFLNK.as_() {
libc::chmod(self.as_ptr(), (attr.st.st_mode & 0o777).as_()).as_os_err()?;
}
libc::lchown(self.as_ptr(), attr.st.st_uid, attr.st.st_gid).as_os_err()?;
#[cfg(feature = "selinux")]
if !attr.con.is_empty() {
libc::lsetxattr(
self.as_ptr(),
XATTR_NAME_SELINUX.as_ptr().cast(),
attr.con.as_ptr().cast(),
attr.con.len() + 1,
0,
)
.as_os_err()?;
}
}
Ok(())
}
pub fn copy_to(&self, path: &FsPath) -> io::Result<()> {
let attr = self.get_attr()?;
if (attr.st.st_mode & libc::S_IFMT as c_uint) == S_IFDIR.as_() {
path.mkdir(0o777)?;
let mut src = Directory::open(self)?;
let dest = Directory::open(path)?;
src.copy_into(&dest)?;
} else {
// It's OK if remove failed
path.remove().ok();
if (attr.st.st_mode & libc::S_IFMT as c_uint) == S_IFREG.as_() {
let mut src = self.open(O_RDONLY | O_CLOEXEC)?;
let mut dest = path.create(O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0o777)?;
std::io::copy(&mut src, &mut dest)?;
} else if (attr.st.st_mode & libc::S_IFMT as c_uint) == S_IFLNK.as_() {
let mut buf = Utf8CStrBufArr::default();
self.read_link(&mut buf)?;
unsafe {
libc::symlink(buf.as_ptr(), path.as_ptr()).as_os_err()?;
}
}
}
path.set_attr(&attr)?;
Ok(())
}
pub fn move_to(&self, path: &FsPath) -> io::Result<()> {
if path.exists() {
let attr = path.get_attr()?;
if (attr.st.st_mode & libc::S_IFMT as c_uint) == S_IFDIR.as_() {
let mut src = Directory::open(self)?;
let dest = Directory::open(path)?;
return src.move_into(&dest);
} else {
path.remove()?;
}
}
self.rename_to(path)
}
pub fn link_to(&self, path: &FsPath) -> io::Result<()> {
let attr = self.get_attr()?;
if (attr.st.st_mode & libc::S_IFMT as c_uint) == S_IFDIR.as_() {
path.mkdir(0o777)?;
path.set_attr(&attr)?;
let mut src = Directory::open(self)?;
let dest = Directory::open(path)?;
src.link_into(&dest)
} else {
unsafe { libc::link(self.as_ptr(), path.as_ptr()).as_os_err() }
}
}
}
pub fn fd_get_attr(fd: RawFd) -> io::Result<FileAttr> {
let mut attr = FileAttr::new();
unsafe {
libc::fstat(fd, &mut attr.st).as_os_err()?;
#[cfg(feature = "selinux")]
{
let sz = libc::fgetxattr(
fd,
XATTR_NAME_SELINUX.as_ptr().cast(),
attr.con.as_mut_ptr().cast(),
attr.con.capacity(),
)
.check_os_err()?;
attr.con.set_len((sz - 1) as usize);
}
}
Ok(attr)
}
pub fn fd_set_attr(fd: RawFd, attr: &FileAttr) -> io::Result<()> {
unsafe {
libc::fchmod(fd, (attr.st.st_mode & 0o777).as_()).as_os_err()?;
libc::fchown(fd, attr.st.st_uid, attr.st.st_gid).as_os_err()?;
#[cfg(feature = "selinux")]
if !attr.con.is_empty() {
libc::fsetxattr(
fd,
XATTR_NAME_SELINUX.as_ptr().cast(),
attr.con.as_ptr().cast(),
attr.con.len() + 1,
0,
)
.as_os_err()?;
}
}
Ok(())
}
pub fn clone_attr(a: &FsPath, b: &FsPath) -> io::Result<()> {
let attr = a.get_attr()?;
b.set_attr(&attr)
}
pub fn fclone_attr(a: RawFd, b: RawFd) -> io::Result<()> {
let attr = fd_get_attr(a)?;
fd_set_attr(b, &attr)
}
pub struct MappedFile(&'static mut [u8]);
impl MappedFile {
@@ -476,13 +812,13 @@ impl Drop for MappedFile {
}
}
extern "C" {
// Don't use the declaration from the libc crate as request should be u32 not i32
fn ioctl(fd: RawFd, request: u32, ...) -> i32;
}
// We mark the returned slice static because it is valid until explicitly unmapped
pub(crate) fn map_file(path: &Utf8CStr, rw: bool) -> io::Result<&'static mut [u8]> {
extern "C" {
// Don't use the declaration from the libc crate as request should be u32 not i32
fn ioctl(fd: RawFd, request: u32, ...) -> i32;
}
#[cfg(target_pointer_width = "64")]
const BLKGETSIZE64: u32 = 0x80081272;
@@ -495,7 +831,7 @@ pub(crate) fn map_file(path: &Utf8CStr, rw: bool) -> io::Result<&'static mut [u8
let st = f.metadata()?;
let sz = if st.file_type().is_block_device() {
let mut sz = 0_u64;
unsafe { ioctl(f.as_raw_fd(), BLKGETSIZE64, &mut sz) }.check_os_err()?;
unsafe { ioctl(f.as_raw_fd(), BLKGETSIZE64, &mut sz) }.as_os_err()?;
sz
} else {
st.st_size()

View File

@@ -1,40 +0,0 @@
#pragma once
// selinuxfs paths
#define SELINUX_MNT "/sys/fs/selinux"
#define SELINUX_ENFORCE SELINUX_MNT "/enforce"
#define SELINUX_POLICY SELINUX_MNT "/policy"
#define SELINUX_LOAD SELINUX_MNT "/load"
#define SELINUX_CONTEXT SELINUX_MNT "/context"
#define SELINUX_VERSION SELINUX_MNT "/policyvers"
// sepolicy paths
#define PLAT_POLICY_DIR "/system/etc/selinux/"
#define VEND_POLICY_DIR "/vendor/etc/selinux/"
#define PROD_POLICY_DIR "/product/etc/selinux/"
#define ODM_POLICY_DIR "/odm/etc/selinux/"
#define SYSEXT_POLICY_DIR "/system_ext/etc/selinux/"
#define SPLIT_PLAT_CIL PLAT_POLICY_DIR "plat_sepolicy.cil"
// Unconstrained domain the daemon and root processes run in
#define SEPOL_PROC_DOMAIN "magisk"
#define MAGISK_PROC_CON "u:r:" SEPOL_PROC_DOMAIN ":s0"
// Unconstrained file type that anyone can access
#define SEPOL_FILE_TYPE "magisk_file"
#define MAGISK_FILE_CON "u:object_r:" SEPOL_FILE_TYPE ":s0"
extern void (*freecon)(char *con);
extern int (*setcon)(const char *con);
extern int (*getfilecon)(const char *path, char **con);
extern int (*lgetfilecon)(const char *path, char **con);
extern int (*fgetfilecon)(int fd, char **con);
extern int (*setfilecon)(const char *path, const char *con);
extern int (*lsetfilecon)(const char *path, const char *con);
extern int (*fsetfilecon)(int fd, const char *con);
void getfilecon_at(int dirfd, const char *name, char **con);
void setfilecon_at(int dirfd, const char *name, const char *con);
bool selinux_enabled();
void enable_selinux();
void restorecon();
void restore_tmpcon();

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