Compare commits

..

589 Commits

Author SHA1 Message Date
weishu
d78f24098a Revert "manager: don't remember state when process died." close #728
This reverts commit 12761ee167.
2023-07-08 01:22:21 +08:00
dabao1955
cd952f5e45 kernel/ksu.c:Fix word mistakes when enabling CONFIG_KSU_DEBUG (#724)
According to the instructions in Kconfig, when the `CONFIG_KSU_DEBUG`
option is turned on, KernelSU will run in `debug mode` instead of the
`debug version` mentioned in kernel/ksu.c.
2023-07-08 01:22:06 +08:00
awakened
156b17f69d Support Samsung S10/N10 and Oneplus 9/9Pro (#725)
Co-authored-by: Phạm Tiên Sinh <song.long.dai.duong@gmail.com>
2023-07-06 13:25:28 +08:00
4qwerty7
f4d2b0feab Distinguish different PT_REGS_PARM4 under x86 (#711)
1. `PT_REGS_CCALL_PARM4` 表示存放C调用约定的第4个参数的寄存器
2. `PT_REGS_SYSCALL_PARM4` 表示存放linux syscall调用约定的第4个参数的寄存器
3. 将原有 `PT_REGS_PARM4` 改为上述之一
4. 将原有 `ksu_handle_execveat_ksud` 和 `ksu_handle_execveat_sucompat` 可能被
kprobe 传递错误实参、且不使用的形参标记为 never_used 并传递 `NULL`
5. 为 `ksu_handle_execveat_ksud` 提供正确的 argv 参数用以在 x86 下也能正确识别 `init
second_stage`

---------

Co-authored-by: weishu <twsxtd@gmail.com>
2023-07-06 09:01:35 +08:00
th1nhhdk
2c0a9cd64c repos.json: Updated repo link for Sony Xperia 1 II & Sony Xperia 5 II (#722)
The old one is outdated and unmaintained
2023-07-05 21:00:49 +08:00
Howard Wu
134507b928 ci: Fix checkout branch (#720)
Don't set ref branch for properly check PR
2023-07-05 08:03:27 +08:00
Howard Wu
2b42d14ef8 ci: Fix WSA build output path (#717) 2023-07-04 12:41:14 +08:00
Jakub Skorłutowski
e6071b5247 Add Polish language (#716) 2023-07-04 12:37:06 +08:00
dabao1955
f288cfccae update featrue_request issue temple (#715)
Compared with markdown, yaml may be more focused on the required
information, and will not easily destroy the content in the template.
And I think the "feature request" might not require users to upload
their logs.

It looks like this:


![Screenshot_2023-07-03-22-53-28-88_a252b927494330cdc2c8ba3b3f952e5e](https://github.com/tiann/KernelSU/assets/79307765/ef15e532-2d69-4dea-ba7a-326b7fa2e0ef)

Co-authored-by: dabao1955 <195328750@qq.com>
2023-07-03 23:05:19 +08:00
naxitoo
1cc9da5efe Update Spanish translations + Spanish README (#710) 2023-07-03 09:52:17 +08:00
longhuan1999
0aee64f339 Update app-profile.md and strings.xml (#712)
1. website: Correcting several errors in docs of App Profile
2. manager: Remove the 'app name' field except for the default
strings.xml file
2023-07-03 09:51:54 +08:00
Ali Beyaz
cbbdc665c8 Changed some Turkish translations (#707) 2023-07-02 19:42:58 +08:00
weishu
1b2635784f website: Add docs for App Profile 2023-07-02 19:07:09 +08:00
weishu
ee5d2f8c84 kernel: fix compile err in old kernel 2023-07-02 19:06:31 +08:00
weishu
dfc2a86e70 kernel: fix compile err and format code. close #706 2023-07-02 14:51:14 +08:00
4qwerty7
c0066b68f5 kernel: support the case that init_task.mnt_ns != zygote.mnt_ns(WSA) (#698)
Basic support for the case that init_task.mnt_ns != zygote.mnt_ns(WSA),
just copy nsproxy and fs pointers for solve #276.

Note the copy in `apk_sign.c` is not required but suggested for
secure(ensure the checked mnt_ns is what ns android running, not created
by user, although many distributions does not have user ns.).

Tested with latest release on Win10 19045.3086(with WSAPatch).

Further review required for:
- [x] Security of this operation (without locking).
- [x] The impact of these modifications on other Android distributions.
2023-07-02 00:20:01 +08:00
Ali Beyaz
6ef5e4ef76 Update Turkish strings.xml (#703) 2023-07-01 21:22:50 +08:00
weishu
e3e77fde78 kernel: authorize the newly type for all roles. refer: http://aospxref.com/kernel-android12-5.10-lts/xref/security/selinux/ss/policydb.c#950 2023-07-01 20:54:13 +08:00
weishu
8ea55c7f2f manager: bump minimal kernel version 2023-07-01 20:46:20 +08:00
raystef66
d2a976b3cc Update Flemish/Dutch translation (#702) 2023-07-01 20:14:51 +08:00
weishu
d675662862 kernel: add some log 2023-07-01 19:35:28 +08:00
weishu
839b318785 ksud: don't create dir when read 2023-07-01 19:01:09 +08:00
weishu
971f59c11e ksud: fix fmt 2023-07-01 18:59:41 +08:00
weishu
ab58808b64 ksud: fix compile err 2023-07-01 18:55:01 +08:00
weishu
9cbb7cb10e ksud: apply selinux rule when profile is set 2023-07-01 18:46:21 +08:00
weishu
70f2df11d1 manager: support setting selinux rules profile 2023-07-01 18:44:56 +08:00
weishu
827a2f2901 ksud: don't apply rule when check grammer 2023-07-01 17:43:40 +08:00
weishu
a9c33f6940 ksud: load profile sepolicy rules when boot 2023-07-01 16:50:10 +08:00
weishu
2bb73a2a92 ksud: support root profile's sepolicy 2023-07-01 16:34:43 +08:00
weishu
90407986be ksud: remove unused command 2023-07-01 15:31:53 +08:00
weishu
b85ece440b manager: show context menu on touch position 2023-07-01 12:13:30 +08:00
weishu
a10d2651c1 manager: Add context menu for app profile 2023-07-01 12:13:30 +08:00
SirRGB
b308a368d3 misc grammar and typo fixes (#699) 2023-06-30 23:54:15 +08:00
weishu
e6fea652de manager: only check update for enabled module 2023-06-30 23:49:11 +08:00
Aquarius223
0856b718de kernel: Modify KERNEL_SU_VERSION logic and behavior (#696)
This patch modifies the following:
- Move the version addition logic in ksu.h to Makefile processing
- Print the current version number of KernelSU during make build

build test (normal):
 buildlog:
HOSTCC scripts/basic/bin2c Using .. as source for kernel -- KernelSU
version: 11055
  CHK     include/generated/utsrelease.h
  UPD     include/generated/utsrelease.h

 KernelSU software:
  KernelSU Working Version: 11055 (v) Superusers: 0 Modules: 0


![11055](https://github.com/tiann/KernelSU/assets/47409494/10506289-04d2-41c0-bd48-bad9f0dbdec5)

build test (missing .git file):
 buildlog:
HOSTCC scripts/basic/bin2c Using .. as source for kernel
../drivers/kernelsu/Makefile:23: "KSU_GIT_VERSION not defined! It is
better to make KernelSU a git submodule!"
  CHK     include/generated/utsrelease.h
  CHK     scripts/mod/devicetable-offsets.h

 KernelSU software:
  KernelSU Working Version: 16 (v) Superusers: 0 Modules: 0

The current kernel version 16 is too low for the manager to function
properly. Please upgrade to version 10977 or higher!


![16](https://github.com/tiann/KernelSU/assets/47409494/9ea877a7-7b91-4a27-b6ab-58ce6e1b386f)

(cherry picked from commit 0c38a1614a77d80de752aba20908e3f9d21660a8)
Change-Id: I570f2ee33db224e1a36770f847137f290ba9bcfd

Co-authored-by: stic-server-open <1138705738@qq.com>
2023-06-28 21:45:36 +08:00
Zillion
6f1ccc5b3c Remove fontFamily from the Unsupported Warning (#694)
Just a small design fix, to make the Unsupported Warning text have the
same font as the Working text.

## Before

![before](https://github.com/tiann/KernelSU/assets/77107077/7e3f2382-446a-4039-8bec-d72c7e4471b3)

## After

![after](https://github.com/tiann/KernelSU/assets/77107077/31905aa3-a274-4289-b51b-0c45bbeee90e)
2023-06-27 21:17:48 +08:00
weishu
da959b4e17 kernel: fix compile err on lower kernel 2023-06-27 20:46:09 +08:00
likkai
0bfd6d9e30 Add device (lisa) (#691)
Co-authored-by: weishu <twsxtd@gmail.com>
2023-06-27 10:55:05 +08:00
weishu
980f1d09bc kernel: allow kernel to mount loop devices. close #514 2023-06-26 19:29:29 +08:00
weishu
b644c124e3 kernel: copy filename ourself instead of getname 2023-06-26 19:28:40 +08:00
weishu
65005131bd Create FUNDING.yml 2023-06-26 18:53:27 +08:00
syntaxticsugr
18aa7f2a17 Fixed Banner Art (#687)
Minor change (added spaces) to fix KSU Banner Art.
2023-06-26 18:22:56 +08:00
Zillion
cd5bc2efa9 Add Spanish Translation (#689) 2023-06-26 10:45:24 +08:00
Pegioner
477361f119 Update Russian translation (#681) 2023-06-24 20:17:51 +08:00
Gustavo Mendes
d3632e4b3b Update Portuguese brazilian translation (#682)
Signed-off-by: Gustavo Mendes <gusttavo.me@outlook.com>
2023-06-24 20:17:15 +08:00
SoDebug
0c2f90123b repos.json: Update the link of the KernelSU kernel release repo of the device I maintain (#686)
Update the link of the KernelSU kernel release repo of the device I
maintain
2023-06-24 20:16:25 +08:00
Howard Wu
09d90e1a0a ci: update gki version (#679)
Fix the version name of android13-5.15.74
Add android12-5.10.117
2023-06-23 17:48:18 +08:00
Trịnh Văn Lợi
4fe167c361 Update Vietnamese strings (#678) 2023-06-23 17:30:04 +08:00
raystef66
58ffaeb4e2 Update Flemish/Dutch translation (#677) 2023-06-23 09:31:58 +08:00
Ali Beyaz
76499ee629 Translated latest strings to Turkish (#676) 2023-06-23 09:31:23 +08:00
weishu
fedfa3e3fd manager: update card color 2023-06-23 00:35:35 +08:00
Igor Sorocean
2902e42f91 manager: update ro translation (#674) 2023-06-23 00:32:26 +08:00
weishu
37f4045499 manager: add a simple manager updater, close #627 2023-06-23 00:31:36 +08:00
weishu
12761ee167 manager: don't remember state when process died. 2023-06-22 23:24:35 +08:00
weishu
0d254237a4 manager: fix module install 2023-06-22 23:20:13 +08:00
weishu
f5bb24676e manager: fix download state 2023-06-22 19:46:26 +08:00
weishu
303a3a8482 manager: fix update button 2023-06-22 19:29:37 +08:00
weishu
07273b6971 manager: support module update online 2023-06-22 18:40:28 +08:00
weishu
c7c9e9c3ed ksud: respect the skip_mount flag of module 2023-06-22 17:00:02 +08:00
weishu
c3c990c50a ksud: increase reserved size to 256M 2023-06-22 16:48:13 +08:00
weishu
6942fe12b5 manager: set keyboard options for inputtext 2023-06-22 16:46:41 +08:00
weishu
f5cfb32882 kernel: fix incorrect umount for apps 2023-06-22 15:17:32 +08:00
weishu
e17f3eab96 Revert "kernel: use vfs_fstatat on kernel 5.10+, vfs_statx may have cfi."
This reverts commit cd3e292489.
2023-06-22 14:37:17 +08:00
weishu
08884da423 kernel: don't alloc groups for default groups 2023-06-22 13:42:28 +08:00
weishu
5f1d70dabb Revert "kernel: getname might sleep in kprobe handler (#670)"
This reverts commit 79bb9813ef.
2023-06-22 12:54:30 +08:00
weishu
79bb9813ef kernel: getname might sleep in kprobe handler (#670) 2023-06-22 10:54:50 +08:00
Ali Beyaz
1cda4ba245 Update latest strings to Turkish (#662) 2023-06-20 18:45:24 +08:00
raystef66
1cc678d20b Update Flemish/Dutch translation (#665) 2023-06-20 18:44:04 +08:00
weishu
cd3e292489 kernel: use vfs_fstatat on kernel 5.10+, vfs_statx may have cfi. 2023-06-20 18:42:41 +08:00
Howard Wu
40ea27a59c ci: Fix kernel version (#666) 2023-06-20 18:10:07 +08:00
Azeroth
e95ca9316c Fix typo (#667)
Fixed typo in this section
https://kernelsu.org/guide/installation.html#patch-boot-img-manully
2023-06-20 17:58:05 +08:00
Ikko Eltociear Ashimine
9b2f907a48 kernel: fix typo in allowlist.c (#663)
creat -> create
2023-06-20 11:03:09 +08:00
Coconut
90299ad0bb kernel:Fix the issue of incompatible __maybe_unused in the GCC compiler kernel used in versions 4.4. x to 4.9. x. (#660) 2023-06-20 10:35:07 +08:00
weishu
22d084f89b manager: Add selinux rules UI 2023-06-19 22:20:40 +08:00
Muhammad Fadlyas
99770a7362 Update Indonesian translation (#659) 2023-06-19 20:07:47 +08:00
weishu
bbc7ebe5b1 kernel: Enforcement of Manager Signature Verification 2023-06-19 17:57:19 +08:00
exer
d131b7561d [add device]: Sony Tama (XZ2/c/p, XZ3) (#656) 2023-06-18 17:06:41 +08:00
weishu
ff8c614737 kernel: allow uid 1000(system_uid) to grant root. close #645 2023-06-18 13:00:37 +08:00
weishu
c12ad9d1c7 kernel: fix compile err. close #647 2023-06-18 12:51:34 +08:00
weishu
1703c16948 ci: support deprecated kernel versions (#648) 2023-06-18 12:47:29 +08:00
github-actions[bot]
a48d7b112f [add device]: (#650)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/644

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-06-17 23:11:41 +08:00
Ylarod
f2d5e57f01 fix add-device (#649) 2023-06-17 22:07:39 +08:00
Gustavo Mendes
4111bbf720 Update Portuguese brazilian translation (#643)
Signed-off-by: Gustavo Mendes <gusttavo.me@outlook.com>
2023-06-17 21:14:36 +08:00
Ali Beyaz
cd32ad8751 Fixed some Turkish strings again (#646) 2023-06-17 21:14:09 +08:00
Rem01Gaming
fefb826177 Update Indonesian translation (#634) 2023-06-16 20:50:31 +08:00
Ali Beyaz
e27fc04b5b Fixed some Turkish strings (#640) 2023-06-16 20:50:13 +08:00
SupeChicken666
168f412324 Add CI workflow for ChromeOS ARCVM (#641)
All changes are tested on my fork (the Telegram error was fixed in
9b16150):
https://github.com/supechicken/KernelSU/actions/runs/5287864543

---------

Co-authored-by: weishu <twsxtd@gmail.com>
2023-06-16 20:49:51 +08:00
Juhyung Park
bd8434f4f4 Hook improvements (take 2) (#563)
Hi @tiann.

Thanks for the great project, I had great fun playing around with it.

This PR mainly tries to further minimize the possible delays caused by
KernelSU hooking.

There are 3 major changes:
- Processes with 0 < UID < 2000 are blocked straight-up before going
through the allow_list.
I don't see any need for such processes to be interested in root, and
this allows returning early before going through a more expensive
lookup.
If there's an expected breakage due to this change, I'll remove it. Let
me know.
- A page-sized (4K) bitmap is added.
This allows O(1) lookup for UID <= 32767.
This speeds up `ksu_is_allow_uid()` by about 4.8x by sacrificing a 4K
memory. IMHO, a good trade-off.
Most notably, this reduces the 99.999% result previously from worrying
milliseconds scale to microseconds scale.
For UID > 32767, another page-sized (4K) sequential array is used to
cache allow_list.

Compared to the previous PR #557, this new approach gives another nice
25% performance boost in average, 63-96% boost in worst cases.

Benchmark results are available at
https://docs.google.com/spreadsheets/d/1w_tO1zRLPNMFRer49pL1TQfL6ndEhilRrDU1XFIcWXY/edit?usp=sharing

Thanks!

---------

Signed-off-by: Juhyung Park <qkrwngud825@gmail.com>
2023-06-16 19:53:15 +08:00
weishu
c697398893 kernel: fix warning on x86_64, close #637 2023-06-16 19:32:48 +08:00
Ali Beyaz
1e0176242a Translated latest 3 strings to Turkish (#630) 2023-06-14 11:03:42 +08:00
Pegioner
0e5e12b331 Update Russian translation and typo fix (#631) 2023-06-14 11:03:27 +08:00
Igor Sorocean
a2b240121a Update ro translation (#629) 2023-06-13 19:23:48 +08:00
raystef66
246dadea05 Update Flemish/Dutch translation (#626) 2023-06-13 14:22:45 +08:00
Hikari-no-Tenshi
b5291077a9 manager: Make more strings translatable (#622)
Co-authored-by: weishu <twsxtd@gmail.com>
2023-06-13 12:51:03 +08:00
Ali Beyaz
ee548d513a Turkish translation (#618) 2023-06-13 12:11:12 +08:00
YuKongA
bdd269ea22 ci: upgrade kernel branches (#614)
* Add android12-5.10.177 & android13-5.10.177
2023-06-10 20:40:50 +08:00
weishu
e1d7bb91e8 ci: Fix incorrect patch level for a13 kernel. close #601 2023-06-10 20:12:15 +08:00
weishu
593bc06302 ci: fix clippy (#616) 2023-06-10 20:04:12 +08:00
weishu
8b6204a534 ksud: Fix su parameter parsing. close #530, close #305, close #330, close #305 2023-06-10 15:23:45 +08:00
weishu
01ea9c9dce manager: Add title to profile list dialog 2023-06-09 20:43:44 +08:00
weishu
12e664b0a4 manager: Add desc to profile list item 2023-06-09 20:04:23 +08:00
weishu
0ca92b9de9 manager: minor fixes for uid/gid input 2023-06-09 19:59:11 +08:00
Pegioner
2fc9e03d86 Update Russian translation (#611) 2023-06-09 11:06:50 +08:00
Fiqri Ardyansyah
4218aa488f Fix error build when using GCC 12.0.0 (#609)
Signed-off-by: Fiqri Ardyansyah <fiqri0927936@gmail.com>
2023-06-09 10:35:16 +08:00
Gustavo Mendes
d95ede1f76 Update Portuguese brazilian translation (#608)
Signed-off-by: Gustavo Mendes <gusttavo.me@outlook.com>
2023-06-08 10:48:02 +08:00
Rushi Ranpise
56f72e8702 Update English translation (#605)
Fixes https://github.com/tiann/KernelSU/issues/602
2023-06-07 16:37:08 +08:00
raystef66
964bf34325 Update Flemish/Dutch translation (#604) 2023-06-07 11:13:04 +08:00
WeeAris
3191165ba2 website: Update unofficial device maintainer information (#603)
RealKing kernel has included kernelsu officially, so I don't need to
keep maintaining this fork. With the consent of the author of the
RealKing kernel, the maintainer information here is updated to his.
2023-06-07 10:37:16 +08:00
weishu
3ad27c5999 kernel: use macro for default domain 2023-06-06 21:07:25 +08:00
weishu
5b27f6c010 kernel: Fix shell permission under KSU_DEBUG 2023-06-06 21:05:37 +08:00
weishu
be44fad288 ci: android13-5.15-2022-11 is deprecated: https://android.googlesource.com/kernel/common/+refs 2023-06-06 20:59:15 +08:00
weishu
2a5fb76f95 manager: sync kernel struct and bump profile version 2023-06-06 20:56:27 +08:00
weishu
5db7075432 kernel: bump format version to force clear allowlist, prepare to release a new version 2023-06-06 20:49:39 +08:00
weishu
1408175a35 kernel: fix set groups for kernel 4.9- 2023-06-06 20:45:42 +08:00
weishu
ab1dc894e1 manager: disable template ui temporarily 2023-06-06 19:06:03 +08:00
weishu
c5bc1c8b15 manager: make template ui work 2023-06-06 17:54:57 +08:00
Soo-Hwan Na
6d1ee60d67 kernel/selinux: Need to force include errno.h sometimes (#572)
- Seen with Linux 4.14 kernel with error message:

In file included from ../drivers/android/kernelsu/selinux/sepolicy.c:1:
In file included from ../drivers/android/kernelsu/selinux/sepolicy.h:6:
In file included from ../security/selinux/ss/policydb.h:30: In file
included from ../security/selinux/ss/avtab.h:26:
../security/selinux/include/security.h:240:10: error: use of undeclared
identifier 'EIDRM'
        return -EIDRM;
                ^
  CC      drivers/base/transport_class.o
  CC      kernel/rcu/update.o
../security/selinux/include/security.h:246:10: error: use of undeclared
identifier 'ENOENT'
        return -ENOENT;
                ^
2023-06-06 16:42:45 +08:00
weishu
a58e929205 manager: Default selinux context should be "u:r:su:s0" 2023-06-06 16:37:14 +08:00
weishu
53be8612c8 kernel: support setting selinux context for profile 2023-06-06 16:35:25 +08:00
weishu
c7f6a7d11b kernel: support settings supplementary groups for profile 2023-06-06 13:19:11 +08:00
weishu
e9011041c5 manager: Fix groups overflow, close #598 2023-06-06 12:40:07 +08:00
weishu
9803371fdb ci: respect the CONFIG_KSU options (#599)
close #596, #597
2023-06-06 12:12:27 +08:00
weishu
710edb72fa kernel: prevent root process to exec su, which makes app can escape root profile by exec it twice 2023-06-06 11:08:57 +08:00
Igor Sorocean
a4ddf59562 Update ro translation (#595) 2023-06-05 22:40:44 +08:00
weishu
37dc9a27a7 kernel: fix incorrect prune uid for work profile app, close #587 2023-06-05 17:41:41 +08:00
weishu
27ccfa6395 manager: change minimal CAP to DAC_READ_SEARCH 2023-06-05 10:17:10 +08:00
weishu
116bc56cfe manager: Fix set profile failed. 2023-06-05 10:10:16 +08:00
weishu
9ae0126be5 manager: Add default minimal caps for default root profile 2023-06-05 09:08:41 +08:00
weishu
e8755f8ae0 manager: Fix groups and caps selection, close #592 2023-06-05 08:31:15 +08:00
Gustavo Mendes
6ba2bd3af9 Add Portuguese brazilian translation (#593)
Signed-off-by: Gustavo Mendes <gusttavo.me@outlook.com>
2023-06-05 08:24:41 +08:00
raystef66
4c5e485e76 Update Flemish/Dutch translation (#590) 2023-06-05 05:48:10 +08:00
Womsxd
05c6892f43 ksubot.py: Increase timeout (#589)
Increase the timeout duration and try to resolve the
'telegram.error.TimedOut: Timed out' issue when sending messages in a
Telegram group.
2023-06-04 23:31:37 +08:00
weishu
670a20c37f manager: Fix selection 2023-06-04 23:24:19 +08:00
weishu
75509aba72 ksud: fix gid is override by uid 2023-06-04 23:14:44 +08:00
weishu
887f02e742 manager: optimize uid/gid panel 2023-06-04 23:14:44 +08:00
Hikari-no-Tenshi
ef8da39d34 manager: Update Ukrainian translation (#584) 2023-06-04 21:41:46 +08:00
Jia-Bin
b7c759ece1 Update Traditional Chinese (#586)
Update Traditional Chinese
Modify the translation to meet localization and usage habits
2023-06-04 21:36:32 +08:00
weishu
019da4a634 ksud: respect the kernel default uid 2023-06-04 18:09:58 +08:00
weishu
33aa6de50b manager: Add desc for umount modules. 2023-06-04 17:42:58 +08:00
weishu
0b3688c3b1 manager: unify kernel and user structs 2023-06-04 17:29:31 +08:00
weishu
076e5d3655 kernel: make the profile uid, gid, capabilities really work 2023-06-04 17:29:12 +08:00
weishu
c9608af0c8 manager: fix capabilities and namespace save/load 2023-06-04 16:12:03 +08:00
weishu
908fbadaf5 manager: remove unused resources 2023-06-04 16:12:02 +08:00
weishu
ee97fdfc56 kernel: add more capailities 2023-06-04 16:09:27 +08:00
weishu
4ac137313f manager: rename "umount modules" -> "Hide modules" 2023-06-04 14:25:50 +08:00
weishu
11d0029a4b manager: Add default groups when empty 2023-06-04 14:25:50 +08:00
weishu
8af5a9038b kernel: fix set app profile may override other user's 2023-06-04 13:59:22 +08:00
weishu
5d449988fb manager: Fix app profile umount default 2023-06-04 09:58:02 +08:00
weishu
e969563df0 manager: Add UMOUNT badge 2023-06-04 09:52:51 +08:00
weishu
990626cf7d kernel: Fixing the issue of a delay in updating the default profile. 2023-06-04 09:47:31 +08:00
weishu
fc77ca989f kernel: use uid instead of package to compare allowlist, fix #580 2023-06-04 09:18:39 +08:00
diphons
2ce3976023 Fixup: build under linux 4.14 (#581)
Split compiler_types.h from compiler.h only available for linux 4.14
2023-06-04 09:15:03 +08:00
weishu
63ec531814 kernel: dont prune uid used for app profile 2023-06-04 01:01:39 +08:00
weishu
a4b55b30ca manager: Add log for fallbacked app profile 2023-06-04 00:59:59 +08:00
weishu
807556f361 manager: show default value for app profile. 2023-06-04 00:22:36 +08:00
weishu
2d854f2f37 manager: the default value of umountModules is actually "true" in kernel 2023-06-04 00:05:19 +08:00
weishu
5980c113fe kernel: respect the app profile's umount modules field for kernel umounting 2023-06-04 00:03:56 +08:00
weishu
1491465b55 manager: require kernel 10931 2023-06-03 23:58:23 +08:00
weishu
728380222a kernel: Add version field for struct app_profile 2023-06-03 23:57:05 +08:00
weishu
005404f552 kernel: support load/restore default profiles 2023-06-03 23:57:05 +08:00
weishu
b55c229038 manager: add support for setting default non root profile. 2023-06-03 23:54:15 +08:00
weishu
32538c9833 manager: remove unused 2023-06-03 23:54:15 +08:00
weishu
b31fc47197 kernel: support CMD_IS_UID_GRANTED_ROOT and CMD_IS_UID_SHOULD_UMOUNT 2023-06-03 22:44:01 +08:00
s1204IT
5003824fa8 Update WSA Kernel (#575)
Remove: 5.10.117.2
Change: 5.15.98.1 -> 5.15.98.**4**
2023-06-03 19:29:04 +08:00
Hikari-no-Tenshi
eea75b72a4 manager: Update Ukrainian translation (#579) 2023-06-03 19:28:38 +08:00
weishu
82d5ec3cc1 kernel: fix CMD_GET_ALLOW_LIST error 2023-06-03 19:23:51 +08:00
weishu
75721be8c0 manager: use default profile when kernel return null. 2023-06-03 17:26:38 +08:00
weishu
de72eedb46 kernel: don't copy profile when not found 2023-06-03 17:26:00 +08:00
weishu
66827ab7de manager: show profile info in superuser list 2023-06-03 17:17:19 +08:00
weishu
2a33433272 manager: don't obfuscate Profile 2023-06-03 16:20:13 +08:00
weishu
581dff8a5f manager: only show warning when installed. 2023-06-03 15:30:51 +08:00
weishu
fc425cbba2 manager: remove semicolon for require new version 2023-06-03 15:25:54 +08:00
weishu
87f55c1acb manager: Add require new kernel version. 2023-06-03 15:23:35 +08:00
weishu
68d639e325 manager: Add groups and caps for profile 2023-06-03 15:01:57 +08:00
weishu
89f6cd044e kernel: minor fixes for profiles 2023-06-03 10:18:11 +08:00
weishu
bd3a1291da kernel: don't fill default value for app profile 2023-06-03 00:06:58 +08:00
weishu
3abb7e4ca2 kernel: baby version of profile 2023-06-03 00:01:00 +08:00
weishu
41265b0203 manager: implement app profile api call 2023-06-02 23:58:07 +08:00
sajadasadollahi83
f2cb841b8a Update Persian Translation. (#569) 2023-06-02 16:01:46 +08:00
dabao1955
c69da29081 Kconfig:Update text information (#567)
![Screenshot_2023-05-31-12-56-27-57_84d3000e3f4017145260f7618db1d683](https://github.com/tiann/KernelSU/assets/79307765/84ab8d8e-c034-4567-b815-ebeccde1fdbc)

![Screenshot_2023-05-31-12-56-09-68_84d3000e3f4017145260f7618db1d683](https://github.com/tiann/KernelSU/assets/79307765/a4209212-997f-4e2f-bbcb-2c5136ab6e71)
2023-06-02 10:41:40 +08:00
github-actions[bot]
e304ef8cfb [add device]: Kernel 4.14.194 exynos9610 Non-GKI Device, Added KernelSu using manual method (#574)
Kernel 4.14.194 exynos9610 Non-GKI Device, Added KernelSu using manual
method has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/573

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-06-02 10:31:41 +08:00
Hikari-no-Tenshi
2ce76351da manager: Scroll app profile view (#565)
close #536
2023-05-31 13:04:22 +08:00
sajadasadollahi83
66cbd931a7 Create strings.xml (#561)
add translation for persian.
2023-05-31 12:44:06 +08:00
s1204IT
07bc28e386 Fix README languages (#564) 2023-05-31 12:08:58 +08:00
AndroPlus
2ef4ffe5eb Update Japanese readme (#560)
Changed the installation link to Japanese one (build page is English)
2023-05-29 20:17:43 +08:00
Murat Kozan
128e7e394e Update Turkish translation (#553) 2023-05-29 10:30:59 +08:00
Akari
998dc9b94b added support(README.md) for Brazilian Portuguese (#558)
added README_PT-BR.md support as mentioned before, for Brazilian
Portuguese.
2023-05-29 10:30:23 +08:00
Hikari-no-Tenshi
c6dafb1333 manager: Shorten long Ukrainian strings (#550) 2023-05-25 11:46:47 +08:00
Hikari-no-Tenshi
8ae7299d59 manager: Update Ukrainian translation (#540) 2023-05-23 10:49:39 +08:00
raystef66
8f1b9c579b Update Flemish/Dutch translation (#541) 2023-05-23 10:43:33 +08:00
ahmeda9a
4b6573b521 Fine tuning for Arabic translation. (#543)
Done some changes to make the translation Arabic clearer
2023-05-23 10:43:03 +08:00
Eduardo Novella
325e843569 (scripts) check_v2.c -add missing header (#548) 2023-05-23 10:24:42 +08:00
dabao1955
d014947a54 change warning about disable kprobes (#549)
#479


Co-authored-by: dabao1955 <195328750@qq.com>
2023-05-23 10:24:18 +08:00
weishu
8858cc899e kernel: remove no-macro-redefined 2023-05-22 10:50:04 +08:00
weishu
8f3e59803f kernel: fix format warnning 2023-05-22 10:39:54 +08:00
weishu
95044bb551 kernel: fix incorrect prune uid in allowlist for work profile app. close #535 2023-05-22 10:32:20 +08:00
Aquarius223
b56448a929 kernel: Modify and adjust KernelSU Kconfig (#538)
1. List KSU as a "KernelSU" menu
2. Overlayfs[1] may be disabled for some early kernels(4.4.y), so
choosing depends on OVERLAY_FS here is useless.
3. KSU_DEBUG is a bool option, it is not a module, fixed from tristate
to bool.
4. Adjust the config order

[1]: github.com/LineageOS/android_kernel_xiaomi_msm8998/commit/dcc27641

Change-Id: I49c77ba30f0a8ed00efc44afef8a12f9ad039d7e

Co-authored-by: admin <paper@localhost>
2023-05-21 20:28:59 +08:00
Mohamed Elsayed
c2b981dbdb Update Arabic translation (#534) 2023-05-20 11:36:29 +08:00
Muhammad Fadlyas
28fb482720 Update Indonesian translation (#532) 2023-05-20 11:28:37 +08:00
Muhammad Fadlyas
d744a705a8 Fix little typo in README.md (#531) 2023-05-20 09:53:38 +08:00
Nipin NA
c62b89f02b [add device]: Xiaomi Redmi Note 7 Pro (violet) (#524) 2023-05-17 17:17:00 +08:00
AndroPlus
f876b0114e Update Japanese translation (#518) 2023-05-17 17:16:24 +08:00
diphons
9965988f26 [add device]: Xiaomi Poco F1 (#520)
Also update link device Xiaomi Poco X3 Pro
2023-05-17 12:43:39 +08:00
github-actions[bot]
828bb6fbb4 [add device]: OPPO Reno6 on ColorOS11.x/ColorOS12.x,kernel version4.14.186+ (#522)
OPPO Reno6 on ColorOS11.x/ColorOS12.x,kernel version4.14.186+ has been
added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/521

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-17 12:43:06 +08:00
Howard Wu
10d8d9efcd ci: upgrade android13 kernel version (#516)
+ android13-5.10.168
+ android13-5.15.94
2023-05-17 10:48:13 +08:00
AndroPlus
e59f3333cb Update and fix Japanese translation (#517) 2023-05-17 10:00:46 +08:00
Nullptr
31a9189d80 manager: several UI improvements (#515) 2023-05-17 09:34:08 +08:00
dabao1955
d162221fac a little change (#513)
Though it is a little not suitable?
2023-05-17 09:31:38 +08:00
weishu
0cdca0d053 website: fix build error 2023-05-16 23:54:36 +08:00
AndroPlus
4c934d460b Update Japanese translation (#508)
I'm not familiar with vitepress, so there may be some mistakes in the
settings.
2023-05-16 23:40:54 +08:00
Nullptr
76612b9cf7 manager: several updates (#510)
+ update deps
+ update app profile page
+ don't show su and module page if no root
2023-05-16 22:32:48 +08:00
github-actions[bot]
9cf8ac9c51 [add device]: (#512)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/511

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-16 22:31:19 +08:00
tiann
b80e06256d Revert "Add option to enable global namespace (#497)"
This reverts commit f81caf75a9.
2023-05-16 22:27:01 +08:00
tiann
08d9e5d6bc manager: add app_profile set/get 2023-05-16 20:33:09 +08:00
tiann
ed0cfd231e ci: fix debug build 2023-05-16 19:46:49 +08:00
weishu
538d3f06f4 ci: Add debug kernel build (#506) 2023-05-16 18:30:33 +08:00
Vayruz Rafli
f5d3fb6217 Fix little typo in setup script. (#505) 2023-05-16 18:12:16 +08:00
tiann
ffa3579e6f manager: minor fixes for app profile 2023-05-16 17:31:57 +08:00
tiann
c7adb8e3b1 manager: Add app profile implementation 2023-05-16 17:15:01 +08:00
tiann
c1427f658a manager: Add working mode UI 2023-05-16 16:31:56 +08:00
tiann
eccce7b31f manager: Add app profile UI 2023-05-16 15:07:26 +08:00
Hikari-no-Tenshi
f81caf75a9 Add option to enable global namespace (#497)
Disabled by default.
To enable/disable use terminal with root.

To enable:
echo 1 > /sys/module/ksu/parameters/global_namespace_enable

To disable:
echo 0 > /sys/module/ksu/parameters/global_namespace_enable

Value will be reset to 0 (disabled) on reboot.
2023-05-16 11:39:48 +08:00
dabao1955
d4680c6de7 Add Japanese language for Readme (#501)
Co-authored-by: dabao1955 <195328750@qq.com>
2023-05-16 10:40:39 +08:00
浅秋枫影
2716ec58a0 Revert 67667b6 (#500)
确实会导致卡住问题,一旦卡住,其他程序就无法正确卸载。
可能是,卸载目录那里一直在等待前面的空闲后再卸载,然后把后面的事件全部阻塞了?
2023-05-15 23:18:34 +08:00
TheNoFace
f25dbd8fed [Add Device]: OnePlus 5/5T (cheeseburger/dumpling) (#499)
Issue https://github.com/tiann/KernelSU/issues/498 closed without any
explicit reason, so made a pull request.
2023-05-15 18:13:58 +08:00
weishu
e35180c919 Update build-manager.yml 2023-05-15 12:14:30 +08:00
Howard Wu
2f54ceb7c4 ci: android12-5.10 drop deprecated tag (#495) 2023-05-15 09:58:25 +08:00
Mohamed Elsayed
6506ef468d Add Arabic translation (#491) 2023-05-13 16:25:10 +08:00
5ec1cff
da46dfbde1 ksud: use MS_RDONLY when mounting overlayfs (#490)
fix https://github.com/tiann/KernelSU/issues/489
2023-05-13 16:17:22 +08:00
Alessandro Paluzzi
09ecc2c9b5 Add italian translation (#486) 2023-05-13 07:07:34 +08:00
github-actions[bot]
0b2899a961 [add device]: (#485)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/484

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-13 06:03:40 +08:00
dabao1955
c6ed3fa27f Change the device supported by the kernel source code I maintain. (#483) 2023-05-12 23:34:25 +08:00
TheNoFace
43cd3b9cad Add Korean translation (#480) 2023-05-12 20:27:43 +08:00
tiann
294d6fa05e kernel: don't umount for process in global namespace 2023-05-12 12:32:35 +08:00
Syuugo
009a479c17 WSA: 5.15.94.1 (#475)
![](https://github.com/tiann/KernelSU/assets/52069677/99edfd12-c0a1-4430-bf2f-b17b76dbc44f)

Co-authored-by: weishu <twsxtd@gmail.com>
2023-05-11 18:45:15 +08:00
tiann
72ee14e6be kernel: revert init stage for x86_64 temporarily 2023-05-11 17:20:55 +08:00
Murat Kozan
2b01a1c395 Add Turkish translation (#474) 2023-05-11 11:14:38 +08:00
tiann
f69793d38e ksud: REPLACE must be directory, if you need to replace normal file, just put it to module's system corresponding location, don't need extra steps. fix #466 2023-05-10 14:36:02 +08:00
github-actions[bot]
eda0d6d23b [add device]: OPPO Reno 6 (#473)
OPPO Reno 6 has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/472

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-10 07:12:39 +08:00
S M Mahbub Hossain
abba36d786 Add Bangla/Bengali translation (#471)
Signed-off-by: S M Mahbub Hossain  <118460787+smmahbubhossain@users.noreply.github.com>
2023-05-09 19:03:58 +08:00
raystef66
33ea9a6f33 Add Flemish/Dutch translation (#470) 2023-05-08 23:21:20 +08:00
Kurisu Cat
9a0da7270b document: fix typo (#467)
修正文档中的错别字
2023-05-08 00:12:38 +08:00
github-actions[bot]
9caf440200 [add device]: (#462)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/461

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-05 18:57:39 +08:00
github-actions[bot]
c9e53cf355 [add device]: (#459)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/458

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-05 10:42:42 +08:00
RyuujiX
432eb318ac kernel: Kconfig: Remove KPROBES dependancy (#453)
For those who want to Implement KernelSU Manually with KPROBES disabled.

When KPROBES Broken and Still enabled, this will causing Loop at splash
logo even Already Manually Imported because this
842c0b674f/kernel/ksu.c (L57).
And when KPROBES is disabled, KSU also will not compiled (I Know it'll
still build if obj-y is set for KSU, but it's better to remove, who
knows if someone set as obj-$(CONFIG_KSU)).

Signed-off-by: RyuujiX <saputradenny712@gmail.com>
2023-05-04 22:57:49 +08:00
セリカ・シルフィル
cea0db4e0d manager: Open guide in the current language if it exist (#452)
If not present, the English page will be opened by default.
2023-05-04 21:10:33 +08:00
weishu
842c0b674f ci: Fix setlocalversion patch failed (#451) 2023-05-04 15:37:06 +08:00
Huy Minh
36ed99d1f6 ksud.c : Include compat.h (#450)
Fix compiling on Android-x86

Signed-off-by: hmtheboy154 <buingoc67@gmail.com>
2023-05-04 11:49:21 +08:00
shygos
86d0f37b37 kernel: Use a better way to link submodule directory (#449)
Use ../ instead of absolute path
2023-05-03 22:05:36 +08:00
github-actions[bot]
5303c9c461 [add device]: (#448)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/447

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-02 06:56:35 +08:00
tiann
67667b6df2 kernel: umount by lazy 2023-05-02 00:12:01 +08:00
Lvc Revincx
d9d27b4229 readme: fix credits link title of genuine project (#446)
The credit link title of [genuine](https://github.com/brevent/genuine)
in `README_CN.md` and `README_TW.md` is `true`.
2023-05-01 16:56:31 +08:00
Sreeshankar K
a2a1b19758 Add OnePlus Nord (avicii) (#444) 2023-04-29 23:45:07 +08:00
github-actions[bot]
fb9d39d6d5 [add device]: (#443)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/442

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-29 12:03:07 +08:00
github-actions[bot]
0f3d425f64 [add device]: (#439)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/438

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-28 08:35:02 +08:00
Abdelhay-Ali
08e3580646 make huawei hi6250 4.9.319 kernel compile (#431) 2023-04-27 13:30:04 +08:00
Igor Sorocean
0fa4a4c6db Update ro strings (#434) 2023-04-26 17:22:53 +08:00
diphons
d452e01a3d [add device]: Xiaomi Poco X3 Pro | Vayu - Bhima (#433) 2023-04-26 11:45:50 +08:00
diphons
f7da373f8b [add device]: Xiaomi Poco F3 - F4 - MI10T/Pro (#432) 2023-04-25 14:55:32 +08:00
Koinu
b80cf7ba15 Update repos.json (#430)
他的内核已经不支持KernelSU了
2023-04-24 11:22:48 +08:00
Kung-chih
fe1cd4b27a website: add Traditional Chinese (#429)
Also README_TW added, hope it works :)
2023-04-23 18:54:33 +08:00
Hikari-no-Tenshi
925206f9c8 Add Ukrainian translation (#427) 2023-04-23 13:55:43 +08:00
Abdelhay-Ali
f24a317e2d Update repos.json (#428)
add Huawei P20 lite (hi6250) (Linux 4.9)
2023-04-23 10:28:29 +08:00
TireX228
aeaa3ce982 manager: Update Russian language (#423) 2023-04-22 23:26:53 +08:00
Kung-chih
8c6913a9af Update zh-rHK and zh-rTW (#425)
@cracky5322 For zh-rTW with Android Style: 

> Log: 記錄(檔)
Developer: 開發人員
Access: 存取(權)
Support: 支援(For users) 支持(For devs)
2023-04-22 23:26:37 +08:00
TinyHai
7795232a58 manager: fix ConfirmDialog (#426) 2023-04-22 23:26:21 +08:00
TinyHai
057330c68f manager: refine dialog component and make a small fix in AboutCard (#422)
Co-authored-by: weishu <twsxtd@gmail.com>
2023-04-22 18:40:11 +08:00
github-actions[bot]
91c80279bd [add device]: (#421)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/420

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-22 15:25:07 +08:00
Nullptr
5715df0b10 manager: small fix for navigation (#416) 2023-04-21 23:52:46 +08:00
github-actions[bot]
9f0c540fba [add device]: (#418)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/417

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-21 23:52:16 +08:00
Nullptr
f9d19a957a manager: refactor to use AGP 8.0.0 (#414) 2023-04-21 16:19:49 +08:00
tiann
76b1165572 kernel: fix incorrect invalidate for manager in work profile 2023-04-21 14:45:47 +08:00
tiann
80c85b3bb9 manager: update libsu to make it work in work profile standalone! 2023-04-21 14:34:40 +08:00
Amicia De Rune
900652a82b update id translation (#412)
Signed-off-by: RooGhz720 <rooghz720@gmail.com>
2023-04-21 10:26:14 +08:00
Jia-Bin
6cbef7d987 Update Traditional Chinese (#413)
Update Traditional Chinese
Optimize the text for easier reading
2023-04-21 10:25:46 +08:00
TireX228
01d66834f0 manager: Update Russian language (#411) 2023-04-20 19:15:14 +08:00
Trịnh Văn Lợi
a40eae9b8c Update vi strings (#408) 2023-04-20 16:16:08 +08:00
github-actions[bot]
23b46bde2b [add device]: (#410)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/409

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-04-20 16:15:28 +08:00
tiann
b38ada30e6 manager: remove html-text dependency 2023-04-20 15:46:05 +08:00
3452841752 selinux: use grep to check api supports (#402)
This checks `selinux_state` and `current_sid` supports in a raw way.
Feels more reliable than the version checks.

Supersedes #401, fixes #280, fixes #400.
2023-04-20 15:22:03 +08:00
tiann
3b9cab3432 manager: refine about dialog 2023-04-20 15:20:10 +08:00
tiann
2f6df20085 manager: remake home page 2023-04-20 13:52:56 +08:00
tiann
609ea40d1c manager: show loading dialog when collect bugreport 2023-04-20 11:40:09 +08:00
tiann
515a309831 Revert "ci: Add version to build artifacts"
This reverts commit 0b4f4683b3.
2023-04-20 10:55:41 +08:00
tiann
02c2228ab7 Revert "ci: Fix img upload"
This reverts commit ea93140b8a.
2023-04-20 10:55:41 +08:00
Trịnh Văn Lợi
ca246ba67d Update vi strings (#406) 2023-04-20 10:01:03 +08:00
easterNday
f9008b67c4 [add device]: Xiaomi 10S (#405)
增加小米10S的非GKi内核KSU支持。
2023-04-19 23:22:19 +08:00
tiann
e228197906 Revert "manager: manager: disable user scroll when refreshing"
This reverts commit d86b524558.
2023-04-19 21:16:23 +08:00
tiann
d98e324618 manager: upgrade compose dependencies to fix some weird bugs. close #367 2023-04-19 21:15:59 +08:00
Igor Sorocean
1880fdfda9 Update ro strings (#403) 2023-04-19 21:10:08 +08:00
tiann
d86b524558 manager: manager: disable user scroll when refreshing 2023-04-19 18:14:09 +08:00
tiann
70fa38a589 manager: upgrade AGP 2023-04-19 18:10:48 +08:00
tiann
ea93140b8a ci: Fix img upload 2023-04-19 14:02:39 +08:00
tiann
45c229dc9f kernel: fix snprintf 2023-04-18 19:38:58 +08:00
tiann
2b5ac95165 manager: Fix snprintf 2023-04-18 19:35:42 +08:00
Howard Wu
38c65e7e4b [skip ci] ci: fix job name typo (#398) 2023-04-18 18:44:04 +08:00
tiann
f40eaf4499 manager: Fix loading state 2023-04-18 18:42:41 +08:00
tiann
3a667ef389 manager: allow become_manager in work profile. 2023-04-18 18:40:32 +08:00
tiann
f35e03d816 kernel: allow manager to be installed in work profile 2023-04-18 18:32:33 +08:00
tiann
2bfd4d71d8 manager: use ParceledListSlice to transport List<PackageInfo>, avoiding TransactionTooLargeException. 2023-04-18 18:04:49 +08:00
tiann
2bc84014c2 manager: supports grant root access to cross profile. close #271 2023-04-18 17:38:48 +08:00
tiann
a3c72c22c1 manager: add selinux state to bugreport. 2023-04-18 14:47:21 +08:00
tiann
ddf2b7e9ff manager: add allowlist to bugreport. 2023-04-18 14:47:21 +08:00
tiann
04d1bee7b4 manager: remove directory tree in bugreport. 2023-04-18 14:47:21 +08:00
tiann
0c9ecf3abc kernel: always apply sepolicy rules even if selinux is permissive 2023-04-18 14:15:37 +08:00
Kung-chih
c8b4798b61 Update zh-rHK and zh-rTW (#396) 2023-04-18 13:25:55 +08:00
tiann
550c8ae45d Revert "ksud: update faked Magisk version to 26.1 to make some modules happy"
This reverts commit 48cd6e112b.
2023-04-18 13:24:35 +08:00
tiann
0b4f4683b3 ci: Add version to build artifacts 2023-04-18 13:24:35 +08:00
tiann
5504b0dd29 Revert "kernel: don't save allowlist in worker"
This reverts commit c569d803c5.
2023-04-18 13:19:49 +08:00
tiann
f0dcddd391 kernel: don't show log when get allowlist 2023-04-18 13:19:49 +08:00
Howard Wu
75be1e1bd6 ci: avoid ccache key conflict (#397) 2023-04-18 12:12:03 +08:00
tiann
c569d803c5 kernel: don't save allowlist in worker 2023-04-18 09:18:06 +08:00
tiann
48cd6e112b ksud: update faked Magisk version to 26.1 to make some modules happy 2023-04-17 23:20:10 +08:00
tiann
d41354e1d7 manager: show confirm dialog when grant root to app. 2023-04-17 18:19:33 +08:00
tiann
9a5e36c0a4 ksud: remove unused dependency 2023-04-17 18:19:18 +08:00
5ec1cff
f963e40a5f ksud: fix bind mount failed again (#395)
This fixes https://github.com/Dr-TSNG/ZygiskOnKernelSU/issues/18
2023-04-17 12:05:13 +08:00
tiann
f1e2402316 ksud: avoid using master commit dependency 2023-04-17 11:37:54 +08:00
tiann
31bb8c75f5 ksud: fix clippy 2023-04-16 22:14:53 +08:00
tiann
fb4ab44aa5 manager: add bootlog for bugreport 2023-04-15 17:45:20 +08:00
tiann
71216b1458 ksud: catch bootlog when post-fs-data 2023-04-15 17:45:20 +08:00
aiamadeus
c969ff4011 website: fix web link address of taichi (#391)
Co-authored-by: AmadeusGhost <42570690+AmadeusGhost@users.noreply.github.com>
2023-04-15 15:32:07 +08:00
tiann
dc45eb6ed4 kernel: Make sure logd has started before post-fs-data. 2023-04-15 00:17:28 +08:00
tiann
29aaaae4b4 ksud: fix clippy 2023-04-14 23:06:11 +08:00
tiann
1fe53b9549 ci: run clippy with release build 2023-04-14 22:59:29 +08:00
weishu
6274dbebc0 Ci (#390) 2023-04-14 22:55:43 +08:00
weishu
a1cd3ab6fa ci: update clippy check (#389) 2023-04-14 22:42:25 +08:00
5ec1cff
c058cb8848 ksud: refactor module mount (#384) 2023-04-14 22:30:34 +08:00
セリカ・シルフィル
029061177b kernel: Fix pull when we are not currently on a branch (#388)
Before fix:
```
[celica@arch msm-5.4]$ curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -
++ pwd
+ GKI_ROOT=/home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4
+ echo '[+] GKI_ROOT: /home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4'
[+] GKI_ROOT: /home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4
+ test -d /home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4/common/drivers
+ test -d /home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4/drivers
+ DRIVER_DIR=/home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4/drivers
+ test -d /home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4/KernelSU
+ cd /home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4/KernelSU
+ git stash
没有要保存的本地修改
+ git pull
您当前不在一个分支上。
请指定您要合并哪一个分支。
详见 git-pull(1)。

    git pull <远程> <分支>
```

After fix:
```
[celica@arch msm-5.4]$ curl -LSs "https://raw.githubusercontent.com/natsumerinchan/KernelSU/main/kernel/setup.sh" | bash -s main
++ pwd
+ GKI_ROOT=/home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4
+ echo '[+] GKI_ROOT: /home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4'
[+] GKI_ROOT: /home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4
+ test -d /home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4/common/drivers
+ test -d /home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4/drivers
+ DRIVER_DIR=/home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4/drivers
+ test -d /home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4/KernelSU
+ cd /home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4/KernelSU
+ git stash
没有要保存的本地修改
++ git status
++ grep -Po 'v\d+(\.\d+)*'
++ head -n1
+ '[' v0.5.2 ']'
+ git checkout main
之前的 HEAD 位置是 0bda101 ci: fix WSA upload path (#372)
切换到分支 'main'
您的分支与上游分支 'origin/main' 一致。
+ git pull
已经是最新的。
+ '[' -z main ']'
+ git checkout main
已经位于 'main'
您的分支与上游分支 'origin/main' 一致。
+ cd /home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4
+ echo '[+] GKI_ROOT: /home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4'
[+] GKI_ROOT: /home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4
+ echo '[+] Copy kernel su driver to /home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4/drivers'
[+] Copy kernel su driver to /home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4/drivers
+ test -e /home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4/drivers/kernelsu
+ echo '[+] Add kernel su driver to Makefile'
[+] Add kernel su driver to Makefile
+ DRIVER_MAKEFILE=/home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4/drivers/Makefile
+ grep -q kernelsu /home/celica/workdir/mvaisakh-kernel/kernel/msm-5.4/drivers/Makefile
+ echo '[+] Done.'
[+] Done.
```
2023-04-14 15:31:30 +08:00
セリカ・シルフィル
9c8e813642 Kernel: Fix "bash: line 21: $1: unbound variable" (#385) 2023-04-13 22:15:17 +08:00
Coconut
7be61b9657 Make Huawei 4.9 Kernel compiler Happy and Does not affect other kernels (#374)
Adapt to SELinux with Huawei 4.9.xxx kernel without affecting other
mainstream kernels
2023-04-13 17:08:05 +08:00
セリカ・シルフィル
2f67d24ec9 kernel: Support switch branch or tag (#382) 2023-04-13 14:40:56 +08:00
Amicia De Rune
17d6f1cdf1 manager: update translation (#381)
Signed-off-by: RooGhz720 <rooghz720@gmail.com>
2023-04-13 13:19:39 +08:00
Terminator850
a0c34b40c6 Ensure the stability of use (#380)
I think we can add tag selection commands in the setup.sh script, such
as git checkout v0.5.1, to ensure the stability of use #379
2023-04-13 12:30:32 +08:00
tiann
00856f8cb9 misc: add .clang-format 2023-04-13 10:41:49 +08:00
Mike Evans
3df6387ee0 promotion: KernelSU integrated Bool-X kernel for raphael (#378)
Hi, I have made yet another KernelSU integrated kernel for Redmi #K20Pro
(#Raphael), based on a popular custom & optimized kernel called Bool-X
in the community.

Forked source code:
https://github.com/etnperlong/kernel_xiaomi_raphael_bool-x/tree/13.0-ksu
upstream source: https://github.com/onettboots/bool-x_xiaomi_raphael
(thanks to @onettboots)

I have tested the KernelSU feature on this kernel, everything works
fine.
2023-04-13 08:07:23 +08:00
Howard Wu
fe1c826b1b ci: Install dependency python-telegram-bot (#373) 2023-04-12 20:37:41 +08:00
Howard Wu
0bda101d4d ci: fix WSA upload path (#372) 2023-04-12 18:31:59 +08:00
Howard Wu
5e738129d9 ci: WSA build fix typo (#370) 2023-04-12 17:52:24 +08:00
tiann
39b5014add ksud: ensure parent dir when create file 2023-04-12 17:45:56 +08:00
tiann
3c6560ade9 ksud: format anyhow error 2023-04-12 13:21:13 +08:00
tiann
183d1a91c1 ksud: add error context to log 2023-04-12 13:17:13 +08:00
tiann
d711ab8b1f Revert "ksud: sort the stock mounts correctly."
This reverts commit 273a0b0b99.
2023-04-12 13:12:10 +08:00
Howard Wu
6c1a48952e WSA Kernel update to 5.15 (#369)
Checks: https://github.com/Howard20181/KernelSU/actions/runs/4672228625
2023-04-12 12:16:56 +08:00
chen2021-web
a343aa5eb0 Try to solve 4.14 build don't pass problem (#368) 2023-04-11 23:13:34 +08:00
tiann
273a0b0b99 ksud: sort the stock mounts correctly. 2023-04-11 21:23:30 +08:00
tiann
2f1e64dc1b ksud: make compiler happy 2023-04-11 20:45:21 +08:00
tiann
a46d4ecd3e ksud: use move mount instead of remount for stock mounts
Because some stock mounts are difficult to remount it back, so we bind mount it to somewhere else before overlayfs mount. And then use move mount to mount it back.
2023-04-11 20:32:08 +08:00
tiann
5f04954a5c ksud: don't umount stock overlayfs, just remount it 2023-04-11 16:24:02 +08:00
tiann
d065a7ca22 manager: don't create root shell everytime. this should close #361. MeiZu kernel seems cache something in execve syscall, which will cause double free in kernel. 2023-04-11 12:56:19 +08:00
Trịnh Văn Lợi
2f8373f9c5 Update strings.xml (#366)
Update missing translation
2023-04-11 11:05:35 +08:00
weishu
2d36e98246 kernel: make /system/bin/init second_stage more precisely (#357) 2023-04-11 10:55:17 +08:00
5ec1cff
f2d8f1ee60 kernel: fix search git in path (#363)
Prevent failing to get KSU_GIT_VERSION when PATH contains space.


[Details](https://github.com/5ec1cff/my-notes/blob/master/mi-kernel.md#%E4%B8%80%E4%B8%AA%E7%BC%BA%E5%B0%91%E5%BC%95%E5%8F%B7%E5%BC%95%E5%8F%91%E7%9A%84%E8%A1%80%E6%A1%88)
2023-04-09 17:16:35 +08:00
weishu
e7881c350c ksud: handle partition after REMOVE and REPLACE 2023-04-08 12:51:16 +08:00
Ylarod
ffe3e68c35 ksud: ensure ksud context when install (#356)
Incorrect se context will make module system broken
2023-04-07 12:46:59 +08:00
Xeonacid
4d6fafd778 website: fix typo (#354) 2023-04-06 22:40:47 +08:00
tiann
2bbf77ab4c ci: shortten image file name 2023-04-06 19:23:09 +08:00
tiann
f9df8d3351 Revert "ci: Remove tags with same KMI"
This reverts commit ddbc71b273.
2023-04-06 13:35:43 +08:00
tiann
8f4299ef62 ksud: keep pwd after switch mnt ns 2023-04-06 13:20:23 +08:00
zhcnUTF8
fabaa61279 kernel: check CONFIG_SECCOMP status (#351) 2023-04-05 19:09:47 +08:00
Howard Wu
f17de87952 Save install logs to public download folder (#350) 2023-04-05 15:54:55 +08:00
Ylarod
93a607083a ksud: exec uninstall.sh while uninstalling (#347) 2023-04-05 14:36:35 +08:00
Ylarod
7544558173 website: fix typo, add hidden-features (#349) 2023-04-05 14:36:22 +08:00
Ylarod
c96b0e8f8b ksud: support .ksurc (#345) 2023-04-05 13:30:21 +08:00
Igor Sorocean
b181147922 Fix ro translation (#344) 2023-04-05 12:16:02 +08:00
Ylarod
862d12a904 ksud: add /data/adb/ksu/bin to PATH (#343) 2023-04-05 11:47:35 +08:00
tiann
ddbc71b273 ci: Remove tags with same KMI 2023-04-04 19:09:04 +08:00
tiann
c68ea8abbd ci: Add latest GKI tags 2023-04-04 19:07:31 +08:00
tiann
cd5c7f599a ci: trigger build su only if userspace/su changed 2023-04-04 19:01:50 +08:00
tiann
1bb3a23bc4 userspace: remove simple su 2023-04-04 17:24:35 +08:00
tiann
b191ec94a5 ksud: fix unknown hang of root shell 2023-04-04 16:41:57 +08:00
tiann
8f910fbb75 ksud: fix build 2023-04-04 15:09:53 +08:00
tiann
693d827144 ksud: fix windows build again 2023-04-04 14:59:17 +08:00
tiann
effcaf0cde ksud: Remove sufix of 'v' in version tag
close #331
2023-04-04 14:44:51 +08:00
tiann
5be8fe39d0 ksud: fix windows build 2023-04-04 14:33:25 +08:00
tiann
8d12f96d8b ksud: fix compile err in x86_64 2023-04-04 14:12:37 +08:00
tiann
c1b30458d6 ksud: fmt 2023-04-04 13:55:36 +08:00
tiann
48e76f9096 ksud: refine su and make it compitable with MagiskSU
Supported features:

1.  --mount-master, -M, -mm which would make the command run in global mount namespace.
2. - user to switch a specific user's shell.
3. -v, -V to print version code and name.

fix #330 #306 #305 #32
2023-04-04 13:50:48 +08:00
セリカ・シルフィル
6fc8cc7e8e ksud: modules_update will be mounted to /data/adb/modules_update (#336)
ee09b9f9f4
and https://github.com/tiann/KernelSU/pull/327 have moved
`/data/adb/ksu/modules` to `/data/adb/modules`,but `modules_update` has
not to do it.Many modules hard-coded this directory.
2023-04-03 22:32:13 +08:00
tiann
a3874dd089 kernel: use ksud as root shell instead of /system/bin/sh 2023-04-03 20:29:10 +08:00
tiann
bdd5e31b6f ksud: enter root shell when arg0 equals su 2023-04-03 20:28:13 +08:00
tiann
ed0e9cff4b website: fix typo 2023-04-03 20:26:16 +08:00
tiann
62bbee56db kernel: fix incorrect dput 2023-04-03 19:22:05 +08:00
tiann
ec4a233e04 kernel: basicly umount overlayfs in kernel 2023-04-03 19:16:24 +08:00
Igor Sorocean
9efab243ae Add Romanian translation (#335) 2023-04-03 18:03:19 +08:00
浅秋枫影
219970bba5 ksud: Fix installer.sh modules path (#327)
ee09b9f9f4
修改了模块路径,installer.sh 没有修改,导致管理器无法刷新模块(安装/更新/卸载)状态
2023-04-03 11:46:27 +08:00
MilkD
dcbd196c02 Update repos.json (#329)
add a unofficial kernel
2023-03-30 00:35:25 +08:00
tiann
814d65cc28 kernel: Fix side channel attack 2023-03-28 12:07:18 +08:00
Abhiram
8c222add7c ci: Bump rustfmt-check to latest (#326) 2023-03-28 00:25:55 +08:00
Amicia De Rune
ab07557aa5 website: update id translation (#325)
Signed-off-by: RooGhz720 <rooghz720@gmail.com>
2023-03-27 23:42:42 +08:00
Dhruv Gera
7be405e4e4 selinux: Update 4.9 to the correct check (#324)
4.9's last release aka 4.9.337 still needs the same fallbacks as 4.9.212
and breaks otherwise, upgrade this to fix compilation

Tested and working on POCO F1, 4.9.337
2023-03-27 21:26:37 +08:00
tiann
726f44bc60 ksud: Don't umount stock bind mount, just bind it again after overlay. 2023-03-27 18:43:37 +08:00
tiann
c4c597da9e website: Add docs for REPLACE variables 2023-03-27 17:27:53 +08:00
tiann
e5617e236c website: Fix sidebar of zh_CN 2023-03-27 17:01:01 +08:00
tiann
b1af4ada60 ksud: fix clippy 2023-03-27 15:44:18 +08:00
tiann
284b962d64 website: Add anchors for zh_CN 2023-03-27 15:35:57 +08:00
tiann
86ff022dc6 website: Add docs for REMOVE 2023-03-27 15:17:55 +08:00
tiann
dcbbbab11e ksud: Support remove files in customize.sh by REMOVE variables.
e.g:

REMOVE="
/system/app/YouTube
/system/app/Bloatware
"
2023-03-27 15:04:28 +08:00
tiann
14b2afe78d feat: Add documentation for rescuing from bootloop.
- Add new link to sidebar of zh_CN documentation page
- Add new link to sidebar navigation in English documentation page
- Add new guide for rescuing from bootloop
- Include methods for rescuing wrong module flashing
- Provide mechanisms for safe mode and AB updates for module recovery
2023-03-27 11:37:18 +08:00
tiann
ba4ffa7598 ksud: Since we have forbidden module running when Magisk installed, we
can now move common script from /data/adb/ksu/post-fs-data.d ->
/data/adb/post-fs-data.d and /data/adb/ksu/service.d ->
/data/adb/service.d
2023-03-27 10:51:25 +08:00
tiann
92ae0e5460 ci: Fix cross build error with Rust 1.68 2023-03-26 17:35:33 +08:00
Kung-chih
1ace028cef Update zh-rHK and zh-rTW strings (#323) 2023-03-26 15:51:01 +08:00
tiann
43ca2b9831 Add docs for module 2023-03-26 15:43:34 +08:00
Shatyuka
ecd5af76ab kernel: use git from PATH (#316)
One should have git in PATH in order to build Android kernel.
Also it's weird that git is used in `setup.sh` without absolute path.
2023-03-23 15:01:24 +08:00
Shatyuka
be452a22f0 kernel: Makefile new line with posix compatible (#318)
30abd9e310 (commitcomment-105526985)
2023-03-23 10:41:12 +08:00
tiann
6d6f793c69 Revert "kernel: add new line in driver Makefile (#317)"
This reverts commit 30abd9e310.
2023-03-22 19:33:08 +08:00
Shatyuka
30abd9e310 kernel: add new line in driver Makefile (#317)
some device tree has no new line in Makefile
2023-03-22 15:39:12 +08:00
Soo-Hwan Na
d0e3b2672d kernel: Add input hook to ksu_hooks.h (#315)
Then we don't have to do extern input_hook(...) ; input_hook(..) and
just include header file and use input_hook(...) only
Like
f39f4823a1
Not

0c491aca8a
2023-03-21 09:45:12 +08:00
github-actions[bot]
3b8a3ca26f [add device]: (#311)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/310

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: weishu <twsxtd@gmail.com>
2023-03-20 10:23:16 +08:00
github-actions[bot]
33a096da22 [add device]: (#309)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/308

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: weishu <twsxtd@gmail.com>
2023-03-20 10:22:01 +08:00
github-actions[bot]
72ba3ba086 [add device]: Asus Zenfone Max Pro M1/M2 (#313)
Asus Zenfone Max Pro M1/M2 has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/312

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-20 10:19:47 +08:00
tiann
5dd430e6a6 website: update FAQ 2023-03-14 11:00:35 +08:00
tiann
77056a7100 kernel: remove unused poll wait becuase we always call this in post-fs-data, no need to wait for /data mounted 2023-03-08 15:45:56 +08:00
TinyHai
76b9790ffb manager: make a small adjustment to module screen (#291) 2023-03-03 17:29:53 +08:00
weishu
54d2962a0d kernel: add_type for 5.4 is supported actually. 2023-03-03 11:17:17 +07:00
TinyHai
7846b2a440 manager: replace SwipeRefresh with PullRefreshIndicator & refactor so… (#288)
- replace SwipeRefresh with PullRefreshIndicator
- optimize pull refresh
- refactor some code
- fix install bottom in module page again
2023-03-02 12:35:41 +08:00
tiann
8bbfe0c26d manager: Add pstore and diag to bugreport 2023-03-02 11:46:12 +08:00
Amicia De Rune
5c67334889 manager: update id translation (#286)
Signed-off-by: RooGhz720 <rooghz720@gmail.com>
2023-03-02 11:00:43 +08:00
tiann
0b1b73a05d manager: Fix install button in module page 2023-03-01 14:22:46 +08:00
tiann
203dc42e75 manager: hide install button when magisk installed. 2023-03-01 12:51:04 +08:00
tiann
9f6e9f5db6 manager: Show module conflict state with Magisk 2023-03-01 12:12:31 +08:00
tiann
ee09b9f9f4 ksud: Breaking change: modules are mounted to /data/adb/modules and will disable itself when magisk installed. 2023-03-01 11:49:54 +08:00
tiann
c534ef672e manager: Add prop to bugreport 2023-03-01 11:48:24 +08:00
tiann
c34a5ae2a6 ksud: Disable modules when magisk installed 2023-03-01 11:41:53 +08:00
tiann
1c65048813 website: fix typo and add KernelFlasher 2023-03-01 10:56:20 +08:00
uaevuon
3b8d0b83d4 website: Fix typo (#283) 2023-02-28 14:10:31 +08:00
Fankesyooni
b2c39af069 website: Fix wrong directory name in document (#282)
I think there is a misspell in document
2023-02-27 22:57:40 +08:00
rhjdvsgsgks
5c3df7e7a5 kernel: make some compiler happy again (#279)
e743722449
still not fix #252
2023-02-26 22:08:50 +08:00
tiann
ffa5a93c75 ksud: fix mount and remount order 2023-02-26 11:44:08 +08:00
tiann
794b725928 website: Update sirius device. close #275 2023-02-25 10:50:50 +08:00
tiann
ffc06525fb ksud: don't touch rootfs mount 2023-02-24 20:00:57 +08:00
tiann
3fe99712ba manager: Remove the confusing UI of system rw. Many users don't know what is used for and most users don't need this (it is recommended to use module to modify /system). Maybe i'll add it back for cli usage (such as ksud enable system_rw 2023-02-24 12:41:32 +08:00
TinyHai
765c2b7d1f manager: update dep version to fix bug #269 (#272) 2023-02-24 12:25:01 +08:00
tiann
f789bb8c53 ksud: make it buildable without git installed 2023-02-24 11:55:03 +08:00
tiann
745f109686 Revert "ksud: make it buildable without git installed"
This reverts commit 8ed3bd53ac.
2023-02-24 11:53:04 +08:00
tiann
8ed3bd53ac ksud: make it buildable without git installed 2023-02-24 11:41:39 +08:00
weishu
40d7d62af2 kernel: optimize vfs_read probe. 2023-02-23 12:12:50 +07:00
weishu
09fb118d22 kernel: return early for prctl command 2023-02-22 14:26:53 +07:00
Howard Wu
0c3731b0bd Fix WSA Kernel build (#267)
1. Use ubuntu-20.04
1. Use LLVM 12
1. Fix build cache
1. Fix KernelSU version
2023-02-22 09:20:37 +08:00
tiann
349fd09440 ksud: remove original file after copy 2023-02-22 00:08:18 +08:00
tiann
bd3773f32a Revert "ci: use ubuntu-latest for wsa build"
This reverts commit 572708c283.
2023-02-21 23:58:31 +08:00
tiann
572708c283 ci: use ubuntu-latest for wsa build 2023-02-21 23:56:19 +08:00
tiann
fafdacfc41 ksud: copy file when rename failed 2023-02-21 23:52:04 +08:00
tiann
c3ba483b81 ksud: fix clippy 2023-02-21 22:09:41 +08:00
tiann
e309a03515 ksud: Fix windows compile 2023-02-21 21:39:14 +08:00
tiann
82a304e054 ksud: fmt 2023-02-21 20:24:10 +08:00
tiann
b76d973f3a ksud: restore stock mount after overlay mount. close #233 2023-02-21 20:22:00 +08:00
github-actions[bot]
237e477876 [add device]: Miatoll [curtana, excalibur, gram, joyeuse] (#265)
Miatoll [curtana, excalibur, gram, joyeuse] has been added to the
website.
Related issue: https://github.com/tiann/KernelSU/issues/264

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-21 18:50:58 +08:00
tiann
47bcccdce3 ksud: fmt 2023-02-21 13:10:32 +08:00
tiann
ba8ca1f9f2 ksud: fmt 2023-02-21 13:09:03 +08:00
tiann
4837f2101c ksud: fix incorrect umask 2023-02-21 13:06:37 +08:00
tiann
37d2914611 ksud: Fix common script may not be executed 2023-02-21 12:54:05 +08:00
weishu
849164e4de kernel: fix compile err 2023-02-20 20:06:56 +07:00
weishu
683ba112aa kernel: add prefix to avoid symbol confliction 2023-02-20 18:51:59 +07:00
weishu
e743722449 kernel: make some compiler happy 2023-02-20 18:51:59 +07:00
Ylarod
a5ee2ef93b ksud: setns to init for module commands (#262) 2023-02-20 19:43:49 +08:00
Re*Index. (ot_inc)
3e66f5e8cf fix translation (#244)
Japanese Translation Adjustments and Fixes

---------

Co-authored-by: weishu <twsxtd@gmail.com>
2023-02-20 19:37:35 +08:00
weishu
83b0aed52a kernel: apply rules should return success when selinux is disabled or permissive 2023-02-20 18:13:53 +07:00
Amicia De Rune
498763505a manager: update id translation language (#259)
Signed-off-by: RooGhz720 <rooghz720@gmail.com>
2023-02-20 14:33:16 +08:00
Wahid Khan
8cc4ad4d80 website: fix typos (#258) 2023-02-20 14:13:21 +08:00
TinyHai
6ec0c25173 manager: show confirm dialog before uninstall module (#257)
manager: Add Dialog component, show confirm dialog before uninstall
module, fix a bug in listModules
2023-02-20 10:52:23 +08:00
TinyHai
93bcd78f89 manager: Update the bottom bar navigation logic(#254)
close #232
2023-02-20 10:37:40 +08:00
TinyHai
ebf6a52237 manager: Add key to LazyColumn's items to prevent incorrect allow sta… (#255) 2023-02-20 10:31:58 +08:00
tiann
a2906093ec ksud: Fix denpendency 2023-02-20 10:07:30 +08:00
Nullptr
a161c318a1 kernel: allow root processes to get allow/deny list (#256) 2023-02-19 16:09:21 +08:00
github-actions[bot]
3f1ee2f784 [add device]: (#250)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/249

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-18 09:26:51 +08:00
Ylarod
60de2e4a6e manager: send app list in bug report (#248)
We need this for uid in dmesg
2023-02-16 23:39:21 +08:00
tiann
d5bb79edd5 website: Add safemode integrate instruction 2023-02-16 12:08:30 +08:00
tiann
7264a00813 ci: Fix ksud version incorrect 2023-02-16 10:05:35 +08:00
Arya Hajalizade
cf21767975 Update faq.md (#246)
Changed a line towards a better grammar and made it more readable.
2023-02-16 10:00:20 +08:00
Enes Sastim
8fbdd996de use selinux_state for 4.9.212+ (#245)
_selinux_state_ is backported to 4.9 kernel with the 4.9.212 release,
use it to fix the build.
many thanks to @reallysnow for figuring this out.
inspired by
d7c2c5f02a
2023-02-15 11:39:16 +08:00
Amicia De Rune
2c3dcae117 manager: update id translation language (#243)
Signed-off-by: RooGhz720 <rooghz720@gmail.com>
2023-02-14 22:41:41 +08:00
weishu
b024b5d006 kernel: support add_type for 4.x kernel
Co-authored-by: Ookiineko <chiisaineko@protonmail.com>
2023-02-14 19:08:18 +07:00
weishu
d5bab2317e kernel: correctly handle add attr 2023-02-14 18:52:48 +07:00
tiann
0c8b4a48de ksud: ignore empty sepolicy rule 2023-02-14 18:10:39 +08:00
weishu
f9b3218ded kernel: fix policydb length 2023-02-14 14:41:00 +07:00
Amicia De Rune
acc37fb387 manager: Update ID language translation (#239)
Signed-off-by: RooGhz720 <rooghz720@gmail.com>

Signed-off-by: RooGhz720 <rooghz720@gmail.com>
2023-02-14 13:02:16 +08:00
tiann
f50b4dfe34 ksud: fmt 2023-02-14 12:59:21 +08:00
tiann
9ce7351aaa ksud: support check_sepolicy in scripts 2023-02-14 12:57:08 +08:00
tiann
c691a1adb2 manager: Add reboot shortcut for module screen 2023-02-14 12:01:05 +08:00
tiann
9a2a21ec5d manager: Add more info to bugreport 2023-02-14 11:44:57 +08:00
tiann
a9fd0aa132 manager: Add kernel version to bugreport 2023-02-14 11:40:24 +08:00
tiann
198674d889 manager: show manager version 2023-02-14 11:37:37 +08:00
tiann
203a5683ac manager: show safemode in homescreen 2023-02-14 11:29:16 +08:00
tiann
eeb8cda175 manager: show module state in safemode 2023-02-13 23:33:56 +08:00
tiann
b268971323 ksud: support module disable in safemode 2023-02-13 23:33:56 +08:00
weishu
051fc53a4f kernel: count time of volumedown to enter safemode 2023-02-13 22:01:59 +07:00
tiann
55602f1f16 manager: ui state for safemode 2023-02-13 22:41:32 +08:00
tiann
42428345ff ksud: check kernel safemode 2023-02-13 22:28:43 +08:00
weishu
ca950d909b kernel: press KEY_VOLUMEDOWN over 2 seconds will enter safemode and disable all modules
Co-authored-by: Ylarod <me@ylarod.cn>
2023-02-13 21:23:28 +07:00
weishu
20ff530962 kernel: fix sepolicy apply may not work #227
Co-authored-by: sekaiacg <sekaiacg@gmail.com>
2023-02-13 09:12:31 +07:00
tiann
a5dbbf4881 Revert "[add device]: GKI 1.0 (#236)"
This reverts commit e91b1fc89a.
2023-02-13 09:38:03 +08:00
github-actions[bot]
e91b1fc89a [add device]: GKI 1.0 (#236)
GKI 1.0 has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/235

---------

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: weishu <twsxtd@gmail.com>
2023-02-12 18:44:31 +08:00
tiann
4e35e4ae86 ksud: fix vendor only overlay not working 2023-02-12 18:29:27 +08:00
Aquarius223
6d15cb7e33 kernel: Fix f6967d2c lost parameters after ack-linux 4.14.y (>=163) (#234)
* [android-4.14-stable tree:
https://github.com/aosp-mirror/kernel_common/commit/5d0939e1]

Change-Id: Ice92dd83df4c4f1ae272156cb57f95998e45819f

Co-authored-by: stic-server-open <1138705738@qq.com>
2023-02-12 18:11:28 +08:00
tiann
095acad8a6 ksud: Fix mount ext4 failed of sys-mount 2023-02-12 18:07:50 +08:00
skbeh
c187d1ad8a ksud: remove tailing "/" from PATH (#230) 2023-02-12 18:07:07 +08:00
weishu
f6967d2cfb kernel: reset avc cache for sepolicy
Co-authored-by: sekaiacg <sekaiacg@gmail.com>
2023-02-12 13:09:00 +07:00
weishu
388d2b0b59 kernel: disable inofity for fd opened for manager 2023-02-12 12:15:58 +07:00
github-actions[bot]
d9aecbcbca [add device]: (#229)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/228

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-11 19:55:23 +08:00
rxuglr
eabdf3e78c manager: Add Russian language (#225) 2023-02-11 15:26:55 +08:00
tiann
a1fb7c5fdf ksud: don't hardcode system unzip becuase we use busybox now 2023-02-10 18:51:22 +08:00
f19
89394245b1 fix KSU_GIT_VERSION is not defined while importing KSU by 'git submodule add' (#224)
.git is a text file while the module is imported by 'git submodule add'.
2023-02-10 16:34:47 +08:00
Re*Index. (ot_inc)
91f1eb2d6a Added Japanese language to KernelSU Manager (#223)
Japanese translation added.
2023-02-09 23:51:53 +08:00
tiann
ab5f6db54b website: Update installation 2023-02-09 14:04:41 +08:00
tiann
626642af76 ksud: e2fsck before resize2fs 2023-02-09 13:53:07 +08:00
tiann
473f02396f website: Update installation 2023-02-09 10:51:16 +08:00
tiann
aa4b1bf9d8 website: Update installation instruction 2023-02-09 09:28:16 +08:00
tiann
8e5a72fc35 ci: Fix release build 2023-02-08 23:58:47 +08:00
weishu
7302653879 Add release ci (#218) 2023-02-08 22:31:43 +08:00
github-actions[bot]
b2b563547c [add device]: (#220)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/219

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-08 22:18:05 +08:00
tiann
cc29ad151a ksud: Add KSU_KERNEL_VER_CODE 2023-02-08 15:09:36 +08:00
tiann
a4a93d8945 ksud: clippy 2023-02-08 12:33:00 +08:00
tiann
3389cd0aea ksud: Fix module operation order 2023-02-08 12:26:33 +08:00
tiann
d26956ff72 ksud: Fix confliction with stock system overlayfs 2023-02-08 12:14:31 +08:00
Aquarius223
66284bfbe3 kernel: Correctly judge the version of selinux_state (#214)
* Merged related changes in android-common-kernel-4.14.163 [1] Handle
correct checks for older versions (below 4.14.163, 4.9, 4.4)
* fixes 14be7562, it is required in 4.14.163 kernel, it is not needed in
4.14.163 and later

[1]: https://github.com/MiCode/Xiaomi_Kernel_OpenSource/commits/1cfd8419

Change-Id: Iade104312d058a249667ca836259d5608418bb55

Co-authored-by: admin <paper@localhost>
2023-02-07 15:02:48 +08:00
初羽
14be75629b kernel: selinux: Fix build error (#213)
* d77ab8d although fixed some typo, but since there is no include avc.h,
this will cause the build to fail
* Error:


/mnt/HDD/fish/aospa/kernel/msm-4.9/drivers/staging/ksu/selinux/selinux.c:60:2:
error: use of undeclared identifier 'selinux_enforcing'
        selinux_enforcing = enforce;
        ^

/mnt/HDD/fish/aospa/kernel/msm-4.9/drivers/staging/ksu/selinux/selinux.c:81:9:
error: use of undeclared identifier 'selinux_enforcing'
        return selinux_enforcing;
               ^
2 errors generated.

Change-Id: I4cc8917b2b73ca467873222e02d498da8718988e
2023-02-07 09:50:55 +08:00
小さい猫
d77ab8dbff kernel: selinux: fix more typos introduced in #166 (#212)
i didn't realize these typos in #181

Signed-off-by: Ookiineko <chiisaineko@protonmail.com>
2023-02-06 16:31:26 +08:00
weishu
c2ac548ac7 kernel: allow use without git submodule 2023-02-06 15:30:58 +07:00
tiann
ad4d8e939e ksud: clippy 2023-02-06 09:16:15 +08:00
tiann
aa7a00b299 ksud: don't mount module when in safe mode 2023-02-06 08:58:02 +08:00
tiann
1ff421365e ksud: pass KSU_VER and KSU_VER_CODE to installer script 2023-02-06 08:53:18 +08:00
weishu
0a12d0139d kernel: make sure KernelSU is a submodule to avoding incorrect git version 2023-02-05 16:31:50 +07:00
Daybit
181ab4f545 [add device]:Pixel4XL (#210)
[add device]:Pixel4XL
2023-02-05 13:21:40 +08:00
github-actions[bot]
3e29e98f2c [add device]: (#209)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/208

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-05 11:42:58 +08:00
Amicia De Rune
a66c1de660 manager: update translation ID language (#207)
Signed-off-by: RooGhz720 <rooghz720@gmail.com>

Signed-off-by: RooGhz720 <rooghz720@gmail.com>
2023-02-05 07:15:21 +08:00
f19
0c322a33bc kernel: fix filp_open on older kernel's kworker (#205)
On older kernel, kworker missing keyring from init process , and this
keyring is related to FBE , which causes filp_open return ENOKEY or
other errors.To fix this,just install init's keyring to per
kworkers.This works on Kernel 4.4 and 4.9.
2023-02-05 07:14:59 +08:00
小さい猫
cd33a6dd07 website: document the replacement of do_faccessat for some non-GKI (#206)
Signed-off-by: Ookiineko <chiisaineko@protonmail.com>
2023-02-04 21:56:04 +08:00
github-actions[bot]
c1dceaf11f [add device]: (#204)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/203

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-04 15:35:26 +08:00
skbeh
3181dd17bc ci: add CI for clippy, rustfmt and shell scripts (#193) 2023-02-04 13:52:20 +08:00
VINC3NT
c93fa1af59 [add device]: Redmi K40s / POCO F4 (#201) 2023-02-04 13:36:01 +08:00
skbeh
9f4a8d3dfc ksud, kernel: update explanation and fix some issues (#194) 2023-02-04 13:16:51 +08:00
weishu
4da829792f kernel: unify version 2023-02-03 23:01:02 +07:00
github-actions[bot]
1a073224c3 [add device]: Redmi K40 / POCO F3 (#198)
Redmi K40 / POCO F3 has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/197

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-03 23:33:36 +08:00
tiann
175de861bf ksud: Fix incorrect dependency 2023-02-03 23:19:22 +08:00
tiann
aa73c34db2 ksud: unify version 2023-02-03 21:02:11 +08:00
github-actions[bot]
ed2176af8c [add device]: (#196)
has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/195

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-03 19:12:44 +08:00
tiann
49f7d56fdd manager: Add send log 2023-02-03 18:14:42 +08:00
tiann
71cc166f72 ksud: Fix macOS compile 2023-02-03 14:46:48 +08:00
tiann
8ee00839dc ksud: Fix script exec 2023-02-03 14:26:26 +08:00
github-actions[bot]
6239662a7f [add device]: Redmi Note 9 Pro/ Mi 10T Lite/ Mi 10i (#190)
Redmi Note 9 Pro/ Mi 10T Lite/ Mi 10i has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/189

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-03 14:12:24 +08:00
Huy Minh
216c2aa2cd website: vi_VN: Update FAQs (#191) 2023-02-03 14:03:05 +08:00
tiann
70b8b43b48 ksud: support sepolicy check 2023-02-03 13:16:17 +08:00
tiann
430c2e709f website: Add some faq 2023-02-03 11:11:41 +08:00
tiann
b975950b07 ksud: fix module update 2023-02-03 10:05:09 +08:00
tiann
ed42cf42d2 ksud: restore syscon before module install script; this revert 2a4675e25b 2023-02-03 10:00:52 +08:00
tiann
d80c282644 ksud: tweaks for setcon 2023-02-03 09:55:03 +08:00
tiann
a05edb3872 manager: coming soon for system writable 2023-02-03 09:45:42 +08:00
tiann
43b8987b4b manager: open installation guide when install 2023-02-03 09:45:42 +08:00
skbeh
219ea1c458 ksud: fix issues found by clippy (#167)
These issues are mostly found by `cargo clippy -- -W clippy::pedantic`.
2023-02-03 09:45:07 +08:00
skbeh
bea93f6ad7 ksud: compress embed assets (#186) 2023-02-03 09:31:32 +08:00
耀風
e4267848f0 manager: Update Traditional Chinese (#185) 2023-02-03 08:37:07 +08:00
Huy Minh
bc5953b510 manager: vi_VN: small edit (#184) 2023-02-03 05:15:32 +08:00
Arthur
e41b7cd117 website: fix description error (#183) 2023-02-03 05:14:36 +08:00
Nguyễn Long
cab78e7893 manager: add vi translation (#182)
Signed-off-by: HoangLong-Lumi <hoanglong.lumi404@gmail.com>
2023-02-02 23:39:10 +08:00
小さい猫
199f5cc223 fix some typos introduced in #166 (#181)
Signed-off-by: Ookiineko <chiisaineko@protonmail.com>
Co-authored-by: f19 <58457605+F-19-F@users.noreply.github.com>
Co-authored-by: Scirese <nuclearlight91@gmail.com>
2023-02-02 23:38:04 +08:00
Amicia De Rune
962649f7ca manager: add id translation (#179)
Signed-off-by: RooGhz720 <rooghz720@gmail.com>
2023-02-02 22:40:33 +08:00
tiann
7b32c0e37b ksud: opti module mount 2023-02-02 21:56:08 +08:00
tiann
12f353a1ae ksud: Add bin path to script PATH 2023-02-02 21:42:04 +08:00
tiann
c26e170c87 ksud: default umask 022(0644 for file) 2023-02-02 21:24:11 +08:00
tiann
6a706de09e ksud: use busybox to exec all shell scripts 2023-02-02 20:37:17 +08:00
tiann
2a4675e25b ksud: set /system permission after installation script 2023-02-02 20:37:17 +08:00
tiann
0bc36b3299 ksud: fix incorrecy RAII 2023-02-02 20:37:17 +08:00
tiann
dc902b16d4 ksud: copy when rename failed 2023-02-02 20:37:17 +08:00
tiann
86998a032e ksud: fallback to system mount when rust lib mount failed 2023-02-02 20:37:17 +08:00
github-actions[bot]
1727ec41c4 [add device]: OnePlus 8 Serials (#178)
OnePlus 8 Serials has been added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/177

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-02 20:10:51 +08:00
tiann
3eb812be5b ksud: Fix module may mount failed 2023-02-02 14:02:02 +08:00
Amicia De Rune
64c2f6ba5c website: update translation in ID language (#176)
Signed-off-by: RooGhz720 <rooghz720@gmail.com>

Signed-off-by: RooGhz720 <rooghz720@gmail.com>
2023-02-02 13:59:10 +08:00
WeeAris
2db7da0766 website:fix devices info error (#175)
Fix devices info error for unofficially supported devices.
#173
2023-02-02 11:23:21 +08:00
weishu
d1e7bad18f kernel: version 15 2023-02-02 09:05:37 +07:00
tiann
d7cef25665 manager: Superuser support refresh and hide system apps 2023-02-02 09:59:40 +08:00
tiann
23f41145b0 ksud: Fix module resize error 2023-02-02 09:25:41 +08:00
tiann
a969af8159 relicense kernel source code to GPL-v2 2023-02-02 09:04:07 +08:00
tiann
001fa00355 ksud: Add logs for module installation 2023-02-02 08:58:34 +08:00
tiann
a6dddd32b3 website: fix build err 2023-02-02 08:40:28 +08:00
tiann
cd825e34da ksud: support common post-fs-data.d and service.d 2023-02-02 08:39:26 +08:00
github-actions[bot]
2bba088319 [add device]: non-GKI devices, 4.19.x kernel, sm8250, repo for AOSP only. (#171)
non-GKI devices, 4.19.x kernel, sm8250, repo for AOSP only. has been
added to the website.
Related issue: https://github.com/tiann/KernelSU/issues/170

Co-authored-by: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-02 03:20:19 +08:00
Amicia De Rune
4905bd9bb8 website: fix missing directory in ID language (#169)
sry missing /guide/

Signed-off-by: RooGhz720 <rooghz720@gmail.com>

Signed-off-by: RooGhz720 <rooghz720@gmail.com>
2023-02-02 03:19:27 +08:00
Amicia De Rune
3f625a000b website: fix missing pages in ID language (#168)
Signed-off-by: RooGhz720 <rooghz720@gmail.com>

Signed-off-by: RooGhz720 <rooghz720@gmail.com>
2023-02-01 22:41:53 +08:00
tiann
3bfee10a0d ksud: set SELinux context for /vendor 2023-02-01 21:10:16 +08:00
tiann
d5a05da5b8 ci: don't build kernel when ksud changes 2023-02-01 21:01:32 +08:00
tiann
d8042a36c3 ksud: fix post-fs-data.sh and service.sh may be not executed 2023-02-01 20:28:38 +08:00
tiann
85bf01eb65 ksud: use logcat log 2023-02-01 20:28:38 +08:00
f19
4f2b8b7077 kernel: backport to 4.4 (#166)
These changes make KernelSU work on kernel4.4
[link](https://github.com/F-19-F/android_kernel_oneplus_msm8998).
LINUX_VERSION_CODE macro changes have been vertied on 4.4 4.9 4.14.
For kernel 4.4,just pick two commits
* [introduce
KernelSU](2993524f2f)
* [allow init exec ksud under
nosuid](3df9df42a6)
2023-02-01 19:48:36 +08:00
tiann
417ff8a6c5 ksud: fix module installation failed when size < 1M 2023-02-01 19:30:39 +08:00
tiann
681c4a3f0d ksud: minor tweaks 2023-02-01 19:12:25 +08:00
tiann
619dd1ace1 ksud: make it compilable for non-android 2023-02-01 19:04:33 +08:00
tiann
1cd18a643d ksud: some refactor 2023-02-01 18:33:38 +08:00
tiann
3519d61636 ksud: format code 2023-02-01 17:59:16 +08:00
skbeh
46913671a8 kernel, ksud: collect binaries into /data/adb/ksu (#161) 2023-02-01 17:58:58 +08:00
224 changed files with 14909 additions and 2494 deletions

5
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,5 @@
# These are supported funding model platforms
github: tiann
patreon: weishu
custom: https://vxposed.com/donate.html

View File

@@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -0,0 +1,40 @@
name: Feature Request
description: "Suggest an idea for this project"
title: "[Feature]"
labels: "feature"
assignees: tiann
body:
- type: markdown
id: feature-info
attributes:
value: "## Feature Infomation"
- type: textarea
id: feature-main
validations:
required: true
attributes:
label: "Is your feature request related to a problem? Please describe."
description: "A clear and concise description of what the problem is."
placeholder: "I'm always frustrated when [...]"
- type: textarea
id: feature-solution
validations:
required: true
attributes:
label: "Describe the solution you'd like."
description: "A clear and concise description of what you want to happen."
- type: textarea
id: feature-describe
validations:
required: true
attributes:
label: "Describe alternatives you've considered."
description: "A clear and concise description of any alternative solutions or features you've considered."
- type: textarea
id: feature-extra
validations:
required: false
attributes:
label: "Additional context"
description: "Add any other context or screenshots about the feature request here."

View File

@@ -1,43 +0,0 @@
From dbdd2906c0b3a967ca28c6b870b46f905c170661 Mon Sep 17 00:00:00 2001
From: Park Ju Hyung <qkrwngud825@gmail.com>
Date: Wed, 13 Mar 2019 13:36:37 +0900
Subject: [PATCH] setlocalversion: don't check for uncommitted changes
I ofter push after the build is done and I hate seeing "-dirty"
Signed-off-by: Park Ju Hyung <qkrwngud825@gmail.com>
Signed-off-by: Danny Lin <danny@kdrag0n.dev>
Signed-off-by: Divyanshu-Modi <divyan.m05@gmail.com>
Change-Id: I240c516520879da680794fd144b1f273f9e21e13
Signed-off-by: Divyanshu-Modi <divyan.m05@gmail.com>
---
scripts/setlocalversion | 13 -------------
1 file changed, 13 deletions(-)
diff --git a/scripts/setlocalversion b/scripts/setlocalversion
index 842936656b84..ef27a273ebf5 100755
--- a/scripts/setlocalversion
+++ b/scripts/setlocalversion
@@ -107,19 +107,6 @@ scm_version()
printf -- '-svn%s' "$(git svn find-rev $head)"
fi
- # Check for uncommitted changes.
- # First, with git-status, but --no-optional-locks is only
- # supported in git >= 2.14, so fall back to git-diff-index if
- # it fails. Note that git-diff-index does not refresh the
- # index, so it may give misleading results. See
- # git-update-index(1), git-diff-index(1), and git-status(1).
- if {
- git --no-optional-locks status -uno --porcelain 2>/dev/null ||
- git diff-index --name-only HEAD
- } | grep -qvE '^(.. )?scripts/package'; then
- printf '%s' -dirty
- fi
-
# All done with git
return
fi
--
2.37.2

View File

@@ -1,46 +0,0 @@
From bbb9e7fb1ccadac47b58ba615e6874ddeaa9e628 Mon Sep 17 00:00:00 2001
From: Park Ju Hyung <qkrwngud825@gmail.com>
Date: Wed, 13 Mar 2019 13:36:37 +0900
Subject: [PATCH] setlocalversion: don't check for uncommitted changes
I ofter push after the build is done and I hate seeing "-dirty"
Signed-off-by: Park Ju Hyung <qkrwngud825@gmail.com>
Signed-off-by: Danny Lin <danny@kdrag0n.dev>
Signed-off-by: Divyanshu-Modi <divyan.m05@gmail.com>
Change-Id: I240c516520879da680794fd144b1f273f9e21e13
Signed-off-by: Divyanshu-Modi <divyan.m05@gmail.com>
---
scripts/setlocalversion | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/scripts/setlocalversion b/scripts/setlocalversion
index 1b733ae4c..2a3ea7684 100755
--- a/scripts/setlocalversion
+++ b/scripts/setlocalversion
@@ -90,22 +90,6 @@ scm_version()
printf '%s%s' -g "$(echo $head | cut -c1-12)"
fi
- # Check for uncommitted changes.
- # This script must avoid any write attempt to the source tree,
- # which might be read-only.
- # You cannot use 'git describe --dirty' because it tries to
- # create .git/index.lock .
- # First, with git-status, but --no-optional-locks is only
- # supported in git >= 2.14, so fall back to git-diff-index if
- # it fails. Note that git-diff-index does not refresh the
- # index, so it may give misleading results. See
- # git-update-index(1), git-diff-index(1), and git-status(1).
- if {
- git --no-optional-locks status -uno --porcelain 2>/dev/null ||
- git diff-index --name-only HEAD
- } | read dummy; then
- printf '%s' -dirty
- fi
fi
}
--
2.37.2

View File

@@ -1,51 +1,64 @@
build_from_image(){
export TITLE=kernel-aarch64-$(echo $1 | sed 's/Image-//g')
#!/bin/bash
set -euo pipefail
build_from_image() {
export TITLE
TITLE=kernel-aarch64-${1//Image-/}
echo "[+] title: $TITLE"
export PATCH_LEVEL=$(echo $1 | awk -F_ '{ print $2}')
export PATCH_LEVEL
PATCH_LEVEL=$(echo "$1" | awk -F_ '{ print $2}')
echo "[+] patch level: $PATCH_LEVEL"
echo "[+] Download prebuilt ramdisk"
curl -Lo gki-kernel.zip https://dl.google.com/android/gki/gki-certified-boot-android12-5.10-${PATCH_LEVEL}_r1.zip
echo '[+] Download prebuilt ramdisk'
GKI_URL=https://dl.google.com/android/gki/gki-certified-boot-android12-5.10-"${PATCH_LEVEL}"_r1.zip
FALLBACK_URL=https://dl.google.com/android/gki/gki-certified-boot-android12-5.10-2023-01_r1.zip
status=$(curl -sL -w "%{http_code}" "$GKI_URL" -o /dev/null)
if [ "$status" = "200" ]; then
curl -Lo gki-kernel.zip "$GKI_URL"
else
echo "[+] $GKI_URL not found, using $FALLBACK_URL"
curl -Lo gki-kernel.zip "$FALLBACK_URL"
fi
unzip gki-kernel.zip && rm gki-kernel.zip
echo "[+] Unpack prebuilt boot.img"
echo '[+] Unpack prebuilt boot.img'
BOOT_IMG=$(find . -maxdepth 1 -name "boot*.img")
$UNPACK_BOOTIMG --boot_img=$BOOT_IMG
rm $BOOT_IMG
$UNPACK_BOOTIMG --boot_img="$BOOT_IMG"
rm "$BOOT_IMG"
echo "[+] Building Image.gz"
cat Image | $GZIP -n -f -9 > Image.gz
echo '[+] Building Image.gz'
$GZIP -n -k -f -9 Image >Image.gz
echo "[+] Building boot.img"
$MKBOOTIMG --header_version 4 --kernel Image --output boot.img --ramdisk out/ramdisk --os_version 12.0.0 --os_patch_level ${PATCH_LEVEL}
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64*1024*1024)) --image boot.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
echo '[+] Building boot.img'
$MKBOOTIMG --header_version 4 --kernel Image --output boot.img --ramdisk out/ramdisk --os_version 12.0.0 --os_patch_level "${PATCH_LEVEL}"
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
echo "[+] Building boot-gz.img"
$MKBOOTIMG --header_version 4 --kernel Image.gz --output boot-gz.img --ramdisk out/ramdisk --os_version 12.0.0 --os_patch_level ${PATCH_LEVEL}
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64*1024*1024)) --image boot-gz.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
echo '[+] Building boot-gz.img'
$MKBOOTIMG --header_version 4 --kernel Image.gz --output boot-gz.img --ramdisk out/ramdisk --os_version 12.0.0 --os_patch_level "${PATCH_LEVEL}"
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot-gz.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
echo "[+] Building boot-lz4.img"
$MKBOOTIMG --header_version 4 --kernel Image.lz4 --output boot-lz4.img --ramdisk out/ramdisk --os_version 12.0.0 --os_patch_level ${PATCH_LEVEL}
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64*1024*1024)) --image boot-lz4.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
echo '[+] Building boot-lz4.img'
$MKBOOTIMG --header_version 4 --kernel Image.lz4 --output boot-lz4.img --ramdisk out/ramdisk --os_version 12.0.0 --os_patch_level "${PATCH_LEVEL}"
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot-lz4.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
echo "[+] Compress images"
for image in boot*.img; do
$GZIP -n -f -9 $image
mv $image.gz ksu-$VERSION-$image.gz
done
echo '[+] Compress images'
for image in boot*.img; do
$GZIP -n -f -9 "$image"
mv "$image".gz "${1//Image-/}"-"$image".gz
done
echo "[+] Images to upload"
find . -type f -name "*.gz"
echo "[+] Images to upload"
find . -type f -name "*.gz"
find . -type f -name "*.gz" | xargs python3 $GITHUB_WORKSPACE/KernelSU/scripts/ksubot.py
find . -type f -name "*.gz" -exec python3 "$GITHUB_WORKSPACE"/KernelSU/scripts/ksubot.py {} +
}
for dir in Image*; do
if [ -d "$dir" ]; then
echo "----- Building $dir -----"
cd $dir
build_from_image $dir
cd "$dir"
build_from_image "$dir"
cd ..
fi
done
done

View File

@@ -1,38 +1,43 @@
build_from_image(){
export TITLE=kernel-aarch64-$(echo $1 | sed 's/Image-//g')
#!/bin/bash
set -euo pipefail
build_from_image() {
export TITLE
TITLE=kernel-aarch64-${1//Image-/}
echo "[+] title: $TITLE"
echo "[+] Building Image.gz"
cat Image | $GZIP -n -f -9 > Image.gz
echo '[+] Building Image.gz'
$GZIP -n -k -f -9 Image >Image.gz
echo "[+] Building boot.img"
echo '[+] Building boot.img'
$MKBOOTIMG --header_version 4 --kernel Image --output boot.img
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64*1024*1024)) --image boot.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
echo "[+] Building boot-gz.img"
echo '[+] Building boot-gz.img'
$MKBOOTIMG --header_version 4 --kernel Image.gz --output boot-gz.img
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64*1024*1024)) --image boot-gz.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot-gz.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
echo "[+] Building boot-lz4.img"
echo '[+] Building boot-lz4.img'
$MKBOOTIMG --header_version 4 --kernel Image.lz4 --output boot-lz4.img
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64*1024*1024)) --image boot-lz4.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot-lz4.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
echo "[+] Compress images"
for image in boot*.img; do
$GZIP -n -f -9 $image
mv $image.gz ksu-$VERSION-$image.gz
done
echo '[+] Compress images'
for image in boot*.img; do
$GZIP -n -f -9 "$image"
mv "$image".gz "${1//Image-/}"-"$image".gz
done
echo "[+] Images to upload"
find . -type f -name "*.gz"
echo '[+] Images to upload'
find . -type f -name "*.gz"
find . -type f -name "*.gz" | xargs python3 $GITHUB_WORKSPACE/KernelSU/scripts/ksubot.py
find . -type f -name "*.gz" -exec python3 "$GITHUB_WORKSPACE"/KernelSU/scripts/ksubot.py {} +
}
for dir in Image*; do
if [ -d "$dir" ]; then
echo "----- Building $dir -----"
cd $dir
build_from_image $dir
cd "$dir"
build_from_image "$dir"
cd ..
fi
done
done

View File

@@ -42,12 +42,12 @@ jobs:
run: |
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
- uses: ben-z/actions-comment-on-issue@1.0.2
- uses: Kernel-SU/actions-comment-on-issue@master
if: ${{ steps.cpr.outputs.pull-request-number }}
with:
message: "Automatically created pull request: ${{ steps.cpr.outputs.pull-request-url }}"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: ben-z/actions-comment-on-issue@1.0.2
- uses: Kernel-SU/actions-comment-on-issue@master
if: steps.handle-add-device.outputs.success != 'true'
with:
message: "Cannot create pull request. Please check the issue content. Or you can create a pull request manually."
@@ -56,4 +56,4 @@ jobs:
uses: peter-evans/close-issue@v1
with:
issue-number: ${{ github.event.issue.number }}
token: ${{ secrets.GITHUB_TOKEN }}
token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,98 +0,0 @@
name: Build WSA-5.10.117-Kernel
on:
push:
branches: [ "main" ]
paths:
- '.github/workflows/build-WSA-5.10.117-kernel.yml'
- 'kernel/**'
pull_request:
branches: [ "main" ]
paths:
- 'kernel/**'
jobs:
build:
strategy:
matrix:
include:
- version: 5.10.117.2
arch: "x86_64"
out_file: "arch/x86/boot/bzImage"
kernel_make_cmd: "bzImage"
make_config: "config-wsa"
date: "20220906"
- version: 5.10.117.2
arch: "arm64"
out_file: "arch/arm64/boot/Image"
kernel_make_cmd: "ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu Image"
make_config: "config-wsa-arm64"
date: "20220906"
name: Build WSA-Kernel-${{ matrix.version }}-${{ matrix.arch }}
runs-on: ubuntu-18.04
env:
CCACHE_COMPILERCHECK: "%compiler% -dumpmachine; %compiler% -dumpversion"
CCACHE_NOHASHDIR: "true"
CCACHE_MAXSIZE: "2G"
CCACHE_HARDLINK: "true"
steps:
- uses: hendrikmuhs/ccache-action@v1.2
with:
key: ccache-WSA-Kernel-${{ matrix.version }}-${{ matrix.arch }}
append-timestamp: false
save: ${{ github.event_name != 'pull_request' }}
- uses: actions/checkout@v3
with:
path: KernelSU
- name: Install LLVM
run: |
sudo apt install -y --no-install-recommends bc bison build-essential ca-certificates flex git gnupg libelf-dev libssl-dev lsb-release software-properties-common wget libncurses-dev binutils-aarch64-linux-gnu gcc-aarch64-linux-gnu nuget
export LLVM_VERSION=10
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh $LLVM_VERSION
rm ./llvm.sh
sudo ln -s --force /usr/bin/clang-$LLVM_VERSION /usr/bin/clang
sudo ln -s --force /usr/bin/ld.lld-$LLVM_VERSION /usr/bin/ld.lld
sudo ln -s --force /usr/bin/llvm-objdump-$LLVM_VERSION /usr/bin/llvm-objdump
sudo ln -s --force /usr/bin/llvm-ar-$LLVM_VERSION /usr/bin/llvm-ar
sudo ln -s --force /usr/bin/llvm-nm-$LLVM_VERSION /usr/bin/llvm-nm
sudo ln -s --force /usr/bin/llvm-strip-$LLVM_VERSION /usr/bin/llvm-strip
sudo ln -s --force /usr/bin/llvm-objcopy-$LLVM_VERSION /usr/bin/llvm-objcopy
sudo ln -s --force /usr/bin/llvm-readelf-$LLVM_VERSION /usr/bin/llvm-readelf
sudo ln -s --force /usr/bin/clang++-$LLVM_VERSION /usr/bin/clang++
- name: Download kernel source
run: |
cd $GITHUB_WORKSPACE
KERNEL_ROOT=$GITHUB_WORKSPACE/WSA-Linux-Kernel
echo "[+] 克隆远程仓库 WSA-Linux-Kernel..."
git clone https://github.com/microsoft/WSA-Linux-Kernel
cd WSA-Linux-Kernel && git checkout android-lts/latte/${{ matrix.version }}
echo "[+] 切换到分支 android-lts/latte/${{ matrix.version }}"
echo "[+] 导入 KernelSU"
echo "[+] KERNEL_ROOT: $KERNEL_ROOT"
echo "[+] 复制 kernel su driver 到路径:$KERNEL_ROOT/drivers"
ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $KERNEL_ROOT/drivers/kernelsu
DRIVER_MAKEFILE=$KERNEL_ROOT/drivers/Makefile
echo "[+] 添加 kernel su driver 到文件:$DRIVER_MAKEFILE"
grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_MAKEFILE
echo "[+] KernelSU 导入完成"
cd $KERNEL_ROOT && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/5.10/*.patch
cd -
- name: Build Kernel
working-directory: WSA-Linux-Kernel
run: |
KERNEL_ROOT=$GITHUB_WORKSPACE/WSA-Linux-Kernel
echo "[+] 构建 kernel"
cp configs/wsa/${{ matrix.make_config }}-5.10 $KERNEL_ROOT/.config
echo "[+] 复制配置文件 configs/wsa/${{ matrix.make_config }}-5.10 到 $KERNEL_ROOT/.config"
echo "执行: make -j`nproc` LLVM=1 ${{ matrix.kernel_make_cmd }}"
make -j`nproc` LLVM=1 ${{ matrix.kernel_make_cmd }} CCACHE="/usr/bin/ccache"
- name: Upload kernel-${{ matrix.arch }}-${{ matrix.version }}
uses: actions/upload-artifact@v3
with:
name: kernel-WSA-${{ matrix.arch }}-${{ matrix.version }}-${{ matrix.date }}
path: WSA-Linux-Kernel/${{ matrix.out_file }}

View File

@@ -0,0 +1,31 @@
name: Build debug kernel
on:
workflow_dispatch:
jobs:
build-debug-kernel-a12:
uses: ./.github/workflows/gki-kernel.yml
with:
version: android12-5.10
version_name: android12-5.10.177
tag: android12-5.10-2023-06
os_patch_level: 2023-06
patch_path: "5.10"
debug: true
build-debug-kernel-a13:
strategy:
matrix:
include:
- version: "5.10"
sub_level: 177
os_patch_level: 2023-06
- version: "5.15"
sub_level: 94
os_patch_level: 2023-06
uses: ./.github/workflows/gki-kernel.yml
with:
version: android13-${{ matrix.version }}
version_name: android13-${{ matrix.version }}.${{ matrix.sub_level }}
tag: android13-${{ matrix.version }}-${{ matrix.os_patch_level }}
patch_path: ${{ matrix.version }}
debug: true

View File

@@ -7,7 +7,6 @@ on:
- ".github/workflows/gki-kernel.yml"
- ".github/scripts/build_a12.sh"
- "kernel/**"
- "userspace/ksud/**"
pull_request:
branches: ["main"]
paths:
@@ -15,7 +14,7 @@ on:
- ".github/workflows/gki-kernel.yml"
- ".github/scripts/build-a12.sh"
- "kernel/**"
- "userspace/ksud/**"
workflow_call:
jobs:
build-kernel:
if: github.event_name != 'pull_request'
@@ -23,15 +22,25 @@ jobs:
matrix:
include:
- sub_level: 66
os_patch_level: 2021-11
os_patch_level: 2022-01
- sub_level: 81
os_patch_level: 2022-03
- sub_level: 101
os_patch_level: 2022-05
- sub_level: 110
os_patch_level: 2022-07
- sub_level: 117
os_patch_level: 2022-09
- sub_level: 136
os_patch_level: 2022-11
- sub_level: 149
os_patch_level: 2023-01
- sub_level: 160
os_patch_level: 2023-03
- sub_level: 168
os_patch_level: 2023-05
- sub_level: 177
os_patch_level: 2023-06
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
@@ -43,7 +52,7 @@ jobs:
upload-artifacts:
needs: build-kernel
runs-on: ubuntu-latest
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' || github.ref == 'refs/heads/ci' }}
env:
CHAT_ID: ${{ secrets.CHAT_ID }}
CACHE_CHAT_ID: ${{ secrets.CACHE_CHAT_ID }}
@@ -93,17 +102,26 @@ jobs:
export MKBOOTIMG=$GITHUB_WORKSPACE/mkbootimg/mkbootimg.py
export UNPACK_BOOTIMG=$GITHUB_WORKSPACE/mkbootimg/unpack_bootimg.py
cd $GITHUB_WORKSPACE/KernelSU
export VERSION=$(git rev-list --count HEAD)
export VERSION=$(($(git rev-list --count HEAD) + 10200))
echo "VERSION: $VERSION"
cd -
bash $GITHUB_WORKSPACE/KernelSU/.github/scripts/build_a12.sh
- name: Display structure of boot files
run: ls -R
- name: Upload images artifact
uses: actions/upload-artifact@v3
with:
name: boot-images-android12
path: Image-android12*/*.img.gz
check-build-kernel:
if: github.event_name == 'pull_request'
uses: ./.github/workflows/gki-kernel.yml
with:
version: android12-5.10
version_name: android12-5.10.101
tag: android12-5.10-2022-05
os_patch_level: 2022-05
version_name: android12-5.10.177
tag: android12-5.10-2023-06
os_patch_level: 2023-06
patch_path: "5.10"

View File

@@ -7,7 +7,6 @@ on:
- ".github/workflows/gki-kernel.yml"
- ".github/scripts/build_a13.sh"
- "kernel/**"
- "userspace/ksud/**"
pull_request:
branches: ["main"]
paths:
@@ -15,7 +14,7 @@ on:
- ".github/workflows/gki-kernel.yml"
- ".github/scripts/build-a13.sh"
- "kernel/**"
- "userspace/ksud/**"
workflow_call:
jobs:
build-kernel:
if: github.event_name != 'pull_request'
@@ -28,23 +27,42 @@ jobs:
- version: "5.10"
sub_level: 149
os_patch_level: 2023-01
- version: "5.10"
sub_level: 157
os_patch_level: 2023-03
- version: "5.10"
sub_level: 168
os_patch_level: 2023-05
- version: "5.10"
sub_level: 177
os_patch_level: 2023-06
- version: "5.15"
sub_level: 41
os_patch_level: 2022-11
- version: "5.15"
sub_level: 74
os_patch_level: 2022-12
os_patch_level: 2023-01
- version: "5.15"
sub_level: 78
os_patch_level: 2023-03
- version: "5.15"
sub_level: 94
os_patch_level: 2023-05
- version: "5.15"
sub_level: 104
os_patch_level: 2023-06
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
version: android13-${{ matrix.version }}
version_name: android13-${{ matrix.version }}.${{ matrix.sub_level }}
tag: android13-${{ matrix.version }}-${{ matrix.os_patch_level }}
os_patch_level: ${{ matrix.os_patch_level }}
patch_path: ${{ matrix.version }}
upload-artifacts:
needs: build-kernel
runs-on: ubuntu-latest
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' || github.ref == 'refs/heads/ci' }}
env:
CHAT_ID: ${{ secrets.CHAT_ID }}
CACHE_CHAT_ID: ${{ secrets.CACHE_CHAT_ID }}
@@ -94,10 +112,19 @@ jobs:
export MKBOOTIMG=$GITHUB_WORKSPACE/mkbootimg/mkbootimg.py
export UNPACK_BOOTIMG=$GITHUB_WORKSPACE/mkbootimg/unpack_bootimg.py
cd $GITHUB_WORKSPACE/KernelSU
export VERSION=$(git rev-list --count HEAD)
export VERSION=$(($(git rev-list --count HEAD) + 10200))
echo "VERSION: $VERSION"
cd -
bash $GITHUB_WORKSPACE/KernelSU/.github/scripts/build_a13.sh
- name: Display structure of boot files
run: ls -R
- name: Upload images artifact
uses: actions/upload-artifact@v3
with:
name: boot-images-android13
path: Image-android13*/*.img.gz
check-build-kernel:
if: github.event_name == 'pull_request'
@@ -105,14 +132,14 @@ jobs:
matrix:
include:
- version: "5.10"
sub_level: 107
os_patch_level: 2022-11
sub_level: 177
os_patch_level: 2023-06
- version: "5.15"
sub_level: 41
os_patch_level: 2022-11
sub_level: 104
os_patch_level: 2023-06
uses: ./.github/workflows/gki-kernel.yml
with:
version: android13-${{ matrix.version }}
version_name: android13-${{ matrix.version }}.${{ matrix.sub_level }}
tag: android13-${{ matrix.version }}-${{ matrix.os_patch_level }}
patch_path: ${{ matrix.version }}
patch_path: ${{ matrix.version }}

136
.github/workflows/build-kernel-arcvm.yml vendored Normal file
View File

@@ -0,0 +1,136 @@
name: Build Kernel - ChromeOS ARCVM
on:
push:
branches: ["main"]
paths:
- ".github/workflows/build-kernel-arcvm.yml"
- "kernel/**"
pull_request:
branches: ["main"]
paths:
- ".github/workflows/build-kernel-arcvm.yml"
- "kernel/**"
workflow_call:
workflow_dispatch:
jobs:
build:
strategy:
matrix:
arch: [x86_64]
version: ["5.10.178"]
include:
- arch: x86_64
git_tag: chromeos-5.10-arcvm
file_name: "bzImage"
name: Build ChromeOS ARCVM kernel
runs-on: ubuntu-20.04
env:
LTO: thin
ROOT_DIR: /
KERNEL_DIR: ${{ github.workspace }}/kernel
steps:
- name: Install Build Tools
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends bc \
bison build-essential ca-certificates flex git gnupg \
libelf-dev libssl-dev lsb-release software-properties-common wget \
libncurses-dev binutils-aarch64-linux-gnu gcc-aarch64-linux-gnu nuget gzip \
rsync python3 device-tree-compiler
sudo ln -s --force python3 /usr/bin/python
export LLVM_VERSION=12
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh $LLVM_VERSION
rm ./llvm.sh
sudo ln -s --force /usr/bin/clang-$LLVM_VERSION /usr/bin/clang
sudo ln -s --force /usr/bin/ld.lld-$LLVM_VERSION /usr/bin/ld.lld
sudo ln -s --force /usr/bin/llvm-objdump-$LLVM_VERSION /usr/bin/llvm-objdump
sudo ln -s --force /usr/bin/llvm-ar-$LLVM_VERSION /usr/bin/llvm-ar
sudo ln -s --force /usr/bin/llvm-nm-$LLVM_VERSION /usr/bin/llvm-nm
sudo ln -s --force /usr/bin/llvm-strip-$LLVM_VERSION /usr/bin/llvm-strip
sudo ln -s --force /usr/bin/llvm-objcopy-$LLVM_VERSION /usr/bin/llvm-objcopy
sudo ln -s --force /usr/bin/llvm-readelf-$LLVM_VERSION /usr/bin/llvm-readelf
sudo ln -s --force /usr/bin/clang++-$LLVM_VERSION /usr/bin/clang++
- name: Checkout KernelSU
uses: actions/checkout@v3
with:
path: KernelSU
fetch-depth: 0
- name: Setup kernel source
run: git clone https://chromium.googlesource.com/chromiumos/third_party/kernel.git -b ${{ matrix.git_tag }} --depth=1
- name: Setup KernelSU
working-directory: kernel
run: |
echo "[+] KernelSU setup"
KERNEL_ROOT=$GITHUB_WORKSPACE/kernel
echo "[+] KERNEL_ROOT: $KERNEL_ROOT"
echo "[+] Copy KernelSU driver to $KERNEL_ROOT/drivers"
ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $KERNEL_ROOT/drivers/kernelsu
echo "[+] Add KernelSU driver to Makefile"
DRIVER_MAKEFILE=$KERNEL_ROOT/drivers/Makefile
grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_MAKEFILE
echo "[+] Apply KernelSU patches"
cd $KERNEL_ROOT && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/5.10/*.patch
echo "[+] Patch script/setlocalversion"
sed -i 's/-dirty//g' $KERNEL_ROOT/scripts/setlocalversion
echo "[+] KernelSU setup done."
cd $GITHUB_WORKSPACE/KernelSU
VERSION=$(($(git rev-list --count HEAD) + 10200))
echo "VERSION: $VERSION"
echo "kernelsu_version=$VERSION" >> $GITHUB_ENV
- name: Build Kernel
working-directory: kernel
run: |
set -a && . build.config.gki.x86_64; set +a
export DEFCONFIG=x86_64_arcvm_defconfig
make LLVM=1 LLVM_IAS=1 DEPMOD=depmod DTC=dtc O=${PWD} mrproper
make LLVM=1 LLVM_IAS=1 DEPMOD=depmod DTC=dtc O=${PWD} ${DEFCONFIG} < /dev/null
scripts/config --file .config -e LTO_CLANG -d LTO_NONE -e LTO_CLANG_THIN -d LTO_CLANG_FULL -e THINLTO
make LLVM=1 LLVM_IAS=1 DEPMOD=depmod DTC=dtc O=${PWD} -j$(nproc) bzImage modules prepare-objtool
echo "file_path=${PWD}/arch/x86/boot/bzImage" >> $GITHUB_ENV
- name: Upload kernel-ARCVM-${{ matrix.arch }}-${{ matrix.version }}
uses: actions/upload-artifact@v3
with:
name: kernel-ARCVM-${{ matrix.arch }}-${{ matrix.version }}
path: "${{ env.file_path }}"
- name: Post to Telegram
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
env:
CHAT_ID: ${{ secrets.CHAT_ID }}
CACHE_CHAT_ID: ${{ secrets.CACHE_CHAT_ID }}
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
COMMIT_URL: ${{ github.event.head_commit.url }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
TITLE=kernel-ARCVM-${{ matrix.arch }}-${{ matrix.version }}
echo "[+] title: $TITLE"
export TITLE
export VERSION="${{ env.kernelsu_version }}"
echo "[+] Compress images"
gzip -n -f -9 "${{ env.file_path }}"
echo "[+] Image to upload"
ls -l "${{ env.file_path }}.gz"
if [ -n "${{ secrets.BOT_TOKEN }}" ]; then
pip3 install python-telegram-bot
python3 "$GITHUB_WORKSPACE/KernelSU/scripts/ksubot.py" "${{ env.file_path }}.gz"
fi

151
.github/workflows/build-kernel-wsa.yml vendored Normal file
View File

@@ -0,0 +1,151 @@
name: Build Kernel - WSA
on:
push:
branches: ["main"]
paths:
- ".github/workflows/build-kernel-wsa.yml"
- "kernel/**"
pull_request:
branches: ["main"]
paths:
- ".github/workflows/build-kernel-wsa.yml"
- "kernel/**"
workflow_call:
workflow_dispatch:
jobs:
build:
strategy:
matrix:
arch: [x86_64, arm64]
version: ["5.15.78.1", "5.15.94.4"]
include:
- arch: x86_64
file_name: "bzImage"
- arch: arm64
file_name: "Image"
cross_compile: "aarch64-linux-gnu"
- version: "5.15.78.1"
arch: x86_64
make_config: config-wsa-x64
- version: "5.15.78.1"
arch: arm64
make_config: config-wsa-arm64
- version: "5.15.94.4"
arch: x86_64
make_config: config-wsa-x64
- version: "5.15.94.4"
arch: arm64
make_config: config-wsa-arm64
- version: "5.15.78.1"
device_code: latte-2
kernel_version: "5.15"
- version: "5.15.94.4"
device_code: latte-2
kernel_version: "5.15"
name: Build WSA-Kernel-${{ matrix.version }}-${{ matrix.arch }}
runs-on: ubuntu-20.04
env:
CCACHE_COMPILERCHECK: "%compiler% -dumpmachine; %compiler% -dumpversion"
CCACHE_NOHASHDIR: "true"
CCACHE_HARDLINK: "true"
steps:
- name: Install Build Tools
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends bc bison build-essential ca-certificates flex git gnupg libelf-dev libssl-dev lsb-release software-properties-common wget libncurses-dev binutils-aarch64-linux-gnu gcc-aarch64-linux-gnu nuget gzip
export LLVM_VERSION=12
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh $LLVM_VERSION
rm ./llvm.sh
sudo ln -s --force /usr/bin/clang-$LLVM_VERSION /usr/bin/clang
sudo ln -s --force /usr/bin/ld.lld-$LLVM_VERSION /usr/bin/ld.lld
sudo ln -s --force /usr/bin/llvm-objdump-$LLVM_VERSION /usr/bin/llvm-objdump
sudo ln -s --force /usr/bin/llvm-ar-$LLVM_VERSION /usr/bin/llvm-ar
sudo ln -s --force /usr/bin/llvm-nm-$LLVM_VERSION /usr/bin/llvm-nm
sudo ln -s --force /usr/bin/llvm-strip-$LLVM_VERSION /usr/bin/llvm-strip
sudo ln -s --force /usr/bin/llvm-objcopy-$LLVM_VERSION /usr/bin/llvm-objcopy
sudo ln -s --force /usr/bin/llvm-readelf-$LLVM_VERSION /usr/bin/llvm-readelf
sudo ln -s --force /usr/bin/clang++-$LLVM_VERSION /usr/bin/clang++
- name: Checkout KernelSU
uses: actions/checkout@v3
with:
path: KernelSU
fetch-depth: 0
- name: Setup kernel source
uses: actions/checkout@v3
with:
repository: microsoft/WSA-Linux-Kernel
ref: android-lts/${{ matrix.device_code }}/${{ matrix.version }}
path: WSA-Linux-Kernel
- name: Setup Ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: WSA-Kernel-${{ matrix.version }}-${{ matrix.arch }}
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
max-size: 2G
- name: Setup KernelSU
working-directory: WSA-Linux-Kernel
run: |
echo "[+] KernelSU setup"
KERNEL_ROOT=$GITHUB_WORKSPACE/WSA-Linux-Kernel
echo "[+] KERNEL_ROOT: $KERNEL_ROOT"
echo "[+] Copy KernelSU driver to $KERNEL_ROOT/drivers"
ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $KERNEL_ROOT/drivers/kernelsu
echo "[+] Add KernelSU driver to Makefile"
DRIVER_MAKEFILE=$KERNEL_ROOT/drivers/Makefile
grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_MAKEFILE
echo "[+] Apply KernelSU patches"
cd $KERNEL_ROOT && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/${{ matrix.kernel_version }}/*.patch
echo "[+] KernelSU setup done."
cd $GITHUB_WORKSPACE/KernelSU
VERSION=$(($(git rev-list --count HEAD) + 10200))
echo "VERSION: $VERSION"
echo "kernelsu_version=$VERSION" >> $GITHUB_ENV
- name: Build Kernel
working-directory: WSA-Linux-Kernel
run: |
cp configs/wsa/${{ matrix.make_config }} .config
make olddefconfig
make -j`nproc` LLVM=1 ARCH=${{ matrix.arch }} CROSS_COMPILE=${{ matrix.cross_compile }} ${{ matrix.file_name }} CCACHE="/usr/bin/ccache"
declare -A ARCH_MAP=(["x86_64"]="x86" ["arm64"]="arm64")
echo "file_path=WSA-Linux-Kernel/arch/${ARCH_MAP[${{ matrix.arch }}]}/boot/${{ matrix.file_name }}" >> $GITHUB_ENV
- name: Upload kernel-${{ matrix.arch }}-${{ matrix.version }}
uses: actions/upload-artifact@v3
with:
name: kernel-WSA-${{ matrix.arch }}-${{ matrix.version }}
path: "${{ env.file_path }}"
- name: Post to Telegram
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
env:
CHAT_ID: ${{ secrets.CHAT_ID }}
CACHE_CHAT_ID: ${{ secrets.CACHE_CHAT_ID }}
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
COMMIT_URL: ${{ github.event.head_commit.url }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
TITLE=kernel-${{ matrix.arch }}-WSA-${{ matrix.version }}
echo "[+] title: $TITLE"
export TITLE
export VERSION="${{ env.kernelsu_version }}"
echo "[+] Compress images"
gzip -n -f -9 "${{ env.file_path }}"
echo "[+] Image to upload"
ls -l "${{ env.file_path }}.gz"
if [ -n "${{ secrets.BOT_TOKEN }}" ]; then
pip3 install python-telegram-bot
python3 "$GITHUB_WORKSPACE/KernelSU/scripts/ksubot.py" "${{ env.file_path }}.gz"
fi

View File

@@ -19,6 +19,7 @@ jobs:
include:
- target: aarch64-linux-android
- target: x86_64-linux-android
- target: x86_64-pc-windows-gnu # only for build
uses: ./.github/workflows/ksud.yml
with:
target: ${{ matrix.target }}

View File

@@ -1,15 +1,18 @@
name: Build Manager
on:
push:
branches: [ "main" ]
paths:
paths:
- '.github/workflows/build-manager.yml'
- 'manager/**'
- 'userspace/ksud/**'
pull_request:
branches: [ "main" ]
paths:
paths:
- 'manager/**'
workflow_call:
jobs:
build-ksud:
strategy:
@@ -20,87 +23,104 @@ jobs:
uses: ./.github/workflows/ksud.yml
with:
target: ${{ matrix.target }}
build-manager:
needs: build-ksud
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./manager
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup need_upload
id: need_upload
run: |
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
echo "UPLOAD=true" >> $GITHUB_OUTPUT
else
echo "UPLOAD=false" >> $GITHUB_OUTPUT
fi
- name: set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
cache: gradle
- uses: nttld/setup-ndk@v1
with:
ndk-version: r25b
local-cache: true
- name: Extract keystore
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
run: |
if [ ! -z "${{ secrets.KEYSTORE }}" ]; then
echo KEYSTORE_PASSWORD='${{ secrets.KEYSTORE_PASSWORD }}' >> sign.properties
echo KEY_ALIAS='${{ secrets.KEY_ALIAS }}' >> sign.properties
echo KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}' >> sign.properties
echo KEYSTORE_FILE='../key.jks' >> sign.properties
echo ${{ secrets.KEYSTORE }} | base64 --decode > key.jks
fi
- name: Download arm64 ksud
uses: actions/download-artifact@v3
with:
name: ksud-aarch64-linux-android
path: .
- name: Download x86_64 ksud
uses: actions/download-artifact@v3
with:
name: ksud-x86_64-linux-android
path: .
- name: Copy ksud to app jniLibs
run: |
mkdir -p app/src/main/jniLibs/arm64-v8a
mkdir -p app/src/main/jniLibs/x86_64
cp -f ../aarch64-linux-android/release/ksud ../manager/app/src/main/jniLibs/arm64-v8a/libksud.so
cp -f ../x86_64-linux-android/release/ksud ../manager/app/src/main/jniLibs/x86_64/libksud.so
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew clean assembleRelease
- name: Upload build artifact
uses: actions/upload-artifact@v3
with:
name: manager
path: manager/app/build/outputs/apk/release/*.apk
- name: Setup mutex for uploading
uses: ben-z/gh-action-mutex@v1.0-alpha-7
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
- name: Upload to telegram
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
env:
CHAT_ID: ${{ secrets.CHAT_ID }}
CACHE_CHAT_ID: ${{ secrets.CACHE_CHAT_ID }}
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
COMMIT_URL: ${{ github.event.head_commit.url }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
TITLE: Manager
run: |
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
export VERSION=$(git rev-list --count HEAD)
APK=$(find ./app/build/outputs/apk/release -name "*.apk")
pip3 install python-telegram-bot
python3 $GITHUB_WORKSPACE/scripts/ksubot.py $APK
fi
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup need_upload
id: need_upload
run: |
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
echo "UPLOAD=true" >> $GITHUB_OUTPUT
else
echo "UPLOAD=false" >> $GITHUB_OUTPUT
fi
- name: Write key
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
run: |
if [ ! -z "${{ secrets.KEYSTORE }}" ]; then
echo KEYSTORE_PASSWORD='${{ secrets.KEYSTORE_PASSWORD }}' >> gradle.properties
echo KEY_ALIAS='${{ secrets.KEY_ALIAS }}' >> gradle.properties
echo KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}' >> gradle.properties
echo KEYSTORE_FILE='../key.jks' >> gradle.properties
echo ${{ secrets.KEYSTORE }} | base64 --decode > key.jks
fi
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: "temurin"
java-version: "17"
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
with:
gradle-home-cache-cleanup: true
- name: Download arm64 ksud
uses: actions/download-artifact@v3
with:
name: ksud-aarch64-linux-android
path: .
- name: Download x86_64 ksud
uses: actions/download-artifact@v3
with:
name: ksud-x86_64-linux-android
path: .
- name: Copy ksud to app jniLibs
run: |
mkdir -p app/src/main/jniLibs/arm64-v8a
mkdir -p app/src/main/jniLibs/x86_64
cp -f ../aarch64-linux-android/release/ksud ../manager/app/src/main/jniLibs/arm64-v8a/libksud.so
cp -f ../x86_64-linux-android/release/ksud ../manager/app/src/main/jniLibs/x86_64/libksud.so
- name: Build with Gradle
run: |
echo 'org.gradle.parallel=true' >> gradle.properties
echo 'org.gradle.vfs.watch=true' >> gradle.properties
echo 'org.gradle.jvmargs=-Xmx2048m' >> gradle.properties
echo 'android.native.buildOutput=verbose' >> gradle.properties
sed -i 's/org.gradle.configuration-cache=true//g' gradle.properties
./gradlew clean assembleRelease
- name: Upload build artifact
uses: actions/upload-artifact@v3
with:
name: manager
path: manager/app/build/outputs/apk/release/*.apk
- name: Setup mutex for uploading
uses: ben-z/gh-action-mutex@v1.0-alpha-7
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
- name: Upload to telegram
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
env:
CHAT_ID: ${{ secrets.CHAT_ID }}
CACHE_CHAT_ID: ${{ secrets.CACHE_CHAT_ID }}
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
COMMIT_URL: ${{ github.event.head_commit.url }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
TITLE: Manager
run: |
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
export VERSION=$(git rev-list --count HEAD)
APK=$(find ./app/build/outputs/apk/release -name "*.apk")
pip3 install python-telegram-bot
python3 $GITHUB_WORKSPACE/scripts/ksubot.py $APK
fi

View File

@@ -4,12 +4,12 @@ on:
branches: [ "main" ]
paths:
- '.github/workflows/build-su.yml'
- 'userspace/**'
- 'userspace/su/**'
- 'scripts/ksubot.py'
pull_request:
branches: [ "main" ]
paths:
- 'userspace/**'
- 'userspace/su/**'
jobs:
build-su:
name: Build userspace su

37
.github/workflows/clippy.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: Clippy check
on:
push:
branches:
- main
paths:
- '.github/workflows/clippy.yml'
- 'userspace/ksud/**'
pull_request:
branches:
- main
paths:
- '.github/workflows/clippy.yml'
- 'userspace/ksud/**'
env:
RUSTFLAGS: '-Dwarnings'
jobs:
clippy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# cross build failed after Rust 1.68, see https://github.com/cross-rs/cross/issues/1222
- run: rustup default 1.67.0
- uses: Swatinem/rust-cache@v2
with:
workspaces: userspace/ksud
- name: Install cross
run: cargo install cross
- name: Run clippy
run: |
cross clippy --manifest-path userspace/ksud/Cargo.toml --target aarch64-linux-android --release
cross clippy --manifest-path userspace/ksud/Cargo.toml --target x86_64-linux-android --release

View File

@@ -45,6 +45,10 @@ on:
description: >
Artifact name of prebuilt ksud to be embedded
for example: ksud-aarch64-linux-android
debug:
required: false
type: boolean
default: false
secrets:
BOOT_SIGN_KEY:
required: false
@@ -64,7 +68,6 @@ jobs:
env:
CCACHE_COMPILERCHECK: "%compiler% -dumpmachine; %compiler% -dumpversion"
CCACHE_NOHASHDIR: "true"
CCACHE_MAXSIZE: "2G"
CCACHE_HARDLINK: "true"
steps:
- uses: actions/checkout@v3
@@ -72,13 +75,6 @@ jobs:
path: KernelSU
fetch-depth: 0
- uses: hendrikmuhs/ccache-action@v1.2
if: inputs.use_cache == true
with:
key: ccache-aarch64-${{ inputs.version_name }}
append-timestamp: false
save: ${{ github.event_name != 'pull_request' }}
- name: Setup need_upload
id: need_upload
run: |
@@ -94,11 +90,18 @@ jobs:
git clone https://gerrit.googlesource.com/git-repo
mkdir android-kernel && cd android-kernel
../git-repo/repo init --depth=1 --u https://android.googlesource.com/kernel/manifest -b common-${{ inputs.tag }}
REMOTE_BRANCH=$(git ls-remote https://android.googlesource.com/kernel/common ${{ inputs.tag }})
if grep -q deprecated <<< $REMOTE_BRANCH; then
echo "Found deprecated branch: ${{ inputs.tag }}"
sed -i 's/"${{ inputs.tag }}"/"deprecated\/${{ inputs.tag }}"/g' .repo/manifests/default.xml
cat .repo/manifests/default.xml
fi
../git-repo/repo sync -j$(nproc --all)
- name: Setup KernelSU
env:
PATCH_PATH: ${{ inputs.patch_path }}
IS_DEBUG_KERNEL: ${{ inputs.debug }}
run: |
cd $GITHUB_WORKSPACE/android-kernel
echo "[+] KernelSU setup"
@@ -111,6 +114,13 @@ jobs:
grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_MAKEFILE
echo "[+] Apply KernelSU patches"
cd $GKI_ROOT/common/ && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/$PATCH_PATH/*.patch
echo "[+] Patch script/setlocalversion"
sed -i 's/-dirty//g' $GKI_ROOT/common/scripts/setlocalversion
if [ "$IS_DEBUG_KERNEL" = "true" ]; then
echo "[+] Enable debug features for kernel"
echo "ccflags-y += -DCONFIG_KSU_DEBUG" >> $GITHUB_WORKSPACE/KernelSU/kernel/Makefile
fi
echo "[+] KernelSU setup done."
- name: Symbol magic
@@ -124,6 +134,14 @@ jobs:
echo "[+] Add KernelSU symbols"
cat $KSU_ROOT/kernel/export_symbol.txt | awk '{sub("[ \t]+","");print " "$0}' >> $SYMBOL_LIST
- name: Setup ccache
if: inputs.use_cache == true
uses: hendrikmuhs/ccache-action@v1.2
with:
key: gki-kernel-aarch64-${{ inputs.version_name }}
max-size: 2G
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
- name: Build boot.img
working-directory: android-kernel
run: CCACHE="/usr/bin/ccache" LTO=thin BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh
@@ -149,4 +167,4 @@ jobs:
uses: actions/upload-artifact@v3
with:
name: AnyKernel3-${{ inputs.version_name }}_${{ inputs.os_patch_level }}
path: ./AnyKernel3/*
path: ./AnyKernel3/*

View File

@@ -14,19 +14,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up cargo cache
if: inputs.use_cache == true
uses: actions/cache@v3
continue-on-error: false
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-
fetch-depth: 0
# cross build failed after Rust 1.68, see https://github.com/cross-rs/cross/issues/1222
- run: rustup default 1.67.0
- uses: Swatinem/rust-cache@v2
with:
workspaces: userspace/ksud
cache-targets: false
- name: Install cross
run: cargo install cross
- name: Build ksud
run: cross build --target ${{ inputs.target }} --release --manifest-path ./userspace/ksud/Cargo.toml
@@ -35,5 +33,4 @@ jobs:
uses: actions/upload-artifact@v3
with:
name: ksud-${{ inputs.target }}
path: ./userspace/ksud/target/**/release/ksud
path: userspace/ksud/target/**/release/ksud

56
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,56 @@
name: Release
on:
push:
tags:
- "v*"
workflow_dispatch:
jobs:
build-manager:
uses: ./.github/workflows/build-manager.yml
secrets: inherit
build-a12-kernel:
uses: ./.github/workflows/build-kernel-a12.yml
build-a13-kernel:
uses: ./.github/workflows/build-kernel-a13.yml
build-wsa-kernel:
uses: ./.github/workflows/build-kernel-wsa.yml
release:
needs:
- build-manager
- build-a12-kernel
- build-a13-kernel
- build-wsa-kernel
runs-on: ubuntu-latest
steps:
- name: Download artifacts
uses: actions/download-artifact@v3
- name: Zip AnyKernel3
run: |
for dir in AnyKernel3-*; do
if [ -d "$dir" ]; then
echo "----- Zip $dir -----"
(cd $dir && zip -r9 "$dir".zip ./* -x .git .gitignore ./*.zip && mv *.zip ..)
fi
done
- name: Zip WSA kernel
run: |
for dir in kernel-WSA-*; do
if [ -d "$dir" ]; then
echo "------ Zip $dir ----------"
(cd $dir && zip -r9 "$dir".zip ./* -x .git .gitignore ./*.zip && mv *.zip ..)
fi
done
- name: Display structure of downloaded files
run: ls -R
- name: release
uses: softprops/action-gh-release@v1
with:
files: |
manager/*.apk
AnyKernel3-*.zip
boot-images-*/Image-*/*.img.gz
kernel-WSA*.zip

33
.github/workflows/rustfmt.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
name: Rustfmt check
on:
push:
branches:
- 'main'
paths:
- '.github/workflows/rustfmt.yml'
- 'userspace/ksud/**'
pull_request:
branches:
- 'main'
paths:
- '.github/workflows/rustfmt.yml'
- 'userspace/ksud/**'
permissions:
checks: write
jobs:
format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@nightly
with:
components: rustfmt
- uses: LoliGothick/rustfmt-check@v0.3.1
with:
token: ${{ github.token }}
options: --manifest-path userspace/ksud/Cargo.toml

27
.github/workflows/shellcheck.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: ShellCheck
on:
push:
branches:
- 'main'
paths:
- '.github/workflows/shellcheck.yml'
- '**/*.sh'
pull_request:
branches:
- 'main'
paths:
- '.github/workflows/shellcheck.yml'
- '**/*.sh'
jobs:
shellcheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@2.0.0
with:
ignore_names: gradlew
ignore_paths: ./userspace/ksud/src/installer.sh

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.idea
.vscode

View File

@@ -1,4 +1,4 @@
**English** | [中文](README_CN.md)
**English** | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md)
# KernelSU
@@ -11,7 +11,7 @@ A Kernel based root solution for Android devices.
## Compatibility State
KernelSU officially supports Android GKI 2.0 devices(with kernel 5.10+), old kernels(4.14+) is also compatiable, but you need to build kernel yourself.
KernelSU officially supports Android GKI 2.0 devices(with kernel 5.10+), old kernels(4.14+) is also compatible, but you need to build kernel yourself.
WSA and containter-based Android should also work with KernelSU integrated.
@@ -31,7 +31,8 @@ And the current supported ABIs are : `arm64-v8a` and `x86_64`
## License
[GPL-3](http://www.gnu.org/copyleft/gpl.html)
- Files under `kernel` directory are [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- All other parts except `kernel` directory are [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
## Credits

View File

@@ -1,4 +1,4 @@
[English](README.md) | **中文**
[English](README.md) | [Español](README_ES.md) | **简体中文** | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md)
# KernelSU
@@ -31,11 +31,12 @@ WSA 和运行在容器上的 Android 也可以与 KernelSU 一起工作。
## 许可证
[GPL-3](http://www.gnu.org/copyleft/gpl.html)
- 目录 `kernel` 下所有文件为 [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
-`kernel` 目录的其他部分均为 [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
## 鸣谢
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/)KernelSU 的灵感。
- [true](https://github.com/brevent/genuine/)apk v2 签名验证。
- [genuine](https://github.com/brevent/genuine/)apk v2 签名验证。
- [Diamorphine](https://github.com/m0nad/Diamorphine):一些 rootkit 技巧。
- [Magisk](https://github.com/topjohnwu/Magisk)sepolicy 的实现。

47
README_ES.md Normal file
View File

@@ -0,0 +1,47 @@
[ 🇬🇧 English](README.md) | 🇪🇸 **Español** | [🇨🇳 简体中文](README_CN.md) | [🇹🇼 繁體中文](README_TW.md) | [ 🇯🇵 日本語](README_JP.md) | [🇵🇱 Polski](README_PL.md) | [🇧🇷 Portuguese-Brazil](README_PT-BR.md) | [🇹🇷 Türkçe](README_TR.md)
<div style="display: flex; align-items: center;">
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="">
<div style="margin-left: 20px;">
<span style="font-size: large; "><b>KernelSU</b></span>
<br>
<span style="font-size: medium; "><i>Una solución root basada en el kernel para dispositivos Android.</i></span>
</div>
</div>
## 🚀 Características
**1.** Binario `su` basado en el kernel y gestión de acceso root.<br/>
**2.** Sistema de módulos basado en **OverlayFS**.
## ✅ Estado de compatibilidad
**KernelSU** soporta de forma oficial dispositivos Android con **GKI 2.0** (a partir de la versión **5.10** del kernel). Los kernels antiguos (a partir de la versión **4.14**) también son compatibles, pero necesitas compilarlos por tu cuenta.
El **Subsistema de Windows para Android (WSA)** e implementaciones de Android basadas en contenedores, como **Waydroid**, también deberían funcionar con **KernelSU** integrado.
Actualmente se soportan las siguientes **ABIs**: `arm64-v8a`; `x86_64`.
## 📖 Uso
[¿Cómo instalarlo?](https://kernelsu.org/guide/installation.html)
## 🔨 Compilación
[¿Cómo compilarlo?](https://kernelsu.org/guide/how-to-build.html)
## 💬 Discusión
- Telegram: [@KernelSU](https://t.me/KernelSU)
## ⚖️ Licencia
- Los archivos bajo el directorio `kernel` están licenciados bajo [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
- Todas las demás partes, a excepción del directorio `kernel`, están licenciados bajo [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html).
## 👥 Créditos
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): la idea de **KernelSU**.
- [genuine](https://github.com/brevent/genuine/): la validación del **esquema de firmas APK v2**.
- [Diamorphine](https://github.com/m0nad/Diamorphine): algunas habilidades de rootkit.
- [Magisk](https://github.com/topjohnwu/Magisk): la implementación de la **política de SELinux (SEPolicy)**.

42
README_JP.md Normal file
View File

@@ -0,0 +1,42 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | **日本語** | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md)
# KernelSU
Android におけるカーネルベースの root ソリューションです。
## 特徴
1. カーネルベースの `su` と権限管理
2. OverlayFS に基づくモジュールシステム
## 対応状況
KernelSU は GKI 2.0 デバイス(カーネルバージョン 5.10 以上を公式にサポートしています。古いカーネル4.14以上)とも互換性がありますが、自分でカーネルをビルドする必要があります。
WSA とコンテナ上で動作する Android でも KernelSU を統合して動かせます。
現在サポートしているアーキテクチャは `arm64-v8a` および `x86_64` です。
## 使用方法
[インストール方法はこちら](https://kernelsu.org/ja_JP/guide/installation.html)
## ビルド
[ビルド方法はこちら](https://kernelsu.org/guide/how-to-build.html)
### ディスカッション
- Telegram: [@KernelSU](https://t.me/KernelSU)
## ライセンス
- `kernel` ディレクトリの下にあるすべてのファイル: [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- `kernel` ディレクトリ以外のすべてのファイル: [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
## クレジット
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/)KernelSU のアイデア元
- [genuine](https://github.com/brevent/genuine/)apk v2 の署名検証
- [Diamorphine](https://github.com/m0nad/Diamorphine): rootkit のスキル
- [Magisk](https://github.com/topjohnwu/Magisk)sepolicy の実装

42
README_PL.md Normal file
View File

@@ -0,0 +1,42 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | **Polski** | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md)
# KernelSU
Rozwiązanie root oparte na jądrze dla urządzeń z systemem Android.
## Cechy
1. Oparte na jądrze `su` i zarządzanie dostępem roota.
2. System modułów oparty na overlayfs.
## Kompatybilność
KernelSU oficjalnie obsługuje urządzenia z Androidem GKI 2.0 (z jądrem 5.10+), starsze jądra (4.14+) są również kompatybilne, ale musisz sam skompilować jądro.
WSA i Android oparty na kontenerach również powinny działać ze zintegrowanym KernelSU.
Aktualnie obsługiwane ABI to : `arm64-v8a` i `x86_64`.
## Użycie
[Instalacja](https://kernelsu.org/guide/installation.html)
## Kompilacja
[Jak skompilować?](https://kernelsu.org/guide/how-to-build.html)
### Dyskusja
- Telegram: [@KernelSU](https://t.me/KernelSU)
## Licencja
- Pliki w katalogu `kernel` są na licencji [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- Wszystkie inne części poza katalogiem `kernel` są na licencji [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
## Podziękowania
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): pomysłodawca KernelSU.
- [genuine](https://github.com/brevent/genuine/): walidacja podpisu apk v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): cenna znajomość rootkitów.
- [Magisk](https://github.com/topjohnwu/Magisk): implementacja sepolicy.

47
README_PT-BR.md Normal file
View File

@@ -0,0 +1,47 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | **Portuguese-Brazil** | [Türkçe](README_TR.md)
# KernelSU
Uma solução raiz baseada em Kernel para dispositivos Android.
## Características
1. `su` baseado em kernel e gerenciamento de acesso root.
2. Sistema modular baseado em overlayfs.
## Estado de compatibilidade
O KernelSU suporta oficialmente dispositivos Android GKI 2.0 (com kernel 5.10+), kernels antigos (4.14+) também são compatíveis, mas você mesmo precisa construir o kernel.
O Android baseado em WSA e contêiner também deve funcionar com o KernelSU integrado.
E os ABIs atualmente suportados são: `arm64-v8a` e `x86_64`
## Uso
[Instalação](https://kernelsu.org/guide/installation.html)
## Construir
[Como construir?](https://kernelsu.org/guide/how-to-build.html)
### Discussão
- Telegram: [@KernelSU](https://t.me/KernelSU)
## Licença
- Os arquivos no diretório `kernel` são [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- Todas as outras partes, exceto o diretório `kernel`, são [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
## Créditos
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): a ideia do KernelSU.
- [genuine](https://github.com/brevent/genuine/): validação de assinatura apk v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): algumas habilidades de rootkit.
- [Magisk](https://github.com/topjohnwu/Magisk): a implementação da sepolicy.

42
README_TR.md Normal file
View File

@@ -0,0 +1,42 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.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ı.

42
README_TW.md Normal file
View File

@@ -0,0 +1,42 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | **繁體中文** | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md)
# KernelSU
一個基於核心的 Android 裝置 Root 解決方案
## 功能
- 基於核心的 Su 和 Root 存取權管理。
- 基於 Overlayfs 的模組系統。
## 相容性狀態
KernelSU 官方支援 Android GKI 2.0 的裝置 (核心版本 5.10+);舊版核心同樣相容 (最低 4.14+),但需要自行編譯核心。
WSA 和執行在容器中的 Android 也可以與 KernelSU 一同運作。
目前支援架構:`arm64-v8a``x86_64`
## 使用方法
[安裝教學](https://kernelsu.org/zh_TW/guide/installation.html)
## 建置
[如何建置?](https://kernelsu.org/zh_TW/guide/how-to-build.html)
### 討論
- Telegram[@KernelSU](https://t.me/KernelSU)
## 授權
- 目錄 `kernel` 下所有檔案為 [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
-`kernel` 目錄的其他部分均為 [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
## 致謝
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/)KernelSU 的靈感。
- [genuine](https://github.com/brevent/genuine/)apk v2 簽章驗證。
- [Diamorphine](https://github.com/m0nad/Diamorphine):一些 rootkit 技巧。
- [Magisk](https://github.com/topjohnwu/Magisk)sepolicy 實作。

548
kernel/.clang-format Normal file
View File

@@ -0,0 +1,548 @@
# SPDX-License-Identifier: GPL-2.0
#
# clang-format configuration file. Intended for clang-format >= 4.
#
# For more information, see:
#
# Documentation/process/clang-format.rst
# https://clang.llvm.org/docs/ClangFormat.html
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
#
---
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
#AlignEscapedNewlines: Left # Unknown to clang-format-4.0
AlignOperands: true
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
#AfterExternBlock: false # Unknown to clang-format-5.0
BeforeCatch: false
BeforeElse: false
IndentBraces: false
#SplitEmptyFunction: true # Unknown to clang-format-4.0
#SplitEmptyRecord: true # Unknown to clang-format-4.0
#SplitEmptyNamespace: true # Unknown to clang-format-4.0
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false
#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
#CompactNamespaces: false # Unknown to clang-format-4.0
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
#FixNamespaceComments: false # Unknown to clang-format-4.0
# Taken from:
# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \
# | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \
# | sort | uniq
ForEachMacros:
- 'apei_estatus_for_each_section'
- 'ata_for_each_dev'
- 'ata_for_each_link'
- '__ata_qc_for_each'
- 'ata_qc_for_each'
- 'ata_qc_for_each_raw'
- 'ata_qc_for_each_with_internal'
- 'ax25_for_each'
- 'ax25_uid_for_each'
- '__bio_for_each_bvec'
- 'bio_for_each_bvec'
- 'bio_for_each_bvec_all'
- 'bio_for_each_integrity_vec'
- '__bio_for_each_segment'
- 'bio_for_each_segment'
- 'bio_for_each_segment_all'
- 'bio_list_for_each'
- 'bip_for_each_vec'
- 'bitmap_for_each_clear_region'
- 'bitmap_for_each_set_region'
- 'blkg_for_each_descendant_post'
- 'blkg_for_each_descendant_pre'
- 'blk_queue_for_each_rl'
- 'bond_for_each_slave'
- 'bond_for_each_slave_rcu'
- 'bpf_for_each_spilled_reg'
- 'btree_for_each_safe128'
- 'btree_for_each_safe32'
- 'btree_for_each_safe64'
- 'btree_for_each_safel'
- 'card_for_each_dev'
- 'cgroup_taskset_for_each'
- 'cgroup_taskset_for_each_leader'
- 'cpufreq_for_each_entry'
- 'cpufreq_for_each_entry_idx'
- 'cpufreq_for_each_valid_entry'
- 'cpufreq_for_each_valid_entry_idx'
- 'css_for_each_child'
- 'css_for_each_descendant_post'
- 'css_for_each_descendant_pre'
- 'device_for_each_child_node'
- 'dma_fence_chain_for_each'
- 'do_for_each_ftrace_op'
- 'drm_atomic_crtc_for_each_plane'
- 'drm_atomic_crtc_state_for_each_plane'
- 'drm_atomic_crtc_state_for_each_plane_state'
- 'drm_atomic_for_each_plane_damage'
- 'drm_client_for_each_connector_iter'
- 'drm_client_for_each_modeset'
- 'drm_connector_for_each_possible_encoder'
- 'drm_for_each_bridge_in_chain'
- 'drm_for_each_connector_iter'
- 'drm_for_each_crtc'
- 'drm_for_each_encoder'
- 'drm_for_each_encoder_mask'
- 'drm_for_each_fb'
- 'drm_for_each_legacy_plane'
- 'drm_for_each_plane'
- 'drm_for_each_plane_mask'
- 'drm_for_each_privobj'
- 'drm_mm_for_each_hole'
- 'drm_mm_for_each_node'
- 'drm_mm_for_each_node_in_range'
- 'drm_mm_for_each_node_safe'
- 'flow_action_for_each'
- 'for_each_active_dev_scope'
- 'for_each_active_drhd_unit'
- 'for_each_active_iommu'
- 'for_each_aggr_pgid'
- 'for_each_available_child_of_node'
- 'for_each_bio'
- 'for_each_board_func_rsrc'
- 'for_each_bvec'
- 'for_each_card_auxs'
- 'for_each_card_auxs_safe'
- 'for_each_card_components'
- 'for_each_card_dapms'
- 'for_each_card_pre_auxs'
- 'for_each_card_prelinks'
- 'for_each_card_rtds'
- 'for_each_card_rtds_safe'
- 'for_each_card_widgets'
- 'for_each_card_widgets_safe'
- 'for_each_cgroup_storage_type'
- 'for_each_child_of_node'
- 'for_each_clear_bit'
- 'for_each_clear_bit_from'
- 'for_each_cmsghdr'
- 'for_each_compatible_node'
- 'for_each_component_dais'
- 'for_each_component_dais_safe'
- 'for_each_comp_order'
- 'for_each_console'
- 'for_each_cpu'
- 'for_each_cpu_and'
- 'for_each_cpu_not'
- 'for_each_cpu_wrap'
- 'for_each_dapm_widgets'
- 'for_each_dev_addr'
- 'for_each_dev_scope'
- 'for_each_displayid_db'
- 'for_each_dma_cap_mask'
- 'for_each_dpcm_be'
- 'for_each_dpcm_be_rollback'
- 'for_each_dpcm_be_safe'
- 'for_each_dpcm_fe'
- 'for_each_drhd_unit'
- 'for_each_dss_dev'
- 'for_each_efi_memory_desc'
- 'for_each_efi_memory_desc_in_map'
- 'for_each_element'
- 'for_each_element_extid'
- 'for_each_element_id'
- 'for_each_endpoint_of_node'
- 'for_each_evictable_lru'
- 'for_each_fib6_node_rt_rcu'
- 'for_each_fib6_walker_rt'
- 'for_each_free_mem_pfn_range_in_zone'
- 'for_each_free_mem_pfn_range_in_zone_from'
- 'for_each_free_mem_range'
- 'for_each_free_mem_range_reverse'
- 'for_each_func_rsrc'
- 'for_each_hstate'
- 'for_each_if'
- 'for_each_iommu'
- 'for_each_ip_tunnel_rcu'
- 'for_each_irq_nr'
- 'for_each_link_codecs'
- 'for_each_link_cpus'
- 'for_each_link_platforms'
- 'for_each_lru'
- 'for_each_matching_node'
- 'for_each_matching_node_and_match'
- 'for_each_member'
- 'for_each_mem_region'
- 'for_each_memblock_type'
- 'for_each_memcg_cache_index'
- 'for_each_mem_pfn_range'
- '__for_each_mem_range'
- 'for_each_mem_range'
- '__for_each_mem_range_rev'
- 'for_each_mem_range_rev'
- 'for_each_migratetype_order'
- 'for_each_msi_entry'
- 'for_each_msi_entry_safe'
- 'for_each_net'
- 'for_each_net_continue_reverse'
- 'for_each_netdev'
- 'for_each_netdev_continue'
- 'for_each_netdev_continue_rcu'
- 'for_each_netdev_continue_reverse'
- 'for_each_netdev_feature'
- 'for_each_netdev_in_bond_rcu'
- 'for_each_netdev_rcu'
- 'for_each_netdev_reverse'
- 'for_each_netdev_safe'
- 'for_each_net_rcu'
- 'for_each_new_connector_in_state'
- 'for_each_new_crtc_in_state'
- 'for_each_new_mst_mgr_in_state'
- 'for_each_new_plane_in_state'
- 'for_each_new_private_obj_in_state'
- 'for_each_node'
- 'for_each_node_by_name'
- 'for_each_node_by_type'
- 'for_each_node_mask'
- 'for_each_node_state'
- 'for_each_node_with_cpus'
- 'for_each_node_with_property'
- 'for_each_nonreserved_multicast_dest_pgid'
- 'for_each_of_allnodes'
- 'for_each_of_allnodes_from'
- 'for_each_of_cpu_node'
- 'for_each_of_pci_range'
- 'for_each_old_connector_in_state'
- 'for_each_old_crtc_in_state'
- 'for_each_old_mst_mgr_in_state'
- 'for_each_oldnew_connector_in_state'
- 'for_each_oldnew_crtc_in_state'
- 'for_each_oldnew_mst_mgr_in_state'
- 'for_each_oldnew_plane_in_state'
- 'for_each_oldnew_plane_in_state_reverse'
- 'for_each_oldnew_private_obj_in_state'
- 'for_each_old_plane_in_state'
- 'for_each_old_private_obj_in_state'
- 'for_each_online_cpu'
- 'for_each_online_node'
- 'for_each_online_pgdat'
- 'for_each_pci_bridge'
- 'for_each_pci_dev'
- 'for_each_pci_msi_entry'
- 'for_each_pcm_streams'
- 'for_each_physmem_range'
- 'for_each_populated_zone'
- 'for_each_possible_cpu'
- 'for_each_present_cpu'
- 'for_each_prime_number'
- 'for_each_prime_number_from'
- 'for_each_process'
- 'for_each_process_thread'
- 'for_each_property_of_node'
- 'for_each_registered_fb'
- 'for_each_requested_gpio'
- 'for_each_requested_gpio_in_range'
- 'for_each_reserved_mem_range'
- 'for_each_reserved_mem_region'
- 'for_each_rtd_codec_dais'
- 'for_each_rtd_codec_dais_rollback'
- 'for_each_rtd_components'
- 'for_each_rtd_cpu_dais'
- 'for_each_rtd_cpu_dais_rollback'
- 'for_each_rtd_dais'
- 'for_each_set_bit'
- 'for_each_set_bit_from'
- 'for_each_set_clump8'
- 'for_each_sg'
- 'for_each_sg_dma_page'
- 'for_each_sg_page'
- 'for_each_sgtable_dma_page'
- 'for_each_sgtable_dma_sg'
- 'for_each_sgtable_page'
- 'for_each_sgtable_sg'
- 'for_each_sibling_event'
- 'for_each_subelement'
- 'for_each_subelement_extid'
- 'for_each_subelement_id'
- '__for_each_thread'
- 'for_each_thread'
- 'for_each_unicast_dest_pgid'
- 'for_each_wakeup_source'
- 'for_each_zone'
- 'for_each_zone_zonelist'
- 'for_each_zone_zonelist_nodemask'
- 'fwnode_for_each_available_child_node'
- 'fwnode_for_each_child_node'
- 'fwnode_graph_for_each_endpoint'
- 'gadget_for_each_ep'
- 'genradix_for_each'
- 'genradix_for_each_from'
- 'hash_for_each'
- 'hash_for_each_possible'
- 'hash_for_each_possible_rcu'
- 'hash_for_each_possible_rcu_notrace'
- 'hash_for_each_possible_safe'
- 'hash_for_each_rcu'
- 'hash_for_each_safe'
- 'hctx_for_each_ctx'
- 'hlist_bl_for_each_entry'
- 'hlist_bl_for_each_entry_rcu'
- 'hlist_bl_for_each_entry_safe'
- 'hlist_for_each'
- 'hlist_for_each_entry'
- 'hlist_for_each_entry_continue'
- 'hlist_for_each_entry_continue_rcu'
- 'hlist_for_each_entry_continue_rcu_bh'
- 'hlist_for_each_entry_from'
- 'hlist_for_each_entry_from_rcu'
- 'hlist_for_each_entry_rcu'
- 'hlist_for_each_entry_rcu_bh'
- 'hlist_for_each_entry_rcu_notrace'
- 'hlist_for_each_entry_safe'
- '__hlist_for_each_rcu'
- 'hlist_for_each_safe'
- 'hlist_nulls_for_each_entry'
- 'hlist_nulls_for_each_entry_from'
- 'hlist_nulls_for_each_entry_rcu'
- 'hlist_nulls_for_each_entry_safe'
- 'i3c_bus_for_each_i2cdev'
- 'i3c_bus_for_each_i3cdev'
- 'ide_host_for_each_port'
- 'ide_port_for_each_dev'
- 'ide_port_for_each_present_dev'
- 'idr_for_each_entry'
- 'idr_for_each_entry_continue'
- 'idr_for_each_entry_continue_ul'
- 'idr_for_each_entry_ul'
- 'in_dev_for_each_ifa_rcu'
- 'in_dev_for_each_ifa_rtnl'
- 'inet_bind_bucket_for_each'
- 'inet_lhash2_for_each_icsk_rcu'
- 'key_for_each'
- 'key_for_each_safe'
- 'klp_for_each_func'
- 'klp_for_each_func_safe'
- 'klp_for_each_func_static'
- 'klp_for_each_object'
- 'klp_for_each_object_safe'
- 'klp_for_each_object_static'
- 'kunit_suite_for_each_test_case'
- 'kvm_for_each_memslot'
- 'kvm_for_each_vcpu'
- 'list_for_each'
- 'list_for_each_codec'
- 'list_for_each_codec_safe'
- 'list_for_each_continue'
- 'list_for_each_entry'
- 'list_for_each_entry_continue'
- 'list_for_each_entry_continue_rcu'
- 'list_for_each_entry_continue_reverse'
- 'list_for_each_entry_from'
- 'list_for_each_entry_from_rcu'
- 'list_for_each_entry_from_reverse'
- 'list_for_each_entry_lockless'
- 'list_for_each_entry_rcu'
- 'list_for_each_entry_reverse'
- 'list_for_each_entry_safe'
- 'list_for_each_entry_safe_continue'
- 'list_for_each_entry_safe_from'
- 'list_for_each_entry_safe_reverse'
- 'list_for_each_prev'
- 'list_for_each_prev_safe'
- 'list_for_each_safe'
- 'llist_for_each'
- 'llist_for_each_entry'
- 'llist_for_each_entry_safe'
- 'llist_for_each_safe'
- 'mci_for_each_dimm'
- 'media_device_for_each_entity'
- 'media_device_for_each_intf'
- 'media_device_for_each_link'
- 'media_device_for_each_pad'
- 'nanddev_io_for_each_page'
- 'netdev_for_each_lower_dev'
- 'netdev_for_each_lower_private'
- 'netdev_for_each_lower_private_rcu'
- 'netdev_for_each_mc_addr'
- 'netdev_for_each_uc_addr'
- 'netdev_for_each_upper_dev_rcu'
- 'netdev_hw_addr_list_for_each'
- 'nft_rule_for_each_expr'
- 'nla_for_each_attr'
- 'nla_for_each_nested'
- 'nlmsg_for_each_attr'
- 'nlmsg_for_each_msg'
- 'nr_neigh_for_each'
- 'nr_neigh_for_each_safe'
- 'nr_node_for_each'
- 'nr_node_for_each_safe'
- 'of_for_each_phandle'
- 'of_property_for_each_string'
- 'of_property_for_each_u32'
- 'pci_bus_for_each_resource'
- 'pcm_for_each_format'
- 'ping_portaddr_for_each_entry'
- 'plist_for_each'
- 'plist_for_each_continue'
- 'plist_for_each_entry'
- 'plist_for_each_entry_continue'
- 'plist_for_each_entry_safe'
- 'plist_for_each_safe'
- 'pnp_for_each_card'
- 'pnp_for_each_dev'
- 'protocol_for_each_card'
- 'protocol_for_each_dev'
- 'queue_for_each_hw_ctx'
- 'radix_tree_for_each_slot'
- 'radix_tree_for_each_tagged'
- 'rbtree_postorder_for_each_entry_safe'
- 'rdma_for_each_block'
- 'rdma_for_each_port'
- 'rdma_umem_for_each_dma_block'
- 'resource_list_for_each_entry'
- 'resource_list_for_each_entry_safe'
- 'rhl_for_each_entry_rcu'
- 'rhl_for_each_rcu'
- 'rht_for_each'
- 'rht_for_each_entry'
- 'rht_for_each_entry_from'
- 'rht_for_each_entry_rcu'
- 'rht_for_each_entry_rcu_from'
- 'rht_for_each_entry_safe'
- 'rht_for_each_from'
- 'rht_for_each_rcu'
- 'rht_for_each_rcu_from'
- '__rq_for_each_bio'
- 'rq_for_each_bvec'
- 'rq_for_each_segment'
- 'scsi_for_each_prot_sg'
- 'scsi_for_each_sg'
- 'sctp_for_each_hentry'
- 'sctp_skb_for_each'
- 'shdma_for_each_chan'
- '__shost_for_each_device'
- 'shost_for_each_device'
- 'sk_for_each'
- 'sk_for_each_bound'
- 'sk_for_each_entry_offset_rcu'
- 'sk_for_each_from'
- 'sk_for_each_rcu'
- 'sk_for_each_safe'
- 'sk_nulls_for_each'
- 'sk_nulls_for_each_from'
- 'sk_nulls_for_each_rcu'
- 'snd_array_for_each'
- 'snd_pcm_group_for_each_entry'
- 'snd_soc_dapm_widget_for_each_path'
- 'snd_soc_dapm_widget_for_each_path_safe'
- 'snd_soc_dapm_widget_for_each_sink_path'
- 'snd_soc_dapm_widget_for_each_source_path'
- 'tb_property_for_each'
- 'tcf_exts_for_each_action'
- 'udp_portaddr_for_each_entry'
- 'udp_portaddr_for_each_entry_rcu'
- 'usb_hub_for_each_child'
- 'v4l2_device_for_each_subdev'
- 'v4l2_m2m_for_each_dst_buf'
- 'v4l2_m2m_for_each_dst_buf_safe'
- 'v4l2_m2m_for_each_src_buf'
- 'v4l2_m2m_for_each_src_buf_safe'
- 'virtio_device_for_each_vq'
- 'while_for_each_ftrace_op'
- 'xa_for_each'
- 'xa_for_each_marked'
- 'xa_for_each_range'
- 'xa_for_each_start'
- 'xas_for_each'
- 'xas_for_each_conflict'
- 'xas_for_each_marked'
- 'xbc_array_for_each_value'
- 'xbc_for_each_key_value'
- 'xbc_node_for_each_array_value'
- 'xbc_node_for_each_child'
- 'xbc_node_for_each_key_value'
- 'zorro_for_each_dev'
#IncludeBlocks: Preserve # Unknown to clang-format-5.0
IncludeCategories:
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
#IndentPPDirectives: None # Unknown to clang-format-5.0
IndentWidth: 8
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0
ObjCBlockIndentWidth: 8
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
# Taken from git's rules
#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0
PenaltyBreakBeforeFirstCallParameter: 30
PenaltyBreakComment: 10
PenaltyBreakFirstLessLess: 0
PenaltyBreakString: 10
PenaltyExcessCharacter: 100
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: false
SortIncludes: false
#SortUsingDeclarations: false # Unknown to clang-format-4.0
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0
#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0
SpaceBeforeParens: ControlStatements
#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp03
TabWidth: 8
UseTab: Always
...

View File

@@ -1,4 +1,4 @@
Diagnostics:
UnusedIncludes: Strict
ClangTidy:
Remove: bugprone-sizeof-expression
Remove: bugprone-sizeof-expression

View File

@@ -1,14 +1,17 @@
menu "KernelSU"
config KSU
tristate "KernelSU module"
tristate "KernelSU function support"
select OVERLAY_FS
default y
depends on KPROBES
depends on OVERLAY_FS
help
This is the KSU privilege driver for android system.
Enable kernel-level root privileges on Android System.
config KSU_DEBUG
tristate "KernelSU module debug mode"
default n
bool "KernelSU debug mode"
depends on KSU
default n
help
This enables debug mode for KSU
Enable KernelSU debug mode
endmenu

339
kernel/LICENSE Normal file
View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -9,8 +9,20 @@ obj-y += manager.o
obj-y += core_hook.o
obj-y += ksud.o
obj-y += embed_ksud.o
obj-y += kernel_compat.o
obj-y += selinux/
# .git is a text file while the module is imported by 'git submodule add'.
ifeq ($(shell test -e $(srctree)/$(src)/../.git; echo $$?),0)
KSU_GIT_VERSION := $(shell cd $(srctree)/$(src); /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin git rev-list --count HEAD)
# ksu_version: major * 10000 + git version + 200 for historical reasons
$(eval KSU_VERSION=$(shell expr 10000 + $(KSU_GIT_VERSION) + 200))
$(info -- KernelSU version: $(KSU_VERSION))
ccflags-y += -DKSU_VERSION=$(KSU_VERSION)
else # If there is no .git file, the default version will be passed.
$(warning "KSU_GIT_VERSION not defined! It is better to make KernelSU a git submodule!")
ccflags-y += -DKSU_VERSION=16
endif
ifndef EXPECTED_SIZE
EXPECTED_SIZE := 0x033b
@@ -23,4 +35,4 @@ endif
ccflags-y += -DEXPECTED_SIZE=$(EXPECTED_SIZE)
ccflags-y += -DEXPECTED_HASH=$(EXPECTED_HASH)
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat
ccflags-y += -Wno-macro-redefined -Wno-declaration-after-statement
ccflags-y += -Wno-declaration-after-statement

View File

@@ -1,27 +1,92 @@
#include "linux/delay.h"
#include "ksu.h"
#include "linux/compiler.h"
#include "linux/fs.h"
#include "linux/gfp.h"
#include "linux/kernel.h"
#include "linux/list.h"
#include "linux/printk.h"
#include "linux/slab.h"
#include "linux/types.h"
#include "linux/version.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
#include "linux/compiler_types.h"
#endif
#include "klog.h" // IWYU pragma: keep
#include "selinux/selinux.h"
#include "kernel_compat.h"
#include "allowlist.h"
#define FILE_MAGIC 0x7f4b5355 // ' KSU', u32
#define FILE_FORMAT_VERSION 1 // u32
#define FILE_FORMAT_VERSION 3 // u32
#define KSU_APP_PROFILE_PRESERVE_UID 9999 // NOBODY_UID
#define KSU_DEFAULT_SELINUX_DOMAIN "u:r:su:s0"
static DEFINE_MUTEX(allowlist_mutex);
// default profiles, these may be used frequently, so we cache it
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;
default_root_profile.gid = 0;
default_root_profile.groups_count = 1;
default_root_profile.groups[0] = 0;
memset(&default_root_profile.capabilities, 0xff,
sizeof(default_root_profile.capabilities));
default_root_profile.namespaces = 0;
strcpy(default_root_profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN);
// This means that we will umount modules by default!
default_non_root_profile.umount_modules = true;
}
struct perm_data {
struct list_head list;
uid_t uid;
bool allow;
struct app_profile profile;
};
static struct list_head allow_list;
#define KERNEL_SU_ALLOWLIST "/data/adb/.ksu_allowlist"
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;
static struct work_struct ksu_load_work;
@@ -35,65 +100,231 @@ void ksu_show_allow_list(void)
pr_info("ksu_show_allow_list");
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
pr_info("uid :%d, allow: %d\n", p->uid, p->allow);
pr_info("uid :%d, allow: %d\n", p->profile.current_uid,
p->profile.allow_su);
}
}
bool ksu_allow_uid(uid_t uid, bool allow, bool persist)
#ifdef CONFIG_KSU_DEBUG
static void ksu_grant_root_to_shell()
{
struct app_profile profile = {
.allow_su = true,
.current_uid = 2000,
};
strcpy(profile.key, "com.android.shell");
strcpy(profile.rp_config.profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN);
ksu_set_app_profile(&profile, false);
}
#endif
bool ksu_get_app_profile(struct app_profile *profile)
{
struct perm_data *p = NULL;
struct list_head *pos = NULL;
bool found = false;
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
bool uid_match = profile->current_uid == p->profile.current_uid;
if (uid_match) {
// found it, override it with ours
memcpy(profile, &p->profile, sizeof(*profile));
found = true;
goto exit;
}
}
exit:
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;
}
if (profile->allow_su) {
if (profile->rp_config.profile.groups_count > KSU_MAX_GROUPS) {
return false;
}
if (strlen(profile->rp_config.profile.selinux_domain) == 0) {
return false;
}
}
return true;
}
bool ksu_set_app_profile(struct app_profile *profile, bool persist)
{
// find the node first!
struct perm_data *p = NULL;
struct list_head *pos = NULL;
bool result = false;
if (!profile_valid(profile)) {
pr_err("Failed to set app profile: invalid profile!\n");
return false;
}
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
if (uid == p->uid) {
p->allow = allow;
// both uid and package must match, otherwise it will break multiple package with different user id
if (profile->current_uid == p->profile.current_uid &&
!strcmp(profile->key, p->profile.key)) {
// found it, just override it all!
memcpy(&p->profile, profile, sizeof(*profile));
result = true;
goto exit;
goto out;
}
}
// not found, alloc a new node!
p = (struct perm_data *)kmalloc(sizeof(struct perm_data), GFP_KERNEL);
if (!p) {
pr_err("alloc allow node failed.\n");
pr_err("ksu_set_app_profile alloc failed\n");
return false;
}
p->uid = uid;
p->allow = allow;
memcpy(&p->profile, profile, sizeof(*profile));
if (profile->allow_su) {
pr_info("set root profile, key: %s, uid: %d, gid: %d, context: %s\n",
profile->key, profile->current_uid,
profile->rp_config.profile.gid,
profile->rp_config.profile.selinux_domain);
} else {
pr_info("set app profile, key: %s, uid: %d, umount modules: %d\n",
profile->key, profile->current_uid,
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
memcpy(&default_non_root_profile, &profile->nrp_config.profile,
sizeof(default_non_root_profile));
}
if (unlikely(!strcmp(profile->key, "#"))) {
// set default root profile
memcpy(&default_root_profile, &profile->rp_config.profile,
sizeof(default_root_profile));
}
if (persist)
persistent_allow_list();
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->uid) {
return p->allow;
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;
}
}
return false;
}
bool ksu_uid_should_umount(uid_t uid)
{
struct app_profile profile = { .current_uid = uid };
bool found = ksu_get_app_profile(&profile);
if (!found) {
// no app profile found, it must be non root app
return default_non_root_profile.umount_modules;
}
if (profile.allow_su) {
// if found and it is granted to su, we shouldn't umount for it
return false;
} else {
// found an app profile
if (profile.nrp_config.use_default) {
return default_non_root_profile.umount_modules;
} else {
return profile.nrp_config.profile.umount_modules;
}
}
}
struct root_profile *ksu_get_root_profile(uid_t uid)
{
struct perm_data *p = NULL;
struct list_head *pos = NULL;
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
if (uid == p->profile.current_uid && p->profile.allow_su) {
if (!p->profile.rp_config.use_default) {
return &p->profile.rp_config.profile;
}
}
}
// use default profile
return &default_root_profile;
}
bool ksu_get_allow_list(int *array, int *length, bool allow)
{
struct perm_data *p = NULL;
@@ -101,9 +332,9 @@ bool ksu_get_allow_list(int *array, int *length, bool allow)
int i = 0;
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
pr_info("get_allow_list uid: %d allow: %d\n", p->uid, p->allow);
if (p->allow == allow) {
array[i++] = p->uid;
// pr_info("get_allow_list uid: %d allow: %d\n", p->uid, p->allow);
if (p->profile.allow_su == allow) {
array[i++] = p->profile.current_uid;
}
}
*length = i;
@@ -111,7 +342,7 @@ bool ksu_get_allow_list(int *array, int *length, bool allow)
return true;
}
void do_persistent_allow_list(struct work_struct *work)
void do_save_allow_list(struct work_struct *work)
{
u32 magic = FILE_MAGIC;
u32 version = FILE_FORMAT_VERSION;
@@ -120,20 +351,20 @@ void do_persistent_allow_list(struct work_struct *work)
loff_t off = 0;
struct file *fp =
filp_open(KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT, 0644);
ksu_filp_open_compat(KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT, 0644);
if (IS_ERR(fp)) {
pr_err("save_allow_list creat file failed: %d\n", PTR_ERR(fp));
pr_err("save_allow_list create file failed: %ld\n", PTR_ERR(fp));
return;
}
// store magic and version
if (kernel_write(fp, &magic, sizeof(magic), &off) != sizeof(magic)) {
if (ksu_kernel_write_compat(fp, &magic, sizeof(magic), &off) !=
sizeof(magic)) {
pr_err("save_allow_list write magic failed.\n");
goto exit;
}
if (kernel_write(fp, &version, sizeof(version), &off) !=
if (ksu_kernel_write_compat(fp, &version, sizeof(version), &off) !=
sizeof(version)) {
pr_err("save_allow_list write version failed.\n");
goto exit;
@@ -141,10 +372,12 @@ void do_persistent_allow_list(struct work_struct *work)
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
pr_info("save allow list uid :%d, allow: %d\n", p->uid,
p->allow);
kernel_write(fp, &p->uid, sizeof(p->uid), &off);
kernel_write(fp, &p->allow, sizeof(p->allow), &off);
pr_info("save allow list, name: %s uid :%d, allow: %d\n",
p->profile.key, p->profile.current_uid,
p->profile.allow_su);
ksu_kernel_write_compat(fp, &p->profile, sizeof(p->profile),
&off);
}
exit:
@@ -159,48 +392,27 @@ void do_load_allow_list(struct work_struct *work)
u32 magic;
u32 version;
fp = filp_open("/data/adb/", O_RDONLY, 0);
if (IS_ERR(fp)) {
int errno = PTR_ERR(fp);
pr_err("load_allow_list open '/data/adb': %d\n", PTR_ERR(fp));
if (errno == -ENOENT) {
msleep(2000);
ksu_queue_work(&ksu_load_work);
return;
} else {
pr_info("load_allow list dir exist now!");
}
} else {
filp_close(fp, 0);
}
#ifdef CONFIG_KSU_DEBUG
// always allow adb shell by default
ksu_grant_root_to_shell();
#endif
// load allowlist now!
fp = filp_open(KERNEL_SU_ALLOWLIST, O_RDONLY, 0);
fp = ksu_filp_open_compat(KERNEL_SU_ALLOWLIST, O_RDONLY, 0);
if (IS_ERR(fp)) {
#ifdef CONFIG_KSU_DEBUG
int errno = PTR_ERR(fp);
if (errno == -ENOENT) {
ksu_allow_uid(2000, true,
true); // allow adb shell by default
} else {
pr_err("load_allow_list open file failed: %d\n",
PTR_ERR(fp));
}
#else
pr_err("load_allow_list open file failed: %d\n", PTR_ERR(fp));
#endif
pr_err("load_allow_list open file failed: %ld\n", PTR_ERR(fp));
return;
}
// verify magic
if (kernel_read(fp, &magic, sizeof(magic), &off) != sizeof(magic) ||
if (ksu_kernel_read_compat(fp, &magic, sizeof(magic), &off) !=
sizeof(magic) ||
magic != FILE_MAGIC) {
pr_err("allowlist file invalid: %d!\n", magic);
goto exit;
}
if (kernel_read(fp, &version, sizeof(version), &off) !=
if (ksu_kernel_read_compat(fp, &version, sizeof(version), &off) !=
sizeof(version)) {
pr_err("allowlist read version: %d failed\n", version);
goto exit;
@@ -209,18 +421,19 @@ void do_load_allow_list(struct work_struct *work)
pr_info("allowlist version: %d\n", version);
while (true) {
u32 uid;
bool allow = false;
ret = kernel_read(fp, &uid, sizeof(uid), &off);
struct app_profile profile;
ret = ksu_kernel_read_compat(fp, &profile, sizeof(profile),
&off);
if (ret <= 0) {
pr_info("load_allow_list read err: %d\n", ret);
pr_info("load_allow_list read err: %zd\n", ret);
break;
}
ret = kernel_read(fp, &allow, sizeof(allow), &off);
pr_info("load_allow_uid: %d, allow: %d\n", uid, allow);
ksu_allow_uid(uid, allow, false);
pr_info("load_allow_uid, name: %s, uid: %d, allow: %d\n",
profile.key, profile.current_uid, profile.allow_su);
ksu_set_app_profile(&profile, false);
}
exit:
@@ -237,11 +450,16 @@ void ksu_prune_allowlist(bool (*is_uid_exist)(uid_t, void *), void *data)
// TODO: use RCU!
mutex_lock(&allowlist_mutex);
list_for_each_entry_safe (np, n, &allow_list, list) {
uid_t uid = np->uid;
if (!is_uid_exist(uid, data)) {
uid_t uid = np->profile.current_uid;
// we use this uid for special cases, don't prune it!
bool is_preserved_uid = uid == KSU_APP_PROFILE_PRESERVE_UID;
if (!is_preserved_uid && !is_uid_exist(uid, 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);
}
}
@@ -265,10 +483,20 @@ 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_persistent_allow_list);
INIT_WORK(&ksu_save_work, do_save_allow_list);
INIT_WORK(&ksu_load_work, do_load_allow_list);
init_default_profiles();
}
void ksu_allowlist_exit(void)
@@ -276,7 +504,7 @@ void ksu_allowlist_exit(void)
struct perm_data *np = NULL;
struct perm_data *n = NULL;
do_persistent_allow_list(NULL);
do_save_allow_list(NULL);
// free allowlist
mutex_lock(&allowlist_mutex);
@@ -285,4 +513,4 @@ void ksu_allowlist_exit(void)
kfree(np);
}
mutex_unlock(&allowlist_mutex);
}
}

View File

@@ -2,6 +2,7 @@
#define __KSU_H_ALLOWLIST
#include "linux/types.h"
#include "ksu.h"
void ksu_allowlist_init(void);
@@ -11,12 +12,16 @@ bool ksu_load_allow_list(void);
void ksu_show_allow_list(void);
bool ksu_is_allow_uid(uid_t uid);
bool ksu_allow_uid(uid_t uid, bool allow, bool persist);
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);
void ksu_prune_allowlist(bool (*is_uid_exist)(uid_t, void *), void *data);
#endif
bool ksu_get_app_profile(struct app_profile *);
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

View File

@@ -3,6 +3,7 @@
#include "apk_sign.h"
#include "klog.h" // IWYU pragma: keep
#include "kernel_compat.h"
static __always_inline int
check_v2_signature(char *path, unsigned expected_size, unsigned expected_hash)
@@ -14,21 +15,25 @@ check_v2_signature(char *path, unsigned expected_size, unsigned expected_hash)
loff_t pos;
int sign = -1;
struct file *fp = filp_open(path, O_RDONLY, 0);
int i;
struct file *fp = ksu_filp_open_compat(path, O_RDONLY, 0);
if (IS_ERR(fp)) {
pr_err("open %s error.", path);
return PTR_ERR(fp);
}
// disable inotify for this file
fp->f_mode |= FMODE_NONOTIFY;
sign = 1;
// https://en.wikipedia.org/wiki/Zip_(file_format)#End_of_central_directory_record_(EOCD)
for (int i = 0;; ++i) {
for (i = 0;; ++i) {
unsigned short n;
pos = generic_file_llseek(fp, -i - 2, SEEK_END);
kernel_read(fp, &n, 2, &pos);
ksu_kernel_read_compat(fp, &n, 2, &pos);
if (n == i) {
pos -= 22;
kernel_read(fp, &size4, 4, &pos);
ksu_kernel_read_compat(fp, &size4, 4, &pos);
if ((size4 ^ 0xcafebabeu) == 0xccfbf1eeu) {
break;
}
@@ -41,17 +46,17 @@ check_v2_signature(char *path, unsigned expected_size, unsigned expected_hash)
pos += 12;
// offset
kernel_read(fp, &size4, 0x4, &pos);
ksu_kernel_read_compat(fp, &size4, 0x4, &pos);
pos = size4 - 0x18;
kernel_read(fp, &size8, 0x8, &pos);
kernel_read(fp, buffer, 0x10, &pos);
ksu_kernel_read_compat(fp, &size8, 0x8, &pos);
ksu_kernel_read_compat(fp, buffer, 0x10, &pos);
if (strcmp((char *)buffer, "APK Sig Block 42")) {
goto clean;
}
pos = size4 - (size8 + 0x8);
kernel_read(fp, &size_of_block, 0x8, &pos);
ksu_kernel_read_compat(fp, &size_of_block, 0x8, &pos);
if (size_of_block != size8) {
goto clean;
}
@@ -59,37 +64,37 @@ check_v2_signature(char *path, unsigned expected_size, unsigned expected_hash)
for (;;) {
uint32_t id;
uint32_t offset;
kernel_read(fp, &size8, 0x8, &pos); // sequence length
ksu_kernel_read_compat(fp, &size8, 0x8, &pos); // sequence length
if (size8 == size_of_block) {
break;
}
kernel_read(fp, &id, 0x4, &pos); // id
ksu_kernel_read_compat(fp, &id, 0x4, &pos); // id
offset = 4;
pr_info("id: 0x%08x\n", id);
if ((id ^ 0xdeadbeefu) == 0xafa439f5u ||
(id ^ 0xdeadbeefu) == 0x2efed62f) {
kernel_read(fp, &size4, 0x4,
ksu_kernel_read_compat(fp, &size4, 0x4,
&pos); // signer-sequence length
kernel_read(fp, &size4, 0x4, &pos); // signer length
kernel_read(fp, &size4, 0x4,
ksu_kernel_read_compat(fp, &size4, 0x4, &pos); // signer length
ksu_kernel_read_compat(fp, &size4, 0x4,
&pos); // signed data length
offset += 0x4 * 3;
kernel_read(fp, &size4, 0x4,
ksu_kernel_read_compat(fp, &size4, 0x4,
&pos); // digests-sequence length
pos += size4;
offset += 0x4 + size4;
kernel_read(fp, &size4, 0x4,
ksu_kernel_read_compat(fp, &size4, 0x4,
&pos); // certificates length
kernel_read(fp, &size4, 0x4,
ksu_kernel_read_compat(fp, &size4, 0x4,
&pos); // certificate length
offset += 0x4 * 2;
#if 0
int hash = 1;
signed char c;
for (unsigned i = 0; i < size4; ++i) {
kernel_read(fp, &c, 0x1, &pos);
for (i = 0; i < size4; ++i) {
ksu_kernel_read_compat(fp, &c, 0x1, &pos);
hash = 31 * hash + c;
}
offset += size4;
@@ -98,8 +103,8 @@ check_v2_signature(char *path, unsigned expected_size, unsigned expected_hash)
if (size4 == expected_size) {
int hash = 1;
signed char c;
for (unsigned i = 0; i < size4; ++i) {
kernel_read(fp, &c, 0x1, &pos);
for (i = 0; i < size4; ++i) {
ksu_kernel_read_compat(fp, &c, 0x1, &pos);
hash = 31 * hash + c;
}
offset += size4;
@@ -172,4 +177,4 @@ int is_manager_apk(char *path)
return check_v2_signature(path, EXPECTED_SIZE, EXPECTED_HASH);
}
#endif
#endif

View File

@@ -4,4 +4,4 @@
// return 0 if signature match
int is_manager_apk(char *path);
#endif
#endif

View File

@@ -8,7 +8,8 @@
#define __PT_PARM1_REG regs[0]
#define __PT_PARM2_REG regs[1]
#define __PT_PARM3_REG regs[2]
#define __PT_PARM4_REG regs[3]
#define __PT_SYSCALL_PARM4_REG regs[3]
#define __PT_CCALL_PARM4_REG regs[3]
#define __PT_PARM5_REG regs[4]
#define __PT_PARM6_REG regs[5]
#define __PT_RET_REG regs[30]
@@ -29,8 +30,8 @@
#define __PT_PARM2_REG si
#define __PT_PARM3_REG dx
/* syscall uses r10 for PARM4 */
#define __PT_PARM4_REG r10
// #define __PT_PARM4_REG cx
#define __PT_SYSCALL_PARM4_REG r10
#define __PT_CCALL_PARM4_REG cx
#define __PT_PARM5_REG r8
#define __PT_PARM6_REG r9
#define __PT_RET_REG sp
@@ -56,7 +57,8 @@
#define PT_REGS_PARM1(x) (__PT_REGS_CAST(x)->__PT_PARM1_REG)
#define PT_REGS_PARM2(x) (__PT_REGS_CAST(x)->__PT_PARM2_REG)
#define PT_REGS_PARM3(x) (__PT_REGS_CAST(x)->__PT_PARM3_REG)
#define PT_REGS_PARM4(x) (__PT_REGS_CAST(x)->__PT_PARM4_REG)
#define PT_REGS_SYSCALL_PARM4(x) (__PT_REGS_CAST(x)->__PT_SYSCALL_PARM4_REG)
#define PT_REGS_CCALL_PARM4(x) (__PT_REGS_CAST(x)->__PT_CCALL_PARM4_REG)
#define PT_REGS_PARM5(x) (__PT_REGS_CAST(x)->__PT_PARM5_REG)
#define PT_REGS_PARM6(x) (__PT_REGS_CAST(x)->__PT_PARM6_REG)
#define PT_REGS_RET(x) (__PT_REGS_CAST(x)->__PT_RET_REG)

View File

@@ -1,13 +1,18 @@
#include "linux/capability.h"
#include "linux/cred.h"
#include "linux/dcache.h"
#include "linux/err.h"
#include "linux/init.h"
#include "linux/kernel.h"
#include "linux/kprobes.h"
#include "linux/lsm_hooks.h"
#include "linux/nsproxy.h"
#include "linux/path.h"
#include "linux/printk.h"
#include "linux/uaccess.h"
#include "linux/uidgid.h"
#include "linux/version.h"
#include "linux/mount.h"
#include "linux/fs.h"
#include "linux/namei.h"
@@ -22,6 +27,7 @@
#include "manager.h"
#include "selinux/selinux.h"
#include "uid_observer.h"
#include "kernel_compat.h"
extern int handle_sepolicy(unsigned long arg3, void __user *arg4);
@@ -34,26 +40,99 @@ static inline bool is_allow_su()
return ksu_is_allow_uid(current_uid().val);
}
static inline bool is_isolated_uid(uid_t uid)
{
#define FIRST_ISOLATED_UID 99000
#define LAST_ISOLATED_UID 99999
#define FIRST_APP_ZYGOTE_ISOLATED_UID 90000
#define LAST_APP_ZYGOTE_ISOLATED_UID 98999
uid_t appid = uid % 100000;
return (appid >= FIRST_ISOLATED_UID && appid <= LAST_ISOLATED_UID) ||
(appid >= FIRST_APP_ZYGOTE_ISOLATED_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) {
pr_warn("Failed to setgroups, too large group: %d!\n",
profile->uid);
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) {
pr_warn("Failed to setgroups, ENOMEM for: %d\n", profile->uid);
return;
}
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)) {
pr_warn("Failed to setgroups, invalid gid: %d\n", gid);
put_group_info(group_info);
return;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
group_info->gid[i] = kgid;
#else
GROUP_AT(group_info, i) = kgid;
#endif
}
groups_sort(group_info);
set_groups(cred, group_info);
}
void escape_to_root(void)
{
struct cred *cred;
cred = (struct cred *)__task_cred(current);
memset(&cred->uid, 0, sizeof(cred->uid));
memset(&cred->gid, 0, sizeof(cred->gid));
memset(&cred->suid, 0, sizeof(cred->suid));
memset(&cred->euid, 0, sizeof(cred->euid));
memset(&cred->egid, 0, sizeof(cred->egid));
memset(&cred->fsuid, 0, sizeof(cred->fsuid));
memset(&cred->fsgid, 0, sizeof(cred->fsgid));
memset(&cred->cap_inheritable, 0xff, sizeof(cred->cap_inheritable));
memset(&cred->cap_permitted, 0xff, sizeof(cred->cap_permitted));
memset(&cred->cap_effective, 0xff, sizeof(cred->cap_effective));
memset(&cred->cap_bset, 0xff, sizeof(cred->cap_bset));
memset(&cred->cap_ambient, 0xff, sizeof(cred->cap_ambient));
if (cred->euid.val == 0) {
pr_warn("Already root, don't escape!\n");
return;
}
struct root_profile *profile = ksu_get_root_profile(cred->uid.val);
cred->uid.val = profile->uid;
cred->suid.val = profile->uid;
cred->euid.val = profile->uid;
cred->fsuid.val = profile->uid;
cred->gid.val = profile->gid;
cred->fsgid.val = profile->gid;
cred->sgid.val = profile->gid;
cred->egid.val = profile->gid;
BUILD_BUG_ON(sizeof(profile->capabilities.effective) !=
sizeof(kernel_cap_t));
// capabilities
memcpy(&cred->cap_effective, &profile->capabilities.effective,
sizeof(cred->cap_effective));
memcpy(&cred->cap_inheritable, &profile->capabilities.effective,
sizeof(cred->cap_inheritable));
memcpy(&cred->cap_permitted, &profile->capabilities.effective,
sizeof(cred->cap_permitted));
memcpy(&cred->cap_bset, &profile->capabilities.effective,
sizeof(cred->cap_bset));
memcpy(&cred->cap_ambient, &profile->capabilities.effective,
sizeof(cred->cap_ambient));
// disable seccomp
#if defined(CONFIG_GENERIC_ENTRY) && \
@@ -62,15 +141,16 @@ void escape_to_root(void)
#else
current_thread_info()->flags &= ~(TIF_SECCOMP | _TIF_SECCOMP);
#endif
#ifdef CONFIG_SECCOMP
current->seccomp.mode = 0;
current->seccomp.filter = NULL;
#else
#endif
// setgroup to root
if (cred->group_info)
put_group_info(cred->group_info);
cred->group_info = get_group_info(&root_groups);
setup_groups(profile, cred);
setup_selinux();
setup_selinux(profile->selinux_domain);
}
int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry)
@@ -123,7 +203,17 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
return 0;
}
pr_info("option: 0x%x, cmd: %ld\n", option, arg2);
// always ignore isolated app uid
if (is_isolated_uid(current_uid().val)) {
return 0;
}
static uid_t last_failed_uid = -1;
if (last_failed_uid == current_uid().val) {
return 0;
}
// pr_info("option: 0x%x, cmd: %ld\n", option, arg2);
if (arg2 == CMD_BECOME_MANAGER) {
// quick check
@@ -140,14 +230,26 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
}
// someone wants to be root manager, just check it!
// arg3 should be `/data/data/<manager_package_name>`
// arg3 should be `/data/user/<userId>/<manager_package_name>`
char param[128];
const char *prefix = "/data/data/";
if (copy_from_user(param, arg3, sizeof(param))) {
pr_err("become_manager: copy param err\n");
return 0;
}
// for user 0, it is /data/data
// for user 999, it is /data/user/999
const char *prefix;
char prefixTmp[64];
int userId = current_uid().val / 100000;
if (userId == 0) {
prefix = "/data/data";
} else {
snprintf(prefixTmp, sizeof(prefixTmp), "/data/user/%d",
userId);
prefix = prefixTmp;
}
if (startswith(param, (char *)prefix) != 0) {
pr_info("become_manager: invalid param: %s\n", param);
return 0;
@@ -185,10 +287,6 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("grant_root: prctl reply error\n");
}
} else {
pr_info("deny root for: %d\n", current_uid());
// add it to deny list!
ksu_allow_uid(current_uid().val, false, true);
}
return 0;
}
@@ -199,9 +297,9 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
u32 version = KERNEL_SU_VERSION;
if (copy_to_user(arg3, &version, sizeof(version))) {
pr_err("prctl reply error, cmd: %d\n", arg2);
return 0;
}
}
return 0;
}
if (arg2 == CMD_REPORT_EVENT) {
@@ -233,6 +331,9 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
}
if (arg2 == CMD_SET_SEPOLICY) {
if (0 != current_uid().val) {
return 0;
}
if (!handle_sepolicy(arg3, arg4)) {
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("sepolicy: prctl reply error\n");
@@ -242,45 +343,207 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
return 0;
}
// all other cmds are for 'root manager'
if (!is_manager()) {
pr_info("Only manager can do cmd: %d\n", arg2);
if (arg2 == CMD_CHECK_SAFEMODE) {
if (!is_manager() && 0 != current_uid().val) {
return 0;
}
if (ksu_is_safe_mode()) {
pr_warn("safemode enabled!\n");
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("safemode: prctl reply error\n");
}
}
return 0;
}
// we are already manager
if (arg2 == CMD_ALLOW_SU || arg2 == CMD_DENY_SU) {
bool allow = arg2 == CMD_ALLOW_SU;
bool success = false;
uid_t uid = (uid_t)arg3;
success = ksu_allow_uid(uid, allow, true);
if (success) {
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %d\n", arg2);
if (arg2 == CMD_GET_ALLOW_LIST || arg2 == CMD_GET_DENY_LIST) {
if (is_manager() || 0 == current_uid().val) {
u32 array[128];
u32 array_length;
bool success =
ksu_get_allow_list(array, &array_length,
arg2 == CMD_GET_ALLOW_LIST);
if (success) {
if (!copy_to_user(arg4, &array_length,
sizeof(array_length)) &&
!copy_to_user(arg3, array,
sizeof(u32) * array_length)) {
if (copy_to_user(result, &reply_ok,
sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %d\n",
arg2);
}
} else {
pr_err("prctl copy allowlist error\n");
}
}
}
ksu_show_allow_list();
} else if (arg2 == CMD_GET_ALLOW_LIST || arg2 == CMD_GET_DENY_LIST) {
u32 array[128];
u32 array_length;
bool success = ksu_get_allow_list(array, &array_length,
arg2 == CMD_GET_ALLOW_LIST);
if (success) {
if (!copy_to_user(arg4, &array_length,
sizeof(array_length)) &&
!copy_to_user(arg3, array,
sizeof(u32) * array_length)) {
return 0;
}
if (arg2 == CMD_UID_GRANTED_ROOT || arg2 == CMD_UID_SHOULD_UMOUNT) {
if (is_manager() || 0 == current_uid().val) {
uid_t target_uid = (uid_t)arg3;
bool allow = false;
if (arg2 == CMD_UID_GRANTED_ROOT) {
allow = ksu_is_allow_uid(target_uid);
} else if (arg2 == CMD_UID_SHOULD_UMOUNT) {
allow = ksu_uid_should_umount(target_uid);
} else {
pr_err("unknown cmd: %d\n", arg2);
}
if (!copy_to_user(arg4, &allow, sizeof(allow))) {
if (copy_to_user(result, &reply_ok,
sizeof(reply_ok))) {
sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %d\n",
arg2);
}
} else {
pr_err("prctl copy allowlist error\n");
pr_err("prctl copy err, cmd: %d\n", arg2);
}
}
return 0;
}
// all other cmds are for 'root manager'
if (!is_manager()) {
last_failed_uid = current_uid().val;
return 0;
}
// we are already manager
if (arg2 == CMD_GET_APP_PROFILE) {
struct app_profile profile;
if (copy_from_user(&profile, arg3, sizeof(profile))) {
pr_err("copy profile failed\n");
return 0;
}
bool success = ksu_get_app_profile(&profile);
if (success) {
if (copy_to_user(arg3, &profile, sizeof(profile))) {
pr_err("copy profile failed\n");
return 0;
}
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %d\n", arg2);
}
}
return 0;
}
if (arg2 == CMD_SET_APP_PROFILE) {
struct app_profile profile;
if (copy_from_user(&profile, arg3, sizeof(profile))) {
pr_err("copy profile failed\n");
return 0;
}
// todo: validate the params
if (ksu_set_app_profile(&profile, true)) {
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %d\n", arg2);
}
}
return 0;
}
return 0;
}
static bool is_appuid(kuid_t uid)
{
#define PER_USER_RANGE 100000
#define FIRST_APPLICATION_UID 10000
#define LAST_APPLICATION_UID 19999
uid_t appid = uid.val % PER_USER_RANGE;
return appid >= FIRST_APPLICATION_UID && appid <= LAST_APPLICATION_UID;
}
static bool should_umount(struct path *path)
{
if (!path) {
return false;
}
if (current->nsproxy->mnt_ns == init_nsproxy.mnt_ns) {
pr_info("ignore global mnt namespace process: %d\n",
current_uid().val);
return false;
}
if (path->mnt && path->mnt->mnt_sb && path->mnt->mnt_sb->s_type) {
const char *fstype = path->mnt->mnt_sb->s_type->name;
return strcmp(fstype, "overlay") == 0;
}
return false;
}
static void try_umount(const char *mnt)
{
struct path path;
int err = kern_path(mnt, 0, &path);
if (err) {
return;
}
// we are only interest in some specific mounts
if (!should_umount(&path)) {
return;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
err = path_umount(&path, 0);
if (err) {
pr_info("umount %s failed: %d\n", mnt, err);
}
#endif
}
int ksu_handle_setuid(struct cred *new, const struct cred *old)
{
if (!new || !old) {
return 0;
}
kuid_t new_uid = new->uid;
kuid_t old_uid = old->uid;
if (0 != old_uid.val) {
// old process is not root, ignore it.
return 0;
}
// todo: check old process's selinux context, if it is not zygote, ignore it!
if (!is_appuid(new_uid)) {
// pr_info("handle setuid ignore non application uid: %d\n", new_uid.val);
return 0;
}
if (ksu_is_allow_uid(new_uid.val)) {
// pr_info("handle setuid ignore allowed application: %d\n", new_uid.val);
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);
// fixme: use `collect_mounts` and `iterate_mount` to iterate all mountpoint and
// filter the mountpoint whose target is `/data/adb`
try_umount("/system");
try_umount("/vendor");
try_umount("/product");
return 0;
}
@@ -296,7 +559,14 @@ static int handler_pre(struct kprobe *p, struct pt_regs *regs)
int option = (int)PT_REGS_PARM1(real_regs);
unsigned long arg2 = (unsigned long)PT_REGS_PARM2(real_regs);
unsigned long arg3 = (unsigned long)PT_REGS_PARM3(real_regs);
unsigned long arg4 = (unsigned long)PT_REGS_PARM4(real_regs);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
// PRCTL_SYMBOL is the arch-specificed one, which receive raw pt_regs from syscall
unsigned long arg4 = (unsigned long)PT_REGS_SYSCALL_PARM4(real_regs);
#else
// PRCTL_SYMBOL is the common one, called by C convention in do_syscall_64
// https://elixir.bootlin.com/linux/v4.15.18/source/arch/x86/entry/common.c#L287
unsigned long arg4 = (unsigned long)PT_REGS_CCALL_PARM4(real_regs);
#endif
unsigned long arg5 = (unsigned long)PT_REGS_PARM5(real_regs);
return ksu_handle_prctl(option, arg2, arg3, arg4, arg5);
@@ -316,7 +586,7 @@ static int renameat_handler_pre(struct kprobe *p, struct pt_regs *regs)
struct dentry *new_entry = rd->new_dentry;
#else
struct dentry *old_entry = (struct dentry *)PT_REGS_PARM2(regs);
struct dentry *new_entry = (struct dentry *)PT_REGS_PARM4(regs);
struct dentry *new_entry = (struct dentry *)PT_REGS_CCALL_PARM4(regs);
#endif
return ksu_handle_rename(old_entry, new_entry);
@@ -356,16 +626,42 @@ static int ksu_task_prctl(int option, unsigned long arg2, unsigned long arg3,
ksu_handle_prctl(option, arg2, arg3, arg4, arg5);
return -ENOSYS;
}
// kernel 4.4 and 4.9
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
static int ksu_key_permission(key_ref_t key_ref, const struct cred *cred,
unsigned perm)
{
if (init_session_keyring != NULL) {
return 0;
}
if (strcmp(current->comm, "init")) {
// we are only interested in `init` process
return 0;
}
init_session_keyring = cred->session_keyring;
pr_info("kernel_compat: got init_session_keyring");
return 0;
}
#endif
static int ksu_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
struct inode *new_inode, struct dentry *new_dentry)
{
return ksu_handle_rename(old_dentry, new_dentry);
}
static int ksu_task_fix_setuid(struct cred *new, const struct cred *old,
int flags)
{
return ksu_handle_setuid(new, old);
}
static struct security_hook_list ksu_hooks[] = {
LSM_HOOK_INIT(task_prctl, ksu_task_prctl),
LSM_HOOK_INIT(inode_rename, ksu_inode_rename),
LSM_HOOK_INIT(task_fix_setuid, ksu_task_fix_setuid),
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
LSM_HOOK_INIT(key_permission, ksu_key_permission)
#endif
};
void __init ksu_lsm_hook_init(void)
@@ -395,4 +691,4 @@ void ksu_core_exit(void)
pr_info("ksu_kprobe_exit\n");
ksu_kprobe_exit();
#endif
}
}

View File

@@ -2,4 +2,4 @@
// This file will be regenerated by CI
unsigned int ksud_size = 0;
const char ksud[0] = {};
const char ksud[0] = {};

View File

@@ -1,2 +1,2 @@
register_kprobe
unregister_kprobe
unregister_kprobe

View File

@@ -21,4 +21,8 @@ int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv,
void *envp, int *flags);
#endif
// For volume button
int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code,
int *value);
#endif

135
kernel/kernel_compat.c Normal file
View File

@@ -0,0 +1,135 @@
#include "linux/version.h"
#include "linux/fs.h"
#include "linux/nsproxy.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
#include "linux/sched/task.h"
#else
#include "linux/sched.h"
#endif
#include "klog.h" // IWYU pragma: keep
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
#include "linux/key.h"
#include "linux/errno.h"
struct key *init_session_keyring = NULL;
static inline int install_session_keyring(struct key *keyring)
{
struct cred *new;
int ret;
new = prepare_creds();
if (!new)
return -ENOMEM;
ret = install_session_keyring_to_cred(new, keyring);
if (ret < 0) {
abort_creds(new);
return ret;
}
return commit_creds(new);
}
#endif
extern struct task_struct init_task;
// mnt_ns context switch for environment that android_init->nsproxy->mnt_ns != init_task.nsproxy->mnt_ns, such as WSA
struct ksu_ns_fs_saved {
struct nsproxy *ns;
struct fs_struct *fs;
};
static void ksu_save_ns_fs(struct ksu_ns_fs_saved *ns_fs_saved)
{
ns_fs_saved->ns = current->nsproxy;
ns_fs_saved->fs = current->fs;
}
static void ksu_load_ns_fs(struct ksu_ns_fs_saved *ns_fs_saved)
{
current->nsproxy = ns_fs_saved->ns;
current->fs = ns_fs_saved->fs;
}
static bool android_context_saved_checked = false;
static bool android_context_saved_enabled = false;
static struct ksu_ns_fs_saved android_context_saved;
void ksu_android_ns_fs_check()
{
if (android_context_saved_checked)
return;
android_context_saved_checked = true;
task_lock(current);
if (current->nsproxy && current->fs &&
current->nsproxy->mnt_ns != init_task.nsproxy->mnt_ns) {
android_context_saved_enabled = true;
pr_info("android context saved enabled due to init mnt_ns(%p) != android mnt_ns(%p)\n",
current->nsproxy->mnt_ns, init_task.nsproxy->mnt_ns);
ksu_save_ns_fs(&android_context_saved);
} else {
pr_info("android context saved disabled\n");
}
task_unlock(current);
}
struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
static bool keyring_installed = false;
if (init_session_keyring != NULL && !keyring_installed &&
(current->flags & PF_WQ_WORKER)) {
pr_info("installing init session keyring for older kernel\n");
install_session_keyring(init_session_keyring);
keyring_installed = true;
}
#endif
// switch mnt_ns even if current is not wq_worker, to ensure what we open is the correct file in android mnt_ns, rather than user created mnt_ns
struct ksu_ns_fs_saved saved;
if (android_context_saved_enabled) {
pr_info("start switch current nsproxy and fs to android context\n");
task_lock(current);
ksu_save_ns_fs(&saved);
ksu_load_ns_fs(&android_context_saved);
task_unlock(current);
}
struct file *fp = filp_open(filename, flags, mode);
if (android_context_saved_enabled) {
task_lock(current);
ksu_load_ns_fs(&saved);
task_unlock(current);
pr_info("switch current nsproxy and fs back to saved successfully\n");
}
return fp;
}
ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count,
loff_t *pos)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
return kernel_read(p, buf, count, pos);
#else
loff_t offset = pos ? *pos : 0;
ssize_t result = kernel_read(p, offset, (char *)buf, count);
if (pos && result > 0) {
*pos = offset + result;
}
return result;
#endif
}
ssize_t ksu_kernel_write_compat(struct file *p, const void *buf, size_t count,
loff_t *pos)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
return kernel_write(p, buf, count, pos);
#else
loff_t offset = pos ? *pos : 0;
ssize_t result = kernel_write(p, buf, count, offset);
if (pos && result > 0) {
*pos = offset + result;
}
return result;
#endif
}

26
kernel/kernel_compat.h Normal file
View File

@@ -0,0 +1,26 @@
#ifndef __KSU_H_KERNEL_COMPAT
#define __KSU_H_KERNEL_COMPAT
#include "linux/fs.h"
#include "linux/key.h"
#include "linux/version.h"
#include "linux/uaccess.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
#define ksu_strncpy_from_user_nofault strncpy_from_user_nofault
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
#define ksu_strncpy_from_user_nofault strncpy_from_unsafe_user
#else
#define ksu_strncpy_from_user_nofault strncpy_from_user
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
extern struct key *init_session_keyring;
#endif
extern void ksu_android_ns_fs_check();
extern struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode);
extern ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count, loff_t *pos);
extern ssize_t ksu_kernel_write_compat(struct file *p, const void *buf, size_t count, loff_t *pos);
#endif

View File

@@ -8,4 +8,4 @@
#define pr_fmt(fmt) "KernelSU: " fmt
#endif
#endif
#endif

View File

@@ -39,7 +39,7 @@ int __init kernelsu_init(void)
pr_alert("*************************************************************");
pr_alert("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **");
pr_alert("** **");
pr_alert("** You are running DEBUG version of KernelSU **");
pr_alert("** You are running KernelSU in DEBUG mode **");
pr_alert("** **");
pr_alert("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **");
pr_alert("*************************************************************");
@@ -57,7 +57,7 @@ int __init kernelsu_init(void)
ksu_enable_sucompat();
ksu_enable_ksud();
#else
#warning("KPROBES is disabled, KernelSU may not work, please check https://kernelsu.org/guide/how-to-integrate-for-non-gki.html")
pr_alert("KPROBES is disabled, KernelSU may not work, please check https://kernelsu.org/guide/how-to-integrate-for-non-gki.html");
#endif
return 0;

View File

@@ -1,10 +1,10 @@
#ifndef __KSU_H_KSU
#define __KSU_H_KSU
#include "linux/types.h"
#include "linux/workqueue.h"
#define KERNEL_SU_VERSION 14
#define KERNEL_SU_VERSION KSU_VERSION
#define KERNEL_SU_OPTION 0xDEADBEEF
#define CMD_GRANT_ROOT 0
@@ -16,10 +16,69 @@
#define CMD_GET_DENY_LIST 6
#define CMD_REPORT_EVENT 7
#define CMD_SET_SEPOLICY 8
#define CMD_CHECK_SAFEMODE 9
#define CMD_GET_APP_PROFILE 10
#define CMD_SET_APP_PROFILE 11
#define CMD_UID_GRANTED_ROOT 12
#define CMD_UID_SHOULD_UMOUNT 13
#define EVENT_POST_FS_DATA 1
#define EVENT_BOOT_COMPLETED 2
#define KSU_APP_PROFILE_VER 2
#define KSU_MAX_PACKAGE_NAME 256
// NGROUPS_MAX for Linux is 65535 generally, but we only supports 32 groups.
#define KSU_MAX_GROUPS 32
#define KSU_SELINUX_DOMAIN 64
struct root_profile {
int32_t uid;
int32_t gid;
int32_t groups_count;
int32_t groups[KSU_MAX_GROUPS];
// kernel_cap_t is u32[2] for capabilities v3
struct {
u64 effective;
u64 permitted;
u64 inheritable;
} capabilities;
char selinux_domain[KSU_SELINUX_DOMAIN];
int32_t namespaces;
};
struct non_root_profile {
bool umount_modules;
};
struct app_profile {
// It may be utilized for backward compatibility, although we have never explicitly made any promises regarding this.
u32 version;
// this is usually the package of the app, but can be other value for special apps
char key[KSU_MAX_PACKAGE_NAME];
int32_t current_uid;
bool allow_su;
union {
struct {
bool use_default;
char template_name[KSU_MAX_PACKAGE_NAME];
struct root_profile profile;
} rp_config;
struct {
bool use_default;
struct non_root_profile profile;
} nrp_config;
};
};
bool ksu_queue_work(struct work_struct *work);
static inline int startswith(char *s, char *prefix)

View File

@@ -1,8 +1,9 @@
#include "asm/current.h"
#include "linux/cred.h"
#include "linux/compat.h"
#include "linux/dcache.h"
#include "linux/err.h"
#include "linux/fs.h"
#include "linux/input-event-codes.h"
#include "linux/kprobes.h"
#include "linux/printk.h"
#include "linux/types.h"
@@ -13,39 +14,45 @@
#include "allowlist.h"
#include "arch.h"
#include "klog.h" // IWYU pragma: keep
#include "ksud.h"
#include "kernel_compat.h"
#include "selinux/selinux.h"
static const char KERNEL_SU_RC[] =
"\n"
"on post-fs-data\n"
" start logd\n"
// We should wait for the post-fs-data finish
" exec u:r:su:s0 root -- /data/adb/ksud post-fs-data\n"
" exec u:r:su:s0 root -- " KSUD_PATH " post-fs-data\n"
"\n"
"on nonencrypted\n"
" exec u:r:su:s0 root -- /data/adb/ksud services\n"
" exec u:r:su:s0 root -- " KSUD_PATH " services\n"
"\n"
"on property:vold.decrypt=trigger_restart_framework\n"
" exec u:r:su:s0 root -- /data/adb/ksud services\n"
" exec u:r:su:s0 root -- " KSUD_PATH " services\n"
"\n"
"on property:sys.boot_completed=1\n"
" exec u:r:su:s0 root -- /data/adb/ksud boot-completed\n"
" exec u:r:su:s0 root -- " KSUD_PATH " boot-completed\n"
"\n"
"\n";
static void stop_vfs_read_hook();
static void stop_execve_hook();
static void stop_input_hook();
#ifdef CONFIG_KPROBES
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;
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)
@@ -56,15 +63,87 @@ void on_post_fs_data(void)
return;
}
done = true;
pr_info("ksu_load_allow_list");
pr_info("on_post_fs_data!");
ksu_load_allow_list();
// sanity check, this may influence the performance
stop_input_hook();
}
#define MAX_ARG_STRINGS 0x7FFFFFFF
struct user_arg_ptr {
#ifdef CONFIG_COMPAT
bool is_compat;
#endif
union {
const char __user *const __user *native;
#ifdef CONFIG_COMPAT
const compat_uptr_t __user *compat;
#endif
} ptr;
};
static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr)
{
const char __user *native;
#ifdef CONFIG_COMPAT
if (unlikely(argv.is_compat)) {
compat_uptr_t compat;
if (get_user(compat, argv.ptr.compat + nr))
return ERR_PTR(-EFAULT);
return compat_ptr(compat);
}
#endif
if (get_user(native, argv.ptr.native + nr))
return ERR_PTR(-EFAULT);
return native;
}
/*
* count() counts the number of strings in array ARGV.
*/
/*
* 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;
if (argv.ptr.native != NULL) {
for (;;) {
const char __user *p = get_user_arg_ptr(argv, i);
if (!p)
break;
if (IS_ERR(p))
return -EFAULT;
if (i >= max)
return -E2BIG;
++i;
if (fatal_signal_pending(current))
return -ERESTARTNOHAND;
cond_resched();
}
}
return i;
}
// the call from execve_handler_pre won't provided correct value for __never_use_argument, use them after fix execve_handler_pre, keeping them for consistence for manually patched code
int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
void *argv, void *envp, int *flags)
struct user_arg_ptr *argv, void *__never_use_envp, int *__never_use_flags)
{
#ifndef CONFIG_KPROBES
if (!execveat_hook) {
if (!ksu_execveat_hook) {
return 0;
}
#endif
@@ -73,7 +152,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
static const char app_process[] = "/system/bin/app_process";
static bool first_app_process = true;
static const char system_bin_init[] = "/system/bin/init";
static int init_count = 0;
static bool init_second_stage_executed = false;
if (!filename_ptr)
return 0;
@@ -83,21 +162,33 @@ 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))) {
// /system/bin/init executed
if (++init_count == 2) {
// 1: /system/bin/init selinux_setup
// 2: /system/bin/init second_stage
pr_info("/system/bin/init second_stage executed\n");
apply_kernelsu_rules();
int argc = count(*argv, MAX_ARG_STRINGS);
pr_info("/system/bin/init argc: %d\n", argc);
if (argc > 1 && !init_second_stage_executed) {
const char __user *p = get_user_arg_ptr(*argv, 1);
if (p && !IS_ERR(p)) {
char first_arg[16];
ksu_strncpy_from_user_nofault(first_arg, p, sizeof(first_arg));
pr_info("first arg: %s\n", first_arg);
if (!strcmp(first_arg, "second_stage")) {
pr_info("/system/bin/init second_stage executed\n");
apply_kernelsu_rules();
init_second_stage_executed = true;
ksu_android_ns_fs_check();
}
} else {
pr_err("/system/bin/init parse args err!\n");
}
}
}
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!\n");
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
stop_execve_hook();
}
@@ -105,11 +196,40 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
return 0;
}
static ssize_t (*orig_read)(struct file *, char __user *, size_t, loff_t *);
static ssize_t (*orig_read_iter)(struct kiocb *, struct iov_iter *);
static struct file_operations fops_proxy;
static ssize_t read_count_append = 0;
static ssize_t read_proxy(struct file *file, char __user *buf, size_t count,
loff_t *pos)
{
bool first_read = file->f_pos == 0;
ssize_t ret = orig_read(file, buf, count, pos);
if (first_read) {
pr_info("read_proxy append %ld + %ld", ret, read_count_append);
ret += read_count_append;
}
return ret;
}
static ssize_t read_iter_proxy(struct kiocb *iocb, struct iov_iter *to)
{
bool first_read = iocb->ki_pos == 0;
ssize_t ret = orig_read_iter(iocb, to);
if (first_read) {
pr_info("read_iter_proxy append %ld + %ld", ret,
read_count_append);
ret += read_count_append;
}
return ret;
}
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
@@ -177,12 +297,80 @@ int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
return 0;
}
// we've succeed to insert ksud.rc, now we need to proxy the read and modify the result!
// But, we can not modify the file_operations directly, because it's in read-only memory.
// We just replace the whole file_operations with a proxy one.
memcpy(&fops_proxy, file->f_op, sizeof(struct file_operations));
orig_read = file->f_op->read;
if (orig_read) {
fops_proxy.read = read_proxy;
}
orig_read_iter = file->f_op->read_iter;
if (orig_read_iter) {
fops_proxy.read_iter = read_iter_proxy;
}
// replace the file_operations
file->f_op = &fops_proxy;
read_count_append = rc_count;
*buf_ptr = buf + rc_count;
*count_ptr = count - rc_count;
return 0;
}
static unsigned int volumedown_pressed_count = 0;
static bool is_volumedown_enough(unsigned int count)
{
return count >= 3;
}
int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code,
int *value)
{
#ifndef CONFIG_KPROBES
if (!ksu_input_hook) {
return 0;
}
#endif
if (*type == EV_KEY && *code == KEY_VOLUMEDOWN) {
int val = *value;
pr_info("KEY_VOLUMEDOWN val: %d\n", val);
if (val) {
// key pressed, count it
volumedown_pressed_count += 1;
if (is_volumedown_enough(volumedown_pressed_count)) {
stop_input_hook();
}
}
}
return 0;
}
bool ksu_is_safe_mode()
{
static bool safe_mode = false;
if (safe_mode) {
// don't need to check again, userspace may call multiple times
return true;
}
// stop hook first!
stop_input_hook();
pr_info("volumedown_pressed_count: %d\n", volumedown_pressed_count);
if (is_volumedown_enough(volumedown_pressed_count)) {
// pressed over 3 times
pr_info("KEY_VOLUMEDOWN pressed max times, safe mode detected!\n");
safe_mode = true;
return true;
}
return false;
}
#ifdef CONFIG_KPROBES
// https://elixir.bootlin.com/linux/v5.10.158/source/fs/exec.c#L1864
@@ -191,11 +379,19 @@ static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
int *fd = (int *)&PT_REGS_PARM1(regs);
struct filename **filename_ptr =
(struct filename **)&PT_REGS_PARM2(regs);
void *argv = (void *)&PT_REGS_PARM3(regs);
void *envp = (void *)&PT_REGS_PARM4(regs);
int *flags = (int *)&PT_REGS_PARM5(regs);
struct user_arg_ptr argv;
#ifdef CONFIG_COMPAT
argv.is_compat = PT_REGS_PARM3(regs);
if (unlikely(argv.is_compat)) {
argv.ptr.compat = PT_REGS_CCALL_PARM4(regs);
} else {
argv.ptr.native = PT_REGS_CCALL_PARM4(regs);
}
#else
argv.ptr.native = PT_REGS_PARM3(regs);
#endif
return ksu_handle_execveat_ksud(fd, filename_ptr, argv, envp, flags);
return ksu_handle_execveat_ksud(fd, filename_ptr, &argv, NULL, NULL);
}
static int read_handler_pre(struct kprobe *p, struct pt_regs *regs)
@@ -203,19 +399,26 @@ static int read_handler_pre(struct kprobe *p, struct pt_regs *regs)
struct file **file_ptr = (struct file **)&PT_REGS_PARM1(regs);
char __user **buf_ptr = (char **)&PT_REGS_PARM2(regs);
size_t *count_ptr = (size_t *)&PT_REGS_PARM3(regs);
loff_t **pos_ptr = (loff_t **)&PT_REGS_PARM4(regs);
loff_t **pos_ptr = (loff_t **)&PT_REGS_CCALL_PARM4(regs);
return ksu_handle_vfs_read(file_ptr, buf_ptr, count_ptr, pos_ptr);
}
static int input_handle_event_handler_pre(struct kprobe *p,
struct pt_regs *regs)
{
unsigned int *type = (unsigned int *)&PT_REGS_PARM2(regs);
unsigned int *code = (unsigned int *)&PT_REGS_PARM3(regs);
int *value = (int *)&PT_REGS_CCALL_PARM4(regs);
return ksu_handle_input_handle_event(type, code, value);
}
static struct kprobe execve_kp = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
.symbol_name = "do_execveat_common",
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) && \
LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
.symbol_name = "__do_execve_file",
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) && \
LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
.symbol_name = "do_execveat_common",
#endif
.pre_handler = execve_handler_pre,
@@ -226,6 +429,11 @@ static struct kprobe vfs_read_kp = {
.pre_handler = read_handler_pre,
};
static struct kprobe input_handle_event_kp = {
.symbol_name = "input_handle_event",
.pre_handler = input_handle_event_handler_pre,
};
static void do_stop_vfs_read_hook(struct work_struct *work)
{
unregister_kprobe(&vfs_read_kp);
@@ -235,6 +443,11 @@ static void do_stop_execve_hook(struct work_struct *work)
{
unregister_kprobe(&execve_kp);
}
static void do_stop_input_hook(struct work_struct *work)
{
unregister_kprobe(&input_handle_event_kp);
}
#endif
static void stop_vfs_read_hook()
@@ -243,7 +456,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
}
@@ -253,7 +466,22 @@ 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
}
static void stop_input_hook()
{
static bool input_hook_stopped = false;
if (input_hook_stopped) {
return;
}
input_hook_stopped = true;
#ifdef CONFIG_KPROBES
bool ret = schedule_work(&stop_input_hook_work);
pr_info("unregister input kprobe: %d!\n", ret);
#else
ksu_input_hook = false;
#endif
}
@@ -269,7 +497,11 @@ void ksu_enable_ksud()
ret = register_kprobe(&vfs_read_kp);
pr_info("ksud: vfs_read_kp: %d\n", ret);
ret = register_kprobe(&input_handle_event_kp);
pr_info("ksud: input_handle_event_kp: %d\n", ret);
INIT_WORK(&stop_vfs_read_work, do_stop_vfs_read_hook);
INIT_WORK(&stop_execve_hook_work, do_stop_execve_hook);
INIT_WORK(&stop_input_hook_work, do_stop_input_hook);
#endif
}

View File

@@ -1,6 +1,10 @@
#ifndef __KSU_H_KSUD
#define __KSU_H_KSUD
#define KSUD_PATH "/data/adb/ksud"
void on_post_fs_data(void);
#endif
bool ksu_is_safe_mode(void);
#endif

View File

@@ -13,7 +13,7 @@
#include "ksu.h"
#include "manager.h"
uid_t ksu_manager_uid = INVALID_UID;
uid_t ksu_manager_uid = KSU_INVALID_UID;
bool become_manager(char *pkg)
{
@@ -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);
result = true;
goto clean;
} else {
pr_info("manager signature invalid!");
}
break;
if (startswith(cwd, "/data/app/") != 0 ||
endswith(cwd, "/base.apk") != 0) {
continue;
}
i++;
// 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);
ksu_set_manager_uid(uid);
result = true;
goto clean;
} else {
pr_info("manager signature invalid!");
}
break;
}
clean:

View File

@@ -4,18 +4,18 @@
#include "linux/cred.h"
#include "linux/types.h"
#define INVALID_UID -1
#define KSU_INVALID_UID -1
extern uid_t ksu_manager_uid; // DO NOT DIRECT USE
static inline bool ksu_is_manager_uid_valid()
{
return ksu_manager_uid != INVALID_UID;
return ksu_manager_uid != KSU_INVALID_UID;
}
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()
@@ -30,7 +30,7 @@ static inline void ksu_set_manager_uid(uid_t uid)
static inline void ksu_invalidate_manager_uid()
{
ksu_manager_uid = INVALID_UID;
ksu_manager_uid = KSU_INVALID_UID;
}
bool become_manager(char *pkg);

View File

@@ -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);
// void unregister_kretprobes(struct kretprobe **rps, int num);

View File

@@ -2,8 +2,15 @@ obj-y += selinux.o
obj-y += sepolicy.o
obj-y += rules.o
ifeq ($(shell grep -q " current_sid(void)" $(srctree)/security/selinux/include/objsec.h; echo $$?),0)
ccflags-y += -DKSU_COMPAT_HAS_CURRENT_SID
endif
ifeq ($(shell grep -q "struct selinux_state " $(srctree)/security/selinux/include/security.h; echo $$?),0)
ccflags-y += -DKSU_COMPAT_HAS_SELINUX_STATE
endif
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion
ccflags-y += -Wno-macro-redefined -Wno-declaration-after-statement -Wno-unused-function
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function
ccflags-y += -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
ccflags-y += -I$(objtree)/security/selinux
ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm-generic/errno.h

View File

@@ -6,6 +6,8 @@
#include "selinux.h"
#include "sepolicy.h"
#include "ss/services.h"
#include "linux/lsm_audit.h"
#include "xfrm.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
#define SELINUX_POLICY_INSTEAD_SELINUX_SS
@@ -19,12 +21,17 @@
static struct policydb *get_policydb(void)
{
struct policydb *db;
// selinux_state does not exists before 4.19
#ifdef KSU_COMPAT_USE_SELINUX_STATE
#ifdef SELINUX_POLICY_INSTEAD_SELINUX_SS
struct selinux_policy *policy = rcu_dereference(selinux_state.policy);
db = &policy->policydb;
#else
struct selinux_ss *ss = rcu_dereference(selinux_state.ss);
db = &ss->policydb;
#endif
#else
db = &policydb;
#endif
return db;
}
@@ -32,8 +39,7 @@ static struct policydb *get_policydb(void)
void apply_kernelsu_rules()
{
if (!getenforce()) {
pr_info("SELinux permissive or disabled, don't apply rules.");
return;
pr_info("SELinux permissive or disabled, apply rules!");
}
rcu_read_lock();
@@ -59,7 +65,7 @@ void apply_kernelsu_rules()
ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "chr_file", ALL);
}
// we need to save allowlist in /data/adb
// we need to save allowlist in /data/adb/ksu
ksu_allow(db, "kernel", "adb_data_file", "dir", ALL);
ksu_allow(db, "kernel", "adb_data_file", "file", ALL);
// we may need to do mount on shell
@@ -69,12 +75,14 @@ void apply_kernelsu_rules()
// Android 10+:
// http://aospxref.com/android-12.0.0_r3/xref/system/sepolicy/private/file_contexts#512
ksu_allow(db, "kernel", "packages_list_file", "file", ALL);
// Kernel 4.4
ksu_allow(db, "kernel", "packages_list_file", "dir", ALL);
// Android 9-:
// http://aospxref.com/android-9.0.0_r61/xref/system/sepolicy/private/file_contexts#360
ksu_allow(db, "kernel", "system_data_file", "file", ALL);
ksu_allow(db, "kernel", "system_data_file", "dir", ALL);
// our ksud triggered by init
ksu_allow(db, "init", "adb_data_file", "file", "execute");
ksu_allow(db, "init", "adb_data_file", "file", ALL);
ksu_allow(db, "init", KERNEL_SU_DOMAIN, ALL, ALL);
// copied from Magisk rules
@@ -106,6 +114,10 @@ void apply_kernelsu_rules()
ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "process",
"getattr");
// For mounting loop devices, mirrors, tmpfs
ksu_allow(db, "kernel", ALL, "file", "read");
ksu_allow(db, "kernel", ALL, "file", "write");
// Allow all binder transactions
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "binder", ALL);
@@ -159,6 +171,22 @@ static int get_object(char *buf, char __user *user_object, size_t buf_sz,
return 0;
}
// reset avc cache table, otherwise the new rules will not take effect if already denied
static void reset_avc_cache()
{
#ifndef KSU_COMPAT_USE_SELINUX_STATE
avc_ss_reset(0);
selnl_notify_policyload(0);
selinux_status_update_policyload(0);
#else
struct selinux_avc *avc = selinux_state.avc;
avc_ss_reset(avc, 0);
selnl_notify_policyload(0);
selinux_status_update_policyload(&selinux_state, 0);
#endif
selinux_xfrm_notify_policyload();
}
int handle_sepolicy(unsigned long arg3, void __user *arg4)
{
if (!arg4) {
@@ -166,8 +194,7 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4)
}
if (!getenforce()) {
pr_info("SELinux permissive or disabled, don't apply policies.");
return -1;
pr_info("SELinux permissive or disabled when handle policy!\n");
}
struct sepol_data data;
@@ -427,11 +454,15 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4)
}
ret = 0;
} else {
pr_err("sepol: unknown cmd: %d");
pr_err("sepol: unknown cmd: %d\n", cmd);
}
exit:
rcu_read_unlock();
// only allow and xallow needs to reset avc cache, but we cannot do that because
// we are in atomic context. so we just reset it every time.
reset_avc_cache();
return ret;
}
}

View File

@@ -1,7 +1,10 @@
#include "selinux.h"
#include "objsec.h"
#include "linux/version.h"
#include "../klog.h" // IWYU pragma: keep
#ifndef KSU_COMPAT_USE_SELINUX_STATE
#include "avc.h"
#endif
#define KERNEL_SU_DOMAIN "u:r:su:s0"
@@ -23,7 +26,9 @@ static int transive_to_domain(const char *domain)
}
error = security_secctx_to_secid(domain, strlen(domain), &sid);
pr_info("error: %d, sid: %d\n", error, sid);
if (error) {
pr_info("security_secctx_to_secid %s -> sid: %d, error: %d\n", domain, sid, error);
}
if (!error) {
if (!ksu_sid)
ksu_sid = sid;
@@ -36,9 +41,9 @@ static int transive_to_domain(const char *domain)
return error;
}
void setup_selinux()
void setup_selinux(const char *domain)
{
if (transive_to_domain(KERNEL_SU_DOMAIN)) {
if (transive_to_domain(domain)) {
pr_err("transive domain failed.");
return;
}
@@ -54,26 +59,51 @@ if (!is_domain_permissive) {
void setenforce(bool enforce)
{
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
#ifdef KSU_COMPAT_USE_SELINUX_STATE
selinux_state.enforcing = enforce;
#else
selinux_enforcing = enforce;
#endif
#endif
}
bool getenforce()
{
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
#ifdef KSU_COMPAT_USE_SELINUX_STATE
if (selinux_state.disabled) {
#else
if (selinux_disabled) {
#endif
return false;
}
#endif
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
#ifdef KSU_COMPAT_USE_SELINUX_STATE
return selinux_state.enforcing;
#else
return false;
return selinux_enforcing;
#endif
#else
return true;
#endif
}
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) && \
!defined(KSU_COMPAT_HAS_CURRENT_SID)
/*
* get the subjective security ID of the current task
*/
static inline u32 current_sid(void)
{
const struct task_security_struct *tsec = current_security();
return tsec->sid;
}
#endif
bool is_ksu_domain()
{
return ksu_sid && current_sid() == ksu_sid;
}
}

View File

@@ -2,8 +2,13 @@
#define __KSU_H_SELINUX
#include "linux/types.h"
#include "linux/version.h"
void setup_selinux();
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) || defined(KSU_COMPAT_HAS_SELINUX_STATE)
#define KSU_COMPAT_USE_SELINUX_STATE
#endif
void setup_selinux(const char *);
void setenforce(bool);
@@ -13,4 +18,4 @@ bool is_ksu_domain();
void apply_kernelsu_rules();
#endif
#endif

View File

@@ -7,9 +7,18 @@
#include "../klog.h" // IWYU pragma: keep
#include "ss/symtab.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
// TODO: backport to lower kernel
#define KSU_SUPPORT_ADD_TYPE
/*
* Adapt to Huawei HISI kernel without affecting other kernels ,
* Huawei Hisi Kernel EBITMAP Enable or Disable Flag ,
* From ss/ebitmap.h
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) && \
LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
#ifdef HISI_SELINUX_EBITMAP_RO
#define CONFIG_IS_HW_HISI
#endif
#endif
//////////////////////////////////////////////////////
@@ -64,7 +73,7 @@ static bool add_typeattribute(struct policydb *db, const char *type,
// rules
#define strip_av(effect, invert) ((effect == AVTAB_AUDITDENY) == !invert)
#define hash_for_each(node_ptr, n_slot, cur) \
#define ksu_hash_for_each(node_ptr, n_slot, cur) \
int i; \
for (i = 0; i < n_slot; ++i) \
for (cur = node_ptr[i]; cur; cur = cur->next)
@@ -72,21 +81,22 @@ static bool add_typeattribute(struct policydb *db, const char *type,
// htable is a struct instead of pointer above 5.8.0:
// https://elixir.bootlin.com/linux/v5.8-rc1/source/security/selinux/ss/symtab.h
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
#define hashtab_for_each(htab, cur) hash_for_each (htab.htable, htab.size, cur)
#define ksu_hashtab_for_each(htab, cur) \
ksu_hash_for_each(htab.htable, htab.size, cur)
#else
#define hashtab_for_each(htab, cur) \
hash_for_each (htab->htable, htab->size, cur)
#define ksu_hashtab_for_each(htab, cur) \
ksu_hash_for_each(htab->htable, htab->size, cur)
#endif
// symtab_search is introduced on 5.9.0:
// https://elixir.bootlin.com/linux/v5.9-rc1/source/security/selinux/ss/symtab.h
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0)
#define symtab_search(s, name) hashtab_search((s)->table, name)
#define symtab_insert(s, name, datum) hashtab_insert((s)->table, name, datum)
#endif
#define avtab_for_each(avtab, cur) \
hash_for_each (avtab.htable, avtab.nslot, cur) \
;
ksu_hash_for_each(avtab.htable, avtab.nslot, cur);
static struct avtab_node *get_avtab_node(struct policydb *db,
struct avtab_key *key,
@@ -128,14 +138,13 @@ static struct avtab_node *get_avtab_node(struct policydb *db,
/* this is used to get the node - insertion is actually unique */
node = avtab_insert_nonunique(&db->te_avtab, key, &avdatum);
int grow_size = sizeof(u16) * 4;
int grow_size = sizeof(struct avtab_key);
grow_size += sizeof(struct avtab_datum);
if (key->specified & AVTAB_XPERMS) {
grow_size += sizeof(u8);
grow_size += sizeof(u8);
grow_size += sizeof(u32) *
ARRAY_SIZE(avdatum.u.xperms->perms.p);
} else {
grow_size += sizeof(u32) * 1;
}
db->len += grow_size;
}
@@ -201,14 +210,14 @@ static void add_rule_raw(struct policydb *db, struct type_datum *src,
if (src == NULL) {
struct hashtab_node *node;
if (strip_av(effect, invert)) {
hashtab_for_each(db->p_types.table, node)
ksu_hashtab_for_each(db->p_types.table, node)
{
add_rule_raw(db,
(struct type_datum *)node->datum,
tgt, cls, perm, effect, invert);
};
} else {
hashtab_for_each(db->p_types.table, node)
ksu_hashtab_for_each(db->p_types.table, node)
{
struct type_datum *type =
(struct type_datum *)(node->datum);
@@ -221,14 +230,14 @@ static void add_rule_raw(struct policydb *db, struct type_datum *src,
} else if (tgt == NULL) {
struct hashtab_node *node;
if (strip_av(effect, invert)) {
hashtab_for_each(db->p_types.table, node)
ksu_hashtab_for_each(db->p_types.table, node)
{
add_rule_raw(db, src,
(struct type_datum *)node->datum,
cls, perm, effect, invert);
};
} else {
hashtab_for_each(db->p_types.table, node)
ksu_hashtab_for_each(db->p_types.table, node)
{
struct type_datum *type =
(struct type_datum *)(node->datum);
@@ -240,7 +249,7 @@ static void add_rule_raw(struct policydb *db, struct type_datum *src,
}
} else if (cls == NULL) {
struct hashtab_node *node;
hashtab_for_each(db->p_classes.table, node)
ksu_hashtab_for_each(db->p_classes.table, node)
{
add_rule_raw(db, src, tgt,
(struct class_datum *)node->datum, perm,
@@ -283,7 +292,7 @@ static void add_xperm_rule_raw(struct policydb *db, struct type_datum *src,
{
if (src == NULL) {
struct hashtab_node *node;
hashtab_for_each(db->p_types.table, node)
ksu_hashtab_for_each(db->p_types.table, node)
{
struct type_datum *type =
(struct type_datum *)(node->datum);
@@ -294,7 +303,7 @@ static void add_xperm_rule_raw(struct policydb *db, struct type_datum *src,
};
} else if (tgt == NULL) {
struct hashtab_node *node;
hashtab_for_each(db->p_types.table, node)
ksu_hashtab_for_each(db->p_types.table, node)
{
struct type_datum *type =
(struct type_datum *)(node->datum);
@@ -305,7 +314,7 @@ static void add_xperm_rule_raw(struct policydb *db, struct type_datum *src,
};
} else if (cls == NULL) {
struct hashtab_node *node;
hashtab_for_each(db->p_classes.table, node)
ksu_hashtab_for_each(db->p_classes.table, node)
{
add_xperm_rule_raw(db, src, tgt,
(struct class_datum *)(node->datum),
@@ -456,7 +465,10 @@ static bool add_type_rule(struct policydb *db, const char *s, const char *t,
return true;
}
#ifdef KSU_SUPPORT_ADD_TYPE
// 5.9.0 : static inline int hashtab_insert(struct hashtab *h, void *key, void
// *datum, struct hashtab_key_params key_params) 5.8.0: int
// hashtab_insert(struct hashtab *h, void *k, void *d);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
static u32 filenametr_hash(const void *k)
{
const struct filename_trans_key *ft = k;
@@ -487,7 +499,6 @@ static int filenametr_cmp(const void *k1, const void *k2)
return v;
return strcmp(ft1->name, ft2->name);
}
static const struct hashtab_key_params filenametr_key_params = {
@@ -500,7 +511,6 @@ static bool add_filename_trans(struct policydb *db, const char *s,
const char *t, const char *c, const char *d,
const char *o)
{
#ifdef KSU_SUPPORT_ADD_TYPE
struct type_datum *src, *tgt, *def;
struct class_datum *cls;
@@ -525,14 +535,21 @@ static bool add_filename_trans(struct policydb *db, const char *s,
return false;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)
struct filename_trans_key key;
key.ttype = tgt->value;
key.tclass = cls->value;
key.name = (char *)o;
struct filename_trans_datum *last = NULL;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
struct filename_trans_datum *trans =
policydb_filenametr_search(db, &key);
#else
struct filename_trans_datum *trans =
hashtab_search(&db->filename_trans, &key);
#endif
while (trans) {
if (ebitmap_get_bit(&trans->stypes, src->value - 1)) {
// Duplicate, overwrite existing data and return
@@ -546,21 +563,53 @@ static bool add_filename_trans(struct policydb *db, const char *s,
}
if (trans == NULL) {
trans = (struct filename_trans_datum*) kcalloc(sizeof(*trans), 1, GFP_ATOMIC);
trans = (struct filename_trans_datum *)kcalloc(sizeof(*trans),
1, GFP_ATOMIC);
struct filename_trans_key *new_key =
(struct filename_trans_key*) kmalloc(sizeof(*new_key), GFP_ATOMIC);
(struct filename_trans_key *)kmalloc(sizeof(*new_key),
GFP_ATOMIC);
*new_key = key;
new_key->name = kstrdup(key.name, GFP_ATOMIC);
trans->next = last;
trans->otype = def->value;
hashtab_insert(&db->filename_trans, new_key,
trans, filenametr_key_params);
hashtab_insert(&db->filename_trans, new_key, trans,
filenametr_key_params);
}
db->compat_filename_trans_count++;
return ebitmap_set_bit(&trans->stypes, src->value - 1, 1) == 0;
#else
return false;
#else // < 5.7.0, has no filename_trans_key, but struct filename_trans
struct filename_trans key;
key.ttype = tgt->value;
key.tclass = cls->value;
key.name = (char *)o;
struct filename_trans_datum *trans =
hashtab_search(db->filename_trans, &key);
if (trans == NULL) {
trans = (struct filename_trans_datum *)kcalloc(sizeof(*trans),
1, GFP_ATOMIC);
if (!trans) {
pr_err("add_filename_trans: Failed to alloc datum");
return false;
}
struct filename_trans *new_key =
(struct filename_trans *)kmalloc(sizeof(*new_key),
GFP_ATOMIC);
if (!new_key) {
pr_err("add_filename_trans: Failed to alloc new_key");
return false;
}
*new_key = key;
new_key->name = kstrdup(key.name, GFP_ATOMIC);
trans->otype = def->value;
hashtab_insert(db->filename_trans, new_key, trans);
}
return ebitmap_set_bit(&db->filename_trans_ttypes, src->value - 1, 1) ==
0;
#endif
}
@@ -580,7 +629,7 @@ static bool add_type(struct policydb *db, const char *type_name, bool attr)
}
u32 value = ++db->p_types.nprim;
type = (struct type_datum *)kmalloc(sizeof(struct type_datum),
type = (struct type_datum *)kzalloc(sizeof(struct type_datum),
GFP_ATOMIC);
if (!type) {
pr_err("add_type: alloc type_datum failed.\n");
@@ -589,6 +638,7 @@ static bool add_type(struct policydb *db, const char *type_name, bool attr)
type->primary = 1;
type->value = value;
type->attribute = attr;
char *key = kstrdup(type_name, GFP_ATOMIC);
if (!key) {
@@ -601,6 +651,7 @@ static bool add_type(struct policydb *db, const char *type_name, bool attr)
return false;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
size_t new_size = sizeof(struct ebitmap) * db->p_types.nprim;
struct ebitmap *new_type_attr_map_array =
(krealloc(db->type_attr_map_array, new_size, GFP_ATOMIC));
@@ -642,10 +693,172 @@ static bool add_type(struct policydb *db, const char *type_name, bool attr)
int i;
for (i = 0; i < db->p_roles.nprim; ++i) {
ebitmap_set_bit(&db->role_val_to_struct[i]->types, value - 1,
0);
1);
}
return true;
#elif defined(CONFIG_IS_HW_HISI)
/*
* Huawei use type_attr_map and type_val_to_struct.
* And use ebitmap not flex_array.
*/
size_t new_size = sizeof(struct ebitmap) * db->p_types.nprim;
struct ebitmap *new_type_attr_map =
(krealloc(db->type_attr_map, new_size, GFP_ATOMIC));
struct type_datum **new_type_val_to_struct =
krealloc(db->type_val_to_struct,
sizeof(*db->type_val_to_struct) * db->p_types.nprim,
GFP_ATOMIC);
if (!new_type_attr_map) {
pr_err("add_type: alloc type_attr_map failed\n");
return false;
}
if (!new_type_val_to_struct) {
pr_err("add_type: alloc type_val_to_struct failed\n");
return false;
}
char **new_val_to_name_types =
krealloc(db->sym_val_to_name[SYM_TYPES],
sizeof(char *) * db->symtab[SYM_TYPES].nprim,
GFP_KERNEL);
if (!new_val_to_name_types) {
pr_err("add_type: alloc val_to_name failed\n");
return false;
}
db->type_attr_map = new_type_attr_map;
ebitmap_init(&db->type_attr_map[value - 1], HISI_SELINUX_EBITMAP_RO);
ebitmap_set_bit(&db->type_attr_map[value - 1], value - 1, 1);
db->type_val_to_struct = new_type_val_to_struct;
db->type_val_to_struct[value - 1] = type;
db->sym_val_to_name[SYM_TYPES] = new_val_to_name_types;
db->sym_val_to_name[SYM_TYPES][value - 1] = key;
int i;
for (i = 0; i < db->p_roles.nprim; ++i) {
ebitmap_set_bit(&db->role_val_to_struct[i]->types, value - 1,
1);
}
return true;
#else
// flex_array is not extensible, we need to create a new bigger one instead
struct flex_array *new_type_attr_map_array =
flex_array_alloc(sizeof(struct ebitmap), db->p_types.nprim,
GFP_ATOMIC | __GFP_ZERO);
struct flex_array *new_type_val_to_struct =
flex_array_alloc(sizeof(struct type_datum *), db->p_types.nprim,
GFP_ATOMIC | __GFP_ZERO);
struct flex_array *new_val_to_name_types =
flex_array_alloc(sizeof(char *), db->symtab[SYM_TYPES].nprim,
GFP_ATOMIC | __GFP_ZERO);
if (!new_type_attr_map_array) {
pr_err("add_type: alloc type_attr_map_array failed\n");
return false;
}
if (!new_type_val_to_struct) {
pr_err("add_type: alloc type_val_to_struct failed\n");
return false;
}
if (!new_val_to_name_types) {
pr_err("add_type: alloc val_to_name failed\n");
return false;
}
// preallocate so we don't have to worry about the put ever failing
if (flex_array_prealloc(new_type_attr_map_array, 0, db->p_types.nprim,
GFP_ATOMIC | __GFP_ZERO)) {
pr_err("add_type: prealloc type_attr_map_array failed\n");
return false;
}
if (flex_array_prealloc(new_type_val_to_struct, 0, db->p_types.nprim,
GFP_ATOMIC | __GFP_ZERO)) {
pr_err("add_type: prealloc type_val_to_struct_array failed\n");
return false;
}
if (flex_array_prealloc(new_val_to_name_types, 0,
db->symtab[SYM_TYPES].nprim,
GFP_ATOMIC | __GFP_ZERO)) {
pr_err("add_type: prealloc val_to_name_types failed\n");
return false;
}
int j;
void *old_elem;
// copy the old data or pointers to new flex arrays
for (j = 0; j < db->type_attr_map_array->total_nr_elements; j++) {
old_elem = flex_array_get(db->type_attr_map_array, j);
if (old_elem)
flex_array_put(new_type_attr_map_array, j, old_elem,
GFP_ATOMIC | __GFP_ZERO);
}
for (j = 0; j < db->type_val_to_struct_array->total_nr_elements; j++) {
old_elem = flex_array_get_ptr(db->type_val_to_struct_array, j);
if (old_elem)
flex_array_put_ptr(new_type_val_to_struct, j, old_elem,
GFP_ATOMIC | __GFP_ZERO);
}
for (j = 0; j < db->symtab[SYM_TYPES].nprim; j++) {
old_elem =
flex_array_get_ptr(db->sym_val_to_name[SYM_TYPES], j);
if (old_elem)
flex_array_put_ptr(new_val_to_name_types, j, old_elem,
GFP_ATOMIC | __GFP_ZERO);
}
// store the pointer of old flex arrays first, when assigning new ones we
// should free it
struct flex_array *old_fa;
old_fa = db->type_attr_map_array;
db->type_attr_map_array = new_type_attr_map_array;
if (old_fa) {
flex_array_free(old_fa);
}
ebitmap_init(flex_array_get(db->type_attr_map_array, value - 1));
ebitmap_set_bit(flex_array_get(db->type_attr_map_array, value - 1),
value - 1, 1);
old_fa = db->type_val_to_struct_array;
db->type_val_to_struct_array = new_type_val_to_struct;
if (old_fa) {
flex_array_free(old_fa);
}
flex_array_put_ptr(db->type_val_to_struct_array, value - 1, type,
GFP_ATOMIC | __GFP_ZERO);
old_fa = db->sym_val_to_name[SYM_TYPES];
db->sym_val_to_name[SYM_TYPES] = new_val_to_name_types;
if (old_fa) {
flex_array_free(old_fa);
}
flex_array_put_ptr(db->sym_val_to_name[SYM_TYPES], value - 1, key,
GFP_ATOMIC | __GFP_ZERO);
int i;
for (i = 0; i < db->p_roles.nprim; ++i) {
ebitmap_set_bit(&db->role_val_to_struct[i]->types, value - 1,
1);
}
return true;
#endif
#else
return false;
#endif
@@ -657,7 +870,7 @@ static bool set_type_state(struct policydb *db, const char *type_name,
struct type_datum *type;
if (type_name == NULL) {
struct hashtab_node *node;
hashtab_for_each(db->p_types.table, node)
ksu_hashtab_for_each(db->p_types.table, node)
{
type = (struct type_datum *)(node->datum);
if (ebitmap_set_bit(&db->permissive_map, type->value,
@@ -685,6 +898,12 @@ static void add_typeattribute_raw(struct policydb *db, struct type_datum *type,
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
struct ebitmap *sattr = &db->type_attr_map_array[type->value - 1];
#elif defined(CONFIG_IS_HW_HISI)
/*
* HISI_SELINUX_EBITMAP_RO is Huawei's unique features.
*/
struct ebitmap *sattr = &db->type_attr_map[type->value - 1],
HISI_SELINUX_EBITMAP_RO;
#else
struct ebitmap *sattr =
flex_array_get(db->type_attr_map_array, type->value - 1);
@@ -694,7 +913,7 @@ static void add_typeattribute_raw(struct policydb *db, struct type_datum *type,
struct hashtab_node *node;
struct constraint_node *n;
struct constraint_expr *e;
hashtab_for_each(db->p_classes.table, node)
ksu_hashtab_for_each(db->p_classes.table, node)
{
struct class_datum *cls = (struct class_datum *)(node->datum);
for (n = cls->constraints; n; n = n->next) {
@@ -842,4 +1061,4 @@ bool ksu_genfscon(struct policydb *db, const char *fs_name, const char *path,
const char *ctx)
{
return add_genfscon(db, fs_name, path, ctx);
}
}

View File

@@ -1,6 +1,5 @@
#! /bin/bash
set -x
#!/bin/sh
set -eux
GKI_ROOT=$(pwd)
@@ -11,24 +10,41 @@ if test -d "$GKI_ROOT/common/drivers"; then
elif test -d "$GKI_ROOT/drivers"; then
DRIVER_DIR="$GKI_ROOT/drivers"
else
echo "[ERROR] "drivers/" directory is not found."
echo "[+] You should modify this scrpit by yourself."
echo '[ERROR] "drivers/" directory is not found.'
echo '[+] You should modify this script by yourself.'
exit 127
fi
test -d "$GKI_ROOT/KernelSU" || git clone https://github.com/tiann/KernelSU
cd "$GKI_ROOT/KernelSU"
git stash && git pull
git stash
if [ "$(git status | grep -Po 'v\d+(\.\d+)*' | head -n1)" ]; then
git checkout main
fi
git pull
if [ -z "${1-}" ]; then
git checkout "$(git describe --abbrev=0 --tags)"
else
git checkout "$1"
fi
cd "$GKI_ROOT"
echo "[+] GKI_ROOT: $GKI_ROOT"
echo "[+] Copy kernel su driver to $DRIVER_DIR"
test -e "$DRIVER_DIR/kernelsu" || ln -sf "$GKI_ROOT/KernelSU/kernel" "$DRIVER_DIR/kernelsu"
cd "$DRIVER_DIR"
if test -d "$GKI_ROOT/common/drivers"; then
ln -sf "../../KernelSU/kernel" "kernelsu"
elif test -d "$GKI_ROOT/drivers"; then
ln -sf "../KernelSU/kernel" "kernelsu"
fi
cd "$GKI_ROOT"
echo "[+] Add kernel su driver to Makefile"
echo '[+] Add kernel su driver to Makefile'
DRIVER_MAKEFILE=$DRIVER_DIR/Makefile
grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_MAKEFILE
DRIVER_KCONFIG=$DRIVER_DIR/Kconfig
grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "obj-\$(CONFIG_KSU) += kernelsu/\n" >> "$DRIVER_MAKEFILE"
grep -q "kernelsu" "$DRIVER_KCONFIG" || sed -i "/endmenu/i\\source \"drivers/kernelsu/Kconfig\"" "$DRIVER_KCONFIG"
echo "[+] Done."
echo '[+] Done.'

View File

@@ -15,6 +15,8 @@
#include "allowlist.h"
#include "arch.h"
#include "klog.h" // IWYU pragma: keep
#include "ksud.h"
#include "kernel_compat.h"
#define SU_PATH "/system/bin/su"
#define SH_PATH "/system/bin/sh"
@@ -40,65 +42,58 @@ static char __user *sh_user_path(void)
int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
int *flags)
{
struct filename *filename;
const char su[] = SU_PATH;
if (!ksu_is_allow_uid(current_uid().val)) {
return 0;
}
filename = getname(*filename_user);
char path[sizeof(su)];
memset(path, 0, sizeof(path));
ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path));
if (IS_ERR(filename)) {
return 0;
}
if (!memcmp(filename->name, su, sizeof(su))) {
if (unlikely(!memcmp(path, su, sizeof(su)))) {
pr_info("faccessat su->sh!\n");
*filename_user = sh_user_path();
}
putname(filename);
return 0;
}
int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags)
{
// const char sh[] = SH_PATH;
struct filename *filename;
const char su[] = SU_PATH;
if (!ksu_is_allow_uid(current_uid().val)) {
return 0;
}
if (!filename_user) {
if (unlikely(!filename_user)) {
return 0;
}
filename = getname(*filename_user);
char path[sizeof(su)];
memset(path, 0, sizeof(path));
ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path));
if (IS_ERR(filename)) {
return 0;
}
if (!memcmp(filename->name, su, sizeof(su))) {
if (unlikely(!memcmp(path, su, sizeof(su)))) {
pr_info("newfstatat su->sh!\n");
*filename_user = sh_user_path();
}
putname(filename);
return 0;
}
// the call from execve_handler_pre won't provided correct value for __never_use_argument, use them after fix execve_handler_pre, keeping them for consistence for manually patched code
int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
void *argv, void *envp, int *flags)
void *__never_use_argv, void *__never_use_envp, int *__never_use_flags)
{
struct filename *filename;
const char sh[] = SH_PATH;
const char sh[] = KSUD_PATH;
const char su[] = SU_PATH;
if (!filename_ptr)
if (unlikely(!filename_ptr))
return 0;
filename = *filename_ptr;
@@ -106,16 +101,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;
}
@@ -127,16 +122,23 @@ static int faccessat_handler_pre(struct kprobe *p, struct pt_regs *regs)
int *dfd = (int *)PT_REGS_PARM1(regs);
const char __user **filename_user = (const char **)&PT_REGS_PARM2(regs);
int *mode = (int *)&PT_REGS_PARM3(regs);
int *flags = (int *)&PT_REGS_PARM4(regs);
// Both sys_ and do_ is C function
int *flags = (int *)&PT_REGS_CCALL_PARM4(regs);
return ksu_handle_faccessat(dfd, filename_user, mode, flags);
}
static int newfstatat_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
int *dfd = (int *)PT_REGS_PARM1(regs);
int *dfd = (int *)&PT_REGS_PARM1(regs);
const char __user **filename_user = (const char **)&PT_REGS_PARM2(regs);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
// static int vfs_statx(int dfd, const char __user *filename, int flags, struct kstat *stat, u32 request_mask)
int *flags = (int *)&PT_REGS_PARM3(regs);
#else
// int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,int flag)
int *flags = (int *)&PT_REGS_CCALL_PARM4(regs);
#endif
return ksu_handle_stat(dfd, filename_user, flags);
}
@@ -147,12 +149,8 @@ static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
int *fd = (int *)&PT_REGS_PARM1(regs);
struct filename **filename_ptr =
(struct filename **)&PT_REGS_PARM2(regs);
void *argv = (void *)&PT_REGS_PARM3(regs);
void *envp = (void *)&PT_REGS_PARM4(regs);
int *flags = (int *)&PT_REGS_PARM5(regs);
return ksu_handle_execveat_sucompat(fd, filename_ptr, argv, envp,
flags);
return ksu_handle_execveat_sucompat(fd, filename_ptr, NULL, NULL, NULL);
}
static struct kprobe faccessat_kp = {
@@ -165,18 +163,20 @@ static struct kprobe faccessat_kp = {
};
static struct kprobe newfstatat_kp = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
.symbol_name = "vfs_statx",
#else
.symbol_name = "vfs_fstatat",
#endif
.pre_handler = newfstatat_handler_pre,
};
static struct kprobe execve_kp = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
.symbol_name = "do_execveat_common",
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) && \
LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
.symbol_name = "__do_execve_file",
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) && \
LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
.symbol_name = "do_execveat_common",
#endif
.pre_handler = execve_handler_pre,

View File

@@ -12,6 +12,7 @@
#include "ksu.h"
#include "manager.h"
#include "uid_observer.h"
#include "kernel_compat.h"
#define SYSTEM_PACKAGES_LIST_PATH "/data/system/packages.list"
static struct work_struct ksu_update_uid_work;
@@ -28,7 +29,7 @@ static bool is_uid_exist(uid_t uid, void *data)
bool exist = false;
list_for_each_entry (np, list, list) {
if (np->uid == uid) {
if (np->uid == uid % 100000) {
exist = true;
break;
}
@@ -38,11 +39,11 @@ static bool is_uid_exist(uid_t uid, void *data)
static void do_update_uid(struct work_struct *work)
{
struct file *fp = filp_open(SYSTEM_PACKAGES_LIST_PATH, O_RDONLY, 0);
struct file *fp = ksu_filp_open_compat(SYSTEM_PACKAGES_LIST_PATH, O_RDONLY, 0);
if (IS_ERR(fp)) {
pr_err("do_update_uid, open " SYSTEM_PACKAGES_LIST_PATH
" failed: %d\n",
ERR_PTR(fp));
PTR_ERR(fp));
return;
}
@@ -54,13 +55,15 @@ static void do_update_uid(struct work_struct *work)
loff_t line_start = 0;
char buf[128];
for (;;) {
ssize_t count = kernel_read(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 = kernel_read(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);
@@ -95,7 +98,10 @@ static void do_update_uid(struct work_struct *work)
// first, check if manager_uid exist!
bool manager_exist = false;
list_for_each_entry (np, &uid_list, list) {
if (np->uid == ksu_get_manager_uid()) {
// if manager is installed in work profile, the uid in packages.list is still equals main profile
// don't delete it in this case!
int manager_uid = ksu_get_manager_uid() % 100000;
if (np->uid == manager_uid) {
manager_exist = true;
break;
}
@@ -131,4 +137,4 @@ int ksu_uid_observer_init()
int ksu_uid_observer_exit()
{
return 0;
}
}

View File

@@ -7,4 +7,4 @@ int ksu_uid_observer_exit();
void update_uid();
#endif
#endif

18
manager/.gitignore vendored
View File

@@ -1,17 +1,9 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
sign.properties
.idea
.DS_Store
build
captures
.cxx
key.jks

3
manager/.idea/.gitignore generated vendored
View File

@@ -1,3 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml

1
manager/.idea/.name generated
View File

@@ -1 +0,0 @@
KernelSU

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="11" />
</component>
</project>

View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="Embedded JDK" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

View File

@@ -1,37 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PreviewAnnotationInFunctionWithParameters" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
</profile>
</component>

10
manager/.idea/misc.xml generated
View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

6
manager/.idea/vcs.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

View File

@@ -1,37 +1,52 @@
import com.android.build.gradle.internal.api.BaseVariantOutputImpl
plugins {
id("com.android.application")
id("com.google.devtools.ksp")
kotlin("android")
alias(libs.plugins.agp.app)
alias(libs.plugins.kotlin)
alias(libs.plugins.ksp)
alias(libs.plugins.lsplugin.apksign)
id("kotlin-parcelize")
}
val managerVersionCode: Int by rootProject.extra
val managerVersionName: String by rootProject.extra
apksign {
storeFileProperty = "KEYSTORE_FILE"
storePasswordProperty = "KEYSTORE_PASSWORD"
keyAliasProperty = "KEY_ALIAS"
keyPasswordProperty = "KEY_PASSWORD"
}
android {
namespace = "me.weishu.kernelsu"
ndkVersion = "25.1.8937393"
defaultConfig {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
ndk {
abiFilters += listOf("arm64-v8a", "x86_64")
buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
lint {
checkReleaseBuilds = false
}
buildFeatures {
aidl = true
buildConfig = true
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.3.2"
kotlinOptions {
jvmTarget = "17"
}
packagingOptions {
composeOptions {
kotlinCompilerExtensionVersion = "1.4.3"
}
packaging {
jniLibs {
useLegacyPackaging = true
}
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
@@ -39,15 +54,14 @@ android {
externalNativeBuild {
cmake {
path(file("src/main/cpp/CMakeLists.txt"))
version = "3.18.1"
path("src/main/cpp/CMakeLists.txt")
}
}
applicationVariants.all {
outputs.forEach {
val output = it as BaseVariantOutputImpl
output.outputFileName = "KernelSU_$versionName-${buildType.name}.apk"
output.outputFileName = "KernelSU_${managerVersionName}_${managerVersionCode}-$name.apk"
}
kotlin.sourceSets {
@@ -59,35 +73,42 @@ android {
}
dependencies {
val accompanistVersion = "0.28.0"
val composeDestinationsVersion = "1.7.27-beta"
implementation(platform("androidx.compose:compose-bom:2022.12.00"))
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.navigation.compose)
debugImplementation("androidx.compose.ui:ui-test-manifest")
debugImplementation("androidx.compose.ui:ui-tooling")
implementation("androidx.activity:activity-compose:1.6.1")
implementation("androidx.compose.material:material-icons-extended")
implementation("androidx.compose.material3:material3")
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1")
implementation("androidx.navigation:navigation-compose:2.5.3")
implementation("com.google.accompanist:accompanist-drawablepainter:$accompanistVersion")
implementation("com.google.accompanist:accompanist-navigation-animation:$accompanistVersion")
implementation("com.google.accompanist:accompanist-swiperefresh:$accompanistVersion")
implementation("com.google.accompanist:accompanist-systemuicontroller:$accompanistVersion")
implementation("io.github.raamcosta.compose-destinations:animations-core:$composeDestinationsVersion")
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.compose.material.icons.extended)
implementation(libs.androidx.compose.material)
implementation(libs.androidx.compose.material3)
implementation(libs.androidx.compose.ui)
implementation(libs.androidx.compose.ui.tooling.preview)
implementation("io.coil-kt:coil-compose:2.2.2")
implementation("me.zhanghai.android.appiconloader:appiconloader-coil:1.5.0")
debugImplementation(libs.androidx.compose.ui.test.manifest)
debugImplementation(libs.androidx.compose.ui.tooling)
implementation("com.github.topjohnwu.libsu:core:5.0.3")
implementation("com.github.alorma:compose-settings-ui-m3:0.15.0")
implementation(libs.androidx.lifecycle.runtime.compose)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.lifecycle.viewmodel.compose)
ksp("io.github.raamcosta.compose-destinations:ksp:$composeDestinationsVersion")
implementation(libs.com.google.accompanist.drawablepainter)
implementation(libs.com.google.accompanist.navigation.animation)
implementation(libs.com.google.accompanist.systemuicontroller)
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.4")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
implementation(libs.compose.destinations.animations.core)
ksp(libs.compose.destinations.ksp)
implementation(libs.com.github.topjohnwu.libsu.core)
implementation(libs.com.github.topjohnwu.libsu.service)
implementation(libs.dev.rikka.rikkax.parcelablelist)
implementation(libs.io.coil.kt.coil.compose)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.me.zhanghai.android.appiconloader.coil)
implementation(libs.sheet.compose.dialogs.core)
implementation(libs.sheet.compose.dialogs.list)
implementation(libs.sheet.compose.dialogs.input)
}

View File

@@ -1,21 +1,9 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-dontwarn org.bouncycastle.jsse.BCSSLParameters
-dontwarn org.bouncycastle.jsse.BCSSLSocket
-dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
-dontwarn org.conscrypt.Conscrypt$Version
-dontwarn org.conscrypt.Conscrypt
-dontwarn org.conscrypt.ConscryptHostnameVerifier
-dontwarn org.openjsse.javax.net.ssl.SSLParameters
-dontwarn org.openjsse.javax.net.ssl.SSLSocket
-dontwarn org.openjsse.net.ssl.OpenJSSE

View File

@@ -1,24 +0,0 @@
package me.weishu.kernelsu
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("me.weishu.kernelsu", appContext.packageName)
}
}

View File

@@ -2,22 +2,19 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name=".KernelSUApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:enableOnBackInvokedCallback="true"
android:extractNativeLibs="true"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.KernelSU"
tools:targetApi="31">
tools:targetApi="33">
<activity
android:name=".ui.MainActivity"
android:exported="true"
@@ -32,6 +29,16 @@
android:name="android.app.lib_name"
android:value="" />
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
</application>
</manifest>

View File

@@ -0,0 +1,9 @@
// IKsuInterface.aidl
package me.weishu.kernelsu;
import android.content.pm.PackageInfo;
import rikka.parcelablelist.ParcelableListSlice;
interface IKsuInterface {
ParcelableListSlice<PackageInfo> getPackages(int flags);
}

View File

@@ -3,15 +3,16 @@
#include <sys/prctl.h>
#include <android/log.h>
#include <cstring>
#include "ksu.h"
#define LOG_TAG "KernelSu"
#define LOG_TAG "KernelSU"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_becomeManager(JNIEnv *env, jclass clazz, jstring pkg) {
Java_me_weishu_kernelsu_Natives_becomeManager(JNIEnv *env, jobject, jstring pkg) {
auto cpkg = env->GetStringUTFChars(pkg, nullptr);
auto result = become_manager(cpkg);
env->ReleaseStringUTFChars(pkg, cpkg);
@@ -20,13 +21,13 @@ Java_me_weishu_kernelsu_Natives_becomeManager(JNIEnv *env, jclass clazz, jstring
extern "C"
JNIEXPORT jint JNICALL
Java_me_weishu_kernelsu_Natives_getVersion(JNIEnv *env, jclass clazz) {
Java_me_weishu_kernelsu_Natives_getVersion(JNIEnv *env, jobject) {
return get_version();
}
extern "C"
JNIEXPORT jintArray JNICALL
Java_me_weishu_kernelsu_Natives_getAllowList(JNIEnv *env, jclass clazz) {
Java_me_weishu_kernelsu_Natives_getAllowList(JNIEnv *env, jobject) {
int uids[1024];
int size = 0;
bool result = get_allow_list(uids, &size);
@@ -40,24 +41,259 @@ Java_me_weishu_kernelsu_Natives_getAllowList(JNIEnv *env, jclass clazz) {
}
extern "C"
JNIEXPORT jintArray JNICALL
Java_me_weishu_kernelsu_Natives_getDenyList(JNIEnv *env, jclass clazz) {
int uids[1024];
int size = 0;
bool result = get_deny_list(uids, &size);
if (result) {
// success!
auto array = env->NewIntArray(size);
env->SetIntArrayRegion(array, 0, size, uids);
return array;
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_isSafeMode(JNIEnv *env, jclass clazz) {
return is_safe_mode();
}
static void fillIntArray(JNIEnv *env, jobject list, int *data, int count) {
auto cls = env->GetObjectClass(list);
auto add = env->GetMethodID(cls, "add", "(Ljava/lang/Object;)Z");
auto integerCls = env->FindClass("java/lang/Integer");
auto constructor = env->GetMethodID(integerCls, "<init>", "(I)V");
for (int i = 0; i < count; ++i) {
auto integer = env->NewObject(integerCls, constructor, data[i]);
env->CallBooleanMethod(list, add, integer);
}
return env->NewIntArray(0);
}
static void addIntToList(JNIEnv *env, jobject list, int ele) {
auto cls = env->GetObjectClass(list);
auto add = env->GetMethodID(cls, "add", "(Ljava/lang/Object;)Z");
auto integerCls = env->FindClass("java/lang/Integer");
auto constructor = env->GetMethodID(integerCls, "<init>", "(I)V");
auto integer = env->NewObject(integerCls, constructor, ele);
env->CallBooleanMethod(list, add, integer);
}
static uint64_t capListToBits(JNIEnv *env, jobject list) {
auto cls = env->GetObjectClass(list);
auto get = env->GetMethodID(cls, "get", "(I)Ljava/lang/Object;");
auto size = env->GetMethodID(cls, "size", "()I");
auto listSize = env->CallIntMethod(list, size);
auto integerCls = env->FindClass("java/lang/Integer");
auto intValue = env->GetMethodID(integerCls, "intValue", "()I");
uint64_t result = 0;
for (int i = 0; i < listSize; ++i) {
auto integer = env->CallObjectMethod(list, get, i);
int data = env->CallIntMethod(integer, intValue);
if (cap_valid(data)) {
result |= (1ULL << data);
}
}
return result;
}
static int getListSize(JNIEnv *env, jobject list) {
auto cls = env->GetObjectClass(list);
auto size = env->GetMethodID(cls, "size", "()I");
return env->CallIntMethod(list, size);
}
static void fillArrayWithList(JNIEnv *env, jobject list, int *data, int count) {
auto cls = env->GetObjectClass(list);
auto get = env->GetMethodID(cls, "get", "(I)Ljava/lang/Object;");
auto integerCls = env->FindClass("java/lang/Integer");
auto intValue = env->GetMethodID(integerCls, "intValue", "()I");
for (int i = 0; i < count; ++i) {
auto integer = env->CallObjectMethod(list, get, i);
data[i] = env->CallIntMethod(integer, intValue);
}
}
extern "C"
JNIEXPORT jobject JNICALL
Java_me_weishu_kernelsu_Natives_getAppProfile(JNIEnv *env, jobject, jstring pkg, jint uid) {
if (env->GetStringLength(pkg) > KSU_MAX_PACKAGE_NAME) {
return nullptr;
}
p_key_t key = {};
auto cpkg = env->GetStringUTFChars(pkg, nullptr);
strcpy(key, cpkg);
env->ReleaseStringUTFChars(pkg, cpkg);
app_profile profile = {};
profile.version = KSU_APP_PROFILE_VER;
strcpy(profile.key, key);
profile.current_uid = uid;
bool useDefaultProfile = !get_app_profile(key, &profile);
auto cls = env->FindClass("me/weishu/kernelsu/Natives$Profile");
auto constructor = env->GetMethodID(cls, "<init>", "()V");
auto obj = env->NewObject(cls, constructor);
auto keyField = env->GetFieldID(cls, "name", "Ljava/lang/String;");
auto currentUidField = env->GetFieldID(cls, "currentUid", "I");
auto allowSuField = env->GetFieldID(cls, "allowSu", "Z");
auto rootUseDefaultField = env->GetFieldID(cls, "rootUseDefault", "Z");
auto rootTemplateField = env->GetFieldID(cls, "rootTemplate", "Ljava/lang/String;");
auto uidField = env->GetFieldID(cls, "uid", "I");
auto gidField = env->GetFieldID(cls, "gid", "I");
auto groupsField = env->GetFieldID(cls, "groups", "Ljava/util/List;");
auto capabilitiesField = env->GetFieldID(cls, "capabilities", "Ljava/util/List;");
auto domainField = env->GetFieldID(cls, "context", "Ljava/lang/String;");
auto namespacesField = env->GetFieldID(cls, "namespace", "I");
auto nonRootUseDefaultField = env->GetFieldID(cls, "nonRootUseDefault", "Z");
auto umountModulesField = env->GetFieldID(cls, "umountModules", "Z");
env->SetObjectField(obj, keyField, env->NewStringUTF(profile.key));
env->SetIntField(obj, currentUidField, profile.current_uid);
if (useDefaultProfile) {
// no profile found, so just use default profile:
// don't allow root and use default profile!
LOGD("use default profile for: %s, %d", key, uid);
// allow_su = false
// non root use default = true
env->SetBooleanField(obj, allowSuField, false);
env->SetBooleanField(obj, nonRootUseDefaultField, true);
jobject capList = env->GetObjectField(obj, capabilitiesField);
int DEFAULT_CAPS[] = {CAP_DAC_READ_SEARCH};
for (auto i: DEFAULT_CAPS) {
addIntToList(env, capList, i);
}
return obj;
}
auto allowSu = profile.allow_su;
if (allowSu) {
env->SetBooleanField(obj, rootUseDefaultField, (jboolean) profile.rp_config.use_default);
if (strlen(profile.rp_config.template_name) > 0) {
env->SetObjectField(obj, rootTemplateField,
env->NewStringUTF(profile.rp_config.template_name));
}
env->SetIntField(obj, uidField, profile.rp_config.profile.uid);
env->SetIntField(obj, gidField, profile.rp_config.profile.gid);
jobject groupList = env->GetObjectField(obj, groupsField);
int groupCount = profile.rp_config.profile.groups_count;
if (groupCount > KSU_MAX_GROUPS) {
LOGD("kernel group count too large: %d???", groupCount);
groupCount = KSU_MAX_GROUPS;
}
fillIntArray(env, groupList, profile.rp_config.profile.groups, groupCount);
jobject capList = env->GetObjectField(obj, capabilitiesField);
for (int i = 0; i <= CAP_LAST_CAP; i++) {
if (profile.rp_config.profile.capabilities.effective & (1ULL << i)) {
addIntToList(env, capList, i);
}
}
env->SetObjectField(obj, domainField,
env->NewStringUTF(profile.rp_config.profile.selinux_domain));
env->SetIntField(obj, namespacesField, profile.rp_config.profile.namespaces);
env->SetBooleanField(obj, allowSuField, profile.allow_su);
} else {
env->SetBooleanField(obj, nonRootUseDefaultField,
(jboolean) profile.nrp_config.use_default);
env->SetBooleanField(obj, umountModulesField, profile.nrp_config.profile.umount_modules);
}
return obj;
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_allowRoot(JNIEnv *env, jclass clazz, jint uid, jboolean allow) {
return allow_su(uid, allow);
Java_me_weishu_kernelsu_Natives_setAppProfile(JNIEnv *env, jobject clazz, jobject profile) {
auto cls = env->FindClass("me/weishu/kernelsu/Natives$Profile");
auto keyField = env->GetFieldID(cls, "name", "Ljava/lang/String;");
auto currentUidField = env->GetFieldID(cls, "currentUid", "I");
auto allowSuField = env->GetFieldID(cls, "allowSu", "Z");
auto rootUseDefaultField = env->GetFieldID(cls, "rootUseDefault", "Z");
auto rootTemplateField = env->GetFieldID(cls, "rootTemplate", "Ljava/lang/String;");
auto uidField = env->GetFieldID(cls, "uid", "I");
auto gidField = env->GetFieldID(cls, "gid", "I");
auto groupsField = env->GetFieldID(cls, "groups", "Ljava/util/List;");
auto capabilitiesField = env->GetFieldID(cls, "capabilities", "Ljava/util/List;");
auto domainField = env->GetFieldID(cls, "context", "Ljava/lang/String;");
auto namespacesField = env->GetFieldID(cls, "namespace", "I");
auto nonRootUseDefaultField = env->GetFieldID(cls, "nonRootUseDefault", "Z");
auto umountModulesField = env->GetFieldID(cls, "umountModules", "Z");
auto key = env->GetObjectField(profile, keyField);
if (!key) {
return false;
}
if (env->GetStringLength((jstring) key) > KSU_MAX_PACKAGE_NAME) {
return false;
}
auto cpkg = env->GetStringUTFChars((jstring) key, nullptr);
p_key_t p_key = {};
strcpy(p_key, cpkg);
env->ReleaseStringUTFChars((jstring) key, cpkg);
auto currentUid = env->GetIntField(profile, currentUidField);
auto uid = env->GetIntField(profile, uidField);
auto gid = env->GetIntField(profile, gidField);
auto groups = env->GetObjectField(profile, groupsField);
auto capabilities = env->GetObjectField(profile, capabilitiesField);
auto domain = env->GetObjectField(profile, domainField);
auto allowSu = env->GetBooleanField(profile, allowSuField);
auto umountModules = env->GetBooleanField(profile, umountModulesField);
app_profile p = {};
p.version = KSU_APP_PROFILE_VER;
strcpy(p.key, p_key);
p.allow_su = allowSu;
p.current_uid = currentUid;
if (allowSu) {
p.rp_config.use_default = env->GetBooleanField(profile, rootUseDefaultField);
auto templateName = env->GetObjectField(profile, rootTemplateField);
if (templateName) {
auto ctemplateName = env->GetStringUTFChars((jstring) templateName, nullptr);
strcpy(p.rp_config.template_name, ctemplateName);
env->ReleaseStringUTFChars((jstring) templateName, ctemplateName);
}
p.rp_config.profile.uid = uid;
p.rp_config.profile.gid = gid;
int groups_count = getListSize(env, groups);
if (groups_count > KSU_MAX_GROUPS) {
LOGD("groups count too large: %d", groups_count);
return false;
}
p.rp_config.profile.groups_count = groups_count;
fillArrayWithList(env, groups, p.rp_config.profile.groups, groups_count);
p.rp_config.profile.capabilities.effective = capListToBits(env, capabilities);
auto cdomain = env->GetStringUTFChars((jstring) domain, nullptr);
strcpy(p.rp_config.profile.selinux_domain, cdomain);
env->ReleaseStringUTFChars((jstring) domain, cdomain);
p.rp_config.profile.namespaces = env->GetIntField(profile, namespacesField);
} else {
p.nrp_config.use_default = env->GetBooleanField(profile, nonRootUseDefaultField);
p.nrp_config.profile.umount_modules = umountModules;
}
return set_app_profile(&p);
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_uidShouldUmount(JNIEnv *env, jobject thiz, jint uid) {
return uid_should_umount(uid);
}

View File

@@ -6,6 +6,7 @@
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "ksu.h"
@@ -17,8 +18,15 @@
#define CMD_GET_VERSION 2
#define CMD_ALLOW_SU 3
#define CMD_DENY_SU 4
#define CMD_GET_ALLOW_LIST 5
#define CMD_GET_SU_LIST 5
#define CMD_GET_DENY_LIST 6
#define CMD_CHECK_SAFEMODE 9
#define CMD_GET_APP_PROFILE 10
#define CMD_SET_APP_PROFILE 11
#define CMD_IS_UID_GRANTED_ROOT 12
#define CMD_IS_UID_SHOULD_UMOUNT 13
static bool ksuctl(int cmd, void* arg1, void* arg2) {
int32_t result = 0;
@@ -28,7 +36,14 @@ static bool ksuctl(int cmd, void* arg1, void* arg2) {
bool become_manager(const char* pkg) {
char param[128];
sprintf(param, "/data/data/%s", pkg);
uid_t uid = getuid();
uint32_t userId = uid / 100000;
if (userId == 0) {
sprintf(param, "/data/data/%s", pkg);
} else {
snprintf(param, sizeof(param), "/data/user/%d/%s", userId, pkg);
}
return ksuctl(CMD_BECOME_MANAGER, param, nullptr);
}
@@ -40,15 +55,23 @@ int get_version() {
return version;
}
bool allow_su(int uid, bool allow) {
int cmd = allow ? CMD_ALLOW_SU : CMD_DENY_SU;
return ksuctl(cmd, (void*) uid, nullptr);
}
bool get_allow_list(int *uids, int *size) {
return ksuctl(CMD_GET_ALLOW_LIST, uids, size);
return ksuctl(CMD_GET_SU_LIST, uids, size);
}
bool get_deny_list(int *uids, int *size) {
return ksuctl(CMD_GET_DENY_LIST, uids, size);
}
bool is_safe_mode() {
return ksuctl(CMD_CHECK_SAFEMODE, nullptr, nullptr);
}
bool uid_should_umount(int uid) {
bool should;
return ksuctl(CMD_IS_UID_SHOULD_UMOUNT, reinterpret_cast<void*>(uid), &should) && should;
}
bool set_app_profile(const app_profile *profile) {
return ksuctl(CMD_SET_APP_PROFILE, (void*) profile, nullptr);
}
bool get_app_profile(p_key_t key, app_profile *profile) {
return ksuctl(CMD_GET_APP_PROFILE, (void*) profile, nullptr);
}

View File

@@ -5,14 +5,76 @@
#ifndef KERNELSU_KSU_H
#define KERNELSU_KSU_H
bool become_manager(const char*);
#include <linux/capability.h>
bool become_manager(const char *);
int get_version();
bool allow_su(int uid, bool allow);
bool get_allow_list(int *uids, int *size);
bool get_deny_list(int *uids, int *size);
bool uid_should_umount(int uid);
bool is_safe_mode();
#define KSU_APP_PROFILE_VER 2
#define KSU_MAX_PACKAGE_NAME 256
// NGROUPS_MAX for Linux is 65535 generally, but we only supports 32 groups.
#define KSU_MAX_GROUPS 32
#define KSU_SELINUX_DOMAIN 64
using p_key_t = char[KSU_MAX_PACKAGE_NAME];
struct root_profile {
int32_t uid;
int32_t gid;
int32_t groups_count;
int32_t groups[KSU_MAX_GROUPS];
// kernel_cap_t is u32[2] for capabilities v3
struct {
uint64_t effective;
uint64_t permitted;
uint64_t inheritable;
} capabilities;
char selinux_domain[KSU_SELINUX_DOMAIN];
int32_t namespaces;
};
struct non_root_profile {
bool umount_modules;
};
struct app_profile {
// It may be utilized for backward compatibility, although we have never explicitly made any promises regarding this.
uint32_t version;
// this is usually the package of the app, but can be other value for special apps
char key[KSU_MAX_PACKAGE_NAME];
int32_t current_uid;
bool allow_su;
union {
struct {
bool use_default;
char template_name[KSU_MAX_PACKAGE_NAME];
struct root_profile profile;
} rp_config;
struct {
bool use_default;
struct non_root_profile profile;
} nrp_config;
};
};
bool set_app_profile(const app_profile *profile);
bool get_app_profile(p_key_t key, app_profile *profile);
#endif //KERNELSU_KSU_H

View File

@@ -1,24 +0,0 @@
package me.weishu.kernelsu;
/**
* @author weishu
* @date 2022/12/8.
*/
public final class Natives {
static {
System.loadLibrary("kernelsu");
}
// become root manager, return true if success.
public static native boolean becomeManager(String pkg);
public static native int getVersion();
// get the uid list of allowed su processes.
public static native int[] getAllowList();
public static native int[] getDenyList();
public static native boolean allowRoot(int uid, boolean allow);
}

View File

@@ -0,0 +1,107 @@
package me.weishu.kernelsu
import android.os.Parcelable
import androidx.annotation.Keep
import androidx.compose.runtime.Immutable
import kotlinx.parcelize.Parcelize
/**
* @author weishu
* @date 2022/12/8.
*/
object Natives {
// minimal supported kernel version
// 10915: allowlist breaking change, add app profile
// 10931: app profile struct add 'version' field
// 10946: add capabilities
// 10977: change groups_count and groups to avoid overflow write
// 11071: Fix the issue of failing to set a custom SELinux type.
const val MINIMAL_SUPPORTED_KERNEL = 11071
init {
System.loadLibrary("kernelsu")
}
// become root manager, return true if success.
external fun becomeManager(pkg: String?): Boolean
val version: Int
external get
// get the uid list of allowed su processes.
val allowList: IntArray
external get
val isSafeMode: Boolean
external get
external fun uidShouldUmount(uid: Int): Boolean
/**
* Get the profile of the given package.
* @param key usually the package name
* @return return null if failed.
*/
external fun getAppProfile(key: String?, uid: Int): Profile
external fun setAppProfile(profile: Profile?): Boolean
private const val NON_ROOT_DEFAULT_PROFILE_KEY = "$"
private const val ROOT_DEFAULT_PROFILE_KEY = "#"
private const val NOBODY_UID = 9999
fun setDefaultUmountModules(umountModules: Boolean): Boolean {
Profile(
NON_ROOT_DEFAULT_PROFILE_KEY,
NOBODY_UID,
false,
umountModules = umountModules
).let {
return setAppProfile(it)
}
}
fun isDefaultUmountModules(): Boolean {
getAppProfile(NON_ROOT_DEFAULT_PROFILE_KEY, NOBODY_UID).let {
return it.umountModules
}
}
fun requireNewKernel(): Boolean {
return version < MINIMAL_SUPPORTED_KERNEL
}
@Immutable
@Parcelize
@Keep
data class Profile(
// and there is a default profile for root and non-root
val name: String,
// current uid for the package, this is convivent for kernel to check
// if the package name doesn't match uid, then it should be invalidated.
val currentUid: Int = 0,
// if this is true, kernel will grant root permission to this package
val allowSu: Boolean = false,
// these are used for root profile
val rootUseDefault: Boolean = true,
val rootTemplate: String? = null,
val uid: Int = 0,
val gid: Int = 0,
val groups: List<Int> = mutableListOf(),
val capabilities: List<Int> = mutableListOf(),
val context: String = "u:r:su:s0",
val namespace: Int = Namespace.Inherited.ordinal,
val nonRootUseDefault: Boolean = true,
val umountModules: Boolean = true,
var rules: String = "", // this field is save in ksud!!
) : Parcelable {
enum class Namespace {
Inherited,
Global,
Individual,
}
constructor() : this("")
}
}

View File

@@ -0,0 +1,49 @@
package me.weishu.kernelsu.profile
/**
* @author weishu
* @date 2023/6/3.
*/
enum class Capabilities(val cap: Int, val display: String, val desc: String) {
CAP_CHOWN(0, "CHOWN", "Make arbitrary changes to file UIDs and GIDs (see chown(2))"),
CAP_DAC_OVERRIDE(1, "DAC_OVERRIDE", "Bypass file read, write, and execute permission checks"),
CAP_DAC_READ_SEARCH(2, "DAC_READ_SEARCH", "Bypass file read permission checks and directory read and execute permission checks"),
CAP_FOWNER(3, "FOWNER", "Bypass permission checks on operations that normally require the filesystem UID of the process to match the UID of the file (e.g., chmod(2), utime(2)), excluding those operations covered by CAP_DAC_OVERRIDE and CAP_DAC_READ_SEARCH"),
CAP_FSETID(4, "FSETID", "Dont clear set-user-ID and set-group-ID permission bits when a file is modified; set the set-group-ID bit for a file whose GID does not match the filesystem or any of the supplementary GIDs of the calling process"),
CAP_KILL(5, "KILL", "Bypass permission checks for sending signals (see kill(2))."),
CAP_SETGID(6, "SETGID", "Make arbitrary manipulations of process GIDs and supplementary GID list; allow setgid(2) manipulation of the callers effective and real group IDs"),
CAP_SETUID(7, "SETUID", "Make arbitrary manipulations of process UIDs (setuid(2), setreuid(2), setresuid(2), setfsuid(2)); allow changing the current process user IDs; allow changing of the current process group ID to any value in the systems range of legal group IDs"),
CAP_SETPCAP(8, "SETPCAP", "If file capabilities are supported: grant or remove any capability in the callers permitted capability set to or from any other process. (This property supersedes the obsolete notion of giving a process all capabilities by granting all capabilities in its permitted set, and of removing all capabilities from a process by granting no capabilities in its permitted set. It does not permit any actions that were not permitted before.)"),
CAP_LINUX_IMMUTABLE(9, "LINUX_IMMUTABLE", "Set the FS_APPEND_FL and FS_IMMUTABLE_FL inode flags (see chattr(1))."),
CAP_NET_BIND_SERVICE(10, "NET_BIND_SERVICE", "Bind a socket to Internet domain"),
CAP_NET_BROADCAST(11, "NET_BROADCAST", "Make socket broadcasts, and listen to multicasts"),
CAP_NET_ADMIN(12, "NET_ADMIN", "Perform various network-related operations: interface configuration, administration of IP firewall, masquerading, and accounting, modify routing tables, bind to any address for transparent proxying, set type-of-service (TOS), clear driver statistics, set promiscuous mode, enabling multicasting, use setsockopt(2) to set the following socket options: SO_DEBUG, SO_MARK, SO_PRIORITY (for a priority outside the range 0 to 6), SO_RCVBUFFORCE, and SO_SNDBUFFORCE"),
CAP_NET_RAW(13, "NET_RAW", "Use RAW and PACKET sockets"),
CAP_IPC_LOCK(14, "IPC_LOCK", "Lock memory (mlock(2), mlockall(2), mmap(2), shmctl(2))"),
CAP_IPC_OWNER(15, "IPC_OWNER", "Bypass permission checks for operations on System V IPC objects"),
CAP_SYS_MODULE(16, "SYS_MODULE", "Load and unload kernel modules (see init_module(2) and delete_module(2)); in kernels before 2.6.25, this also granted rights for various other operations related to kernel modules"),
CAP_SYS_RAWIO(17, "SYS_RAWIO", "Perform I/O port operations (iopl(2) and ioperm(2)); access /proc/kcore"),
CAP_SYS_CHROOT(18, "SYS_CHROOT", "Use chroot(2)"),
CAP_SYS_PTRACE(19, "SYS_PTRACE", "Trace arbitrary processes using ptrace(2)"),
CAP_SYS_PACCT(20, "SYS_PACCT", "Use acct(2)"),
CAP_SYS_ADMIN(21, "SYS_ADMIN", "Perform a range of system administration operations including: quotactl(2), mount(2), umount(2), swapon(2), swapoff(2), sethostname(2), and setdomainname(2); set and modify process resource limits (setrlimit(2)); perform various network-related operations (e.g., setting privileged socket options, enabling multicasting, interface configuration); perform various IPC operations (e.g., SysV semaphores, POSIX message queues, System V shared memory); allow reboot and kexec_load(2); override /proc/sys kernel tunables; perform ptrace(2) PTRACE_SECCOMP_GET_FILTER operation; perform some tracing and debugging operations (see ptrace(2)); administer the lifetime of kernel tracepoints (tracefs(5)); perform the KEYCTL_CHOWN and KEYCTL_SETPERM keyctl(2) operations; perform the following keyctl(2) operations: KEYCTL_CAPABILITIES, KEYCTL_CAPSQUASH, and KEYCTL_PKEY_ OPERATIONS; set state for the Extensible Authentication Protocol (EAP) kernel module; and override the RLIMIT_NPROC resource limit; allow ioperm/iopl access to I/O ports"),
CAP_SYS_BOOT(22, "SYS_BOOT", "Use reboot(2) and kexec_load(2), reboot and load a new kernel for later execution"),
CAP_SYS_NICE(23, "SYS_NICE", "Raise process nice value (nice(2), setpriority(2)) and change the nice value for arbitrary processes; set real-time scheduling policies for calling process, and set scheduling policies and priorities for arbitrary processes (sched_setscheduler(2), sched_setparam(2)"),
CAP_SYS_RESOURCE(24, "SYS_RESOURCE", "Override resource Limits. Set resource limits (setrlimit(2), prlimit(2)), override quota limits (quota(2), quotactl(2)), override reserved space on ext2 filesystem (ext2_ioctl(2)), override size restrictions on IPC message queues (msg(2)) and system V shared memory segments (shmget(2)), and override the /proc/sys/fs/pipe-size-max limit"),
CAP_SYS_TIME(25, "SYS_TIME", "Set system clock (settimeofday(2), stime(2), adjtimex(2)); set real-time (hardware) clock"),
CAP_SYS_TTY_CONFIG(26, "SYS_TTY_CONFIG", "Use vhangup(2); employ various privileged ioctl(2) operations on virtual terminals"),
CAP_MKNOD(27, "MKNOD", "Create special files using mknod(2)"),
CAP_LEASE(28, "LEASE", "Establish leases on arbitrary files (see fcntl(2))"),
CAP_AUDIT_WRITE(29, "AUDIT_WRITE", "Write records to kernel auditing log"),
CAP_AUDIT_CONTROL(30, "AUDIT_CONTROL", "Enable and disable kernel auditing; change auditing filter rules; retrieve auditing status and filtering rules"),
CAP_SETFCAP(31, "SETFCAP", "If file capabilities are supported: grant or remove any capability in any capability set to any file"),
CAP_MAC_OVERRIDE(32, "MAC_OVERRIDE", "Override Mandatory Access Control (MAC). Implemented for the Smack Linux Security Module (LSM)"),
CAP_MAC_ADMIN(33, "MAC_ADMIN", "Allow MAC configuration or state changes. Implemented for the Smack LSM"),
CAP_SYSLOG(34, "SYSLOG", "Perform privileged syslog(2) operations. See syslog(2) for information on which operations require privilege"),
CAP_WAKE_ALARM(35, "WAKE_ALARM", "Trigger something that will wake up the system"),
CAP_BLOCK_SUSPEND(36, "BLOCK_SUSPEND", "Employ features that can block system suspend"),
CAP_AUDIT_READ(37, "AUDIT_READ", "Allow reading the audit log via a multicast netlink socket"),
CAP_PERFMON(38, "PERFMON", "Allow performance monitoring via perf_event_open(2)"),
CAP_BPF(39, "BPF", "Allow BPF operations via bpf(2)"),
CAP_CHECKPOINT_RESTORE(40, "CHECKPOINT_RESTORE", "Allow processes to be checkpointed via checkpoint/restore in user namespace(2)"),
}

View File

@@ -0,0 +1,87 @@
package me.weishu.kernelsu.profile
/**
* @author weishu
* @date 2023/6/3.
*/
enum class Groups(val gid: Int, val display: String, val desc: String) {
ROOT(0, "root", "traditional unix root user"),
DAEMON(1, "daemon", "Traditional unix daemon owner."),
BIN(2, "bin", "Traditional unix binaries owner."),
SYS(3, "sys", "A group with the same gid on Linux/macOS/Android."),
SYSTEM(1000, "system", "system server"),
RADIO(1001, "radio", "telephony subsystem, RIL"),
BLUETOOTH(1002, "bluetooth", "bluetooth subsystem"),
GRAPHICS(1003, "graphics", "graphics devices"),
INPUT(1004, "input", "input devices"),
AUDIO(1005, "audio", "audio devices"),
CAMERA(1006, "camera", "camera devices"),
LOG(1007, "log", "log devices"),
COMPASS(1008, "compass", "compass device"),
MOUNT(1009, "mount", "mountd socket"),
WIFI(1010, "wifi", "wifi subsystem"),
ADB(1011, "adb", "android debug bridge (adbd)"),
INSTALL(1012, "install", "group for installing packages"),
MEDIA(1013, "media", "mediaserver process"),
DHCP(1014, "dhcp", "dhcp client"),
SDCARD_RW(1015, "sdcard_rw", "external storage write access"),
VPN(1016, "vpn", "vpn system"),
KEYSTORE(1017, "keystore", "keystore subsystem"),
USB(1018, "usb", "USB devices"),
DRM(1019, "drm", "DRM server"),
MDNSR(1020, "mdnsr", "MulticastDNSResponder (service discovery)"),
GPS(1021, "gps", "GPS daemon"),
UNUSED1(1022, "unused1", "deprecated, DO NOT USE"),
MEDIA_RW(1023, "media_rw", "internal media storage write access"),
MTP(1024, "mtp", "MTP USB driver access"),
UNUSED2(1025, "unused2", "deprecated, DO NOT USE"),
DRMRPC(1026, "drmrpc", "group for drm rpc"),
NFC(1027, "nfc", "nfc subsystem"),
SDCARD_R(1028, "sdcard_r", "external storage read access"),
CLAT(1029, "clat", "clat part of nat464"),
LOOP_RADIO(1030, "loop_radio", "loop radio devices"),
MEDIA_DRM(1031, "media_drm", "MediaDrm plugins"),
PACKAGE_INFO(1032, "package_info", "access to installed package details"),
SDCARD_PICS(1033, "sdcard_pics", "external storage photos access"),
SDCARD_AV(1034, "sdcard_av", "external storage audio/video access"),
SDCARD_ALL(1035, "sdcard_all", "access all users external storage"),
LOGD(1036, "logd", "log daemon"),
SHARED_RELRO(1037, "shared_relro", "creator of shared GNU RELRO files"),
DBUS(1038, "dbus", "dbus-daemon IPC broker process"),
TLSDATE(1039, "tlsdate", "tlsdate unprivileged user"),
MEDIA_EX(1040, "media_ex", "mediaextractor process"),
AUDIOSERVER(1041, "audioserver", "audioserver process"),
METRICS_COLL(1042, "metrics_coll", "metrics_collector process"),
METRICSD(1043, "metricsd", "metricsd process"),
WEBSERV(1044, "webserv", "webservd process"),
DEBUGGERD(1045, "debuggerd", "debuggerd unprivileged user"),
MEDIA_CODEC(1046, "media_codec", "media_codec process"),
CAMERASERVER(1047, "cameraserver", "cameraserver process"),
FIREWALL(1048, "firewall", "firewall process"),
TRUNKS(1049, "trunks", "trunksd process"),
NVRAM(1050, "nvram", "nvram daemon"),
DNS_TETHER(1051, "dns_tether", "dns_tether device"),
DNS_TETHER_RESERVED(1052, "dns_tether_reserved", "Reserved range for dns_tether"),
WEBVIEW_ZYGOTE(1053, "webview_zygote", "zygote process"),
WEBVIEW_USER(1054, "webview_user", "webview chromium user"),
ETHERNET(1055, "ethernet", "Ethernet"),
TOMBSTONED(1056, "tombstoned", "tombstoned process"),
GRAPHICS_RW(1057, "graphics_rw", "graphics devices"),
SHELL(2000, "shell", "adb and debug shell user"),
CACHE(2001, "cache", "cache access"),
DIAG(2002, "diag", "diagnostics"),
NET_BT_ADMIN(3001, "net_bt_admin", "bluetooth: create any socket"),
NET_BT(3002, "net_bt", "bluetooth: create sco, rfcomm or l2cap sockets"),
INET(3003, "inet", "can create AF_INET and AF_INET6 sockets"),
NET_RAW(3004, "net_raw", "can create raw INET sockets"),
NET_ADMIN(3005, "net_admin", "can configure interfaces and routing tables."),
NET_BW_STATS(3006, "net_bw_stats", "read bandwidth statistics"),
NET_BW_ACCT(3007, "net_bw_acct", "change bandwidth statistics accounting"),
NET_BT_STACK(3008, "net_bt_stack", "access to various bluetooth management functions"),
QCOM_DIAG(3009, "qcom_diag", "allow msm specific diag commands"),
EVERYBODY(9997, "everybody", "Shared external storage read/write"),
MISC(9998, "misc", "Access to misc storage"),
NOBODY(9999, "nobody", "Reserved"),
APP(10000, "app", "Access to app data"),
}

View File

@@ -0,0 +1,77 @@
package me.weishu.kernelsu.ui;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.IBinder;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import androidx.annotation.NonNull;
import com.topjohnwu.superuser.ipc.RootService;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import me.weishu.kernelsu.IKsuInterface;
import rikka.parcelablelist.ParcelableListSlice;
/**
* @author weishu
* @date 2023/4/18.
*/
public class KsuService extends RootService {
private static final String TAG = "KsuService";
class Stub extends IKsuInterface.Stub {
@Override
public ParcelableListSlice<PackageInfo> getPackages(int flags) {
List<PackageInfo> list = getInstalledPackagesAll(flags);
Log.i(TAG, "getPackages: " + list.size());
return new ParcelableListSlice<>(list);
}
}
@Override
public IBinder onBind(@NonNull Intent intent) {
return new Stub();
}
List<Integer> getUserIds() {
List<Integer> result = new ArrayList<>();
UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
List<UserHandle> userProfiles = um.getUserProfiles();
for (UserHandle userProfile : userProfiles) {
int userId = userProfile.hashCode();
result.add(userProfile.hashCode());
}
return result;
}
ArrayList<PackageInfo> getInstalledPackagesAll(int flags) {
ArrayList<PackageInfo> packages = new ArrayList<>();
for (Integer userId : getUserIds()) {
Log.i(TAG, "getInstalledPackagesAll: " + userId);
packages.addAll(getInstalledPackagesAsUser(flags, userId));
}
return packages;
}
List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
try {
PackageManager pm = getPackageManager();
Method getInstalledPackagesAsUser = pm.getClass().getDeclaredMethod("getInstalledPackagesAsUser", int.class, int.class);
return (List<PackageInfo>) getInstalledPackagesAsUser.invoke(pm, flags, userId);
} catch (Throwable e) {
Log.e(TAG, "err", e);
}
return new ArrayList<>();
}
}

View File

@@ -5,27 +5,37 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
import com.ramcosta.composedestinations.DestinationsNavHost
import com.ramcosta.composedestinations.navigation.popBackStack
import com.ramcosta.composedestinations.utils.isRouteOnBackStackAsState
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.ksuApp
import me.weishu.kernelsu.ui.component.rememberDialogHostState
import me.weishu.kernelsu.ui.screen.BottomBarDestination
import me.weishu.kernelsu.ui.screen.NavGraphs
import me.weishu.kernelsu.ui.screen.appCurrentDestinationAsState
import me.weishu.kernelsu.ui.screen.destinations.Destination
import me.weishu.kernelsu.ui.screen.startAppDestination
import me.weishu.kernelsu.ui.theme.KernelSUTheme
import me.weishu.kernelsu.ui.util.LocalDialogHost
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
class MainActivity : ComponentActivity() {
@OptIn(ExperimentalAnimationApi::class, ExperimentalMaterial3Api::class)
@OptIn(ExperimentalAnimationApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -37,7 +47,10 @@ class MainActivity : ComponentActivity() {
bottomBar = { BottomBar(navController) },
snackbarHost = { SnackbarHost(snackbarHostState) }
) { innerPadding ->
CompositionLocalProvider(LocalSnackbarHost provides snackbarHostState) {
CompositionLocalProvider(
LocalSnackbarHost provides snackbarHostState,
LocalDialogHost provides rememberDialogHostState(),
) {
DestinationsNavHost(
modifier = Modifier.padding(innerPadding),
navGraph = NavGraphs.root,
@@ -52,22 +65,21 @@ class MainActivity : ComponentActivity() {
@Composable
private fun BottomBar(navController: NavHostController) {
val currentDestination: Destination = navController.appCurrentDestinationAsState().value
?: NavGraphs.root.startAppDestination
var topDestination by rememberSaveable { mutableStateOf(currentDestination.route) }
LaunchedEffect(currentDestination) {
val queue = navController.backQueue
if (queue.size == 2) topDestination = queue[1].destination.route!!
else if (queue.size > 2) topDestination = queue[2].destination.route!!
}
val isManager = Natives.becomeManager(ksuApp.packageName)
val fullFeatured = isManager && !Natives.requireNewKernel()
NavigationBar(tonalElevation = 8.dp) {
BottomBarDestination.values().forEach { destination ->
if (!fullFeatured && destination.rootRequired) return@forEach
val isCurrentDestOnBackStack by navController.isRouteOnBackStackAsState(destination.direction)
NavigationBarItem(
selected = topDestination == destination.direction.route,
selected = isCurrentDestOnBackStack,
onClick = {
if (isCurrentDestOnBackStack) {
navController.popBackStack(destination.direction, false)
}
navController.navigate(destination.direction.route) {
popUpTo(navController.graph.findStartDestination().id) {
popUpTo(NavGraphs.root.route) {
saveState = true
}
launchSingleTop = true
@@ -75,8 +87,11 @@ private fun BottomBar(navController: NavHostController) {
}
},
icon = {
if (topDestination == destination.direction.route) Icon(destination.iconSelected, stringResource(destination.label))
else Icon(destination.iconNotSelected, stringResource(destination.label))
if (isCurrentDestOnBackStack) {
Icon(destination.iconSelected, stringResource(destination.label))
} else {
Icon(destination.iconNotSelected, stringResource(destination.label))
}
},
label = { Text(stringResource(destination.label)) },
alwaysShowLabel = false

View File

@@ -0,0 +1,126 @@
package me.weishu.kernelsu.ui.component
import android.text.method.LinkMovementMethod
import android.widget.TextView
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.compose.ui.window.Dialog
import androidx.core.content.res.ResourcesCompat
import androidx.core.text.HtmlCompat
import com.google.accompanist.drawablepainter.rememberDrawablePainter
import me.weishu.kernelsu.BuildConfig
import me.weishu.kernelsu.R
@Preview
@Composable
fun AboutCard() {
ElevatedCard(
modifier = Modifier
.fillMaxWidth(),
shape = RoundedCornerShape(8.dp),
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(24.dp)
) {
AboutCardContent()
}
}
}
@Composable
fun AboutDialog(showAboutDialog: MutableState<Boolean>) {
if (showAboutDialog.value) {
Dialog(onDismissRequest = { showAboutDialog.value = false }) {
AboutCard()
}
}
}
@Composable
private fun AboutCardContent() {
Column(
modifier = Modifier
.fillMaxWidth()
) {
val drawable = ResourcesCompat.getDrawable(
LocalContext.current.resources,
R.mipmap.ic_launcher,
LocalContext.current.theme
)
Row {
Image(
painter = rememberDrawablePainter(drawable),
contentDescription = "icon",
modifier = Modifier.size(40.dp)
)
Spacer(modifier = Modifier.width(12.dp))
Column {
Text(
stringResource(id = R.string.app_name),
style = MaterialTheme.typography.titleSmall,
fontSize = 18.sp
)
Text(
BuildConfig.VERSION_NAME,
style = MaterialTheme.typography.bodySmall,
fontSize = 14.sp
)
Spacer(modifier = Modifier.height(8.dp))
HtmlText(
html = stringResource(
id = R.string.about_source_code,
"<b><a href=\"https://github.com/tiann/KernelSU\">GitHub</a></b>",
"<b><a href=\"https://t.me/KernelSU\">Telegram</a></b>"
)
)
}
}
}
}
@Composable
fun HtmlText(html: String, modifier: Modifier = Modifier) {
val contentColor = LocalContentColor.current
AndroidView(
modifier = modifier,
factory = { context ->
TextView(context).also {
it.movementMethod = LinkMovementMethod.getInstance()
}
},
update = {
it.text = HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_COMPACT)
it.setTextColor(contentColor.toArgb())
}
)
}

View File

@@ -0,0 +1,269 @@
package me.weishu.kernelsu.ui.component
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import me.weishu.kernelsu.ui.util.LocalDialogHost
import kotlin.coroutines.resume
interface DialogVisuals
interface LoadingDialogVisuals : DialogVisuals
interface PromptDialogVisuals : DialogVisuals {
val title: String
val content: String
}
interface ConfirmDialogVisuals : PromptDialogVisuals {
val confirm: String?
val dismiss: String?
}
sealed interface DialogData {
val visuals: DialogVisuals
}
interface LoadingDialogData : DialogData {
override val visuals: LoadingDialogVisuals
fun dismiss()
}
interface PromptDialogData : DialogData {
override val visuals: PromptDialogVisuals
fun dismiss()
}
interface ConfirmDialogData : PromptDialogData {
override val visuals: ConfirmDialogVisuals
fun confirm()
}
sealed interface ConfirmResult {
object Confirmed : ConfirmResult
object Canceled : ConfirmResult
}
class DialogHostState {
private object LoadingDialogVisualsImpl : LoadingDialogVisuals
private data class PromptDialogVisualsImpl(
override val title: String,
override val content: String
) : PromptDialogVisuals
private data class ConfirmDialogVisualsImpl(
override val title: String,
override val content: String,
override val confirm: String?,
override val dismiss: String?
) : ConfirmDialogVisuals
private data class LoadingDialogDataImpl(
override val visuals: LoadingDialogVisuals,
private val continuation: CancellableContinuation<Unit>,
) : LoadingDialogData {
override fun dismiss() {
if (continuation.isActive) continuation.resume(Unit)
}
}
private data class PromptDialogDataImpl(
override val visuals: PromptDialogVisuals,
private val continuation: CancellableContinuation<Unit>,
) : PromptDialogData {
override fun dismiss() {
if (continuation.isActive) continuation.resume(Unit)
}
}
private data class ConfirmDialogDataImpl(
override val visuals: ConfirmDialogVisuals,
private val continuation: CancellableContinuation<ConfirmResult>
) : ConfirmDialogData {
override fun confirm() {
if (continuation.isActive) continuation.resume(ConfirmResult.Confirmed)
}
override fun dismiss() {
if (continuation.isActive) continuation.resume(ConfirmResult.Canceled)
}
}
private val mutex = Mutex()
var currentDialogData by mutableStateOf<DialogData?>(null)
private set
suspend fun showLoading() {
try {
mutex.withLock {
suspendCancellableCoroutine { continuation ->
currentDialogData = LoadingDialogDataImpl(
visuals = LoadingDialogVisualsImpl,
continuation = continuation
)
}
}
} finally {
currentDialogData = null
}
}
suspend fun <R> withLoading(block: suspend () -> R) = coroutineScope {
val showLoading = launch {
showLoading()
}
val result = block()
showLoading.cancel()
result
}
suspend fun showPrompt(title: String, content: String) {
try {
mutex.withLock {
suspendCancellableCoroutine { continuation ->
currentDialogData = PromptDialogDataImpl(
visuals = PromptDialogVisualsImpl(title, content),
continuation = continuation
)
}
}
} finally {
currentDialogData = null
}
}
suspend fun showConfirm(
title: String,
content: String,
confirm: String? = null,
dismiss: String? = null
): ConfirmResult = mutex.withLock {
try {
return@withLock suspendCancellableCoroutine { continuation ->
currentDialogData = ConfirmDialogDataImpl(
visuals = ConfirmDialogVisualsImpl(title, content, confirm, dismiss),
continuation = continuation
)
}
} finally {
currentDialogData = null
}
}
}
@Composable
fun rememberDialogHostState(): DialogHostState {
return remember {
DialogHostState()
}
}
private inline fun <reified T : DialogData> DialogData?.tryInto(): T? {
return when (this) {
is T -> this
else -> null
}
}
@Composable
fun LoadingDialog(
state: DialogHostState = LocalDialogHost.current,
) {
state.currentDialogData.tryInto<LoadingDialogData>() ?: return
val dialogProperties = remember {
DialogProperties(dismissOnClickOutside = false, dismissOnBackPress = false)
}
Dialog(onDismissRequest = {}, properties = dialogProperties) {
Surface(
modifier = Modifier
.size(100.dp),
shape = RoundedCornerShape(8.dp)
) {
Box(
contentAlignment = Alignment.Center,
) {
CircularProgressIndicator()
}
}
}
}
@Composable
fun PromptDialog(
state: DialogHostState = LocalDialogHost.current,
) {
val promptDialogData = state.currentDialogData.tryInto<PromptDialogData>() ?: return
val visuals = promptDialogData.visuals
AlertDialog(
onDismissRequest = {
promptDialogData.dismiss()
},
title = {
Text(text = visuals.title)
},
text = {
Text(text = visuals.content)
},
confirmButton = {
TextButton(onClick = { promptDialogData.dismiss() }) {
Text(text = stringResource(id = android.R.string.ok))
}
},
dismissButton = null,
)
}
@Composable
fun ConfirmDialog(state: DialogHostState = LocalDialogHost.current) {
val confirmDialogData = state.currentDialogData.tryInto<ConfirmDialogData>() ?: return
val visuals = confirmDialogData.visuals
AlertDialog(
onDismissRequest = {
confirmDialogData.dismiss()
},
title = {
Text(text = visuals.title)
},
text = {
Text(text = visuals.content)
},
confirmButton = {
TextButton(onClick = { confirmDialogData.confirm() }) {
Text(text = visuals.confirm ?: stringResource(id = android.R.string.ok))
}
},
dismissButton = {
TextButton(onClick = { confirmDialogData.dismiss() }) {
Text(text = visuals.dismiss ?: stringResource(id = android.R.string.cancel))
}
},
)
}

View File

@@ -13,8 +13,19 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.outlined.ArrowBack
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
@@ -36,7 +47,8 @@ fun SearchAppBar(
onSearchTextChange: (String) -> Unit,
onClearClick: () -> Unit,
onBackClick: (() -> Unit)? = null,
onConfirm: (() -> Unit)? = null
onConfirm: (() -> Unit)? = null,
dropdownContent: @Composable (() -> Unit)? = null,
) {
val keyboardController = LocalSoftwareKeyboardController.current
val focusRequester = remember { FocusRequester() }
@@ -116,6 +128,11 @@ fun SearchAppBar(
content = { Icon(Icons.Filled.Search, null) }
)
}
if (dropdownContent != null) {
dropdownContent()
}
}
)
}

View File

@@ -0,0 +1,52 @@
package me.weishu.kernelsu.ui.component
import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.ImageVector
@Composable
fun SwitchItem(
icon: ImageVector? = null,
title: String,
summary: String? = null,
checked: Boolean,
enabled: Boolean = true,
onCheckedChange: (Boolean) -> Unit
) {
ListItem(
headlineContent = {
Text(title)
},
leadingContent = icon?.let {
{ Icon(icon, title) }
},
trailingContent = {
Switch(checked = checked, enabled = enabled, onCheckedChange = onCheckedChange)
},
supportingContent = {
if (summary != null) {
Text(summary)
}
}
)
}
@Composable
fun RadioItem(
title: String,
selected: Boolean,
onClick: () -> Unit,
) {
ListItem(
headlineContent = {
Text(title)
},
leadingContent = {
RadioButton(selected = selected, onClick = onClick)
},
)
}

View File

@@ -0,0 +1,63 @@
package me.weishu.kernelsu.ui.component.profile
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.SwitchItem
@Composable
fun AppProfileConfig(
modifier: Modifier = Modifier,
fixedName: Boolean,
enabled: Boolean,
profile: Natives.Profile,
onProfileChange: (Natives.Profile) -> Unit,
) {
Column(modifier = modifier) {
if (!fixedName) {
OutlinedTextField(
label = { Text(stringResource(R.string.profile_name)) },
value = profile.name,
onValueChange = { onProfileChange(profile.copy(name = it)) }
)
}
SwitchItem(
title = stringResource(R.string.profile_umount_modules),
summary = stringResource(R.string.profile_umount_modules_summary),
checked = if (enabled) {
profile.umountModules
} else {
Natives.isDefaultUmountModules()
},
enabled = enabled,
onCheckedChange = {
onProfileChange(
profile.copy(
umountModules = it,
nonRootUseDefault = false
)
)
}
)
}
}
@Preview
@Composable
private fun AppProfileConfigPreview() {
var profile by remember { mutableStateOf(Natives.Profile("")) }
AppProfileConfig(fixedName = true, enabled = false, profile = profile) {
profile = it
}
}

View File

@@ -0,0 +1,464 @@
@file:OptIn(ExperimentalMaterial3Api::class)
package me.weishu.kernelsu.ui.component.profile
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material.icons.filled.ArrowDropUp
import androidx.compose.material3.AssistChip
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.text.isDigitsOnly
import com.maxkeppeker.sheets.core.models.base.Header
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
import com.maxkeppeler.sheets.input.InputDialog
import com.maxkeppeler.sheets.input.models.InputHeader
import com.maxkeppeler.sheets.input.models.InputSelection
import com.maxkeppeler.sheets.input.models.InputTextField
import com.maxkeppeler.sheets.input.models.InputTextFieldType
import com.maxkeppeler.sheets.input.models.ValidationResult
import com.maxkeppeler.sheets.list.ListDialog
import com.maxkeppeler.sheets.list.models.ListOption
import com.maxkeppeler.sheets.list.models.ListSelection
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.profile.Capabilities
import me.weishu.kernelsu.profile.Groups
import me.weishu.kernelsu.ui.util.isSepolicyValid
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun RootProfileConfig(
modifier: Modifier = Modifier,
fixedName: Boolean,
profile: Natives.Profile,
onProfileChange: (Natives.Profile) -> Unit,
) {
Column(modifier = modifier) {
if (!fixedName) {
OutlinedTextField(
label = { Text(stringResource(R.string.profile_name)) },
value = profile.name,
onValueChange = { onProfileChange(profile.copy(name = it)) }
)
}
var expanded by remember { mutableStateOf(false) }
val currentNamespace = when (profile.namespace) {
Natives.Profile.Namespace.Inherited.ordinal -> stringResource(R.string.profile_namespace_inherited)
Natives.Profile.Namespace.Global.ordinal -> stringResource(R.string.profile_namespace_global)
Natives.Profile.Namespace.Individual.ordinal -> stringResource(R.string.profile_namespace_individual)
else -> stringResource(R.string.profile_namespace_inherited)
}
ListItem(headlineContent = {
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = !expanded }
) {
OutlinedTextField(
modifier = Modifier
.menuAnchor()
.fillMaxWidth(),
readOnly = true,
label = { Text(stringResource(R.string.profile_namespace)) },
value = currentNamespace,
onValueChange = {},
trailingIcon = {
if (expanded) Icon(Icons.Filled.ArrowDropUp, null)
else Icon(Icons.Filled.ArrowDropDown, null)
},
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false }
) {
DropdownMenuItem(
text = { Text(stringResource(R.string.profile_namespace_inherited)) },
onClick = {
onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.Inherited.ordinal))
expanded = false
},
)
DropdownMenuItem(
text = { Text(stringResource(R.string.profile_namespace_global)) },
onClick = {
onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.Global.ordinal))
expanded = false
},
)
DropdownMenuItem(
text = { Text(stringResource(R.string.profile_namespace_individual)) },
onClick = {
onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.Individual.ordinal))
expanded = false
},
)
}
}
})
UidPanel(uid = profile.uid, label = "uid", onUidChange = {
onProfileChange(
profile.copy(
uid = it,
rootUseDefault = false
)
)
})
UidPanel(uid = profile.gid, label = "gid", onUidChange = {
onProfileChange(
profile.copy(
gid = it,
rootUseDefault = false
)
)
})
val selectedGroups = profile.groups.ifEmpty { listOf(0) }.let { e ->
e.mapNotNull { g ->
Groups.values().find { it.gid == g }
}
}
GroupsPanel(selectedGroups) {
onProfileChange(
profile.copy(
groups = it.map { group -> group.gid }.ifEmpty { listOf(0) },
rootUseDefault = false
)
)
}
val selectedCaps = profile.capabilities.mapNotNull { e ->
Capabilities.values().find { it.cap == e }
}
CapsPanel(selectedCaps) {
onProfileChange(
profile.copy(
capabilities = it.map { cap -> cap.cap },
rootUseDefault = false
)
)
}
SELinuxPanel(profile = profile, onSELinuxChange = { domain, rules ->
onProfileChange(
profile.copy(
context = domain,
rules = rules,
rootUseDefault = false
)
)
})
}
}
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun GroupsPanel(selected: List<Groups>, closeSelection: (selection: Set<Groups>) -> Unit) {
var showDialog by remember { mutableStateOf(false) }
if (showDialog) {
val groups = Groups.values()
val options = groups.map { value ->
ListOption(
titleText = value.display,
subtitleText = value.desc,
selected = selected.contains(value),
)
}
val selection = HashSet(selected)
ListDialog(
state = rememberUseCaseState(visible = true, onFinishedRequest = {
closeSelection(selection)
}, onCloseRequest = {
showDialog = false
}),
header = Header.Default(
title = stringResource(R.string.profile_groups),
),
selection = ListSelection.Multiple(
showCheckBoxes = true,
options = options,
maxChoices = 32, // Kernel only supports 32 groups at most
) { indecies, _ ->
// Handle selection
selection.clear()
indecies.forEach { index ->
val group = groups[index]
selection.add(group)
}
}
)
}
OutlinedCard(modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clickable {
showDialog = true
}) {
Column(modifier = Modifier.padding(16.dp)) {
Text(stringResource(R.string.profile_groups))
FlowRow {
selected.forEach { group ->
AssistChip(
modifier = Modifier.padding(3.dp),
onClick = { /*TODO*/ },
label = { Text(group.display) })
}
}
}
}
}
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun CapsPanel(
selected: Collection<Capabilities>,
closeSelection: (selection: Set<Capabilities>) -> Unit
) {
var showDialog by remember { mutableStateOf(false) }
if (showDialog) {
val caps = Capabilities.values()
val options = caps.map { value ->
ListOption(
titleText = value.display,
subtitleText = value.desc,
selected = selected.contains(value),
)
}
val selection = HashSet(selected)
ListDialog(
state = rememberUseCaseState(visible = true, onFinishedRequest = {
closeSelection(selection)
}, onCloseRequest = {
showDialog = false
}),
header = Header.Default(
title = stringResource(R.string.profile_capabilities),
),
selection = ListSelection.Multiple(
showCheckBoxes = true,
options = options
) { indecies, _ ->
// Handle selection
selection.clear()
indecies.forEach { index ->
val group = caps[index]
selection.add(group)
}
}
)
}
OutlinedCard(modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clickable {
showDialog = true
}) {
Column(modifier = Modifier.padding(16.dp)) {
Text(stringResource(R.string.profile_capabilities))
FlowRow {
selected.forEach { group ->
AssistChip(
modifier = Modifier.padding(3.dp),
onClick = { /*TODO*/ },
label = { Text(group.display) })
}
}
}
}
}
@OptIn(ExperimentalComposeUiApi::class)
@Composable
private fun UidPanel(uid: Int, label: String, onUidChange: (Int) -> Unit) {
ListItem(headlineContent = {
var isError by remember {
mutableStateOf(false)
}
var lastValidUid by remember {
mutableStateOf(uid)
}
val keyboardController = LocalSoftwareKeyboardController.current
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
label = { Text(label) },
value = uid.toString(),
isError = isError,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(onDone = {
keyboardController?.hide()
}),
onValueChange = {
if (it.isEmpty()) {
onUidChange(0)
return@OutlinedTextField
}
val valid = isTextValidUid(it)
val targetUid = if (valid) it.toInt() else lastValidUid
if (valid) {
lastValidUid = it.toInt()
}
onUidChange(targetUid)
isError = !valid
}
)
})
}
@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(profile.rules) }
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 in the format of \"user:role:type:level\"")
}
),
InputTextField(
text = rules,
header = InputHeader(
title = stringResource(id = R.string.profile_selinux_rules),
),
type = InputTextFieldType.OUTLINED,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Ascii,
),
singleLine = false,
resultListener = {
rules = it ?: ""
},
validationListener = { value ->
if (isSepolicyValid(value)) ValidationResult.Valid
else ValidationResult.Invalid("SELinux rules is invalid!")
}
)
)
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() {
var profile by remember { mutableStateOf(Natives.Profile("")) }
RootProfileConfig(fixedName = true, profile = profile) {
profile = it
}
}
private fun isTextValidUid(text: String): Boolean {
return text.isNotEmpty() && text.isDigitsOnly() && text.toInt() >= 0 && text.toInt() <= Int.MAX_VALUE
}

View File

@@ -0,0 +1,391 @@
package me.weishu.kernelsu.ui.screen
import androidx.annotation.StringRes
import androidx.compose.animation.Crossfade
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.Android
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material.icons.filled.ArrowDropUp
import androidx.compose.material.icons.filled.Security
import androidx.compose.material3.Divider
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.FilterChip
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.launch
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.SwitchItem
import me.weishu.kernelsu.ui.component.profile.AppProfileConfig
import me.weishu.kernelsu.ui.component.profile.RootProfileConfig
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.util.forceStopApp
import me.weishu.kernelsu.ui.util.getSepolicy
import me.weishu.kernelsu.ui.util.launchApp
import me.weishu.kernelsu.ui.util.restartApp
import me.weishu.kernelsu.ui.util.setSepolicy
import me.weishu.kernelsu.ui.viewmodel.SuperUserViewModel
/**
* @author weishu
* @date 2023/5/16.
*/
@Destination
@Composable
fun AppProfileScreen(
navigator: DestinationsNavigator,
appInfo: SuperUserViewModel.AppInfo,
) {
val context = LocalContext.current
val snackbarHost = LocalSnackbarHost.current
val scope = rememberCoroutineScope()
val failToUpdateAppProfile =
stringResource(R.string.failed_to_update_app_profile).format(appInfo.label)
val failToUpdateSepolicy =
stringResource(R.string.failed_to_update_sepolicy).format(appInfo.label)
val packageName = appInfo.packageName
val initialProfile = Natives.getAppProfile(packageName, appInfo.uid)
if (initialProfile.allowSu) {
initialProfile.rules = getSepolicy(packageName)
}
var profile by rememberSaveable {
mutableStateOf(initialProfile)
}
Scaffold(
topBar = { TopBar { navigator.popBackStack() } },
) { paddingValues ->
AppProfileInner(
modifier = Modifier
.padding(paddingValues)
.verticalScroll(rememberScrollState()),
packageName = appInfo.packageName,
appLabel = appInfo.label,
appIcon = {
AsyncImage(
model = ImageRequest.Builder(context)
.data(appInfo.packageInfo)
.crossfade(true)
.build(),
contentDescription = appInfo.label,
modifier = Modifier
.padding(4.dp)
.width(48.dp)
.height(48.dp)
)
},
profile = profile,
onProfileChange = {
scope.launch {
if (it.allowSu && !it.rootUseDefault && it.rules.isNotEmpty()) {
if (!setSepolicy(profile.name, it.rules)) {
snackbarHost.showSnackbar(failToUpdateSepolicy)
return@launch
}
}
if (!Natives.setAppProfile(it)) {
snackbarHost.showSnackbar(failToUpdateAppProfile.format(appInfo.uid))
} else {
profile = it
}
}
},
)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun AppProfileInner(
modifier: Modifier = Modifier,
packageName: String,
appLabel: String,
appIcon: @Composable () -> Unit,
profile: Natives.Profile,
onProfileChange: (Natives.Profile) -> Unit,
) {
val isRootGranted = profile.allowSu
Column(modifier = modifier) {
AppMenuBox(packageName) {
ListItem(
headlineContent = { Text(appLabel) },
supportingContent = { Text(packageName) },
leadingContent = appIcon,
)
}
SwitchItem(
icon = Icons.Filled.Security,
title = stringResource(id = R.string.superuser),
checked = isRootGranted,
onCheckedChange = { onProfileChange(profile.copy(allowSu = it)) },
)
Crossfade(targetState = isRootGranted, label = "") { current ->
Column {
if (current) {
val initialMode = if (profile.rootUseDefault) {
Mode.Default
} else if (profile.rootTemplate != null) {
Mode.Template
} else {
Mode.Custom
}
var mode by remember {
mutableStateOf(initialMode)
}
ProfileBox(mode, false) {
// template mode shouldn't change profile here!
if (it == Mode.Default || it == Mode.Custom) {
onProfileChange(profile.copy(rootUseDefault = it == Mode.Default))
}
mode = it
}
Crossfade(targetState = mode, label = "") { currentMode ->
if (currentMode == Mode.Template) {
var expanded by remember { mutableStateOf(false) }
val templateNone = "None"
var template by rememberSaveable {
mutableStateOf(
profile.rootTemplate
?: templateNone
)
}
ListItem(headlineContent = {
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = it },
) {
OutlinedTextField(
modifier = Modifier.menuAnchor(),
readOnly = true,
label = { Text(stringResource(R.string.profile_template)) },
value = template,
onValueChange = {
if (template != templateNone) {
onProfileChange(
profile.copy(
rootTemplate = it,
rootUseDefault = false
)
)
template = it
}
},
trailingIcon = {
if (expanded) Icon(Icons.Filled.ArrowDropUp, null)
else Icon(Icons.Filled.ArrowDropDown, null)
},
)
// TODO: Template
}
})
} else if (mode == Mode.Custom) {
RootProfileConfig(
fixedName = true,
profile = profile,
onProfileChange = onProfileChange
)
}
}
} else {
val mode = if (profile.nonRootUseDefault) Mode.Default else Mode.Custom
ProfileBox(mode, false) {
onProfileChange(profile.copy(nonRootUseDefault = (it == Mode.Default)))
}
Crossfade(targetState = mode, label = "") { currentMode ->
val modifyEnabled = currentMode == Mode.Custom
AppProfileConfig(
fixedName = true,
profile = profile,
enabled = modifyEnabled,
onProfileChange = onProfileChange
)
}
}
}
}
}
}
private enum class Mode(@StringRes private val res: Int) {
Default(R.string.profile_default),
Template(R.string.profile_template),
Custom(R.string.profile_custom);
val text: String
@Composable get() = stringResource(res)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopBar(onBack: () -> Unit) {
TopAppBar(
title = {
Text(stringResource(R.string.profile))
},
navigationIcon = {
IconButton(
onClick = onBack
) { Icon(Icons.Filled.ArrowBack, contentDescription = null) }
},
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun ProfileBox(
mode: Mode,
hasTemplate: Boolean,
onModeChange: (Mode) -> Unit,
) {
ListItem(
headlineContent = { Text(stringResource(R.string.profile)) },
supportingContent = { Text(mode.text) },
leadingContent = { Icon(Icons.Filled.AccountCircle, null) },
)
Divider(thickness = Dp.Hairline)
ListItem(headlineContent = {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
FilterChip(
selected = mode == Mode.Default,
label = { Text(stringResource(R.string.profile_default)) },
onClick = { onModeChange(Mode.Default) },
)
if (hasTemplate) {
FilterChip(
selected = mode == Mode.Template,
label = { Text(stringResource(R.string.profile_template)) },
onClick = { onModeChange(Mode.Template) },
)
}
FilterChip(
selected = mode == Mode.Custom,
label = { Text(stringResource(R.string.profile_custom)) },
onClick = { onModeChange(Mode.Custom) },
)
}
})
}
@Composable
private fun AppMenuBox(packageName: String, content: @Composable () -> Unit) {
var expanded by remember { mutableStateOf(false) }
var touchPoint: Offset by remember { mutableStateOf(Offset.Zero) }
val density = LocalDensity.current
BoxWithConstraints(
Modifier
.fillMaxSize()
.pointerInput(Unit) {
detectTapGestures {
touchPoint = it
expanded = true
}
}
) {
content()
val (offsetX, offsetY) = with(density) {
(touchPoint.x.toDp()) to (touchPoint.y.toDp())
}
DropdownMenu(
expanded = expanded,
offset = DpOffset(offsetX, -offsetY),
onDismissRequest = {
expanded = false
},
) {
DropdownMenuItem(
text = { Text(stringResource(id = R.string.launch_app)) },
onClick = {
expanded = false
launchApp(packageName)
},
)
DropdownMenuItem(
text = { Text(stringResource(id = R.string.force_stop_app)) },
onClick = {
expanded = false
forceStopApp(packageName)
},
)
DropdownMenuItem(
text = { Text(stringResource(id = R.string.restart_app)) },
onClick = {
expanded = false
restartApp(packageName)
},
)
}
}
}
@Preview
@Composable
private fun AppProfilePreview() {
var profile by remember { mutableStateOf(Natives.Profile("")) }
AppProfileInner(
packageName = "icu.nullptr.test",
appLabel = "Test",
appIcon = { Icon(Icons.Filled.Android, null) },
profile = profile,
onProfileChange = {
profile = it
},
)
}

View File

@@ -15,9 +15,10 @@ enum class BottomBarDestination(
val direction: DirectionDestinationSpec,
@StringRes val label: Int,
val iconSelected: ImageVector,
val iconNotSelected: ImageVector
val iconNotSelected: ImageVector,
val rootRequired: Boolean,
) {
Home(HomeScreenDestination, R.string.home, Icons.Filled.Home, Icons.Outlined.Home),
SuperUser(SuperUserScreenDestination, R.string.superuser, Icons.Filled.Security, Icons.Outlined.Security),
Module(ModuleScreenDestination, R.string.module, Icons.Filled.Apps, Icons.Outlined.Apps)
Home(HomeScreenDestination, R.string.home, Icons.Filled.Home, Icons.Outlined.Home, false),
SuperUser(SuperUserScreenDestination, R.string.superuser, Icons.Filled.Security, Icons.Outlined.Security, true),
Module(ModuleScreenDestination, R.string.module, Icons.Filled.Apps, Icons.Outlined.Apps, true)
}

View File

@@ -1,7 +1,5 @@
package me.weishu.kernelsu.ui.screen
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.os.Build
import android.os.PowerManager
@@ -21,7 +19,9 @@ 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
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.tooling.preview.Preview
@@ -29,27 +29,22 @@ 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.launch
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
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.util.reboot
import me.weishu.kernelsu.ui.util.getSELinuxStatus
import me.weishu.kernelsu.ui.util.install
import me.weishu.kernelsu.ui.util.*
@OptIn(ExperimentalMaterial3Api::class)
@RootNavGraph(start = true)
@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,15 +57,47 @@ fun HomeScreen(navigator: DestinationsNavigator) {
SideEffect {
if (isManager) install()
}
val ksuVersion = if (isManager) Natives.getVersion() else null
val ksuVersion = if (isManager) Natives.version else null
StatusCard(kernelVersion, ksuVersion)
if (isManager && Natives.requireNewKernel()) {
WarningCard(
stringResource(id = R.string.require_kernel_version).format(
ksuVersion, Natives.MINIMAL_SUPPORTED_KERNEL
)
)
}
UpdateCard()
InfoCard()
DonateCard()
LearnMoreCard()
Spacer(Modifier)
}
}
}
@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 = {
@@ -83,43 +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
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
}) {
Icon(
imageVector = Icons.Filled.Refresh,
contentDescription = stringResource(id = R.string.reboot)
)
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")
}
}
IconButton(onClick = onSettingsClick) {
Icon(
imageVector = Icons.Filled.Settings,
contentDescription = stringResource(id = R.string.settings)
)
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)
)
}
})
}
@Composable
@@ -130,21 +155,26 @@ private fun StatusCard(kernelVersion: KernelVersion, ksuVersion: Int?) {
else MaterialTheme.colorScheme.errorContainer
})
) {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable {
// TODO: Install kernel
val uriHandler = LocalUriHandler.current
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) {
" [${stringResource(id = R.string.safe_mode)}]"
} else {
""
}
Icon(Icons.Outlined.CheckCircle, stringResource(R.string.home_working))
Column(Modifier.padding(start = 20.dp)) {
Text(
text = stringResource(R.string.home_working),
text = stringResource(R.string.home_working) + appendText,
style = MaterialTheme.typography.titleMedium
)
Spacer(Modifier.height(4.dp))
@@ -152,8 +182,20 @@ private fun StatusCard(kernelVersion: KernelVersion, ksuVersion: Int?) {
text = stringResource(R.string.home_working_version, ksuVersion),
style = MaterialTheme.typography.bodyMedium
)
Spacer(Modifier.height(4.dp))
Text(
text = stringResource(
R.string.home_superuser_count, getSuperuserCount()
), style = MaterialTheme.typography.bodyMedium
)
Spacer(Modifier.height(4.dp))
Text(
text = stringResource(R.string.home_module_count, getModuleCount()),
style = MaterialTheme.typography.bodyMedium
)
}
}
kernelVersion.isGKI() -> {
Icon(Icons.Outlined.Warning, stringResource(R.string.home_not_installed))
Column(Modifier.padding(start = 20.dp)) {
@@ -168,12 +210,12 @@ private fun StatusCard(kernelVersion: KernelVersion, ksuVersion: Int?) {
)
}
}
else -> {
Icon(Icons.Outlined.Block, stringResource(R.string.home_unsupported))
Column(Modifier.padding(start = 20.dp)) {
Text(
text = stringResource(R.string.home_unsupported),
fontFamily = FontFamily.Serif,
style = MaterialTheme.typography.titleMedium
)
Spacer(Modifier.height(4.dp))
@@ -188,11 +230,90 @@ private fun StatusCard(kernelVersion: KernelVersion, ksuVersion: Int?) {
}
}
@Composable
fun WarningCard(
message: String, color: Color = MaterialTheme.colorScheme.error, onClick: () -> Unit = {}
) {
ElevatedCard(
colors = CardDefaults.elevatedCardColors(
containerColor = color
)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(24.dp)
.clickable {
onClick()
}, verticalAlignment = Alignment.CenterVertically
) {
Column() {
Text(
text = message, style = MaterialTheme.typography.bodyMedium
)
}
}
}
}
@Composable
fun LearnMoreCard() {
val uriHandler = LocalUriHandler.current
val url = stringResource(R.string.home_learn_kernelsu_url)
ElevatedCard {
Row(modifier = Modifier
.fillMaxWidth()
.clickable {
uriHandler.openUri(url)
}
.padding(24.dp), verticalAlignment = Alignment.CenterVertically) {
Column() {
Text(
text = stringResource(R.string.home_learn_kernelsu),
style = MaterialTheme.typography.titleSmall
)
Spacer(Modifier.height(4.dp))
Text(
text = stringResource(R.string.home_click_to_learn_kernelsu),
style = MaterialTheme.typography.bodyMedium
)
}
}
}
}
@Composable
fun DonateCard() {
val uriHandler = LocalUriHandler.current
ElevatedCard {
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),
style = MaterialTheme.typography.titleSmall
)
Spacer(Modifier.height(4.dp))
Text(
text = stringResource(R.string.home_support_content),
style = MaterialTheme.typography.bodyMedium
)
}
}
}
}
@Composable
private fun InfoCard() {
val context = LocalContext.current
val snackbarHost = LocalSnackbarHost.current
val scope = rememberCoroutineScope()
ElevatedCard {
Column(
@@ -212,41 +333,27 @@ private fun InfoCard() {
InfoCardItem(stringResource(R.string.home_kernel), uname.release)
Spacer(Modifier.height(24.dp))
InfoCardItem(stringResource(R.string.home_arch), uname.machine)
Spacer(Modifier.height(16.dp))
val managerVersion = getManagerVersion(context)
InfoCardItem(
stringResource(R.string.home_manager_version),
"${managerVersion.first} (${managerVersion.second})"
)
Spacer(Modifier.height(24.dp))
InfoCardItem(stringResource(R.string.home_version), uname.version)
Spacer(Modifier.height(24.dp))
InfoCardItem(stringResource(R.string.home_api), Build.VERSION.SDK_INT.toString())
Spacer(Modifier.height(24.dp))
InfoCardItem(stringResource(R.string.home_abi), Build.SUPPORTED_ABIS.joinToString(", "))
Spacer(Modifier.height(24.dp))
Spacer(Modifier.height(16.dp))
InfoCardItem(stringResource(R.string.home_fingerprint), Build.FINGERPRINT)
Spacer(Modifier.height(24.dp))
InfoCardItem(stringResource(R.string.home_securitypatch), Build.VERSION.SECURITY_PATCH)
Spacer(Modifier.height(24.dp))
Spacer(Modifier.height(16.dp))
InfoCardItem(stringResource(R.string.home_selinux_status), getSELinuxStatus())
val copiedMessage = stringResource(R.string.home_copied_to_clipboard)
TextButton(
modifier = Modifier.align(Alignment.End),
onClick = {
val cm = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
cm.setPrimaryClip(ClipData.newPlainText("KernelSU", contents.toString()))
scope.launch { snackbarHost.showSnackbar(copiedMessage) }
},
content = { Text(stringResource(android.R.string.copy)) }
)
}
}
}
fun getManagerVersion(context: Context): Pair<String, Int> {
val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
return Pair(packageInfo.versionName, packageInfo.versionCode)
}
@Preview
@Composable
private fun StatusCardPreview() {

View File

@@ -24,7 +24,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ksuApp
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.util.installModule
import me.weishu.kernelsu.ui.util.reboot
@@ -36,7 +35,6 @@ import java.util.*
* @author weishu
* @date 2023/1/1.
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@Destination
fun InstallScreen(navigator: DestinationsNavigator, uri: Uri) {
@@ -73,7 +71,7 @@ fun InstallScreen(navigator: DestinationsNavigator, uri: Uri) {
val format = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault())
val date = format.format(Date())
val file = File(
ksuApp.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
"KernelSU_install_log_${date}.log"
)
file.writeText(text)

View File

@@ -2,49 +2,51 @@ 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
import androidx.compose.material.pullrefresh.PullRefreshIndicator
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
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.google.accompanist.swiperefresh.SwipeRefresh
import com.google.accompanist.swiperefresh.rememberSwipeRefreshState
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.launch
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.ConfirmDialog
import me.weishu.kernelsu.ui.component.ConfirmResult
import me.weishu.kernelsu.ui.screen.destinations.InstallScreenDestination
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.util.overlayFsAvailable
import me.weishu.kernelsu.ui.util.toggleModule
import me.weishu.kernelsu.ui.util.uninstallModule
import me.weishu.kernelsu.ui.util.*
import me.weishu.kernelsu.ui.viewmodel.ModuleViewModel
@OptIn(ExperimentalMaterial3Api::class)
@Destination
@Composable
fun ModuleScreen(navigator: DestinationsNavigator) {
val viewModel = viewModel<ModuleViewModel>()
val snackBarHost = LocalSnackbarHost.current
val scope = rememberCoroutineScope()
LaunchedEffect(Unit) {
if (viewModel.moduleList.isEmpty()) {
@@ -52,11 +54,17 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
}
}
Scaffold(
topBar = {
TopBar()
},
floatingActionButton = {
val isSafeMode = Natives.isSafeMode
val hasMagisk = hasMagisk()
val hideInstallButton = isSafeMode || hasMagisk
Scaffold(topBar = {
TopBar()
}, floatingActionButton = if (hideInstallButton) {
{ /* Empty */ }
} else {
{
val moduleInstall = stringResource(id = R.string.module_install)
val selectZipLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult()
@@ -83,103 +91,205 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
text = { Text(text = moduleInstall) },
)
}
) { innerPadding ->
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)
val successUninstall = stringResource(R.string.module_uninstall_success)
val swipeState = rememberSwipeRefreshState(viewModel.isRefreshing)
// TODO: Replace SwipeRefresh with RefreshIndicator when it's ready
if (Natives.getVersion() < 8) {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text(stringResource(R.string.require_kernel_version_8))
}
return@Scaffold
}
SwipeRefresh(
state = swipeState,
onRefresh = {
scope.launch { viewModel.fetchModuleList() }
},
modifier = Modifier
.padding(innerPadding)
.padding(16.dp)
.fillMaxSize()
) {
val isOverlayAvailable = overlayFsAvailable()
if (!isOverlayAvailable) {
swipeState.isRefreshing = false
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text(stringResource(R.string.module_overlay_fs_not_available))
}
return@SwipeRefresh
}
val isEmpty = viewModel.moduleList.isEmpty()
if (isEmpty) {
swipeState.isRefreshing = false
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text(stringResource(R.string.module_empty))
}
} else {
LazyColumn(
verticalArrangement = Arrangement.spacedBy(15.dp),
contentPadding = remember { PaddingValues(bottom = 16.dp + 56.dp /* Scaffold Fab Spacing + Fab container height */ ) }
}) { innerPadding ->
ConfirmDialog()
when {
hasMagisk -> {
Box(
modifier = Modifier
.fillMaxSize()
.padding(24.dp),
contentAlignment = Alignment.Center
) {
items(viewModel.moduleList) { module ->
var isChecked by rememberSaveable(module) { mutableStateOf(module.enabled) }
ModuleItem(module,
isChecked,
onUninstall = {
scope.launch {
val result = uninstallModule(module.id)
if (result) {
viewModel.fetchModuleList()
}
snackBarHost.showSnackbar(
if (result) {
successUninstall.format(module.name)
} else {
failedUninstall.format(module.name)
}
)
}
},
onCheckChanged = {
val success = toggleModule(module.id, !isChecked)
if (success) {
isChecked = it
scope.launch {
viewModel.fetchModuleList()
}
} else scope.launch {
val message = if (isChecked) failedDisable else failedEnable
snackBarHost.showSnackbar(message.format(module.name))
}
}
)
// fix last item shadow incomplete in LazyColumn
Spacer(Modifier.height(1.dp))
}
Text(
stringResource(R.string.module_magisk_conflict),
textAlign = TextAlign.Center,
)
}
}
else -> {
ModuleList(
viewModel = viewModel, modifier = Modifier
.padding(innerPadding)
.fillMaxSize()
) {
navigator.navigate(InstallScreenDestination(it))
}
}
}
}
}
@OptIn(ExperimentalMaterialApi::class)
@Composable
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)
val successUninstall = stringResource(R.string.module_uninstall_success)
val reboot = stringResource(id = R.string.reboot)
val rebootToApply = stringResource(id = R.string.reboot_to_apply)
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 dialogHost = LocalDialogHost.current
val snackBarHost = LocalSnackbarHost.current
suspend fun onModuleUninstall(module: ModuleViewModel.ModuleInfo) {
val confirmResult = dialogHost.showConfirm(
moduleStr,
content = moduleUninstallConfirm.format(module.name),
confirm = uninstall,
dismiss = cancel
)
if (confirmResult != ConfirmResult.Confirmed) {
return
}
val success = uninstallModule(module.id)
if (success) {
viewModel.fetchModuleList()
}
val message = if (success) {
successUninstall.format(module.name)
} else {
failedUninstall.format(module.name)
}
val actionLabel = if (success) {
reboot
} else {
null
}
val result = snackBarHost.showSnackbar(message, actionLabel = actionLabel)
if (result == SnackbarResult.ActionPerformed) {
reboot()
}
}
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),
contentPadding = remember {
PaddingValues(
start = 16.dp,
top = 16.dp,
end = 16.dp,
bottom = 16.dp + 16.dp + 56.dp /* Scaffold Fab Spacing + Fab container height */
)
},
) {
val isEmpty = viewModel.moduleList.isEmpty()
if (isEmpty) {
item {
Box(
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) }
val scope = rememberCoroutineScope()
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)
if (success) {
isChecked = it
scope.launch {
viewModel.fetchModuleList()
val result = snackBarHost.showSnackbar(
rebootToApply, actionLabel = reboot
)
if (result == SnackbarResult.ActionPerformed) {
reboot()
}
}
} else scope.launch {
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))
}
}
PullRefreshIndicator(
refreshing = viewModel.isRefreshing, state = refreshState, modifier = Modifier.align(
Alignment.TopCenter
)
)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopBar() {
TopAppBar(
title = { Text(stringResource(R.string.module)) }
)
TopAppBar(title = { Text(stringResource(R.string.module)) })
}
@Composable
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(),
@@ -261,6 +371,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) },
@@ -289,6 +416,7 @@ fun ModuleItemPreview() {
enabled = true,
update = true,
remove = true,
updateJson = ""
)
ModuleItem(module, true, {}, {})
ModuleItem(module, true, "", {}, {}, {})
}

View File

@@ -1,27 +1,39 @@
package me.weishu.kernelsu.ui.screen
import android.content.Intent
import android.net.Uri
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Info
import androidx.compose.material.icons.filled.BugReport
import androidx.compose.material.icons.filled.ContactPage
import androidx.compose.material.icons.filled.RemoveModerator
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
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.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.alorma.compose.settings.ui.*
import androidx.core.content.FileProvider
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import me.weishu.kernelsu.BuildConfig
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.util.LinkifyText
import me.weishu.kernelsu.ui.component.AboutDialog
import me.weishu.kernelsu.ui.component.LoadingDialog
import me.weishu.kernelsu.ui.component.SwitchItem
import me.weishu.kernelsu.ui.util.LocalDialogHost
import me.weishu.kernelsu.ui.util.getBugreportFile
/**
* @author weishu
* @date 2023/1/1.
*/
@OptIn(ExperimentalMaterial3Api::class)
@Destination
@Composable
fun SettingScreen(navigator: DestinationsNavigator) {
@@ -33,47 +45,70 @@ fun SettingScreen(navigator: DestinationsNavigator) {
})
}
) { paddingValues ->
LoadingDialog()
var openDialog by remember { mutableStateOf(false) }
if (openDialog) {
AlertDialog(
onDismissRequest = {
openDialog = false
},
title = {
Text(text = stringResource(id = R.string.about))
},
text = {
SupportCard()
},
confirmButton = {
TextButton(
onClick = {
openDialog = false
}
) {
Text(stringResource(id = android.R.string.ok))
}
},
)
}
val showAboutDialog = remember { mutableStateOf(false) }
AboutDialog(showAboutDialog)
Column(modifier = Modifier.padding(paddingValues)) {
SettingsSwitch(
title = {
Text(stringResource(id = R.string.settings_system_rw))
},
subtitle = {
Text(stringResource(id = R.string.settings_system_rw_summary))
val context = LocalContext.current
val scope = rememberCoroutineScope()
val dialogHost = LocalDialogHost.current
var umountChecked by rememberSaveable {
mutableStateOf(Natives.isDefaultUmountModules())
}
SwitchItem(
icon = Icons.Filled.RemoveModerator,
title = stringResource(id = R.string.settings_umount_modules_default),
summary = stringResource(id = R.string.settings_umount_modules_default_summary),
checked = umountChecked
) {
if (Natives.setDefaultUmountModules(it)) {
umountChecked = it
}
}
ListItem(
leadingContent = { Icon(Icons.Filled.BugReport, stringResource(id = R.string.send_log)) },
headlineContent = { Text(stringResource(id = R.string.send_log)) },
modifier = Modifier.clickable {
scope.launch {
val bugreport = dialogHost.withLoading {
withContext(Dispatchers.IO) {
getBugreportFile(context)
}
}
val uri: Uri =
FileProvider.getUriForFile(
context,
"${BuildConfig.APPLICATION_ID}.fileprovider",
bugreport
)
val shareIntent = Intent(Intent.ACTION_SEND)
shareIntent.putExtra(Intent.EXTRA_STREAM, uri)
shareIntent.setDataAndType(uri, "application/zip")
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
context.startActivity(
Intent.createChooser(
shareIntent,
context.getString(R.string.send_log)
)
)
}
}
)
SettingsMenuLink(title = {
Text(stringResource(id = R.string.about))
},
onClick = {
openDialog = true
val about = stringResource(id = R.string.about)
ListItem(
leadingContent = { Icon(Icons.Filled.ContactPage, stringResource(id = R.string.about)) },
headlineContent = { Text(about) },
modifier = Modifier.clickable {
showAboutDialog.value = true
}
)
}
@@ -92,19 +127,3 @@ private fun TopBar(onBack: () -> Unit = {}) {
},
)
}
@Preview
@Composable
private fun SupportCard() {
Column(
modifier = Modifier
.fillMaxWidth()
) {
CompositionLocalProvider(LocalTextStyle provides MaterialTheme.typography.bodyMedium) {
LinkifyText("Author: weishu")
LinkifyText("Github: https://github.com/tiann/KernelSU")
LinkifyText("Telegram: https://t.me/KernelSU")
LinkifyText("QQ: https://pd.qq.com/s/8lipl1brp")
}
}
}

View File

@@ -1,51 +1,45 @@
package me.weishu.kernelsu.ui.screen
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.util.Log
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
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.MoreVert
import androidx.compose.material.pullrefresh.PullRefreshIndicator
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.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import coil.ImageLoader
import coil.compose.AsyncImage
import coil.compose.rememberAsyncImagePainter
import coil.compose.rememberImagePainter
import coil.decode.DataSource
import coil.fetch.DrawableResult
import coil.fetch.FetchResult
import coil.fetch.Fetcher
import coil.request.CachePolicy
import coil.request.ImageRequest
import coil.request.Options
import com.google.accompanist.swiperefresh.SwipeRefresh
import com.google.accompanist.swiperefresh.rememberSwipeRefreshState
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.launch
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.ConfirmDialog
import me.weishu.kernelsu.ui.component.SearchAppBar
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.screen.destinations.AppProfileScreenDestination
import me.weishu.kernelsu.ui.viewmodel.SuperUserViewModel
import me.zhanghai.android.appiconloader.coil.AppIconKeyer
import java.util.*
@OptIn(ExperimentalMaterial3Api::class)
@OptIn(ExperimentalMaterialApi::class)
@Destination
@Composable
fun SuperUserScreen() {
fun SuperUserScreen(navigator: DestinationsNavigator) {
val viewModel = viewModel<SuperUserViewModel>()
val snackbarHost = LocalSnackbarHost.current
val scope = rememberCoroutineScope()
LaunchedEffect(Unit) {
@@ -60,53 +54,107 @@ fun SuperUserScreen() {
title = { Text(stringResource(R.string.superuser)) },
searchText = viewModel.search,
onSearchTextChange = { viewModel.search = it },
onClearClick = { viewModel.search = "" }
onClearClick = { viewModel.search = "" },
dropdownContent = {
var showDropdown by remember { mutableStateOf(false) }
IconButton(
onClick = { showDropdown = true },
) {
Icon(
imageVector = Icons.Filled.MoreVert,
contentDescription = stringResource(id = R.string.settings)
)
DropdownMenu(expanded = showDropdown, onDismissRequest = {
showDropdown = false
}) {
DropdownMenuItem(text = {
Text(stringResource(R.string.refresh))
}, onClick = {
scope.launch {
viewModel.fetchAppList()
}
showDropdown = false
})
DropdownMenuItem(text = {
Text(
if (viewModel.showSystemApps) {
stringResource(R.string.hide_system_apps)
} else {
stringResource(R.string.show_system_apps)
}
)
}, onClick = {
viewModel.showSystemApps = !viewModel.showSystemApps
showDropdown = false
})
}
}
},
)
}
) { innerPadding ->
val failMessage = stringResource(R.string.superuser_failed_to_grant_root)
// TODO: Replace SwipeRefresh with RefreshIndicator when it's ready
SwipeRefresh(
state = rememberSwipeRefreshState(viewModel.isRefreshing),
onRefresh = {
scope.launch { viewModel.fetchAppList() }
},
ConfirmDialog()
val refreshState = rememberPullRefreshState(
refreshing = viewModel.isRefreshing,
onRefresh = { scope.launch { viewModel.fetchAppList() } },
)
Box(
modifier = Modifier
.padding(innerPadding)
.fillMaxSize()
.pullRefresh(refreshState)
) {
LazyColumn {
items(viewModel.appList) { app ->
var isChecked by rememberSaveable(app) { mutableStateOf(app.onAllowList) }
AppItem(app, isChecked) { checked ->
val success = Natives.allowRoot(app.uid, checked)
if (success) {
isChecked = checked
} else scope.launch {
snackbarHost.showSnackbar(failMessage.format(app.uid))
}
LazyColumn(Modifier.fillMaxSize()) {
items(viewModel.appList, key = { it.packageName + it.uid }) { app ->
AppItem(app) {
navigator.navigate(AppProfileScreenDestination(app))
}
}
}
PullRefreshIndicator(
refreshing = viewModel.isRefreshing,
state = refreshState,
modifier = Modifier.align(Alignment.TopCenter)
)
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@OptIn(ExperimentalLayoutApi::class)
@Composable
private fun AppItem(
app: SuperUserViewModel.AppInfo,
isChecked: Boolean,
onCheckedChange: (Boolean) -> Unit
onClickListener: () -> Unit,
) {
ListItem(
headlineText = { Text(app.label) },
supportingText = { Text(app.packageName) },
modifier = Modifier.clickable(onClick = onClickListener),
headlineContent = { Text(app.label) },
supportingContent = {
Column {
Text(app.packageName)
FlowRow {
if (app.allowSu) {
LabelText(label = "ROOT")
} else {
if (Natives.uidShouldUmount(app.uid)) {
LabelText(label = "UMOUNT")
}
}
if (app.hasCustomProfile) {
LabelText(label = "CUSTOM")
}
}
}
},
leadingContent = {
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(app.icon)
.data(app.packageInfo)
.crossfade(true)
.build(),
contentDescription = app.label,
@@ -116,12 +164,26 @@ private fun AppItem(
.height(48.dp)
)
},
trailingContent = {
Switch(
checked = isChecked,
onCheckedChange = onCheckedChange,
modifier = Modifier.padding(4.dp)
)
}
)
}
@Composable
fun LabelText(label: String) {
Box(
modifier = Modifier
.padding(top = 4.dp, end = 4.dp)
.background(
Color.Black,
shape = RoundedCornerShape(4.dp)
)
) {
Text(
text = label,
modifier = Modifier.padding(vertical = 2.dp, horizontal = 5.dp),
style = TextStyle(
fontSize = 8.sp,
color = Color.White,
)
)
}
}

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