From 8ff98738e7e9e5227850b1033db2ed35fa331b1b Mon Sep 17 00:00:00 2001 From: meloalfa159 Date: Mon, 26 Jun 2023 19:28:18 +0200 Subject: [PATCH] KernelSU: update to v0.6.1 and fix "the kernel version is too low" --- KernelSU/README.md | 2 +- KernelSU/README_CN.md | 2 +- KernelSU/README_JP.md | 2 +- KernelSU/README_PT-BR.md | 2 +- KernelSU/README_TR.md | 42 +++++ KernelSU/README_TW.md | 2 +- KernelSU/kernel/allowlist.c | 108 +++++++++-- KernelSU/kernel/allowlist.h | 5 +- KernelSU/kernel/apk_sign.h | 2 +- KernelSU/kernel/core_hook.c | 28 ++- KernelSU/kernel/embed_ksud.c | 2 +- KernelSU/kernel/export_symbol.txt | 2 +- KernelSU/kernel/kernel_compat.c | 2 +- KernelSU/kernel/kernel_compat.h | 2 +- KernelSU/kernel/klog.h | 2 +- KernelSU/kernel/ksud.c | 34 ++-- KernelSU/kernel/ksud.h | 2 +- KernelSU/kernel/manager.c | 60 +++--- KernelSU/kernel/manager.h | 2 +- KernelSU/kernel/module_api.c | 2 +- KernelSU/kernel/selinux/selinux.h | 2 +- KernelSU/kernel/sucompat.c | 22 +-- KernelSU/kernel/uid_observer.c | 8 +- KernelSU/kernel/uid_observer.h | 2 +- KernelSU/manager/app/build.gradle.kts | 1 + .../manager/app/src/main/AndroidManifest.xml | 2 + .../ui/component/profile/RootProfileConfig.kt | 144 +++++++++++--- .../java/me/weishu/kernelsu/ui/screen/Home.kt | 178 ++++++++++-------- .../me/weishu/kernelsu/ui/screen/Install.kt | 5 +- .../me/weishu/kernelsu/ui/screen/Module.kt | 98 +++++++--- .../me/weishu/kernelsu/ui/util/Downloader.kt | 133 +++++++++++++ .../java/me/weishu/kernelsu/ui/util/KsuCli.kt | 10 + .../kernelsu/ui/viewmodel/ModuleViewModel.kt | 64 +++++++ .../app/src/main/res/values-in/strings.xml | 8 + .../app/src/main/res/values-nl/strings.xml | 16 +- .../src/main/res/values-pt-rBR/strings.xml | 31 +-- .../app/src/main/res/values-ro/strings.xml | 7 +- .../app/src/main/res/values-ru/strings.xml | 50 +++-- .../app/src/main/res/values-tr/strings.xml | 18 +- .../app/src/main/res/values-uk/strings.xml | 3 + .../src/main/res/values-zh-rCN/strings.xml | 17 ++ .../app/src/main/res/values/strings.xml | 13 +- KernelSU/manager/gradle/libs.versions.toml | 3 +- KernelSU/userspace/ksud/src/defs.rs | 1 + KernelSU/userspace/ksud/src/event.rs | 5 + KernelSU/userspace/ksud/src/ksu.rs | 17 +- KernelSU/userspace/ksud/src/module.rs | 2 +- .../guide/how-to-integrate-for-non-gki.md | 33 ++-- KernelSU/website/docs/guide/installation.md | 2 +- .../guide/how-to-integrate-for-non-gki.md | 45 +++-- KernelSU/website/docs/repos.json | 26 ++- .../guide/how-to-integrate-for-non-gki.md | 14 +- .../guide/how-to-integrate-for-non-gki.md | 33 ++-- .../guide/how-to-integrate-for-non-gki.md | 33 ++-- 54 files changed, 1033 insertions(+), 318 deletions(-) create mode 100644 KernelSU/README_TR.md create mode 100644 KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/util/Downloader.kt diff --git a/KernelSU/README.md b/KernelSU/README.md index 33b340f9bff8..421e79fb4f5e 100644 --- a/KernelSU/README.md +++ b/KernelSU/README.md @@ -1,4 +1,4 @@ -**English** | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Portuguese-Brazil](README_PT-BR.md) +**English** | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) # KernelSU diff --git a/KernelSU/README_CN.md b/KernelSU/README_CN.md index 5cae53e5362b..a0f9238e8e63 100644 --- a/KernelSU/README_CN.md +++ b/KernelSU/README_CN.md @@ -1,4 +1,4 @@ -[English](README.md) | **简体中文** | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Portuguese-Brazil](README_PT-BR.md) +[English](README.md) | **简体中文** | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) # KernelSU diff --git a/KernelSU/README_JP.md b/KernelSU/README_JP.md index cc6446e07023..b9b45e978867 100644 --- a/KernelSU/README_JP.md +++ b/KernelSU/README_JP.md @@ -1,4 +1,4 @@ -[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | **日本語** | [Portuguese-Brazil](README_PT-BR.md) +[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | **日本語** | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) # KernelSU diff --git a/KernelSU/README_PT-BR.md b/KernelSU/README_PT-BR.md index 2fd46a35a124..6ce12d366090 100644 --- a/KernelSU/README_PT-BR.md +++ b/KernelSU/README_PT-BR.md @@ -1,4 +1,4 @@ -[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | **Portuguese-Brazil** +[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | **Portuguese-Brazil** | [Türkçe](README_TR.md) # KernelSU diff --git a/KernelSU/README_TR.md b/KernelSU/README_TR.md new file mode 100644 index 000000000000..7cb4698a1591 --- /dev/null +++ b/KernelSU/README_TR.md @@ -0,0 +1,42 @@ +[English](README.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Portuguese-Brazil](README_PT-BR.md) | **Türkçe** + +# KernelSU + +Android cihazlar için kernel tabanlı bir root çözümü. + +## Özellikler + +1. Kernel-tabanlı `su` ve root erişimi yönetimi. +2. Overlayfs'ye dayalı modül sistemi. + +## Uyumluluk Durumu + +KernelSU resmi olarak Android GKI 2.0 cihazlarını ( 5.10+ kernelli) destekler, eski kernellerle de (4.14+) uyumludur, ancak kerneli kendinizin inşaa etmesi gerekir. + +WSA ve konteyner tabanlı Android'in de, KernelSU ile entegre olarak da çalışması gerekmektedir. + +Ve desteklenen mevcut ABI'ler : `arm64-v8a` ve `x86_64` + +## Kullanım + +[Yükleme](https://kernelsu.org/guide/installation.html) + +## İnşaa + +[Nasıl inşa edilir?](https://kernelsu.org/guide/how-to-build.html) + +### Tartışma + +- Telegram: [@KernelSU](https://t.me/KernelSU) + +## Lisans + +- `kernel` klasöründeki dosyalar [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) lisansı altındadır. +- `kernel` klasörü dışındaki bütün diğer bölümler [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html) lisansı altındadır. + +## Krediler + +- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): KernelSU fikri. +- [genuine](https://github.com/brevent/genuine/): apk v2 imza doğrulama. +- [Diamorphine](https://github.com/m0nad/Diamorphine): bazı rootkit becerileri. +- [Magisk](https://github.com/topjohnwu/Magisk): sepolicy uygulaması. diff --git a/KernelSU/README_TW.md b/KernelSU/README_TW.md index 2866d8e5756d..05c38a86db4d 100644 --- a/KernelSU/README_TW.md +++ b/KernelSU/README_TW.md @@ -1,4 +1,4 @@ -[English](README.md) | [简体中文](README_CN.md) | **繁體中文** | [日本語](README_JP.md) | [Portuguese-Brazil](README_PT-BR.md) +[English](README.md) | [简体中文](README_CN.md) | **繁體中文** | [日本語](README_JP.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) # KernelSU diff --git a/KernelSU/kernel/allowlist.c b/KernelSU/kernel/allowlist.c index 19eff4bbc615..fc0003b0c405 100644 --- a/KernelSU/kernel/allowlist.c +++ b/KernelSU/kernel/allowlist.c @@ -29,6 +29,38 @@ static DEFINE_MUTEX(allowlist_mutex); static struct root_profile default_root_profile; static struct non_root_profile default_non_root_profile; +static int allow_list_arr[PAGE_SIZE / sizeof(int)] __read_mostly __aligned(PAGE_SIZE); +static int allow_list_pointer __read_mostly = 0; + +static void remove_uid_from_arr(uid_t uid) +{ + int *temp_arr; + int i, j; + + if (allow_list_pointer == 0) + return; + + temp_arr = kmalloc(sizeof(allow_list_arr), GFP_KERNEL); + if (temp_arr == NULL) { + pr_err("%s: unable to allocate memory\n", __func__); + return; + } + + for (i = j = 0; i < allow_list_pointer; i++) { + if (allow_list_arr[i] == uid) + continue; + temp_arr[j++] = allow_list_arr[i]; + } + + allow_list_pointer = j; + + for (; j < ARRAY_SIZE(allow_list_arr); j++) + temp_arr[j] = -1; + + memcpy(&allow_list_arr, temp_arr, PAGE_SIZE); + kfree(temp_arr); +} + static void init_default_profiles() { default_root_profile.uid = 0; @@ -51,6 +83,9 @@ struct perm_data { static struct list_head allow_list; +static uint8_t allow_list_bitmap[PAGE_SIZE] __read_mostly __aligned(PAGE_SIZE); +#define BITMAP_UID_MAX ((sizeof(allow_list_bitmap) * BITS_PER_BYTE) - 1) + #define KERNEL_SU_ALLOWLIST "/data/adb/ksu/.allowlist" static struct work_struct ksu_save_work; @@ -104,12 +139,23 @@ bool ksu_get_app_profile(struct app_profile *profile) return found; } +static inline bool forbid_system_uid(uid_t uid) { + #define SHELL_UID 2000 + #define SYSTEM_UID 1000 + return uid < SHELL_UID && uid != SYSTEM_UID; +} + static bool profile_valid(struct app_profile *profile) { if (!profile) { return false; } + if (forbid_system_uid(profile->current_uid)) { + pr_err("uid lower than 2000 is unsupported: %d\n", profile->current_uid); + return false; + } + if (profile->version < KSU_APP_PROFILE_VER) { pr_info("Unsupported profile version: %d\n", profile->version); return false; @@ -147,7 +193,7 @@ bool ksu_set_app_profile(struct app_profile *profile, bool persist) // found it, just override it all! memcpy(&p->profile, profile, sizeof(*profile)); result = true; - goto exit; + goto out; } } @@ -170,9 +216,31 @@ bool ksu_set_app_profile(struct app_profile *profile, bool persist) profile->nrp_config.profile.umount_modules); } list_add_tail(&p->list, &allow_list); + +out: + if (profile->current_uid <= BITMAP_UID_MAX) { + if (profile->allow_su) + allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] |= 1 << (profile->current_uid % BITS_PER_BYTE); + else + allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] &= ~(1 << (profile->current_uid % BITS_PER_BYTE)); + } else { + if (profile->allow_su) { + /* + * 1024 apps with uid higher than BITMAP_UID_MAX + * registered to request superuser? + */ + if (allow_list_pointer >= ARRAY_SIZE(allow_list_arr)) { + pr_err("too many apps registered\n"); + WARN_ON(1); + return false; + } + allow_list_arr[allow_list_pointer++] = profile->current_uid; + } else { + remove_uid_from_arr(profile->current_uid); + } + } result = true; -exit: // check if the default profiles is changed, cache it to a single struct to accelerate access. if (unlikely(!strcmp(profile->key, "$"))) { // set default non root profile @@ -192,21 +260,26 @@ bool ksu_set_app_profile(struct app_profile *profile, bool persist) return result; } -bool ksu_is_allow_uid(uid_t uid) +bool __ksu_is_allow_uid(uid_t uid) { - struct perm_data *p = NULL; - struct list_head *pos = NULL; + int i; - if (uid == 0) { + if (unlikely(uid == 0)) { // already root, but only allow our domain. return is_ksu_domain(); } - list_for_each (pos, &allow_list) { - p = list_entry(pos, struct perm_data, list); - // pr_info("is_allow_uid uid :%d, allow: %d\n", p->uid, p->allow); - if (uid == p->profile.current_uid) { - return p->profile.allow_su; + if (forbid_system_uid(uid)) { + // do not bother going through the list if it's system + return false; + } + + if (likely(uid <= BITMAP_UID_MAX)) { + return !!(allow_list_bitmap[uid / BITS_PER_BYTE] & (1 << (uid % BITS_PER_BYTE))); + } else { + for (i = 0; i < allow_list_pointer; i++) { + if (allow_list_arr[i] == uid) + return true; } } @@ -281,7 +354,7 @@ void do_save_allow_list(struct work_struct *work) filp_open(KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT, 0644); if (IS_ERR(fp)) { - pr_err("save_allow_list creat file failed: %ld\n", PTR_ERR(fp)); + pr_err("save_allow_list create file failed: %ld\n", PTR_ERR(fp)); return; } @@ -386,6 +459,9 @@ void ksu_prune_allowlist(bool (*is_uid_exist)(uid_t, void *), void *data) modified = true; pr_info("prune uid: %d\n", uid); list_del(&np->list); + allow_list_bitmap[uid / BITS_PER_BYTE] &= ~(1 << (uid % BITS_PER_BYTE)); + remove_uid_from_arr(uid); + smp_mb(); kfree(np); } } @@ -409,6 +485,14 @@ bool ksu_load_allow_list(void) void ksu_allowlist_init(void) { + int i; + + BUILD_BUG_ON(sizeof(allow_list_bitmap) != PAGE_SIZE); + BUILD_BUG_ON(sizeof(allow_list_arr) != PAGE_SIZE); + + for (i = 0; i < ARRAY_SIZE(allow_list_arr); i++) + allow_list_arr[i] = -1; + INIT_LIST_HEAD(&allow_list); INIT_WORK(&ksu_save_work, do_save_allow_list); diff --git a/KernelSU/kernel/allowlist.h b/KernelSU/kernel/allowlist.h index 63332268c318..04d47fb75b66 100644 --- a/KernelSU/kernel/allowlist.h +++ b/KernelSU/kernel/allowlist.h @@ -12,7 +12,8 @@ bool ksu_load_allow_list(void); void ksu_show_allow_list(void); -bool ksu_is_allow_uid(uid_t uid); +bool __ksu_is_allow_uid(uid_t uid); +#define ksu_is_allow_uid(uid) unlikely(__ksu_is_allow_uid(uid)) bool ksu_get_allow_list(int *array, int *length, bool allow); @@ -23,4 +24,4 @@ bool ksu_set_app_profile(struct app_profile *, bool persist); bool ksu_uid_should_umount(uid_t uid); struct root_profile *ksu_get_root_profile(uid_t uid); -#endif \ No newline at end of file +#endif diff --git a/KernelSU/kernel/apk_sign.h b/KernelSU/kernel/apk_sign.h index 033971f92737..52cbc9d0d2f3 100644 --- a/KernelSU/kernel/apk_sign.h +++ b/KernelSU/kernel/apk_sign.h @@ -4,4 +4,4 @@ // return 0 if signature match int is_manager_apk(char *path); -#endif \ No newline at end of file +#endif diff --git a/KernelSU/kernel/core_hook.c b/KernelSU/kernel/core_hook.c index c44328557ab7..654e2782b0a2 100644 --- a/KernelSU/kernel/core_hook.c +++ b/KernelSU/kernel/core_hook.c @@ -52,6 +52,8 @@ static inline bool is_isolated_uid(uid_t uid) appid <= LAST_APP_ZYGOTE_ISOLATED_UID); } +static struct group_info root_groups = { .usage = ATOMIC_INIT(2) }; + static void setup_groups(struct root_profile *profile, struct cred *cred) { if (profile->groups_count > KSU_MAX_GROUPS) { @@ -60,6 +62,14 @@ static void setup_groups(struct root_profile *profile, struct cred *cred) return; } + if (profile->groups_count == 1 && profile->groups[0] == 0) { + // setgroup to root and return early. + if (cred->group_info) + put_group_info(cred->group_info); + cred->group_info = get_group_info(&root_groups); + return; + } + u32 ngroups = profile->groups_count; struct group_info *group_info = groups_alloc(ngroups); if (!group_info) { @@ -67,7 +77,8 @@ static void setup_groups(struct root_profile *profile, struct cred *cred) return; } - for (int i = 0; i < ngroups; i++) { + int i; + for (i = 0; i < ngroups; i++) { gid_t gid = profile->groups[i]; kgid_t kgid = make_kgid(current_user_ns(), gid); if (!gid_valid(kgid)) { @@ -464,12 +475,7 @@ static bool should_umount(struct path *path) if (path->mnt && path->mnt->mnt_sb && path->mnt->mnt_sb->s_type) { const char *fstype = path->mnt->mnt_sb->s_type->name; - if (strcmp(fstype, "overlay") == 0) { - return ksu_uid_should_umount(current_uid().val); - } -#ifdef CONFIG_KSU_DEBUG - pr_info("uid: %d should not umount!\n", current_uid().val); -#endif + return strcmp(fstype, "overlay") == 0; } return false; } @@ -521,6 +527,14 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old) return 0; } + if (!ksu_uid_should_umount(new_uid.val)) { + return 0; + } else { +#ifdef CONFIG_KSU_DEBUG + pr_info("uid: %d should not umount!\n", current_uid().val); +#endif + } + // umount the target mnt pr_info("handle umount for uid: %d\n", new_uid.val); diff --git a/KernelSU/kernel/embed_ksud.c b/KernelSU/kernel/embed_ksud.c index c82d9eee5bec..24c401219c15 100644 --- a/KernelSU/kernel/embed_ksud.c +++ b/KernelSU/kernel/embed_ksud.c @@ -2,4 +2,4 @@ // This file will be regenerated by CI unsigned int ksud_size = 0; -const char ksud[0] = {}; \ No newline at end of file +const char ksud[0] = {}; diff --git a/KernelSU/kernel/export_symbol.txt b/KernelSU/kernel/export_symbol.txt index d476da1669fb..1abd805e8e6a 100644 --- a/KernelSU/kernel/export_symbol.txt +++ b/KernelSU/kernel/export_symbol.txt @@ -1,2 +1,2 @@ register_kprobe -unregister_kprobe \ No newline at end of file +unregister_kprobe diff --git a/KernelSU/kernel/kernel_compat.c b/KernelSU/kernel/kernel_compat.c index 339650fe63f9..591c31dbe925 100644 --- a/KernelSU/kernel/kernel_compat.c +++ b/KernelSU/kernel/kernel_compat.c @@ -31,4 +31,4 @@ ssize_t ksu_kernel_write_compat(struct file *p, const void *buf, size_t count, l } return result; #endif -} \ No newline at end of file +} diff --git a/KernelSU/kernel/kernel_compat.h b/KernelSU/kernel/kernel_compat.h index 8daa40489f72..b5cc6c9ae220 100644 --- a/KernelSU/kernel/kernel_compat.h +++ b/KernelSU/kernel/kernel_compat.h @@ -39,4 +39,4 @@ static inline int install_session_keyring(struct key *keyring) #define KWORKER_INSTALL_KEYRING() #endif -#endif \ No newline at end of file +#endif diff --git a/KernelSU/kernel/klog.h b/KernelSU/kernel/klog.h index bda4f9cb26dc..a934027fbeeb 100644 --- a/KernelSU/kernel/klog.h +++ b/KernelSU/kernel/klog.h @@ -8,4 +8,4 @@ #define pr_fmt(fmt) "KernelSU: " fmt #endif -#endif \ No newline at end of file +#endif diff --git a/KernelSU/kernel/ksud.c b/KernelSU/kernel/ksud.c index 49ef534994b7..8ef4f445da3e 100644 --- a/KernelSU/kernel/ksud.c +++ b/KernelSU/kernel/ksud.c @@ -52,9 +52,9 @@ static struct work_struct stop_vfs_read_work; static struct work_struct stop_execve_hook_work; static struct work_struct stop_input_hook_work; #else -static bool vfs_read_hook = true; -static bool execveat_hook = true; -static bool input_hook = true; +bool ksu_vfs_read_hook __read_mostly = true; +bool ksu_execveat_hook __read_mostly = true; +bool ksu_input_hook __read_mostly = true; #endif void on_post_fs_data(void) @@ -108,7 +108,13 @@ static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr) /* * count() counts the number of strings in array ARGV. */ -static int count(struct user_arg_ptr argv, int max) + + /* + * Make sure old GCC compiler can use __maybe_unused, + * Test passed in 4.4.x ~ 4.9.x when use GCC. + */ + +static int __maybe_unused count(struct user_arg_ptr argv, int max) { int i = 0; @@ -138,7 +144,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, void *argv, void *envp, int *flags) { #ifndef CONFIG_KPROBES - if (!execveat_hook) { + if (!ksu_execveat_hook) { return 0; } #endif @@ -157,8 +163,8 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, return 0; } - if (!memcmp(filename->name, system_bin_init, - sizeof(system_bin_init) - 1)) { + if (unlikely(!memcmp(filename->name, system_bin_init, + sizeof(system_bin_init) - 1))) { #ifdef __aarch64__ // /system/bin/init executed struct user_arg_ptr *ptr = (struct user_arg_ptr*) argv; @@ -200,8 +206,8 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr, #endif } - if (first_app_process && - !memcmp(filename->name, app_process, sizeof(app_process) - 1)) { + if (unlikely(first_app_process && + !memcmp(filename->name, app_process, sizeof(app_process) - 1))) { first_app_process = false; pr_info("exec app_process, /data prepared, second_stage: %d\n", init_second_stage_executed); on_post_fs_data(); // we keep this for old ksud @@ -244,7 +250,7 @@ int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr, size_t *count_ptr, loff_t **pos) { #ifndef CONFIG_KPROBES - if (!vfs_read_hook) { + if (!ksu_vfs_read_hook) { return 0; } #endif @@ -345,7 +351,7 @@ int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, int *value) { #ifndef CONFIG_KPROBES - if (!input_hook) { + if (!ksu_input_hook) { return 0; } #endif @@ -463,7 +469,7 @@ static void stop_vfs_read_hook() bool ret = schedule_work(&stop_vfs_read_work); pr_info("unregister vfs_read kprobe: %d!\n", ret); #else - vfs_read_hook = false; + ksu_vfs_read_hook = false; #endif } @@ -473,7 +479,7 @@ static void stop_execve_hook() bool ret = schedule_work(&stop_execve_hook_work); pr_info("unregister execve kprobe: %d!\n", ret); #else - execveat_hook = false; + ksu_execveat_hook = false; #endif } @@ -488,7 +494,7 @@ static void stop_input_hook() bool ret = schedule_work(&stop_input_hook_work); pr_info("unregister input kprobe: %d!\n", ret); #else - input_hook = false; + ksu_input_hook = false; #endif } diff --git a/KernelSU/kernel/ksud.h b/KernelSU/kernel/ksud.h index d5a35aec2bea..5a32a527757f 100644 --- a/KernelSU/kernel/ksud.h +++ b/KernelSU/kernel/ksud.h @@ -7,4 +7,4 @@ void on_post_fs_data(void); bool ksu_is_safe_mode(void); -#endif \ No newline at end of file +#endif diff --git a/KernelSU/kernel/manager.c b/KernelSU/kernel/manager.c index 6961999a641f..2329477a9b56 100644 --- a/KernelSU/kernel/manager.c +++ b/KernelSU/kernel/manager.c @@ -39,39 +39,51 @@ bool become_manager(char *pkg) files_table = files_fdtable(current->files); + int pkg_len = strlen(pkg); // todo: use iterate_fd - while (files_table->fd[i] != NULL) { + for (i = 0; files_table->fd[i] != NULL; i++) { files_path = files_table->fd[i]->f_path; if (!d_is_reg(files_path.dentry)) { - i++; continue; } cwd = d_path(&files_path, buf, PATH_MAX); - if (startswith(cwd, "/data/app/") == 0 && - endswith(cwd, "/base.apk") == 0) { - // we have found the apk! - pr_info("found apk: %s", cwd); - if (!strstr(cwd, pkg)) { - pr_info("apk path not match package name!\n"); - i++; - continue; - } - if (is_manager_apk(cwd) == 0) { - // check passed - uid_t uid = current_uid().val; - pr_info("manager uid: %d\n", uid); - - ksu_set_manager_uid(uid); + if (startswith(cwd, "/data/app/") != 0 || + endswith(cwd, "/base.apk") != 0) { + continue; + } + // we have found the apk! + pr_info("found apk: %s", cwd); + char *pkg_index = strstr(cwd, pkg); + if (!pkg_index) { + pr_info("apk path not match package name!\n"); + continue; + } + char *next_char = pkg_index + pkg_len; + // because we ensure the cwd must startswith `/data/app` and endswith `base.apk` + // we don't need to check if the pointer is out of bounds + if (*next_char != '-') { + // from android 8.1: http://aospxref.com/android-8.1.0_r81/xref/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java#17612 + // to android 13: http://aospxref.com/android-13.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java#1208 + // /data/app/~~[randomStringA]/[packageName]-[randomStringB] + // the previous char must be `/` and the next char must be `-` + // because we use strstr instead of equals, this is a strong verfication. + pr_info("invalid pkg: %s\n", pkg); + continue; + } + if (is_manager_apk(cwd) == 0) { + // check passed + uid_t uid = current_uid().val; + pr_info("manager uid: %d\n", uid); - result = true; - goto clean; - } else { - pr_info("manager signature invalid!"); - } + ksu_set_manager_uid(uid); - break; + result = true; + goto clean; + } else { + pr_info("manager signature invalid!"); } - i++; + + break; } clean: diff --git a/KernelSU/kernel/manager.h b/KernelSU/kernel/manager.h index aba3c479c4cf..9429d758f89d 100644 --- a/KernelSU/kernel/manager.h +++ b/KernelSU/kernel/manager.h @@ -15,7 +15,7 @@ static inline bool ksu_is_manager_uid_valid() static inline bool is_manager() { - return ksu_manager_uid == current_uid().val; + return unlikely(ksu_manager_uid == current_uid().val); } static inline uid_t ksu_get_manager_uid() diff --git a/KernelSU/kernel/module_api.c b/KernelSU/kernel/module_api.c index 6a81351d9017..999d5102741f 100644 --- a/KernelSU/kernel/module_api.c +++ b/KernelSU/kernel/module_api.c @@ -30,4 +30,4 @@ RE_EXPORT_SYMBOL1(unsigned long, kallsyms_lookup_name, const char *, name) // int ksu_register_kretprobe(struct kretprobe *rp); // void unregister_kretprobe(struct kretprobe *rp); // int register_kretprobes(struct kretprobe **rps, int num); -// void unregister_kretprobes(struct kretprobe **rps, int num); \ No newline at end of file +// void unregister_kretprobes(struct kretprobe **rps, int num); diff --git a/KernelSU/kernel/selinux/selinux.h b/KernelSU/kernel/selinux/selinux.h index ce5a98e22501..1ccc0d53ea3d 100644 --- a/KernelSU/kernel/selinux/selinux.h +++ b/KernelSU/kernel/selinux/selinux.h @@ -18,4 +18,4 @@ bool is_ksu_domain(); void apply_kernelsu_rules(); -#endif \ No newline at end of file +#endif diff --git a/KernelSU/kernel/sucompat.c b/KernelSU/kernel/sucompat.c index e3078df78707..09e5f501d6bd 100644 --- a/KernelSU/kernel/sucompat.c +++ b/KernelSU/kernel/sucompat.c @@ -53,7 +53,7 @@ int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode, if (IS_ERR(filename)) { return 0; } - if (!memcmp(filename->name, su, sizeof(su))) { + if (unlikely(!memcmp(filename->name, su, sizeof(su)))) { pr_info("faccessat su->sh!\n"); *filename_user = sh_user_path(); } @@ -73,7 +73,7 @@ int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags) return 0; } - if (!filename_user) { + if (unlikely(!filename_user)) { return 0; } @@ -82,7 +82,7 @@ int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags) if (IS_ERR(filename)) { return 0; } - if (!memcmp(filename->name, su, sizeof(su))) { + if (unlikely(!memcmp(filename->name, su, sizeof(su)))) { pr_info("newfstatat su->sh!\n"); *filename_user = sh_user_path(); } @@ -99,7 +99,7 @@ int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, const char sh[] = KSUD_PATH; const char su[] = SU_PATH; - if (!filename_ptr) + if (unlikely(!filename_ptr)) return 0; filename = *filename_ptr; @@ -107,16 +107,16 @@ int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, return 0; } - if (!ksu_is_allow_uid(current_uid().val)) { + if (likely(memcmp(filename->name, su, sizeof(su)))) return 0; - } - if (!memcmp(filename->name, su, sizeof(su))) { - pr_info("do_execveat_common su found\n"); - memcpy((void *)filename->name, sh, sizeof(sh)); + if (!ksu_is_allow_uid(current_uid().val)) + return 0; - escape_to_root(); - } + pr_info("do_execveat_common su found\n"); + memcpy((void *)filename->name, sh, sizeof(sh)); + + escape_to_root(); return 0; } diff --git a/KernelSU/kernel/uid_observer.c b/KernelSU/kernel/uid_observer.c index 95fa1c0a2ac6..d8269c495faa 100644 --- a/KernelSU/kernel/uid_observer.c +++ b/KernelSU/kernel/uid_observer.c @@ -44,7 +44,7 @@ static void do_update_uid(struct work_struct *work) if (IS_ERR(fp)) { pr_err("do_update_uid, open " SYSTEM_PACKAGES_LIST_PATH " failed: %d\n", - ERR_PTR(fp)); + PTR_ERR(fp)); return; } @@ -56,13 +56,15 @@ static void do_update_uid(struct work_struct *work) loff_t line_start = 0; char buf[128]; for (;;) { - ssize_t count = ksu_kernel_read_compat(fp, &chr, sizeof(chr), &pos); + ssize_t count = + ksu_kernel_read_compat(fp, &chr, sizeof(chr), &pos); if (count != sizeof(chr)) break; if (chr != '\n') continue; - count = ksu_kernel_read_compat(fp, buf, sizeof(buf), &line_start); + count = ksu_kernel_read_compat(fp, buf, sizeof(buf), + &line_start); struct uid_data *data = kmalloc(sizeof(struct uid_data), GFP_ATOMIC); diff --git a/KernelSU/kernel/uid_observer.h b/KernelSU/kernel/uid_observer.h index 5604b2191d97..6d06fd6ce192 100644 --- a/KernelSU/kernel/uid_observer.h +++ b/KernelSU/kernel/uid_observer.h @@ -7,4 +7,4 @@ int ksu_uid_observer_exit(); void update_uid(); -#endif \ No newline at end of file +#endif diff --git a/KernelSU/manager/app/build.gradle.kts b/KernelSU/manager/app/build.gradle.kts index 7ebb399c6589..d0056182f513 100644 --- a/KernelSU/manager/app/build.gradle.kts +++ b/KernelSU/manager/app/build.gradle.kts @@ -110,4 +110,5 @@ dependencies { implementation(libs.sheet.compose.dialogs.core) implementation(libs.sheet.compose.dialogs.list) + implementation(libs.sheet.compose.dialogs.input) } diff --git a/KernelSU/manager/app/src/main/AndroidManifest.xml b/KernelSU/manager/app/src/main/AndroidManifest.xml index 026ba0156c9f..96562cd86313 100644 --- a/KernelSU/manager/app/src/main/AndroidManifest.xml +++ b/KernelSU/manager/app/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ + + + onProfileChange( + profile.copy( + context = domain, + rootUseDefault = false + ) ) }) - } } @@ -195,6 +194,7 @@ fun GroupsPanel(selected: List, closeSelection: (selection: Set) val options = groups.map { value -> ListOption( titleText = value.display, + subtitleText = value.desc, selected = selected.contains(value), ) } @@ -206,6 +206,9 @@ fun GroupsPanel(selected: List, closeSelection: (selection: Set) }, onCloseRequest = { showDialog = false }), + header = Header.Default( + title = stringResource(R.string.profile_groups), + ), selection = ListSelection.Multiple( showCheckBoxes = true, options = options, @@ -229,7 +232,7 @@ fun GroupsPanel(selected: List, closeSelection: (selection: Set) }) { Column(modifier = Modifier.padding(16.dp)) { - Text("groups") + Text(stringResource(R.string.profile_groups)) FlowRow { selected.forEach { group -> AssistChip( @@ -257,6 +260,7 @@ fun CapsPanel( val options = caps.map { value -> ListOption( titleText = value.display, + subtitleText = value.desc, selected = selected.contains(value), ) } @@ -268,6 +272,9 @@ fun CapsPanel( }, onCloseRequest = { showDialog = false }), + header = Header.Default( + title = stringResource(R.string.profile_capabilities), + ), selection = ListSelection.Multiple( showCheckBoxes = true, options = options @@ -290,7 +297,7 @@ fun CapsPanel( }) { Column(modifier = Modifier.padding(16.dp)) { - Text("Capabilities") + Text(stringResource(R.string.profile_capabilities)) FlowRow { selected.forEach { group -> AssistChip( @@ -330,6 +337,10 @@ private fun UidPanel(uid: Int, label: String, onUidChange: (Int) -> Unit) { keyboardController?.hide() }), onValueChange = { + if (it.isEmpty()) { + onUidChange(0) + return@OutlinedTextField + } val valid = isTextValidUid(it) val targetUid = if (valid) it.toInt() else lastValidUid @@ -345,6 +356,97 @@ private fun UidPanel(uid: Int, label: String, onUidChange: (Int) -> Unit) { }) } +@Composable +private fun SELinuxPanel(profile: Natives.Profile, onSELinuxChange: (domain: String, rules: String) -> Unit) { + var showDialog by remember { mutableStateOf(false) } + if (showDialog) { + var domain by remember { mutableStateOf(profile.context) } + var rules by remember { mutableStateOf("") } + + val inputOptions = listOf( + InputTextField( + text = domain, + header = InputHeader( + title = stringResource(id = R.string.profile_selinux_domain), + ), + type = InputTextFieldType.OUTLINED, + required = true, + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Ascii, + imeAction = ImeAction.Next + ), + resultListener = { + domain = it ?: "" + }, + validationListener = { value -> + // value can be a-zA-Z0-9_ + val regex = Regex("^[a-z_]+:[a-z0-9_]+:[a-z0-9_]+(:[a-z0-9_]+)?$") + if (value?.matches(regex) == true) ValidationResult.Valid + else ValidationResult.Invalid("Domain must be valid sepolicy") + } + ), + InputTextField( + text = rules, + header = InputHeader( + title = stringResource(id = R.string.profile_selinux_rules), + ), + type = InputTextFieldType.OUTLINED, + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Ascii, + imeAction = ImeAction.Done + ), + singleLine = false, + resultListener = { + rules = it ?: "" + }, + validationListener = { value -> + if (isSepolicyValid(value)) ValidationResult.Valid + else ValidationResult.Invalid("Rules must be valid sepolicy") + }, + ) + ) + + InputDialog( + state = rememberUseCaseState(visible = true, + onFinishedRequest = { + onSELinuxChange(domain, rules) + }, + onCloseRequest = { + showDialog = false + }), + header = Header.Default( + title = stringResource(R.string.profile_selinux_context), + ), + selection = InputSelection( + input = inputOptions, + onPositiveClick = { result -> + // Handle selection + }, + ) + ) + } + + ListItem(headlineContent = { + OutlinedTextField( + modifier = Modifier + .fillMaxWidth() + .clickable { + showDialog = true + }, + enabled = false, + colors = TextFieldDefaults.outlinedTextFieldColors( + disabledTextColor = MaterialTheme.colorScheme.onSurface, + disabledBorderColor = MaterialTheme.colorScheme.outline, + disabledPlaceholderColor = MaterialTheme.colorScheme.onSurfaceVariant, + disabledLabelColor = MaterialTheme.colorScheme.onSurfaceVariant + ), + label = { Text(text = stringResource(R.string.profile_selinux_context)) }, + value = profile.context, + onValueChange = { }, + ) + }) +} + @Preview @Composable private fun RootProfileConfigPreview() { @@ -356,4 +458,4 @@ private fun RootProfileConfigPreview() { private fun isTextValidUid(text: String): Boolean { return text.isNotEmpty() && text.isDigitsOnly() && text.toInt() >= 0 && text.toInt() <= Int.MAX_VALUE -} \ No newline at end of file +} diff --git a/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Home.kt b/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Home.kt index 05ba0b8fe4f9..b724369652a2 100644 --- a/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Home.kt +++ b/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Home.kt @@ -19,6 +19,7 @@ import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.stringResource @@ -28,6 +29,8 @@ import androidx.compose.ui.unit.dp import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.RootNavGraph import com.ramcosta.composedestinations.navigation.DestinationsNavigator +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import me.weishu.kernelsu.* import me.weishu.kernelsu.R import me.weishu.kernelsu.ui.screen.destinations.SettingScreenDestination @@ -37,13 +40,11 @@ import me.weishu.kernelsu.ui.util.* @Destination @Composable fun HomeScreen(navigator: DestinationsNavigator) { - Scaffold( - topBar = { - TopBar(onSettingsClick = { - navigator.navigate(SettingScreenDestination) - }) - } - ) { innerPadding -> + Scaffold(topBar = { + TopBar(onSettingsClick = { + navigator.navigate(SettingScreenDestination) + }) + }) { innerPadding -> Column( modifier = Modifier .padding(innerPadding) @@ -62,11 +63,11 @@ fun HomeScreen(navigator: DestinationsNavigator) { if (isManager && Natives.requireNewKernel()) { WarningCard( stringResource(id = R.string.require_kernel_version).format( - ksuVersion, - Natives.MINIMAL_SUPPORTED_KERNEL + ksuVersion, Natives.MINIMAL_SUPPORTED_KERNEL ) ) } + UpdateCard() InfoCard() DonateCard() LearnMoreCard() @@ -75,6 +76,28 @@ fun HomeScreen(navigator: DestinationsNavigator) { } } +@Composable +fun UpdateCard() { + val context = LocalContext.current + val newVersion by produceState(initialValue = 0 to "") { + value = withContext(Dispatchers.IO) { checkNewVersion() } + } + val currentVersionCode = getManagerVersion(context).second + val newVersionCode = newVersion.first + val newVersionUrl = newVersion.second + if (newVersionCode <= currentVersionCode) { + return + } + + val uriHandler = LocalUriHandler.current + WarningCard( + message = stringResource(id = R.string.new_version_available).format(newVersionCode), + MaterialTheme.colorScheme.outlineVariant + ) { + uriHandler.openUri(newVersionUrl) + } +} + @Composable fun RebootDropdownItem(@StringRes id: Int, reason: String = "") { DropdownMenuItem(text = { @@ -87,44 +110,41 @@ fun RebootDropdownItem(@StringRes id: Int, reason: String = "") { @OptIn(ExperimentalMaterial3Api::class) @Composable private fun TopBar(onSettingsClick: () -> Unit) { - TopAppBar( - title = { Text(stringResource(R.string.app_name)) }, - actions = { - var showDropdown by remember { mutableStateOf(false) } - IconButton(onClick = { - showDropdown = true - }) { - Icon( - imageVector = Icons.Filled.Refresh, - contentDescription = stringResource(id = R.string.reboot) - ) + TopAppBar(title = { Text(stringResource(R.string.app_name)) }, actions = { + var showDropdown by remember { mutableStateOf(false) } + IconButton(onClick = { + showDropdown = true + }) { + Icon( + imageVector = Icons.Filled.Refresh, + contentDescription = stringResource(id = R.string.reboot) + ) - DropdownMenu(expanded = showDropdown, onDismissRequest = { - showDropdown = false - }) { + DropdownMenu(expanded = showDropdown, onDismissRequest = { + showDropdown = false + }) { - RebootDropdownItem(id = R.string.reboot) + RebootDropdownItem(id = R.string.reboot) - val pm = - LocalContext.current.getSystemService(Context.POWER_SERVICE) as PowerManager? - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && pm?.isRebootingUserspaceSupported == true) { - RebootDropdownItem(id = R.string.reboot_userspace, reason = "userspace") - } - RebootDropdownItem(id = R.string.reboot_recovery, reason = "recovery") - RebootDropdownItem(id = R.string.reboot_bootloader, reason = "bootloader") - RebootDropdownItem(id = R.string.reboot_download, reason = "download") - RebootDropdownItem(id = R.string.reboot_edl, reason = "edl") + val pm = + LocalContext.current.getSystemService(Context.POWER_SERVICE) as PowerManager? + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && pm?.isRebootingUserspaceSupported == true) { + RebootDropdownItem(id = R.string.reboot_userspace, reason = "userspace") } + RebootDropdownItem(id = R.string.reboot_recovery, reason = "recovery") + RebootDropdownItem(id = R.string.reboot_bootloader, reason = "bootloader") + RebootDropdownItem(id = R.string.reboot_download, reason = "download") + RebootDropdownItem(id = R.string.reboot_edl, reason = "edl") } + } - IconButton(onClick = onSettingsClick) { - Icon( - imageVector = Icons.Filled.Settings, - contentDescription = stringResource(id = R.string.settings) - ) - } + IconButton(onClick = onSettingsClick) { + Icon( + imageVector = Icons.Filled.Settings, + contentDescription = stringResource(id = R.string.settings) + ) } - ) + }) } @Composable @@ -136,17 +156,14 @@ private fun StatusCard(kernelVersion: KernelVersion, ksuVersion: Int?) { }) ) { val uriHandler = LocalUriHandler.current - Row( - modifier = Modifier - .fillMaxWidth() - .clickable { - if (kernelVersion.isGKI() && ksuVersion == null) { - uriHandler.openUri("https://kernelsu.org/guide/installation.html") - } + Row(modifier = Modifier + .fillMaxWidth() + .clickable { + if (kernelVersion.isGKI() && ksuVersion == null) { + uriHandler.openUri("https://kernelsu.org/guide/installation.html") } - .padding(24.dp), - verticalAlignment = Alignment.CenterVertically - ) { + } + .padding(24.dp), verticalAlignment = Alignment.CenterVertically) { when { ksuVersion != null -> { val appendText = if (Natives.isSafeMode) { @@ -168,10 +185,8 @@ private fun StatusCard(kernelVersion: KernelVersion, ksuVersion: Int?) { Spacer(Modifier.height(4.dp)) Text( text = stringResource( - R.string.home_superuser_count, - getSuperuserCount() - ), - style = MaterialTheme.typography.bodyMedium + R.string.home_superuser_count, getSuperuserCount() + ), style = MaterialTheme.typography.bodyMedium ) Spacer(Modifier.height(4.dp)) Text( @@ -217,22 +232,25 @@ private fun StatusCard(kernelVersion: KernelVersion, ksuVersion: Int?) { } @Composable -fun WarningCard(message: String) { +fun WarningCard( + message: String, color: Color = MaterialTheme.colorScheme.error, onClick: () -> Unit = {} +) { ElevatedCard( colors = CardDefaults.elevatedCardColors( - containerColor = MaterialTheme.colorScheme.error + containerColor = color ) ) { Row( modifier = Modifier .fillMaxWidth() - .padding(24.dp), - verticalAlignment = Alignment.CenterVertically + .padding(24.dp) + .clickable { + onClick() + }, verticalAlignment = Alignment.CenterVertically ) { Column() { Text( - text = message, - style = MaterialTheme.typography.bodyMedium + text = message, style = MaterialTheme.typography.bodyMedium ) } } @@ -246,15 +264,12 @@ fun LearnMoreCard() { ElevatedCard { - Row( - modifier = Modifier - .fillMaxWidth() - .clickable { - uriHandler.openUri(url) - } - .padding(24.dp), - verticalAlignment = Alignment.CenterVertically - ) { + Row(modifier = Modifier + .fillMaxWidth() + .clickable { + uriHandler.openUri(url) + } + .padding(24.dp), verticalAlignment = Alignment.CenterVertically) { Column() { Text( text = stringResource(R.string.home_learn_kernelsu), @@ -276,15 +291,12 @@ fun DonateCard() { ElevatedCard { - Row( - modifier = Modifier - .fillMaxWidth() - .clickable { - uriHandler.openUri("https://patreon.com/weishu") - } - .padding(24.dp), - verticalAlignment = Alignment.CenterVertically - ) { + Row(modifier = Modifier + .fillMaxWidth() + .clickable { + uriHandler.openUri("https://patreon.com/weishu") + } + .padding(24.dp), verticalAlignment = Alignment.CenterVertically) { Column() { Text( text = stringResource(R.string.home_support_title), @@ -323,7 +335,11 @@ private fun InfoCard() { InfoCardItem(stringResource(R.string.home_kernel), uname.release) Spacer(Modifier.height(16.dp)) - InfoCardItem(stringResource(R.string.home_manager_version), getManagerVersion(context)) + val managerVersion = getManagerVersion(context) + InfoCardItem( + stringResource(R.string.home_manager_version), + "${managerVersion.first} (${managerVersion.second})" + ) Spacer(Modifier.height(16.dp)) InfoCardItem(stringResource(R.string.home_fingerprint), Build.FINGERPRINT) @@ -334,9 +350,9 @@ private fun InfoCard() { } } -fun getManagerVersion(context: Context): String { +fun getManagerVersion(context: Context): Pair { val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0) - return "${packageInfo.versionName} (${packageInfo.versionCode})" + return Pair(packageInfo.versionName, packageInfo.versionCode) } @Preview diff --git a/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Install.kt b/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Install.kt index 72a8f7d9c4cd..c871b6ab7c4f 100644 --- a/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Install.kt +++ b/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Install.kt @@ -13,7 +13,6 @@ import androidx.compose.material.icons.filled.Refresh import androidx.compose.material.icons.filled.Save import androidx.compose.material3.* import androidx.compose.runtime.* -import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -39,8 +38,8 @@ import java.util.* @Destination fun InstallScreen(navigator: DestinationsNavigator, uri: Uri) { - var text by rememberSaveable { mutableStateOf("") } - var showFloatAction by rememberSaveable { mutableStateOf(false) } + var text by remember { mutableStateOf("") } + var showFloatAction by remember { mutableStateOf(false) } val snackBarHost = LocalSnackbarHost.current val scope = rememberCoroutineScope() diff --git a/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Module.kt b/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Module.kt index 0dbfd370729c..fd0279c28e9d 100644 --- a/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Module.kt +++ b/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Module.kt @@ -2,12 +2,15 @@ package me.weishu.kernelsu.ui.screen import android.app.Activity.RESULT_OK import android.content.Intent +import android.net.Uri import android.util.Log +import android.widget.Toast import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add @@ -16,9 +19,9 @@ import androidx.compose.material.pullrefresh.pullRefresh import androidx.compose.material.pullrefresh.rememberPullRefreshState import androidx.compose.material3.* import androidx.compose.runtime.* -import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign @@ -105,13 +108,15 @@ fun ModuleScreen(navigator: DestinationsNavigator) { ) } } + else -> { ModuleList( - viewModel = viewModel, - modifier = Modifier + viewModel = viewModel, modifier = Modifier .padding(innerPadding) .fillMaxSize() - ) + ) { + navigator.navigate(InstallScreenDestination(it)) + } } } } @@ -119,7 +124,9 @@ fun ModuleScreen(navigator: DestinationsNavigator) { @OptIn(ExperimentalMaterialApi::class) @Composable -private fun ModuleList(viewModel: ModuleViewModel, modifier: Modifier = Modifier) { +private fun ModuleList( + viewModel: ModuleViewModel, modifier: Modifier = Modifier, onInstallModule: (Uri) -> Unit +) { val failedEnable = stringResource(R.string.module_failed_to_enable) val failedDisable = stringResource(R.string.module_failed_to_disable) val failedUninstall = stringResource(R.string.module_uninstall_failed) @@ -129,8 +136,7 @@ private fun ModuleList(viewModel: ModuleViewModel, modifier: Modifier = Modifier val moduleStr = stringResource(id = R.string.module) val uninstall = stringResource(id = R.string.uninstall) val cancel = stringResource(id = android.R.string.cancel) - val moduleUninstallConfirm = - stringResource(id = R.string.module_uninstall_confirm) + val moduleUninstallConfirm = stringResource(id = R.string.module_uninstall_confirm) val dialogHost = LocalDialogHost.current val snackBarHost = LocalSnackbarHost.current @@ -166,12 +172,12 @@ private fun ModuleList(viewModel: ModuleViewModel, modifier: Modifier = Modifier } } - val refreshState = rememberPullRefreshState( - refreshing = viewModel.isRefreshing, - onRefresh = { viewModel.fetchModuleList() } - ) + val refreshState = rememberPullRefreshState(refreshing = viewModel.isRefreshing, + onRefresh = { viewModel.fetchModuleList() }) Box(modifier.pullRefresh(refreshState)) { if (viewModel.isOverlayAvailable) { + val context = LocalContext.current + LazyColumn( modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.spacedBy(16.dp), @@ -180,8 +186,7 @@ private fun ModuleList(viewModel: ModuleViewModel, modifier: Modifier = Modifier start = 16.dp, top = 16.dp, end = 16.dp, - bottom = 16.dp - + 16.dp + 56.dp /* Scaffold Fab Spacing + Fab container height */ + bottom = 16.dp + 16.dp + 56.dp /* Scaffold Fab Spacing + Fab container height */ ) }, ) { @@ -189,17 +194,23 @@ private fun ModuleList(viewModel: ModuleViewModel, modifier: Modifier = Modifier if (isEmpty) { item { Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center + modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { Text(stringResource(R.string.module_empty)) } } } else { items(viewModel.moduleList) { module -> - var isChecked by rememberSaveable(module) { mutableStateOf(module.enabled) } + var isChecked by remember(module) { mutableStateOf(module.enabled) } val scope = rememberCoroutineScope() - ModuleItem(module, isChecked, onUninstall = { + val updateUrl by produceState(initialValue = "") { + viewModel.checkUpdate(module) { value = it.orEmpty() } + } + + val downloadingText = stringResource(R.string.module_downloading) + val startDownloadingText = stringResource(R.string.module_start_downloading) + + ModuleItem(module, isChecked, updateUrl, onUninstall = { scope.launch { onModuleUninstall(module) } }, onCheckChanged = { val success = toggleModule(module.id, !isChecked) @@ -219,12 +230,37 @@ private fun ModuleList(viewModel: ModuleViewModel, modifier: Modifier = Modifier val message = if (isChecked) failedDisable else failedEnable snackBarHost.showSnackbar(message.format(module.name)) } + }, onUpdate = { + + scope.launch { + Toast.makeText( + context, + startDownloadingText.format(module.name), + Toast.LENGTH_SHORT + ).show() + } + + val downloading = downloadingText.format(module.name) + download( + context, + updateUrl, + "${module.name}-${module.version}.zip", + downloading, + onDownloaded = onInstallModule, + onDownloading = { + Toast.makeText(context, downloading, Toast.LENGTH_SHORT).show() + } + ) }) + // fix last item shadow incomplete in LazyColumn Spacer(Modifier.height(1.dp)) } } } + + DownloadListener(context, onInstallModule) + } else { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Text(stringResource(R.string.module_overlay_fs_not_available)) @@ -232,9 +268,7 @@ private fun ModuleList(viewModel: ModuleViewModel, modifier: Modifier = Modifier } PullRefreshIndicator( - refreshing = viewModel.isRefreshing, - state = refreshState, - modifier = Modifier.align( + refreshing = viewModel.isRefreshing, state = refreshState, modifier = Modifier.align( Alignment.TopCenter ) ) @@ -251,8 +285,10 @@ private fun TopBar() { private fun ModuleItem( module: ModuleViewModel.ModuleInfo, isChecked: Boolean, + updateUrl: String, onUninstall: (ModuleViewModel.ModuleInfo) -> Unit, - onCheckChanged: (Boolean) -> Unit + onCheckChanged: (Boolean) -> Unit, + onUpdate: (ModuleViewModel.ModuleInfo) -> Unit, ) { ElevatedCard( modifier = Modifier.fillMaxWidth(), @@ -334,6 +370,23 @@ private fun ModuleItem( ) { Spacer(modifier = Modifier.weight(1f, true)) + if (updateUrl.isNotEmpty()) { + Button( + modifier = Modifier + .padding(0.dp) + .defaultMinSize(52.dp, 32.dp), + onClick = { onUpdate(module) }, + shape = RoundedCornerShape(6.dp), + contentPadding = PaddingValues(0.dp) + ) { + Text( + fontFamily = MaterialTheme.typography.labelMedium.fontFamily, + fontSize = MaterialTheme.typography.labelMedium.fontSize, + text = stringResource(R.string.module_update), + ) + } + } + TextButton( enabled = !module.remove, onClick = { onUninstall(module) }, @@ -362,6 +415,7 @@ fun ModuleItemPreview() { enabled = true, update = true, remove = true, + updateJson = "" ) - ModuleItem(module, true, {}, {}) + ModuleItem(module, true, "", {}, {}, {}) } \ No newline at end of file diff --git a/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/util/Downloader.kt b/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/util/Downloader.kt new file mode 100644 index 000000000000..7fb0720dc5b4 --- /dev/null +++ b/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/util/Downloader.kt @@ -0,0 +1,133 @@ +package me.weishu.kernelsu.ui.util + +import android.annotation.SuppressLint +import android.app.DownloadManager +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.net.Uri +import android.os.Environment +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect + +/** + * @author weishu + * @date 2023/6/22. + */ +@SuppressLint("Range") +fun download( + context: Context, + url: String, + fileName: String, + description: String, + onDownloaded: (Uri) -> Unit = {}, + onDownloading: () -> Unit = {} +) { + val downloadManager = + context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager + + val query = DownloadManager.Query() + query.setFilterByStatus(DownloadManager.STATUS_RUNNING or DownloadManager.STATUS_PAUSED or DownloadManager.STATUS_PENDING) + downloadManager.query(query).use { cursor -> + while (cursor.moveToNext()) { + val uri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_URI)) + val localUri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)) + val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) + val columnTitle = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_TITLE)) + if (url == uri || fileName == columnTitle) { + if (status == DownloadManager.STATUS_RUNNING || status == DownloadManager.STATUS_PENDING) { + onDownloading() + return + } else if (status == DownloadManager.STATUS_SUCCESSFUL) { + onDownloaded(Uri.parse(localUri)) + return + } + } + } + } + + val request = DownloadManager.Request(Uri.parse(url)) + .setDestinationInExternalPublicDir( + Environment.DIRECTORY_DOWNLOADS, + fileName + ) + .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) + .setMimeType("application/zip") + .setTitle(fileName) + .setDescription(description) + + downloadManager.enqueue(request) +} + +fun checkNewVersion(): Pair { + val url = "https://api.github.com/repos/tiann/KernelSU/releases/latest" + val defaultValue = 0 to "" + runCatching { + okhttp3.OkHttpClient().newCall(okhttp3.Request.Builder().url(url).build()).execute() + .use { response -> + if (!response.isSuccessful) { + return defaultValue + } + val body = response.body?.string() ?: return defaultValue + val json = org.json.JSONObject(body) + + val assets = json.getJSONArray("assets") + for (i in 0 until assets.length()) { + val asset = assets.getJSONObject(i) + val name = asset.getString("name") + if (!name.endsWith(".apk")) { + continue + } + + val regex = Regex("v(.+?)_(\\d+)-") + val matchResult = regex.find(name) ?: continue + val versionName = matchResult.groupValues[1] + val versionCode = matchResult.groupValues[2].toInt() + val downloadUrl = asset.getString("browser_download_url") + + return versionCode to downloadUrl + } + + } + } + return defaultValue +} + +@Composable +fun DownloadListener(context: Context, onDownloaded: (Uri) -> Unit) { + DisposableEffect(context) { + val receiver = object : BroadcastReceiver() { + @SuppressLint("Range") + override fun onReceive(context: Context?, intent: Intent?) { + if (intent?.action == DownloadManager.ACTION_DOWNLOAD_COMPLETE) { + val id = intent.getLongExtra( + DownloadManager.EXTRA_DOWNLOAD_ID, -1 + ) + val query = DownloadManager.Query().setFilterById(id) + val downloadManager = + context?.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager + val cursor = downloadManager.query(query) + if (cursor.moveToFirst()) { + val status = cursor.getInt( + cursor.getColumnIndex(DownloadManager.COLUMN_STATUS) + ) + if (status == DownloadManager.STATUS_SUCCESSFUL) { + val uri = cursor.getString( + cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI) + ) + onDownloaded(Uri.parse(uri)) + } + } + } + } + } + context.registerReceiver( + receiver, + IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE) + ) + onDispose { + context.unregisterReceiver(receiver) + } + } +} \ No newline at end of file diff --git a/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt b/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt index 5805e4603aaf..1a204fd06d64 100644 --- a/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt +++ b/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt @@ -140,4 +140,14 @@ fun hasMagisk(): Boolean { val result = shell.newJob().add("nsenter --mount=/proc/1/ns/mnt which magisk").exec() Log.i(TAG, "has magisk: ${result.isSuccess}") return result.isSuccess +} + +fun isSepolicyValid(rules: String?): Boolean { + if (rules == null) { + return true + } + val shell = getRootShell() + val result = + shell.newJob().add("ksud sepolicy check '$rules'").to(ArrayList(), null).exec() + return result.isSuccess } \ No newline at end of file diff --git a/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt b/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt index 3d2a6e61cd72..f73a42eed0d2 100644 --- a/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt +++ b/KernelSU/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt @@ -1,5 +1,6 @@ package me.weishu.kernelsu.ui.viewmodel +import android.net.Uri import android.os.SystemClock import android.util.Log import androidx.compose.runtime.derivedStateOf @@ -13,6 +14,7 @@ import kotlinx.coroutines.launch import me.weishu.kernelsu.ui.util.listModules import me.weishu.kernelsu.ui.util.overlayFsAvailable import org.json.JSONArray +import org.json.JSONObject import java.text.Collator import java.util.* @@ -33,6 +35,14 @@ class ModuleViewModel : ViewModel() { val enabled: Boolean, val update: Boolean, val remove: Boolean, + val updateJson: String, + ) + + data class ModuleUpdateInfo( + val version: String, + val versionCode: Int, + val zipUrl: String, + val changelog: String, ) var isRefreshing by mutableStateOf(false) @@ -78,6 +88,7 @@ class ModuleViewModel : ViewModel() { obj.getBoolean("enabled"), obj.getBoolean("update"), obj.getBoolean("remove"), + obj.optString("updateJson", "") ) }.toList() }.onFailure { e -> @@ -94,4 +105,57 @@ class ModuleViewModel : ViewModel() { Log.i(TAG, "load cost: ${SystemClock.elapsedRealtime() - start}, modules: $modules") } } + + fun checkUpdate(m: ModuleInfo, callback: (String?) -> Unit) { + if (m.updateJson.isEmpty()) { + callback(null) + return + } + viewModelScope.launch(Dispatchers.IO) { + // download updateJson + val result = kotlin.runCatching { + val url = m.updateJson + Log.i(TAG, "checkUpdate url: $url") + val response = okhttp3.OkHttpClient() + .newCall( + okhttp3.Request.Builder() + .url(url) + .build() + ).execute() + Log.d(TAG, "checkUpdate code: ${response.code}") + if (response.isSuccessful) { + response.body?.string() ?: "" + } else { + "" + } + }.getOrDefault("") + Log.i(TAG, "checkUpdate result: $result") + + if (result.isEmpty()) { + callback(null) + return@launch + } + + val updateJson = kotlin.runCatching { + JSONObject(result) + }.getOrNull() + + if (updateJson == null) { + callback(null) + return@launch + } + + val version = updateJson.optString("version", "") + val versionCode = updateJson.optInt("versionCode", 0) + val zipUrl = updateJson.optString("zipUrl", "") + val changelog = updateJson.optString("changelog", "") + if (versionCode <= m.versionCode || zipUrl.isEmpty()) { + callback(null) + return@launch + } + + callback(zipUrl) + } + } + } diff --git a/KernelSU/manager/app/src/main/res/values-in/strings.xml b/KernelSU/manager/app/src/main/res/values-in/strings.xml index 0fc5d733a997..181bd005ff94 100644 --- a/KernelSU/manager/app/src/main/res/values-in/strings.xml +++ b/KernelSU/manager/app/src/main/res/values-in/strings.xml @@ -65,5 +65,13 @@ Diwariskan Universal Personal + Kelompok + Kemampuan + Konteks SELinux Lepas modul + Gagal memperbarui Profil Apl untuk %s + Versi kernel saat ini %d terlalu rendah bagi manager untuk berfungsi dengan baik. Tolong tingkatkan ke versi %d atau lebih tinggi! + Lepas modul secara bawaan + Nilai bawaan universal untuk \"Lepas modul\" di Profil-profil Apl. Jika diaktifkan, ini akan menghapus semua modifikasi modul pada sistem untuk aplikasi yang tidak memiliki set Profil. + Mengaktifkan opsi ini akan mengizinkan KernelSU memulihkan file-file yang dimodifikasi oleh modul untuk aplikasi ini. diff --git a/KernelSU/manager/app/src/main/res/values-nl/strings.xml b/KernelSU/manager/app/src/main/res/values-nl/strings.xml index d55e89e59f4f..5a3e018c2339 100644 --- a/KernelSU/manager/app/src/main/res/values-nl/strings.xml +++ b/KernelSU/manager/app/src/main/res/values-nl/strings.xml @@ -44,8 +44,8 @@ Auteur overlayfs is niet beschikbaar, module kan niet werken! Vernieuwen - Toon system apps - Verberg system apps + Toon systeem apps + Verberg systeem apps Stuur Log Safe mode Herstart om effect te hebben @@ -65,10 +65,18 @@ Overgenomen Globaal Individuëel + Groepen + Mogelijkheden + SELinux context Ontkoppel modules Mislukt om App Profiel te updaten voor %s De bestaande kernel versie %d is te laag voor de manager om goed te werken. Upgrade best tot versie %d of hoger! Ontkoppel standaard de modules - De globale standaard waarde voor \"Ontkoppel modules\" in App Profielen. Indien geactiveerd, zal het alle module wijzigingen tot het systeeem verwijderen voor applicaties die geen Profiel ingesteld hebben. - Deze optie ingeschakeld zal KernelSU toelaten om alle gewijzigde bestanden door de modules voor deze applicatie te herstellen. + De globale standaard waarde voor \"Ontkoppel modules\" in App Profielen. Indien geactiveerd, zal het alle module wijzigingen tot het systeem verwijderen voor applicaties die geen Profiel ingesteld hebben. + Met deze optie ingeschakeld zal KernelSU toelaten om alle gewijzigde bestanden door de modules voor deze applicatie te herstellen. + Domein + Regels + Update + Downloaden van module: %s + Nieuwe versie: %s is beschikbaar, klik om te downloaden diff --git a/KernelSU/manager/app/src/main/res/values-pt-rBR/strings.xml b/KernelSU/manager/app/src/main/res/values-pt-rBR/strings.xml index 32e8b62e6509..9117ad92d3c9 100644 --- a/KernelSU/manager/app/src/main/res/values-pt-rBR/strings.xml +++ b/KernelSU/manager/app/src/main/res/values-pt-rBR/strings.xml @@ -4,11 +4,11 @@ Início Não instalado Clique para instalar - Trabalhando + Em Execução Versão: %d Superusuários: %d Módulos: %d - Sem suporte + Sem Suporte Por enquanto, KernelSU suporta apenas kernels GKI Kernel @@ -17,8 +17,8 @@ Status do SELinux Desabilitado - Impondo - Permissivo + Enforcing + Permissive Desconhecido Superusuário Falha ao ativar o módulo: %s @@ -33,41 +33,44 @@ Configurações Reinicialização suave Reiniciar para recuperação - Reinicializar para bootloader - Reinicializar para download - Reinicializar para EDL + Reiniciar para bootloader + Reiniciar para download + Reiniciar para EDL Sobre Tem certeza de que deseja desinstalar o módulo %s? %s desinstalado Falha ao desinstalar: %s Versão Autor - overlayfs não está disponível, o módulo não funcioná! + overlayfs não está disponível, o módulo não funcionará! Atualizar Mostrar aplicativos do sistema Ocultar aplicativos do sistema Enviar log Modo de segurança Reinicie para entrar em vigor - Os módulos estão desativados porque estão em conflito com o Magisk\'s! + Os módulos estão desativados porque entraram em conflito com o Magisk\'s! Leia mais sobre KernelSU https://kernelsu.org/guide/what-is-kernelsu.html Saiba como instalar o KernelSU e usar os módulos Apoie-nos - O KernelSU é, e sempre será, gratuito e de código aberto. No entanto, você pode nos mostrar que se importa fazendo uma doação. - Junte-se ao nosso %2$s canal]]> - Perfil do aplicativo + O KernelSU é, e sempre será, gratuito e de código aberto. No entanto, você pode mostrar seu apoio fazendo uma doação. + Junte-se ao nosso canal do %2$s]]> + Perfil do Aplicativo Padrão Modelo Personalizado Nome do perfil Montar namespace - incluído + Padrão Global Individual + Grupos + Permissões + Contexto do SELinux Módulos não montados Falha ao atualizar o perfil do aplicativo para %s - A versão atual do kernel %d é muito baixo para o gerenciador funcionar corretamente. Atualize para a versão %d ou superior! + A versão atual do kernel %d é muito baixa para o gerenciador funcionar corretamente. Atualize para a versão %d ou superior! Não montar módulos por padrão O valor padrão global para \"Módulos não montados\" em perfis de aplicativos. Se ativado, removerá todas as modificações do módulo do sistema para aplicativos que não possuem um perfil definido. Ativar esta opção permitirá que o KernelSU restaure quaisquer arquivos modificados pelos módulos para este aplicativo. diff --git a/KernelSU/manager/app/src/main/res/values-ro/strings.xml b/KernelSU/manager/app/src/main/res/values-ro/strings.xml index 5e8c91455ab2..5421fdfb51ec 100644 --- a/KernelSU/manager/app/src/main/res/values-ro/strings.xml +++ b/KernelSU/manager/app/src/main/res/values-ro/strings.xml @@ -24,7 +24,7 @@ Dezactivarea modulului %s a eșuat Niciun modul instalat - Modul + Module Dezinstalează Instalează Instalează @@ -63,10 +63,15 @@ Moștenit Global Individual + Grupuri + Capabilități + Context SELinux Module u-montate Nu s-a putut actualiza profilul aplicației pentru %s Versiunea actuală a nucleului %d este prea mică pentru ca managerul să funcționeze corect. Actualizează la versiunea %d sau o versiune superioară! U-montează modulele în mod implicit Valoarea implicită globală pentru „Module u-montate” în Profilurile aplicațiilor. Dacă este activat, va elimina toate modificările modulelor aduse sistemului pentru aplicațiile care nu au un profil setat. Activarea acestei opțiuni va permite KernelSU să restaureze orice fișiere modificate de către modulele pentru această aplicație. + Domeniu + Reguli diff --git a/KernelSU/manager/app/src/main/res/values-ru/strings.xml b/KernelSU/manager/app/src/main/res/values-ru/strings.xml index 72e61460d931..0aa6768710cd 100644 --- a/KernelSU/manager/app/src/main/res/values-ru/strings.xml +++ b/KernelSU/manager/app/src/main/res/values-ru/strings.xml @@ -1,16 +1,18 @@ + KernelSU + Главная Не установлен Нажмите чтобы установить Работает Версия: %d - Superusers: %d + Superusers: %d Модули: %d Не поддерживается KernelSU поддерживает только GKI ядра Ядро - Версия + Версия менеджера Подпись Состояние SELinux @@ -18,7 +20,7 @@ Принудительный Разрешающий Неизвестно - Superuser + Superuser Не удалось включить модуль: %s Не удалось отключить модуль: %s Нет установленных модулей @@ -26,32 +28,50 @@ Модули Удалить Установить - Установить - Перезагрузка + Установка + Перезагрузить Настройки - Soft Reboot - Reboot to Recovery - Reboot to Bootloader - Reboot to Download - Reboot to EDL - О KernelSU + Мягкая перезагрузка + Перезагрузить в Recovery + Перезагрузить в Bootloader + Перезагрузить в Download + Перезагрузить в EDL + О приложении Вы уверены, что хотите удалить модуль %s? %s удален Не удалось удалить: %s Версия Автор - overlayfs выключен, модуль не будет работать! + overlayfs недоступен, модуль не может работать! Обновить Показать системные приложения Скрыть системные приложения Отправить лог Безопасный режим - Перезагрузите, чтобы вступить в силу - Модули отключены, потому что они конфликтуют с модулями Magisk! + Перезагрузите, чтобы изменения вступили в силу + Модули отключены, потому что они конфликтуют с Magisk! Узнайте о KernelSU https://kernelsu.org/guide/what-is-kernelsu.html Узнайте, как установить KernelSU и использовать модули Поддержите нас KernelSU был и всегда будет бесплатным и открытым проектом. Однако Вы всегда можете поддержать нас, отправив небольшое пожертвование. - Присоединяйтесь к каналу %2$s]]> + Присоединяйтесь к нашему %2$s каналу]]> + App Profile + По умолчанию + Шаблон + Пользовательский + Название профиля + Монтировать пространство имен + Унаследованный + Глобальный + Индивидуальный + Группы + Возможности + Контекст SELinux + Размонтировать модули + Не удалось обновить App Profile для %s + Текущая версия ядра %d слишком низкая для правильной работы менеджера. Пожалуйста, обновитесь до версии %d или выше! + Размонтировать модули по умолчанию + Глобальное значение по умолчанию для \"Размонтировать модули\" в App Profile. При включении будут удалены все модификации модулей в системе для приложений, у которых не задан Profile. + Включение этой опции позволит KernelSU восстанавливать любые измененные модулями файлы для данного приложения. diff --git a/KernelSU/manager/app/src/main/res/values-tr/strings.xml b/KernelSU/manager/app/src/main/res/values-tr/strings.xml index 8f6b5dea74db..a691162a8554 100644 --- a/KernelSU/manager/app/src/main/res/values-tr/strings.xml +++ b/KernelSU/manager/app/src/main/res/values-tr/strings.xml @@ -15,8 +15,8 @@ SELinux Durumu Devre dışı - Zorunlu - Serbest + Enforcing + Permissive Bilinmiyor Süper kullanıcı Modül etkinleştirilemedi: %s @@ -63,5 +63,19 @@ Kalıtsal Küresel Bireysel + Gruplar + Yetkiler + SELinux içeriği Modüllerin bağlantısını kes + %s için uygulama profili güncellenemedi. + Mevcut kernel versiyonu %d yöneticinin düzgün çalışabilmesi için çok düşük. Lütfen %d veya yukarısına yükseltin! + Varsayılan olarak modüllerin bağlantısını kesin + Uygulama profillerindeki \"Modüllerin bağlantısını kesme\" seçeneği için varsayılan değer. Etkinleştirilirse, profil ayarı yapılmamış uygulamalar için modüllerin sistemde yaptığı tüm değişiklikler kaldırılacaktır. + Bu seçeneğin etkinleştirilmesi ile, bu uygulama için modüller tarafından değiştirilen tüm dosyaların KernelSU tarafından geri alınmasına izin verilecektir. + Etki alanı + Kurallar + Güncelle + Modül indiriliyor: %s + İndirme başladı: %s + Yeni versiyon: %s mevcut, indirmek için tıklayın diff --git a/KernelSU/manager/app/src/main/res/values-uk/strings.xml b/KernelSU/manager/app/src/main/res/values-uk/strings.xml index d217e63b51b4..6525ec03f52b 100644 --- a/KernelSU/manager/app/src/main/res/values-uk/strings.xml +++ b/KernelSU/manager/app/src/main/res/values-uk/strings.xml @@ -65,6 +65,9 @@ Наслідуваний Глобальний Індивідуальний + Групи + Можливості + Контекст SELinux Розмонтувати модулі Не вдалося оновити профіль додатка для %s Поточна версія ядра %d занизька для належної роботи менджера. Будь ласка, оновіть до версії %d або вище! diff --git a/KernelSU/manager/app/src/main/res/values-zh-rCN/strings.xml b/KernelSU/manager/app/src/main/res/values-zh-rCN/strings.xml index 8cf8836ee71e..a28da33f6bc0 100644 --- a/KernelSU/manager/app/src/main/res/values-zh-rCN/strings.xml +++ b/KernelSU/manager/app/src/main/res/values-zh-rCN/strings.xml @@ -52,10 +52,27 @@ 支持开发 KernelSU 将保持免费和开源,向开发者捐赠以表示支持。 加入我们的 %2$s 频道
加入我们的 QQ 频道]]>
+ 默认 + 模版 + 自定义 + 名称 + 命名空间 + 继承 + 全局 + 私有 + + 权能 + SELinux 卸载模块 为 %s 更新 App Profile 失败 当前内核版本 %d 过低,管理器无法正常工作,请升级内核版本至 %d 或以上! 默认卸载模块 App Profile 中\"卸载模块\"的全局默认值,如果启用,将会为没有设置 Profile 的应用移除所有模块针对系统的修改 启用后将允许 KernelSU 为本应用还原被模块修改过的文件 + + 规则 + 更新 + 正在下载模块:%s + 开始下载:%s + 发现新版本:%d,点击下载 diff --git a/KernelSU/manager/app/src/main/res/values/strings.xml b/KernelSU/manager/app/src/main/res/values/strings.xml index 0aa317585745..a8cfc1405e65 100644 --- a/KernelSU/manager/app/src/main/res/values/strings.xml +++ b/KernelSU/manager/app/src/main/res/values/strings.xml @@ -56,7 +56,7 @@ Support Us KernelSU is, and always will be, free, and open source. You can however show us that you care by making a donation. Join our %2$s channel]]> - App profile + App Profile Default Template Custom @@ -65,10 +65,19 @@ Inherited Global Individual - Umoun modules + Groups + Capabilities + SELinux context + Umount modules Failed to update App Profile for %s The current kernel version %d is too low for the manager to function properly. Please upgrade to version %d or higher! Umount modules by default The global default value for \"Umount modules\" in App Profiles. If enabled, it will remove all module modifications to the system for applications that do not have a Profile set. Enabling this option will allow KernelSU to restore any modified files by the modules for this application. + Domain + Rules + Update + Downloading module: %s + Start downloading: %s + New version: %s is available, click to download diff --git a/KernelSU/manager/gradle/libs.versions.toml b/KernelSU/manager/gradle/libs.versions.toml index c8e6e4e21d61..b995ccffcd45 100644 --- a/KernelSU/manager/gradle/libs.versions.toml +++ b/KernelSU/manager/gradle/libs.versions.toml @@ -8,7 +8,7 @@ accompanist = "0.30.0" navigation = "2.5.3" compose-destination = "1.9.42-beta" libsu = "5.0.5" -sheets-compose-dialogs = "1.1.1" +sheets-compose-dialogs = "1.2.0" [plugins] agp-app = { id = "com.android.application", version.ref = "agp" } @@ -55,3 +55,4 @@ compose-destinations-ksp = { group = "io.github.raamcosta.compose-destinations", sheet-compose-dialogs-core = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "core", version.ref = "sheets-compose-dialogs"} sheet-compose-dialogs-list = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "list", version.ref = "sheets-compose-dialogs"} +sheet-compose-dialogs-input = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "input", version.ref = "sheets-compose-dialogs"} diff --git a/KernelSU/userspace/ksud/src/defs.rs b/KernelSU/userspace/ksud/src/defs.rs index 5499e205fdaa..4539e756ab8f 100644 --- a/KernelSU/userspace/ksud/src/defs.rs +++ b/KernelSU/userspace/ksud/src/defs.rs @@ -24,6 +24,7 @@ pub const MODULE_UPDATE_TMP_DIR: &str = concatcp!(ADB_DIR, "modules_update/"); pub const DISABLE_FILE_NAME: &str = "disable"; pub const UPDATE_FILE_NAME: &str = "update"; pub const REMOVE_FILE_NAME: &str = "remove"; +pub const SKIP_MOUNT_FILE_NAME: &str = "skip_mount"; pub const VERSION_CODE: &str = include_str!(concat!(env!("OUT_DIR"), "/VERSION_CODE")); pub const VERSION_NAME: &str = include_str!(concat!(env!("OUT_DIR"), "/VERSION_NAME")); diff --git a/KernelSU/userspace/ksud/src/event.rs b/KernelSU/userspace/ksud/src/event.rs index 0c34b3db9bef..fa9e5eb23b47 100644 --- a/KernelSU/userspace/ksud/src/event.rs +++ b/KernelSU/userspace/ksud/src/event.rs @@ -50,6 +50,11 @@ pub fn mount_systemlessly(module_dir: &str) -> Result<()> { info!("module: {} is disabled, ignore!", module.display()); continue; } + let skip_mount = module.join(defs::SKIP_MOUNT_FILE_NAME).exists(); + if skip_mount { + info!("module: {} skip_mount exist, skip!", module.display()); + continue; + } let module_system = Path::new(&module).join("system"); if module_system.is_dir() { diff --git a/KernelSU/userspace/ksud/src/ksu.rs b/KernelSU/userspace/ksud/src/ksu.rs index 170402cf32e6..855cc76f373b 100644 --- a/KernelSU/userspace/ksud/src/ksu.rs +++ b/KernelSU/userspace/ksud/src/ksu.rs @@ -75,8 +75,21 @@ pub fn root_shell() -> Result<()> { #[cfg(unix)] pub fn root_shell() -> Result<()> { // we are root now, this was set in kernel! - let args: Vec = std::env::args().collect(); - let program = args[0].clone(); + let env_args: Vec = std::env::args().collect(); + let program = env_args[0].clone(); + let args = env_args + .iter() + .position(|arg| arg == "-c") + .map(|i| { + let rest = env_args[i + 1..].to_vec(); + let mut new_args = env_args[..i].to_vec(); + new_args.push("-c".to_string()); + if !rest.is_empty() { + new_args.push(rest.join(" ")); + } + new_args + }) + .unwrap_or_else(|| env_args.clone()); let mut opts = Options::new(); opts.optopt( diff --git a/KernelSU/userspace/ksud/src/module.rs b/KernelSU/userspace/ksud/src/module.rs index 0da9a926ef4f..1711a96d1fe3 100644 --- a/KernelSU/userspace/ksud/src/module.rs +++ b/KernelSU/userspace/ksud/src/module.rs @@ -362,7 +362,7 @@ fn _install_module(zip: &str) -> Result<()> { std::fs::remove_file(tmp_module_path)?; } - let default_reserve_size = 64 * 1024 * 1024; + let default_reserve_size = 256 * 1024 * 1024; let zip_uncompressed_size = get_zip_uncompressed_size(zip)?; let grow_size = default_reserve_size + zip_uncompressed_size; diff --git a/KernelSU/website/docs/guide/how-to-integrate-for-non-gki.md b/KernelSU/website/docs/guide/how-to-integrate-for-non-gki.md index 7528fa3273ee..a5319333191b 100644 --- a/KernelSU/website/docs/guide/how-to-integrate-for-non-gki.md +++ b/KernelSU/website/docs/guide/how-to-integrate-for-non-gki.md @@ -75,14 +75,20 @@ index ac59664eaecf..bdd585e1d2cc 100644 return retval; } ++extern bool ksu_execveat_hook __read_mostly; +extern int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv, + void *envp, int *flags); ++extern int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, ++ void *argv, void *envp, int *flags); static int do_execveat_common(int fd, struct filename *filename, struct user_arg_ptr argv, struct user_arg_ptr envp, int flags) { -+ ksu_handle_execveat(&fd, &filename, &argv, &envp, &flags); ++ if (unlikely(ksu_execveat_hook)) ++ ksu_handle_execveat(&fd, &filename, &argv, &envp, &flags); ++ else ++ ksu_handle_execveat_sucompat(&fd, &filename, &argv, &envp, &flags); return __do_execve_file(fd, filename, argv, envp, flags, NULL); } @@ -115,14 +121,16 @@ index 650fc7e0f3a6..55be193913b6 100644 } EXPORT_SYMBOL(kernel_read); ++extern bool ksu_vfs_read_hook __read_mostly; +extern int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr, + size_t *count_ptr, loff_t **pos); ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { ssize_t ret; -+ ksu_handle_vfs_read(&file, &buf, &count, &pos); -+ ++ if (unlikely(ksu_vfs_read_hook)) ++ ksu_handle_vfs_read(&file, &buf, &count, &pos); ++ if (!(file->f_mode & FMODE_READ)) return -EBADF; if (!(file->f_mode & FMODE_CAN_READ)) @@ -222,19 +230,22 @@ index 45306f9ef247..815091ebfca4 100755 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -367,10 +367,13 @@ static int input_get_disposition(struct input_dev *dev, - return disposition; + return disposition; } - + ++extern bool ksu_input_hook __read_mostly; +extern int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, int *value); + static void input_handle_event(struct input_dev *dev, - unsigned int type, unsigned int code, int value) + unsigned int type, unsigned int code, int value) { - int disposition = input_get_disposition(dev, type, code, &value); -+ ksu_handle_input_handle_event(&type, &code, &value); - - if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN) - add_input_randomness(type, code, value); + int disposition = input_get_disposition(dev, type, code, &value); ++ ++ if (unlikely(ksu_input_hook)) ++ ksu_handle_input_handle_event(&type, &code, &value); + + if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN) + add_input_randomness(type, code, value); ``` Finally, build your kernel again, KernelSU should works well. diff --git a/KernelSU/website/docs/guide/installation.md b/KernelSU/website/docs/guide/installation.md index 1776d8a9926b..42b05c848eed 100644 --- a/KernelSU/website/docs/guide/installation.md +++ b/KernelSU/website/docs/guide/installation.md @@ -125,7 +125,7 @@ After flashing is complete, you should reboot your device: fastboot reboot ``` -## Patch boot.img manully +## Patch boot.img manually For some devices, the boot.img format is not so common, such as not `lz4`, `gz` and uncompressed; the most typical is Pixel, its boot.img format is `lz4_legacy` compressed, ramdisk may be `gz` may also be `lz4_legacy` compression; at this time, if you directly flash the boot.img provided by KernelSU, the phone may not be able to boot; at this time, you can manually patch the boot.img to achieve. diff --git a/KernelSU/website/docs/id_ID/guide/how-to-integrate-for-non-gki.md b/KernelSU/website/docs/id_ID/guide/how-to-integrate-for-non-gki.md index eba6d09e6192..8fcd3c9fa4c3 100644 --- a/KernelSU/website/docs/id_ID/guide/how-to-integrate-for-non-gki.md +++ b/KernelSU/website/docs/id_ID/guide/how-to-integrate-for-non-gki.md @@ -69,18 +69,24 @@ index ac59664eaecf..bdd585e1d2cc 100644 @@ -1890,11 +1890,14 @@ static int __do_execve_file(int fd, struct filename *filename, return retval; } - + ++extern bool ksu_execveat_hook __read_mostly; +extern int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv, + void *envp, int *flags); ++extern int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, ++ void *argv, void *envp, int *flags); static int do_execveat_common(int fd, struct filename *filename, struct user_arg_ptr argv, struct user_arg_ptr envp, int flags) { -+ ksu_handle_execveat(&fd, &filename, &argv, &envp, &flags); ++ if (unlikely(ksu_execveat_hook)) ++ ksu_handle_execveat(&fd, &filename, &argv, &envp, &flags); ++ else ++ ksu_handle_execveat_sucompat(&fd, &filename, &argv, &envp, &flags); return __do_execve_file(fd, filename, argv, envp, flags, NULL); } - + diff --git a/fs/open.c b/fs/open.c index 05036d819197..965b84d486b8 100644 --- a/fs/open.c @@ -88,7 +94,7 @@ index 05036d819197..965b84d486b8 100644 @@ -348,6 +348,8 @@ SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len) return ksys_fallocate(fd, mode, offset, len); } - + +extern int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode, + int *flags); /* @@ -109,14 +115,16 @@ index 650fc7e0f3a6..55be193913b6 100644 @@ -434,10 +434,14 @@ ssize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos) } EXPORT_SYMBOL(kernel_read); - + ++extern bool ksu_vfs_read_hook __read_mostly; +extern int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr, + size_t *count_ptr, loff_t **pos); ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { ssize_t ret; - -+ ksu_handle_vfs_read(&file, &buf, &count, &pos); + ++ if (unlikely(ksu_vfs_read_hook)) ++ ksu_handle_vfs_read(&file, &buf, &count, &pos); + if (!(file->f_mode & FMODE_READ)) return -EBADF; @@ -128,7 +136,7 @@ index 376543199b5a..82adcef03ecc 100644 @@ -148,6 +148,8 @@ int vfs_statx_fd(unsigned int fd, struct kstat *stat, } EXPORT_SYMBOL(vfs_statx_fd); - + +extern int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags); + /** @@ -137,7 +145,7 @@ index 376543199b5a..82adcef03ecc 100644 @@ -170,6 +172,7 @@ int vfs_statx(int dfd, const char __user *filename, int flags, int error = -EINVAL; unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT; - + + ksu_handle_stat(&dfd, &filename, &flags); if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT | AT_EMPTY_PATH | KSTAT_QUERY_FLAGS)) != 0) @@ -217,19 +225,22 @@ index 45306f9ef247..815091ebfca4 100755 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -367,10 +367,13 @@ static int input_get_disposition(struct input_dev *dev, - return disposition; + return disposition; } - + ++extern bool ksu_input_hook __read_mostly; +extern int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, int *value); + static void input_handle_event(struct input_dev *dev, - unsigned int type, unsigned int code, int value) + unsigned int type, unsigned int code, int value) { - int disposition = input_get_disposition(dev, type, code, &value); -+ ksu_handle_input_handle_event(&type, &code, &value); - - if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN) - add_input_randomness(type, code, value); + int disposition = input_get_disposition(dev, type, code, &value); ++ ++ if (unlikely(ksu_input_hook)) ++ ksu_handle_input_handle_event(&type, &code, &value); + + if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN) + add_input_randomness(type, code, value); ``` Terakhir, edit `KernelSU/kernel/ksu.c` dan beri komentar pada `enable_sucompat()` lalu build kernel Anda lagi, KernelSU akan bekerja dengan baik. diff --git a/KernelSU/website/docs/repos.json b/KernelSU/website/docs/repos.json index b0f0729cf55c..d29c72edd208 100644 --- a/KernelSU/website/docs/repos.json +++ b/KernelSU/website/docs/repos.json @@ -105,11 +105,11 @@ "devices": "Mi 8 (dipper) for LineageOS" }, { - "maintainer": "WeeAris", - "maintainer_link": "https://github.com/WeeAris", - "kernel_name": "Realking_su_xiaomi_sm8250", - "kernel_link": "https://github.com/WeeAris/Realking_su_xiaomi_sm8250", - "devices": "Apollo(Redmi K30S Ultra/Mi 10T/Mi 10T Pro)\uff0cAlioth(Redmi K40/POCO F3/Mi 11X)\uff0cMunch(Redmi K40S/POCO F4), repo for AOSP only." + "maintainer": "Rohail33", + "maintainer_link": "https://github.com/Rohail33", + "kernel_name": "RealKing Kernel", + "kernel_link": "https://github.com/Rohail33/Realking_kernel_sm8250", + "devices": "Apollo(Redmi K30S Ultra/Mi 10T/Mi 10T Pro)\uff0cAlioth(Redmi K40/POCO F3/Mi 11X)\uff0cMunch(Redmi K40S/POCO F4), both MIUI and AOSP." }, { "maintainer": "lateautumn233", @@ -341,5 +341,19 @@ "kernel_name": "android_kernel_samsung_exynos9610_mint", "kernel_link": "https://github.com/rushiranpise/android_kernel_samsung_exynos9610_mint", "devices": "Kernel 4.14.194 exynos9610 Non-GKI Device, Added KernelSu using manual method" + }, + { + "maintainer": "CN-Scars", + "maintainer_link": "https://github.com/CN-Scars", + "kernel_name": "pixel_experience_kernel_xiaomi_sm8250_kernelSU", + "kernel_link": "https://github.com/CN-Scars/pixel_experience_kernel_xiaomi_sm8250_kernelSU", + "devices": "Pixel Experience Kernel 4.19.282 for Xiaomi Redmi K40S / Xiaomi Poco F4 (munch)" + }, + { + "maintainer": "exer", + "maintainer_link": "https://github.com/ekkusa", + "kernel_name": "Miyo Toku", + "kernel_link": "https://github.com/Miiyo/android_kernel_sony_sdm845/tree/KSU/Toku", + "devices": "Sony Tama (akari, apollo, aurora, akatsuki) (Linux 4.9)" } -] \ No newline at end of file +] diff --git a/KernelSU/website/docs/vi_VN/guide/how-to-integrate-for-non-gki.md b/KernelSU/website/docs/vi_VN/guide/how-to-integrate-for-non-gki.md index d27c5ff00f17..c188b1f2da21 100644 --- a/KernelSU/website/docs/vi_VN/guide/how-to-integrate-for-non-gki.md +++ b/KernelSU/website/docs/vi_VN/guide/how-to-integrate-for-non-gki.md @@ -71,14 +71,20 @@ index ac59664eaecf..bdd585e1d2cc 100644 return retval; } ++extern bool ksu_execveat_hook __read_mostly; +extern int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv, + void *envp, int *flags); ++extern int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, ++ void *argv, void *envp, int *flags); static int do_execveat_common(int fd, struct filename *filename, struct user_arg_ptr argv, struct user_arg_ptr envp, int flags) { -+ ksu_handle_execveat(&fd, &filename, &argv, &envp, &flags); ++ if (unlikely(ksu_execveat_hook)) ++ ksu_handle_execveat(&fd, &filename, &argv, &envp, &flags); ++ else ++ ksu_handle_execveat_sucompat(&fd, &filename, &argv, &envp, &flags); return __do_execve_file(fd, filename, argv, envp, flags, NULL); } @@ -111,14 +117,16 @@ index 650fc7e0f3a6..55be193913b6 100644 } EXPORT_SYMBOL(kernel_read); ++extern bool ksu_vfs_read_hook __read_mostly; +extern int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr, + size_t *count_ptr, loff_t **pos); ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { ssize_t ret; -+ ksu_handle_vfs_read(&file, &buf, &count, &pos); -+ ++ if (unlikely(ksu_vfs_read_hook)) ++ ksu_handle_vfs_read(&file, &buf, &count, &pos); ++ if (!(file->f_mode & FMODE_READ)) return -EBADF; if (!(file->f_mode & FMODE_CAN_READ)) diff --git a/KernelSU/website/docs/zh_CN/guide/how-to-integrate-for-non-gki.md b/KernelSU/website/docs/zh_CN/guide/how-to-integrate-for-non-gki.md index 4f6521460648..492bb349e68e 100644 --- a/KernelSU/website/docs/zh_CN/guide/how-to-integrate-for-non-gki.md +++ b/KernelSU/website/docs/zh_CN/guide/how-to-integrate-for-non-gki.md @@ -75,14 +75,20 @@ index ac59664eaecf..bdd585e1d2cc 100644 return retval; } ++extern bool ksu_execveat_hook __read_mostly; +extern int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv, + void *envp, int *flags); ++extern int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, ++ void *argv, void *envp, int *flags); static int do_execveat_common(int fd, struct filename *filename, struct user_arg_ptr argv, struct user_arg_ptr envp, int flags) { -+ ksu_handle_execveat(&fd, &filename, &argv, &envp, &flags); ++ if (unlikely(ksu_execveat_hook)) ++ ksu_handle_execveat(&fd, &filename, &argv, &envp, &flags); ++ else ++ ksu_handle_execveat_sucompat(&fd, &filename, &argv, &envp, &flags); return __do_execve_file(fd, filename, argv, envp, flags, NULL); } @@ -115,14 +121,16 @@ index 650fc7e0f3a6..55be193913b6 100644 } EXPORT_SYMBOL(kernel_read); ++extern bool ksu_vfs_read_hook __read_mostly; +extern int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr, + size_t *count_ptr, loff_t **pos); ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { ssize_t ret; -+ ksu_handle_vfs_read(&file, &buf, &count, &pos); -+ ++ if (unlikely(ksu_vfs_read_hook)) ++ ksu_handle_vfs_read(&file, &buf, &count, &pos); ++ if (!(file->f_mode & FMODE_READ)) return -EBADF; if (!(file->f_mode & FMODE_CAN_READ)) @@ -222,19 +230,22 @@ index 45306f9ef247..815091ebfca4 100755 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -367,10 +367,13 @@ static int input_get_disposition(struct input_dev *dev, - return disposition; + return disposition; } - + ++extern bool ksu_input_hook __read_mostly; +extern int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, int *value); + static void input_handle_event(struct input_dev *dev, - unsigned int type, unsigned int code, int value) + unsigned int type, unsigned int code, int value) { - int disposition = input_get_disposition(dev, type, code, &value); -+ ksu_handle_input_handle_event(&type, &code, &value); - - if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN) - add_input_randomness(type, code, value); + int disposition = input_get_disposition(dev, type, code, &value); ++ ++ if (unlikely(ksu_input_hook)) ++ ksu_handle_input_handle_event(&type, &code, &value); + + if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN) + add_input_randomness(type, code, value); ``` 改完之后重新编译内核即可。 diff --git a/KernelSU/website/docs/zh_TW/guide/how-to-integrate-for-non-gki.md b/KernelSU/website/docs/zh_TW/guide/how-to-integrate-for-non-gki.md index fe6fc72e2542..83ab5eb3fed6 100644 --- a/KernelSU/website/docs/zh_TW/guide/how-to-integrate-for-non-gki.md +++ b/KernelSU/website/docs/zh_TW/guide/how-to-integrate-for-non-gki.md @@ -75,14 +75,20 @@ index ac59664eaecf..bdd585e1d2cc 100644 return retval; } ++extern bool ksu_execveat_hook __read_mostly; +extern int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv, + void *envp, int *flags); ++extern int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, ++ void *argv, void *envp, int *flags); static int do_execveat_common(int fd, struct filename *filename, struct user_arg_ptr argv, struct user_arg_ptr envp, int flags) { -+ ksu_handle_execveat(&fd, &filename, &argv, &envp, &flags); ++ if (unlikely(ksu_execveat_hook)) ++ ksu_handle_execveat(&fd, &filename, &argv, &envp, &flags); ++ else ++ ksu_handle_execveat_sucompat(&fd, &filename, &argv, &envp, &flags); return __do_execve_file(fd, filename, argv, envp, flags, NULL); } @@ -115,14 +121,16 @@ index 650fc7e0f3a6..55be193913b6 100644 } EXPORT_SYMBOL(kernel_read); ++extern bool ksu_vfs_read_hook __read_mostly; +extern int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr, + size_t *count_ptr, loff_t **pos); ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { ssize_t ret; -+ ksu_handle_vfs_read(&file, &buf, &count, &pos); -+ ++ if (unlikely(ksu_vfs_read_hook)) ++ ksu_handle_vfs_read(&file, &buf, &count, &pos); ++ if (!(file->f_mode & FMODE_READ)) return -EBADF; if (!(file->f_mode & FMODE_CAN_READ)) @@ -222,19 +230,22 @@ index 45306f9ef247..815091ebfca4 100755 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -367,10 +367,13 @@ static int input_get_disposition(struct input_dev *dev, - return disposition; + return disposition; } - + ++extern bool ksu_input_hook __read_mostly; +extern int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, int *value); + static void input_handle_event(struct input_dev *dev, - unsigned int type, unsigned int code, int value) + unsigned int type, unsigned int code, int value) { - int disposition = input_get_disposition(dev, type, code, &value); -+ ksu_handle_input_handle_event(&type, &code, &value); - - if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN) - add_input_randomness(type, code, value); + int disposition = input_get_disposition(dev, type, code, &value); ++ ++ if (unlikely(ksu_input_hook)) ++ ksu_handle_input_handle_event(&type, &code, &value); + + if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN) + add_input_randomness(type, code, value); ``` 最後,再次建置您的核心,KernelSU 將會如期運作。