326 Commits

Author SHA1 Message Date
ShirkNeko
19a67fb76c mamager: fix the crash of Superuser in multi-user environments 2025-11-16 14:03:06 +08:00
AlexLiuDev233
3a2d55237d manager: make group shows like upstream & add some animation to SuperUser menu i18n file pick from upstream
Co-authored-by: YuKongA <70465933+YuKongA@users.noreply.github.com>
2025-11-16 13:34:26 +08:00
生于生时 亡于亡刻
98e617f1bd refactor(ksud): refactor ksud's kpm
- remove useless code
- ignore create dir all return
- when kpm file delete failed, return Error
2025-11-16 07:11:16 +08:00
AlexLiuDev233
d84a88f059 manager: disable webuix exitConfirm 2025-11-16 00:58:32 +08:00
ShirkNeko
ae7b4dcbed manager: fix MarkdownContent scrollBehavior
Co-authored-by: AlexLiuDev233 <wzylin11@outlook.com>
2025-11-16 00:02:29 +08:00
ShirkNeko
684a5d1ccd manager: display the same UID as a group
Co-authored-by: YuKongA <70465933+YuKongA@users.noreply.github.com>
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
2025-11-15 23:44:38 +08:00
Tools-app
35b02e3c73 ci: remove cache for ksud
Because it no truth save

Signed-off-by: Tools-app <localhost.hutao@gmail.com>
2025-11-15 19:57:40 +08:00
5ec1cff
db6a59ec4e kernel: file_wrapper: copy mode of original inode
Bionic uses fstat to determine whether an fd is a tty and set proper
buffering flags, so we also need to set the wrapper file's inode mode to
the original inode mode.

see:
https://cs.android.com/android/platform/superproject/main/+/main:bionic/libc/upstream-openbsd/lib/libc/stdio/makebuf.c;l=61-95;drc=9a4b68e20d617b2cb3355071521f16e8c3d538df
2025-11-15 19:54:16 +08:00
ShirkNeko
46846dce91 kernel: Utilise the existing try_umount to avoid repackaging 2025-11-15 19:29:12 +08:00
Tools-app
cd21af6728 ci: fix shared-key not find (ksud)
Signed-off-by: Tools-app <localhost.hutao@gmail.com>
2025-11-15 18:56:19 +08:00
生于生时 亡于亡刻
92a483d222 ksud: Optimise ksud (#576)
* opt: Optimize printing for result isn't successful
- print chain && backtrace to stderr

Signed-off-by: Tools-app <localhost.hutao@gmail.com>

* ci(ksud): add CARGO_TERM_COLOR for build

Signed-off-by: Tools-app <localhost.hutao@gmail.com>

* fix(ksud): fix uninstall package name is `me.weishu.kernelsu`

Signed-off-by: Tools-app <localhost.hutao@gmail.com>

* fix(ksud): Reverted to a private function for get_kernel_version

Signed-off-by: Tools-app <localhost.hutao@gmail.com>

* chore: format code for magic_mount.rs

Signed-off-by: Tools-app <localhost.hutao@gmail.com>

* fix: fix rustfmt

Signed-off-by: Tools-app <localhost.hutao@gmail.com>

* feat: Move the statement to the correct place && remove allow dead_code

Signed-off-by: Tools-app <localhost.hutao@gmail.com>

---------

Signed-off-by: Tools-app <localhost.hutao@gmail.com>
2025-11-15 18:25:17 +08:00
5ec1cff
04ca981e4d kernel: no need to remark process on post-fs-data and boot-completed
- Remark on post-fs-data may unmark zygote unexpectedly, and there is no
necessity to remark on these stages, so simply remove them.
2025-11-15 17:27:48 +08:00
ShirkNeko
83209a5259 ci: Fixed build information 2025-11-15 12:47:11 +08:00
YC酱luyancib
3cfc6d6a31 Manager/CI: Add spoofed manager build (#570)
* manager: add script for randomizing pkg name

Signed-off-by: rsuntk <rsuntk@yukiprjkt.my.id>
Co-Authored-By: YC酱luyancib <luyancib@qq.com>

* manager: Update randomizer to avoid bug

Revert "manager: Update randomizer to avoid bug"

This reverts commit af9205e70a11db3e3d43bb34de880bbd6b4185b5.

manager: Update randomizer to avoid bug

* mamager: Update randomizer to fix error
fixed
> Task :app:compileReleaseAidl FAILED
ERROR: /home/runner/work/SukiSU-Ultra/SukiSU-Ultra/manager/app/src/main/aidl/org/knifhr/zako/IKsuInterface.aidl:7.1-10: IKsuInterface should be declared in a file called com/sukisu/zako/IKsuInterface.aidl

* manager:clean randomizer

* ci:add spoofed manager build with matrix

* 更新 build-manager.yml

* 更新 build-manager.yml

* fix

* Revert "更新 build-manager.yml"

This reverts commit da80e3f13a.

* ksubot: make MESSAGE_THREAD_ID optional

---------

Signed-off-by: rsuntk <rsuntk@yukiprjkt.my.id>
Co-authored-by: rifsxd <rifat.44.azad.rifs@gmail.com>
Co-authored-by: 5ec1cff <ewtqyqyewtqyqy@gmail.com>
2025-11-15 10:58:10 +08:00
Wang Han
01ac06c3fd kernel: Prune allowlist only after boot completed
For unknown reason, packages.list is not reliable during boot for oplus
devices, so we have to disable pruning and re-run pruning after boot.
2025-11-15 10:54:19 +08:00
ShirkNeko
906c4bdb01 manager: bump susfs version to 2.0.0
- Remove versions below susfs 2.0.0 that are no longer supported.
2025-11-14 21:53:17 +08:00
weishu
c17d7b38eb ci: fix android16-6.12 gki build (#2931) 2025-11-14 19:02:48 +08:00
KOWX712
fa57ccccf4 manager: introduce webui package manager api (#2928)
this is a squash of:

* manager: introduce app package info API for webui-next
(KernelSU-Next/KernelSU-Next@58167a4)

* manager: sort a-z order for webui-next list packages api
(KernelSU-Next/KernelSU-Next@4a9733c)

* manager: implement getPackagesIcons and cacheAllPackageIcons api to
webui-next (KernelSU-Next/KernelSU-Next@a361fa3)

* manager/webui: let getPackagesIcons generate icon and store in cache
as well when called (KernelSU-Next/KernelSU-Next@6afa86d)

* POC: load icon app via ksu://icon/[packageName] (KernelSU-Next#674)
(KernelSU-Next/KernelSU-Next@bc9927b)

* manager: refine webui package manager (KOWX712/KernelSU@0400c42)

Co-Authored-By: Rifat Azad <33044977+rifsxd@users.noreply.github.com>
Co-Authored-By: Fahrez256Bit
<167403685+fahrez256@users.noreply.github.com>
Signed-off-by: KOWX712 <leecc0503@gmail.com>

---------

Signed-off-by: KOWX712 <leecc0503@gmail.com>
Co-authored-by: Rifat Azad <33044977+rifsxd@users.noreply.github.com>
Co-authored-by: Fahrez256Bit <167403685+fahrez256@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-14 19:02:21 +08:00
ShirkNeko
7e7713ee4a kernel/sulog: Optimise the sulog log format 2025-11-14 12:55:57 +08:00
ShirkNeko
7afcdb3059 kernel: Optimise sulog to prevent deadlocks caused by global lock contexts. 2025-11-14 12:29:55 +08:00
ShirkNeko
5df821ed41 kernel: Resolved potential deadlock issues arising from operations not being performed within locks. 2025-11-14 11:55:06 +08:00
YuKongA
12fc2e6d5e userspace: remove vendor_boot selection logic
- Only patch it when user actively selects vendor_boot.
2025-11-13 20:36:44 +08:00
5ec1cff
9f869090d2 kernel: refine syscall_hook_manager
- Don't unmark process when setuid if syscall tracepoint is in use
- Remark process when app profile updated
- Ensure zygote is marked on first boot
2025-11-13 20:09:32 +08:00
ShirkNeko
bb8b991110 kernel: restart enable sulog for LKM 2025-11-13 17:46:08 +08:00
ShirkNeko
10548f9243 kernel: fix build 2025-11-13 17:06:27 +08:00
weishu
96d33e62bb kernel: fix zygote mark on first boot (#2924) 2025-11-13 16:31:26 +08:00
ShirkNeko
7be8c15b85 kernel: Remove redundant ksu_handle_inode_permission hooks, calling only for manual_su 2025-11-13 15:02:20 +08:00
ShirkNeko
14bb6afd0b New Crowdin updates (#568)
* New translations strings.xml (Russian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Chinese Simplified)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Chinese Traditional, Hong Kong)
2025-11-13 13:23:31 +08:00
ShirkNeko
54dad4ceb2 assets: bump KPM version to 0.12.2 2025-11-12 18:52:22 +08:00
ShirkNeko
a60395ba35 manager: install: do not always recommended to select boot partition if not rooted
Co-authored-by: YuKongA <70465933+YuKongA@users.noreply.github.com>
2025-11-12 18:04:49 +08:00
5ec1cff
095385f814 kernel: fix wrong show_fdinfo impl
Signed-off-by: Wang Han <416810799@qq.com>
2025-11-12 13:25:20 +08:00
ShirkNeko
7e595e1730 kernel: Public ksu_handle_sys_reboot
- clean code
2025-11-11 16:49:09 +08:00
Wang Han
ded31c2043 kernel: Fix task flag marking for root and shell UID
Signed-off-by: Wang Han <416810799@qq.com>
Co-authored-by: 5ec1cff <56485584+5ec1cff@users.noreply.github.com>
2025-11-11 16:26:37 +08:00
ShirkNeko
a7f840d811 manager: fix template status display issue (#2910)
manager: 修复模板状态显示问题 (#2910)

修复当 app 设置过模板后再使用自定义配置,离开页面后再次打开,管理器显示应用使用的是模板而不是自定义配置的问题

- bump AGP version

Co-authored-by: u9521 <63995396+u9521@users.noreply.github.com>
2025-11-11 16:00:54 +08:00
Ylarod
05cca26075 ci: move workflow_dispatch to versioned ci workflow
Signed-off-by: Faris <rissu.ntk@gmail.com>
2025-11-11 15:40:09 +08:00
ShirkNeko
5ce6c210c4 manager: install: add choose partition support
manager: fix KsuCli cmd

userspace: reuse choose_boot_device

- manager: simplify find boot image

Co-authored-by: weishu <twsxtd@gmail.com>
Co-authored-by: YuKongA <70465933+YuKongA@users.noreply.github.com>
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
2025-11-11 15:16:11 +08:00
ShirkNeko
8f49898155 kernel: Use task work to install fd
There are many fd related functions that can sleep, so we have no choice
but move operations to task work. Also close fd when copy_to_user fails.

Co-authored-by: Wang Han <416810799@qq.com>
2025-11-11 01:10:36 +08:00
ShirkNeko
fd3a22360a kernel: Clean code build 2025-11-09 23:18:48 +08:00
Wang Han
ef36a36e9a kernel: Don't save allowlist on module exit
This is not needed and may trigger UAF as work is async.
2025-11-09 23:14:13 +08:00
ShirkNeko
7a1a08064b manager: After flashing anykernel3, release ksud. 2025-11-09 21:26:08 +08:00
AlexLiuDev233
36862d6175 manager: if manager incompatible with current kernel, don't save ksud (#2895)
I think we should'nt install kernelsu's userspace when manager
incompatible with current kernel
this maybe cause a lot of bug, for example, when user install 2.x
kernelsu manager, but not update
his kernel to 2.x, ksud will return "kernel version 0", because ksud
incompatible with old supercall impl
2025-11-09 21:14:40 +08:00
ShirkNeko
cda7e4c6c0 Clean up kernel code (#2898)
1) Fix memory leak of callback head in allowlist.c
2) Remove duplicated logic and incorrect log in kernel_umount.c
3) Prevent sleep in kprobe context in ksud.c
4) Remove useless is_unsupported_uid, use euid for security enhance,
   add FIXME in setuid_hook.c
5) Remove useless fd argument for execve hook, fix incorrent pointer
   usage in syscall_hook_manager.c and sucompat.c
6) Use correct errno in supercalls.c

---------

Co-authored-by: Ylarod <me@ylarod.cn>
2025-11-09 19:20:30 +08:00
ShirkNeko
0b63cc445c kernel: Expose the ksu_handle_sys_read hook 2025-11-09 18:11:30 +08:00
ShirkNeko
2433ced81a kernel: Rollback disable_seccomp
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
Co-authored-by: Faris <rissu.ntk@gmail.com>
2025-11-09 17:00:43 +08:00
ShirkNeko
1f04f13e44 kernel: Remove redundant checks 2025-11-09 16:41:54 +08:00
ShirkNeko
184467c691 kernel: Undo some changes 2025-11-09 16:09:59 +08:00
ShirkNeko
05ed1a3714 fix build 2025-11-09 14:17:27 +08:00
ShirkNeko
163531fcd2 kernel: Simplify state management logic 2025-11-09 14:07:40 +08:00
ShirkNeko
049956aaa9 Fixes only hook in LKM mode __NR_newfstatat ,__NR_faccessat ,__NR_execve system calls 2025-11-09 12:16:23 +08:00
ShirkNeko
6530d06710 kernel: clean build 2025-11-09 04:12:11 +08:00
ShirkNeko
88135d8363 Attempt to refactor and migrate inode_permission, bprm_check_security, and task_alloc entirely to syscall_hook_manager 2025-11-09 02:52:46 +08:00
ShirkNeko
548258f922 kernel: Rewrite the kernel source code (#554)
* clean unused header

* on_module_mounted in ksud.c

* refact: use app_profile

* unified hook manager

* add zygote to hook target

* move reboot hook to supercall.c

* refactor: kernel_umount setuid_hook

* update mark rules, add init mark tracker

* remove reboot from check_syscall_fastpath

* update setuid_hook, remove uneeded sucompat enable

* log freely

* kernel: Migrate kprobe hook configuration items

* kernel: fix build

* cli: add ksud debug mark

* Fix rustfmt warning

---------

Co-authored-by: Ylarod <me@ylarod.cn>
Co-authored-by: Wang Han <416810799@qq.com>
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
2025-11-09 01:14:26 +08:00
weishu
46b9f5fb4b kernel: fix put_task if alloc failed. 2025-11-08 21:44:04 +08:00
ShirkNeko
413e9ab8a9 kernel: Resolved compatibility issues with su when using manual hooks 2025-11-08 20:52:29 +08:00
ShirkNeko
c3644da85b assets: Bump KPM version to 0.12.1 2025-11-08 20:05:59 +08:00
生于生时 亡于亡刻
7b4b5b431f fix: fix ksud install error (#550)
Signed-off-by: Tools-app <localhost.hutao@gmail.com>
2025-11-08 17:31:58 +05:30
ShirkNeko
7479c0b81b kernel: Fix build 2025-11-08 19:54:20 +08:00
ShirkNeko
0381d12be2 kernel: Resolve implicit declaration conflicts 2025-11-08 19:47:03 +08:00
Wang Han
4425c88d5a Fix missing unlock on error path 2025-11-08 19:41:11 +08:00
weishu
7828c5c107 kernel: fix save allowlist 2025-11-08 19:40:16 +08:00
ShirkNeko
76046c84cd kernel: remove unused kernel_compat
Co-authored-by: weishu <twsxtd@gmail.com>
2025-11-08 19:39:41 +08:00
weishu
623dd15cbf kernel: Use real_parent to avoid interference from ptrace. 2025-11-08 19:30:55 +08:00
ShirkNeko
ab13ed5c16 kernel: remove unused wrapper for
Co-authored-by: weishu <twsxtd@gmail.com>
2025-11-08 19:30:44 +08:00
weishu
e171ca15cb kernel: remove ksu_compat_{open,read,write} because we're in the right context now
Co-authored-by: weishu <twsxtd@gmail.com>
2025-11-08 19:28:25 +08:00
ShirkNeko
4fc369a059 kernel: remove workqueue for allowlist
Co-authored-by: weishu <twsxtd@gmail.com>
2025-11-08 19:18:20 +08:00
ShirkNeko
18ad2afadb Reworking fdwrapper
Co-authored-by: 5ec1cff <ewtqyqyewtqyqy@gmail.com>
Co-authored-by: 5ec1cff <56485584+5ec1cff@users.noreply.github.com>
Co-authored-by: Ylarod <me@ylarod.cn>
2025-11-08 19:03:14 +08:00
ShirkNeko
3badbcd4bc assets: Bump KPM version to 0.13.0 2025-11-08 18:38:53 +08:00
technotic
1b5b235bd9 add include for crc32.h in sulog.h (for dedup_calc_hash) (#548)
Co-authored-by: technotic <pixie@technotic.us>
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
2025-11-08 18:12:38 +08:00
AlexLiuDev233
fdf5e7104e refactor: kpm: memory management migrate to sukisu side (#539)
* refactor: kpm: memory management migrate to sukisu side

* fix: build warning in some gki2 device

fix stack frame size warning (maybe) in gki2 device, specialy in ShirkNeko's device

* chore: use pr_info instead of printk

* feat: check the validity of pointers sent from user space
Sometimes, ksud or other root processes might request a kpm ioctl,
but data incorrectly, such as invalid pointer,
which cause the kernel to crash.

If the request is made by ksud at boot time, the situation is even worse,
as it can cause the system to enter the boot loop.

Therefore, I believe we need to check pointer integrity in kernel space to fix this problem.

---------

Co-authored-by: Saksham <typeflu@gmail.com>
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
2025-11-08 18:11:29 +08:00
生于生时 亡于亡刻
ed6b2e0a8e opt: Optimize the kpm && uid_scanner (#549)
* opt: Optimize the structure of kpm.rs

Signed-off-by: Tools-app <localhost.hutao@gmail.com>

* opt: Optimize the uid_scanner startup logic in userspace && code style

Signed-off-by: Tools-app <localhost.hutao@gmail.com>

* opt: rename kpm's ioctl

Signed-off-by: Tools-app <localhost.hutao@gmail.com>

* opt: rename ksucalls::KsuKpmCmd's arg2..arg5

using
```rust
pub struct KsuKpmCmd {
    pub control_code: u64,
    pub arg1: u64,
    pub arg2: u64,
    pub result_code: u64,
}
```
This makes it easier to distinguish parameters.

Signed-off-by: Tools-app <localhost.hutao@gmail.com>

---------

Signed-off-by: Tools-app <localhost.hutao@gmail.com>
2025-11-08 13:43:32 +05:30
AlexLiuDev233
704f7cba32 kernel: core_hook: disable seccomp in 5.10.2- for allowed uids (#545)
* kernel: core_hook: disable seccomp in 5.10.2- for allowed uids

we dont have those new fancy things upstream has
lets just do original thing where we disable seccomp

* Update kernel/core_hook.c

* fmt

---------

Co-authored-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
Co-authored-by: Saksham <saksham.mac@icloud.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-08 12:46:25 +08:00
ShirkNeko
860bdce295 ksud :fmt 2025-11-08 12:41:03 +08:00
生于生时 亡于亡刻
d8a8ef6458 fix: fix self exe path error && opt: Optimize ensure_dir_exists processing (#541)
* fix: fix self exe path error

* opt: Optimize ensure_dir_exists processing

---------

Signed-off-by: Tools-app <localhost.hutao@gmail.com>
2025-11-08 12:34:22 +08:00
ShirkNeko
d37a78ea2d fix build & cleanup 2025-11-08 11:48:35 +08:00
Ylarod
6c9bf69718 fix build 2025-11-08 11:37:07 +08:00
Ylarod
776bcc4d5d rename to proxy_file 2025-11-08 11:36:15 +08:00
ShirkNeko
bf5cb885b5 kernel: remove devpts hook 2025-11-08 11:28:23 +08:00
Wang Han
a533a490bd Use force_sig(SIGKILL) to kill process 2025-11-08 01:34:44 +08:00
Shadichy
c6d9f76c7b kernel: Refactor selinux/selinux.c (#2881)
Signed-off-by: shadichy <shadichy@blisslabs.org>
Co-authored-by: Wang Han <416810799@qq.com>
2025-11-08 01:34:23 +08:00
Wang Han
66032391af Switch kretprobe to heap (#2880)
Co-authored-by: Ylarod <me@ylarod.cn>
2025-11-07 18:39:53 +08:00
Wang Han
da0e16bd26 Replace mutex with spinlock for tracepoint registration (#2882) 2025-11-07 18:37:12 +08:00
ShirkNeko
53d763cdf9 manager: Implement editable and removable mount points for LKM 2025-11-07 15:37:04 +08:00
ShirkNeko
9ebddde0d5 kernel: Avoid calling umount whilst holding a spinlock. 2025-11-07 14:23:58 +08:00
ShirkNeko
03a164ebb7 kernel: By default, MNT_DETACH is used as the value for the mount point. 2025-11-07 13:37:09 +08:00
ShirkNeko
4769065cfc ksud: Implementing editable, removable mount points 2025-11-07 13:15:07 +08:00
ShirkNeko
9b209765c4 kernel: Implementing editable, removable mount points 2025-11-07 12:16:42 +08:00
ShirkNeko
d7c101e244 kernel: Fix compilation 2025-11-07 11:33:02 +08:00
Ylarod
a32f89403b ci: update build 2025-11-07 11:12:21 +08:00
ShirkNeko
2cd673d776 manager: fix where the option displays "Temporary enable" after device reboot
Co-authored-by: YuKongA <70465933+YuKongA@users.noreply.github.com>
2025-11-07 11:08:27 +08:00
Ylarod
14fea6f8a3 build: remove -Wno-implicit-function-declaration 2025-11-07 11:02:48 +08:00
ShirkNeko
02f1aec6e9 ksud: Fix clippy 2025-11-07 00:11:02 +08:00
5ec1cff
826661dffb feature: add devpts fd wrapper (#21)
This feature is intended to resolve devpts problem.
2025-11-06 23:56:53 +08:00
ShirkNeko
f86c71efc5 Compilation fix 2025-11-06 23:26:55 +08:00
Ylarod
06018a2f03 revert: still using workqueue for allowlist 2025-11-06 23:05:29 +08:00
Ylarod
a2193841d5 skip init_features in safe mode 2025-11-06 23:03:43 +08:00
Ylarod
1324a7f54e fix: enhanced security register 2025-11-06 23:02:27 +08:00
Ylarod
5df9431a22 kill pgrp in enhanced security 2025-11-06 23:01:59 +08:00
Ylarod
e54989e51a add mutex for sucompat mark 2025-11-06 23:01:45 +08:00
Ylarod
cf50be122e fix: sucompat (#2874)
Co-authored-by: Wang Han <416810799@qq.com>
2025-11-06 23:01:28 +08:00
ShirkNeko
7f9048724f fix 2025-11-06 22:57:13 +08:00
ShirkNeko
3dde6d9a25 manager: some ui changes
* Steeing: add enhanced security dropdown
* Settings: allow change module update check
* Settings: allow always enable/disable feat
* misc: update all deps

---------

Co-authored-by: weishu <twsxtd@gmail.com>
Co-authored-by: Ylarod <me@ylarod.cn>
Co-authored-by: YuKongA <70465933+YuKongA@users.noreply.github.com>
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
2025-11-06 22:54:43 +08:00
ShirkNeko
132e9ef8ed kernel: Resolve compilation issues 2025-11-06 13:48:26 +08:00
ShirkNeko
e6436b340c kernel: clean headers
Co-authored-by: weishu <twsxtd@gmail.com>
2025-11-06 13:08:01 +08:00
weishu
9cdf98782d kernel: Set the tracepoint flag in a tracepoint manner 2025-11-06 13:02:13 +08:00
Ylarod
dece57cacf feature: add enhanced security (#2873) 2025-11-06 12:59:09 +08:00
ShirkNeko
3f07ea29ae manager: remove outdated lkm condition
Co-authored-by: weishu <twsxtd@gmail.com>
2025-11-06 12:58:44 +08:00
weishu
c8e103062a kernel: remove unused workqueue 2025-11-06 12:56:00 +08:00
Ylarod
91312effba fix sepolicy patch hint (#2872) 2025-11-06 12:53:09 +08:00
Ylarod
fd60cda3b3 fix: mark tif (#2871) 2025-11-06 12:52:52 +08:00
ShirkNeko
5323a500dd kernel: use sys_enter tracepoint for sucompat (#533)
* use sys_enter tracepoint for sucompat

* update sucompat rules

* clean tif mark

* mark tif after load allow list

* clear all tif first, then mark target

* Fix shell su

* allow when escape

* fix bugs

* kernel: Resolve logical inconsistencies

---------

Co-authored-by: Ylarod <me@ylarod.cn>
Co-authored-by: weishu <twsxtd@gmail.com>
2025-11-06 12:45:37 +08:00
ShirkNeko
0ce7bc2627 kernel: Migrate manual_su to ioctl 2025-11-06 02:52:14 +08:00
libingxuan
c9c62b25d2 support mainline kernel (#2869) 2025-11-05 23:00:42 +08:00
ShirkNeko
f8904b1b02 kernel: Resolved permission verification issue 2025-11-05 19:04:51 +08:00
ShirkNeko
89ce65e8ba Use a more appropriate minor version number 2025-11-05 16:41:30 +08:00
ShirkNeko
994fdfddf2 kernel: Use CONFIG_KSU_MANUAL_SU to protect MANUAL_SU 2025-11-05 16:17:54 +08:00
ShirkNeko
557e7f8153 bump KSU_VERSION_API to 4.0.0 2025-11-05 16:07:23 +08:00
backslashxx
9e9bb685f0 kernel: supercall: allow escalation on ioctl interface (#2862)
Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
2025-11-05 15:52:00 +08:00
Wang Han
99bec0e439 Fix legacy prctl check condition (#2864) 2025-11-05 15:47:03 +08:00
ShirkNeko
0400b94674 v2.0.0 2025-11-05 15:43:10 +08:00
ShirkNeko
247f7d4aee Kernel: Enable processes with corresponding UIDs to utilise netlink, and optimise netlink functionality 2025-11-05 15:41:14 +08:00
ShirkNeko
088ce97697 kernel: Remove prctl; use netlink communication to control manual_su 2025-11-05 03:53:54 +08:00
ShirkNeko
c0a86544d8 kernel: Remove macro definitions, pass variables using ccflags -y, and reapply manual su protection.
kernel: stop printing useless message unless its ddk environment
* In-tree build show empty KDIR

-- KDIR:
-- MDIR: /home/runner/work/KernelSU-Test/KernelSU-Test/kernel_414/KernelSU/kernel
  AR      drivers/iommu/built-in.o
  CC      drivers/input/misc/uinput.o
-- KernelSU version: 12329
-- KernelSU: CONFIG_KSU_MANUAL_HOOK
-- Supported KernelSU Manager(s): tiann, rsuntk, 5ec1cff
  CC      drivers/kernelsu/ksu.o
  AR      drivers/input/joystick/built-in.o
  CC      drivers/hid/hid-roccat-pyra.o

Co-authored-by: Faris <rissu.ntk@gmail.com>
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
2025-11-05 02:18:38 +08:00
weishu
47bd84f3d1 kernel: init/exit umount feature 2025-11-04 22:29:55 +08:00
Ylarod
06e714b4e7 ksubot: add branch, happy 2k 2025-11-04 22:26:40 +08:00
weishu
1439e486a1 kernel: rework umount with task_work 2025-11-04 21:57:10 +08:00
ShirkNeko
801bcb0e1f Revert "Implement workqueue for unmounting" 2025-11-04 21:55:00 +08:00
Ylarod
54b5fb5fdb ignore user settings 2025-11-04 21:29:19 +08:00
Ylarod
1cc9fce2c6 rename to managedFeatures 2025-11-04 21:29:11 +08:00
ShirkNeko
46fefc299c kernel: Remove CONFIG_KSU_MANUAL_SU protection 2025-11-04 21:28:39 +08:00
ShirkNeko
23cc0ceff1 Revert "ci: bump ddk to 20251104, fix android16-6.12 lkm"
This reverts commit 257f0ca6de.
2025-11-04 21:08:24 +08:00
ShirkNeko
4a610af452 manager: Fixed warning card status error
- Reuse your own DDK
2025-11-04 20:30:04 +08:00
backslashxx
8177afa81e kernel: core_hook: provide a better reboot handler (#523)
* Revert "feat: try manual reboot hook (#521)"

This reverts commit 1853d9decf.

* kernel: core_hook: provide a better reboot handler

I propose that you pass cmd and arg as reference.
this is so we can have much more extendable use of that pointer

kernel: core_hook: provide sys_reboot handler
- 2e2727d56c

kernel: kp_ksud: add sys_reboot kp hook
- 03285886b0

I'm proposing passing arg as reference to arg pointer and also pass int cmd
we can use it to pass numbers atleast.
for advanced usage, we can use it as a delimiter so we can pass a pointer to array.

example pass a char *array[] which decays to a char ** and then use cmd as the number of array members.
we can pass the pointer of the first member of the array and use cmd as the delimiter (count) of members.

for simpler usecase, heres some that I added.

kernel: core_hook: expose  umount list on sys_reboot interface
- 352de41e4b

kernel: core_hook: expose nuke_ext4_sysfs to sys_reboot interface
- 83fc684ccb

ksud: add cmd for add-try-umount, wipe-umount-list and nuke-ext4-sysfs
- a4eab4b8c3

more usage demos
https://github.com/backslashxx/lkm_template/tree/write-pointer-on-pointer
https://github.com/backslashxx/lkm_template/tree/pointer-reuse

I actually proposed sys_reboot upstream because of this pointer that is very usable.

Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>

---------

Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
2025-11-04 19:51:40 +08:00
ShirkNeko
3588282b43 ci: build dev manager
Co-authored-by: Ylarod <me@ylarod.cn>
2025-11-04 19:49:08 +08:00
ShirkNeko
257f0ca6de ci: bump ddk to 20251104, fix android16-6.12 lkm
-kernel: Using macros to control manual su operations

Co-authored-by: Ylarod <me@ylarod.cn>
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
2025-11-04 19:44:43 +08:00
ShirkNeko
c863ff6f49 ci: Attempting once more to build the LKM using the DDK 2025-11-04 19:28:13 +08:00
ShirkNeko
e99a14290f manager: fix logical confusion 2025-11-04 12:22:49 +08:00
backslashxx
18e60ededa Reapply: "kernel: Allow to use in Private Space" (#2857)
rebase of
0576495b4b

Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
Co-authored-by: weishu <twsxtd@gmail.com>
2025-11-04 11:17:46 +08:00
ShirkNeko
22e4b69231 manager: When the version is less than 13490, enable safe mode. 2025-11-04 11:16:42 +08:00
AlexLiuDev233
1853d9decf feat: try manual reboot hook (#521)
* feat: try manual reboot hook

* refactor: move ksu_handle_reboot to supercalls.c for ShirkNeko

---------
2025-11-04 01:08:49 +08:00
ShirkNeko
d286f49e11 [skip ci]kernel: Migrating KPM to ioctl 2025-11-04 00:52:13 +08:00
ShirkNeko
7103779a11 ksud: Migrating KPM to ioctl
- Fix compatibility manager issues with legacy kernels

Co-authored-by: AlexLiuDev233 <wzylin11@outlook.com>
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
2025-11-04 00:35:26 +08:00
ShirkNeko
4350d309da manager: Implement version restrictions for certain features 2025-11-03 14:59:12 +08:00
ShirkNeko
7051b22536 manager: Provide backward compatibility for legacy kernels 2025-11-03 14:32:16 +08:00
ShirkNeko
e0bce04e79 ksud: clippy happy & fmt 2025-11-03 12:24:36 +08:00
ShirkNeko
c75b041c40 kernel: Reset KERNEL_SU_OPTION to 0xDEADBEEF 2025-11-03 12:12:08 +08:00
ShirkNeko
d2a3f0fcad manager: fix suggest boot partition if we've root.
Co-authored-by: weishu <twsxtd@gmail.com>
2025-11-03 12:10:49 +08:00
ShirkNeko
696c3059b6 manager: fix legacy get version
Co-authored-by: weishu <twsxtd@gmail.com>
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
2025-11-03 12:09:00 +08:00
Ylarod
ab8e966b7f add check_managed_features to installer.sh 2025-11-03 11:48:03 +08:00
Ylarod
7ece40bb2c ksud: add managed_feature 2025-11-03 11:47:39 +08:00
ShirkNeko
d1aa6c8beb manager: improve local LKM selection
Co-authored-by: YuKongA <70465933+YuKongA@users.noreply.github.com>
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
2025-11-03 11:39:42 +08:00
Ylarod
bfed2d700a add legacy get_version & Full get_version
Co-authored-by: Ylarod <me@ylarod.cn>
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
2025-11-03 11:16:55 +08:00
ShirkNeko
59339b806a Revert "ci: use ddk for faster ci, manual gki image build"
This reverts commit 33d1f18395.
2025-11-03 03:49:56 +08:00
ShirkNeko
2433d64b6b Revert "ci: Attempting to resolve the issue with DDK compilation being unavailable"
This reverts commit a622657092.
2025-11-03 03:39:46 +08:00
ShirkNeko
a622657092 ci: Attempting to resolve the issue with DDK compilation being unavailable 2025-11-03 00:57:29 +08:00
Ylarod
b4e682148a kernel: remove dynamic alloc in feature 2025-11-03 00:41:27 +08:00
Ylarod
02474a5953 update embed ksuinit to v2 2025-11-02 23:49:46 +08:00
Ylarod
450dbf14fc kernel: disable setuid debug log 2025-11-02 23:49:40 +08:00
Ylarod
d89eab2c34 use cap_task_fix_setuid hook to avoid inline issue 2025-11-02 22:04:28 +08:00
ShirkNeko
a6b86a4f99 ci: skip dup lkm build
- Fixed and added build 6.12

- Repair construction

Co-authored-by: Ylarod <me@ylarod.cn>
2025-11-02 21:53:53 +08:00
ShirkNeko
33d1f18395 ci: use ddk for faster ci, manual gki image build
Co-authored-by: Ylarod <me@ylarod.cn>
2025-11-02 20:54:58 +08:00
Ylarod
8ebe60ca04 update ioctl macro (#2850) 2025-11-02 20:15:55 +08:00
ShirkNeko
980613c6a9 ksud: fmt 2025-11-02 20:07:35 +08:00
ShirkNeko
47bcc956a3 fix lot (#518)
* refact: use feature subsystem

* use 64bit feature

* fix

* add fixme

* add feature max to get_info

* use 32bit feature id

* allow root to get/set feature

* more clean perm_check functions

* fix

* add feature command to ksud

kernel: do not expose perm checker

* fix security_task_fix_setuid_handler_pre

* add android16-6.12 ci

* manager: add kernel_umount switch

Co-authored-by: YuKongA <70465933+YuKongA@users.noreply.github.com>

* manager: Reinstate the LKM selection function

* kernel: add name and print command value

- Optimise sulog log display

Co-authored-by: Ylarod <me@ylarod.cn>
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>

* fix

* ksud: clippy

---------

Co-authored-by: Ylarod <me@ylarod.cn>
Co-authored-by: YuKongA <70465933+YuKongA@users.noreply.github.com>
Co-authored-by: weishu <twsxtd@gmail.com>
2025-11-02 20:01:24 +08:00
ꑄℭѧᝰ.ᐟ
00de4e1c64 Update Vietnamese Translation (#515)
* Update Vietnamese Translation

* Fix typo strings
2025-11-02 18:42:34 +08:00
Ylarod
97ec718fea switch ns umount 2025-11-02 12:23:23 +08:00
Wang Han
5c96f951b5 Implement workqueue for unmounting
umount schedules, so it cannot be used in kprobe context.
2025-11-02 12:21:00 +08:00
Ylarod
7e446efac4 back to kprobe setuid hook 2025-11-02 12:17:21 +08:00
ShirkNeko
c06d694ebc kernel: When CONFIG_KSU = m, disable sulog 2025-11-02 03:09:55 +08:00
ShirkNeko
bd0b07cba9 kernel: Add sulog records for supercalls 2025-11-02 03:04:35 +08:00
ShirkNeko
e54339cf4e Compilation fixed; defaults to fallback using packages.list 2025-11-02 01:31:41 +08:00
ShirkNeko
320e08b8fb new supercall impl (#511)
* refactor: replace throne tracker with ksud token

* use snprintf

* refactor: new supercall impl

- Import the sukisu command

* disable seccomp for supercall users

* kernel: fmt clear

* kernel: Enable macro protection for sulog

- Only enabled on kernel versions greater than 5.10.245

* kernel: Refactor kprobe hooks and implement LSM hooks for improved security handling

* debug mode

* kernel: Add functionality to generate and validate authentication tokens for cmd_su

* kernel: Simplified manual SU command processing for code

* kernel: replace renameat hook with fsnotify

* Revert "refactor: replace throne tracker with ksud token"

This reverts commit aa2cbbf9cd.

* kernel: fix compile

* kernel: fix compile below 6.0

* Fix compile err; Add become_manager

* kernel: install fd for manager automaticlly

- extend to import the corresponding command

* manager: new supercall impl

* temp changes for ksud

* ksud: fix compile

* fix wrong opcode

* kernel: fix compile

* kernel: Fixed hook type and KPM status retrieval errors

* kernel: Fixed potential null pointer issue with current->mm in kernel version 5.10

When calling get_full_comm() within system call hooks, current->mm may be null (prctl). A fallback mechanism for current->comm must be added beforehand to prevent null pointer dereferences when accessing mm->arg_start/arg_end.

Signed-off-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>

* ksud: fix cargo check

* manager: Fixed an issue where the KSUD release and user-mode scanning switch failed to function correctly.

- kernel: fix spin lock mutual

kernel: Fixed potential null pointer issue with current->mm in kernel version 5.10

When calling get_full_comm() within system call hooks, current->mm may be null (prctl). A fallback mechanism for current->comm must be added beforehand to prevent null pointer dereferences when accessing mm->arg_start/arg_end.

kernel: try introduce like susfs's method to fix prctl delay

* seccomp: allow reboot

* use u32

* update clang-format

* 4 spaces save the world

* ksud: Fix build on macOS

* manager: bump minimal supported kernel.

- When get_hook_type is empty, display “Unknown”.


* Fix ksud build (#2841)

* try fix ksud

* fix for macos

* remove any

* Fix ksud build, take 3

* try fix allowlist

* bring lsm hook back

* fix: a lot again

* Fix ksud build, take 4 (#2846)

Remove init_driver_fd function for non-linux/android targets

* manager: Return to the native method via KSUd installation

* Merge with susfs-mian format

---------

Signed-off-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
Co-authored-by: Ylarod <me@ylarod.cn>
Co-authored-by: weishu <twsxtd@gmail.com>
Co-authored-by: AlexLiuDev233 <wzylin11@outlook.com>
Co-authored-by: Wang Han <416810799@qq.com>
2025-11-01 23:30:30 +08:00
NkBe
0da8ecb071 enjoy: 專門為MiUI桌面卸載添加了提示,提升使用者體驗 (#502) 2025-10-30 14:50:13 +08:00
NkBe
cc54abd273 strings: Update zh-rTW (#501) 2025-10-30 14:49:57 +08:00
ShirkNeko
ee781cf959 kernel: Fixed potential null pointer issue with current->mm in kernel version 5.10
When calling get_full_comm() within system call hooks, current->mm may be null (prctl). A fallback mechanism for current->comm must be added beforehand to prevent null pointer dereferences when accessing mm->arg_start/arg_end.

Signed-off-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
2025-10-27 22:02:12 +08:00
ShirkNeko
a21b18c5de kernel: Simplified manual SU command processing for code 2025-10-27 16:02:04 +08:00
ShirkNeko
1644f22c98 manager: Restore the colour scheme on the sulog page 2025-10-27 12:31:26 +08:00
由崎黑板
7a338b1b43 Revert "Disable Samsung Activation Verify to solve -45(2000) error during activation on China Mainland Samsung devices (#446)" (#492)
This reverts commit 7ef9230d66.
2025-10-26 22:22:11 +08:00
ShirkNeko
324dc0844f kernel: Greenlight the new prctl command 2025-10-26 20:43:51 +08:00
ShirkNeko
f7fe0cf748 kernel: Add functionality to generate and validate authentication tokens for cmd_su 2025-10-26 19:58:16 +08:00
ShirkNeko
bf1a45963b kernel: try introduce like susfs's method to fix prctl delay
Co-authored-by: AlexLiuDev233 <wzylin11@outlook.com>
2025-10-25 18:35:53 +08:00
ShirkNeko
64ee09fd12 kernel: Enable macro protection for sulog
- Only enabled on kernel versions greater than 5.10.245
2025-10-25 00:45:43 +08:00
ShirkNeko
b9a84a15bc manager: Remove sulog file selection 2025-10-24 21:55:32 +08:00
ShirkNeko
6a1e1d788b kernel: sulog: Simplify code using vfs_truncate 2025-10-23 22:16:06 +08:00
ShirkNeko
4b86989bf9 kernel: Restore the sequence of sulog logs 2025-10-23 21:48:55 +08:00
ShirkNeko
d3f8c128da kernel: Add a UID blacklist feature to restrict the operational permissions of specific users 2025-10-23 02:08:45 +08:00
ShirkNeko
bbb2748494 kernel: Adjust the command processing sequence 2025-10-22 23:54:55 +08:00
ShirkNeko
b9e6246d65 manager: Avoid page crashes caused by excessive data. 2025-10-22 23:53:05 +08:00
ShirkNeko
7bf13fbfca manager: Add an option to exclude the current application and certain system calls from the log viewer. 2025-10-22 22:42:26 +08:00
ShirkNeko
e9ee2304d3 kernel: Extend sulog to also record system call logs 2025-10-22 20:56:46 +08:00
ShirkNeko
f7b4b4b82d kernel: Optimized log timestamp processing and added manual refresh functionality. 2025-10-22 18:42:50 +08:00
ShirkNeko
15b9c4dbbf manager: Add the sulog log viewer interface and functionality 2025-10-22 18:19:16 +08:00
ShirkNeko
3b966c536b Kernel: Implement sulog for enhanced logging of SU attempts and permissions 2025-10-22 17:21:25 +08:00
ShirkNeko
b5e5be2572 Revert: ksud, kernel: Pick some upstream changes and remove unused functions
* Upstream commit:
f130f7572f

Signed-off-by: Faris <rsuntk@yukiprjkt.my.id>
2025-10-22 00:09:56 +08:00
ShirkNeko
253df1ea47 New translations strings.xml (Vietnamese) (#484) 2025-10-21 16:40:43 +08:00
ShirkNeko
134684a139 Kernel(Makefile): Add KSU_SRC to set path correctly #483
try Fix version define for 6.12 Kernel

Co-authored-by: YC酱luyancib <luyancib@qq.com>
2025-10-19 19:23:18 +08:00
ShirkNeko
9c07fa6889 ksud: Fixed compilation errors 2025-10-19 19:00:47 +08:00
Sultan Alsawaf
c3f66e15e9 kernel: Fix kernel panics caused by thread info flag corruption
Signed-off-by: Sultan Alsawaf <sultan@kerneltoast.com>
2025-10-19 18:44:15 +08:00
Faris
b6e2fa383a ksud: fix compilation and remove unused imports
Signed-off-by: Faris <rsuntk@yukiprjkt.my.id>
2025-10-19 18:44:07 +08:00
Ylarod
61f85a029e ksud, kernel: Pick some upstream changes and remove unused functions
* Upstream commit:
f130f7572f

Signed-off-by: Faris <rsuntk@yukiprjkt.my.id>
2025-10-19 18:41:30 +08:00
5ec1cff
b1564b77a2 ksud: refine mount
- `magic_mount` now takes the tmp_path from its argument
- `.notmpfs` and `.nomount` now behave the same

skip:
ksud: cache tmp path (74ce44de21963fddc83897846eed28eca89d78aa)

Co-authored-by: shatyuka <shatyuka@qq.com>
Signed-off-by: Faris <rsuntk@yukiprjkt.my.id>
2025-10-19 18:39:57 +08:00
Vayruz Rafli
cc0a3590ce docs: Fix little typo on tracepoint hook guide (#482) 2025-10-19 13:00:58 +08:00
PKQYPKJ
e793219c2b manager: Remove unnecessary translations (#478)
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
2025-10-18 22:43:54 +08:00
ShirkNeko
776a753206 manager: Rewrite UI state management 2025-10-18 22:37:17 +08:00
ShirkNeko
7b6470cc79 manager: Fixed sus tab mapping error 2025-10-18 17:40:23 +08:00
ShirkNeko
eb5fdbbf3f manager: SuSFS: Add SUS_MAP feature configuration item 2025-10-18 15:09:02 +08:00
ShirkNeko
8db55f56a9 manager: Reuse the aidi reflection to retrieve the list of applications 2025-10-17 01:59:56 +08:00
ShirkNeko
62635879e0 manager: Add multiple activity declarations for the backup icon close #469 2025-10-16 23:43:18 +08:00
ShirkNeko
86634aac3d Manager: Increase the loading priority of ksud
- This will resolve data loading errors that occur upon first launch.
2025-10-16 22:51:38 +08:00
ShirkNeko
af25f8d49e manager: Optimize Language Settings
- Do not update language configurations by refreshing activities; instead, introduce consistent language configurations from kernelsu-next.

Co-authored-by: rifsxd <rifat.44.azad.rifs@gmail.com>
2025-10-16 22:37:52 +08:00
Wang Han
cd78c2693a Don't write newline character to cgroup node (#2804)
This prevents su hang on oplus devices, maybe related to bad kernel
hooks.
2025-10-16 12:28:36 +08:00
ShirkNeko
8ff9fab414 manager: Fixed an issue where ksud failed to release properly during the first installation. 2025-10-15 14:15:13 +08:00
ShirkNeko
b8eebcda5a kernel: Bump susfs binary version to 1.5.12
- Removed functionally coupled versions 1.5.10-1.5.11

- Removed `statusMagicMount` status retrieval

- Use `getSuSFSFeatures` to replace `CMD_GET_SUSFS_FEATURE_STATUS` for obtaining SUSFS status.
2025-10-13 17:40:33 +08:00
ShirkNeko
85291de02a manager: Restructure the file directory to keep it clean 2025-10-12 18:58:02 +08:00
Cynthia
cb7abc88dd strings: full Indonesian translation (values-ind/strings.xml) (#464) 2025-10-12 15:50:29 +08:00
James Sparrow
918e7ae0b7 [skip ci]Update Vietnamese Translation (#462) 2025-10-12 15:50:05 +08:00
生于生时 亡于亡刻
0a804ba170 feat: Optimize some codes (ksud) (#465)
* chore: make cargo clippy happy

Signed-off-by: Tools-app <localhost.hutao@gmail.com>

* chore: Optimize import
-  Format as a standard import

Signed-off-by: Tools-app <localhost.hutao@gmail.com>

---------

Signed-off-by: Tools-app <localhost.hutao@gmail.com>
2025-10-12 15:48:24 +08:00
ShirkNeko
4c512dc7ff manager: Add detailed information about the module / anykernel3 compressed package from sharing and direct flashing
- Treat certain XP module APK files as modules for processing
2025-10-11 17:49:36 +08:00
ShirkNeko
fcb7c3e99d manager: Avoid repeated flashing caused by unconditionally clearing the Anykernel3 flashing status. 2025-10-10 23:56:03 +08:00
Prslc
b827360ac6 docs: Sync TRACEPOINT HOOK v1.1 (#456)
- Replace trace_ksu_trace_execveat_sucompat_hook with trace_ksu_trace_execveat_hook to align with v1.1 changes
  The new hook now passes argv/envp and a flags argument, adding support for 32-on-64 environments.
- Remove the devpts hook section from both English and Chinese guides
  The devpts (pty.c) hook example was deprecated in v1.1 and is no longer required.

Link: f1f7c61aee

Signed-off-by: Prslc <prslc113@gmail.com>
2025-10-10 00:39:15 +08:00
ShirkNeko
ca7b53370e manager: Enhanced External Selection Sharing Single/Batch Module Installation
- Reduce the delay exit time in seconds
2025-10-08 19:16:30 +08:00
ShirkNeko
230ca54d63 manager: Expand the option to directly open the file and flash the anykernel3 kernel package 2025-10-08 18:23:53 +08:00
ShirkNeko
2f43ad4f76 manager: add support for opening zip file and directly flash module
- refine zip intent method

- use MMRL method to handle zip, fix failed to open zip from Chrome

Co-Authored-By: Der_Googler <54764558+dergoogler@users.noreply.github.com>
Co-authored-by: rifsxd <rifat.44.azad.rifs@gmail.com>
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
Signed-off-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
2025-10-08 16:11:55 +08:00
ShirkNeko
9c1ff635e3 Kernel: Add support for 6.12
Filtered from tiann/KernelSU #2793

Co-authored-by: libingxuan <84086386+aaaaaaaa-815@users.noreply.github.com>
2025-10-08 15:00:04 +08:00
rsuntk
ef97f0e4d9 kernel: make apk_sign_key as a typedef instead
Style preference.

Signed-off-by: rsuntk <rsuntk@yukiprjkt.my.id>
2025-10-08 14:50:50 +08:00
ShirkNeko
2e394903cc kernel: Simplified Logic 2025-10-08 14:46:58 +08:00
unknow-tech
7978cbafa5 Add support for 6.13 (#454)
Fiz issue https://github.com/SukiSU-Ultra/SukiSU-Ultra/issues/364

cdd30ebb1b
2025-10-08 14:46:50 +08:00
rsuntk
c89a3dbcd9 kernel: add guard for avoiding LKM being builded on Linux 6.8+
* Due to numerous changes on LSM (Linux Security Module) in Linux 6.8+
* This is temporary guard until a working solution exist.

Signed-off-by: rsuntk <rsuntk@yukiprjkt.my.id>
2025-10-08 14:46:00 +08:00
Huy Minh
13c7912320 kernel: add initial 6.8+/6.14 kernel support
* This is a squashed of un-merged pull requests of Official KernelSU
* LKM support are not available.
* Require this additional patch to avoid kernel panic because of "Too many LSMs registered":
7042991a5c

* Un-merged pull requests of Official KernelSU:
https://github.com/tiann/KernelSU/pull/1785
https://github.com/tiann/KernelSU/pull/2662

* This commit probably not 100% completed.

Signed-off-by: rsuntk <rsuntk@yukiprjkt.my.id>
2025-10-08 14:45:36 +08:00
saitama-droid
abbe385382 kernel: core_hook: add config guard for manual SU escalation (#453)
Wrap manual SU escalation handling in CONFIG_KSU_MANUAL_SU
conditional compilation to allow builds without this functionality.

This affects:
- CMD_SU_ESCALATION_REQUEST
- CMD_ADD_PENDING_ROOT

When CONFIG_KSU_MANUAL_SU is disabled, these prctl commands
will not be compiled into the kernel.
2025-10-08 14:33:17 +08:00
Saksham
0b80137f17 Bump to latest stable ndk
Ref:https://developer.android.com/ndk/downloads#stable-downloads
2025-10-07 11:27:09 +05:30
ShirkNeko
c4ff89c13d manager: Add pull-to-refresh functionality 2025-10-07 01:29:00 +08:00
rifsxd
ce3a7ec189 kernel: handle throned UID change if manager is reinstall or changed
drop old UID and throne the new one when the manager is reinstalled or changed

- Add dynamic manager lock

Co-authored-by: rifsxd <rifat.44.azad.rifs@gmail.com>
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
Signed-off-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
2025-10-07 00:08:30 +08:00
ShirkNeko
2bb789212a New translations strings.xml (Vietnamese) (#449) 2025-10-06 23:15:30 +08:00
由崎黑板
7ef9230d66 Disable Samsung Activation Verify to solve -45(2000) error during activation on China Mainland Samsung devices (#446) 2025-10-06 23:02:54 +08:00
ShirkNeko
fbaa69f3fb manager: Raise the minimum version requirement to 3.1.8 close #448 2025-10-06 22:50:24 +08:00
ShirkNeko
e78ee720b5 ksud: fmt 2025-10-06 22:44:09 +08:00
ShirkNeko
04b603394a ksud: Fixed inconsistent parameter passing in kpm_prctl 2025-10-06 22:02:59 +08:00
ShirkNeko
c9c7a5f4e3 manager: Update Repository Naming 2025-10-06 21:08:23 +08:00
ShirkNeko
044b4a2f9c manager: Simplify kpm management by migrating to the ksud side. 2025-10-06 20:53:18 +08:00
ShirkNeko
59cd8d1c3b kernel: core_hook: harden prctl handler
detection is done by comparing a 0xDEADBEEF call to a non-0xDEADBEEF one.
which yeah, you will see that the non-0xDEADBEEF one returns early.

yes I know this causes delays for all prctl calls, as we straight up check uid,
but this keeps the delay consistent, which is what we want.

another is that we only should only perform this recrowning logic for multiuser

- temp fix for cimb octo's prctl abuse

Co-authored-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
2025-10-06 00:19:37 +08:00
ShirkNeko
36617bf0a1 kernel: For cmd_su, bypass the susfs_is_current_proc_umounted check only for system processes. 2025-10-05 20:08:51 +08:00
unknow-tech
5b49054055 Merge pull request #445 from unknow-tech/patch-1
Fix wrong function
2025-10-05 00:37:59 +08:00
NkBe
a17a220745 manager: Update zh-rTW strings (#439)
* manager: Update zh-rTW strings

* Update strings.xml

* Update strings.xml
2025-10-04 20:52:12 +05:30
YC酱luyancib
0729066a6f manager: add susfs 1.5.11 binary (#444) 2025-10-04 18:19:15 +05:30
ShirkNeko
d4dcf610c9 kernel: Fixed disable_seccomp compatibility issues 2025-10-01 00:16:35 +08:00
ShirkNeko
78e0dc6da2 kernel: Add CONFIG_KSU_MANUAL_SU configuration
- Use random passphrase protection for manual su functionality
2025-09-30 23:29:29 +08:00
ShirkNeko
a9a10466b3 Kernel: Enhanced temporary record UID functionality and elevated privileges 2025-09-30 23:27:02 +08:00
ShirkNeko
65d5d6a494 kernel: Add the ability to manually elevate privileges for programs using prctl by specifying UID or PID. 2025-09-30 23:26:28 +08:00
ShirkNeko
e552163d9e Revert "manager: Removed SUSFS_UMOUNT_FOR_ZYGOTE_ISO_SERVICE which are no longer used in susfs 1.5.10."
This reverts commit 475b3998a1.

- bump susfs version 1.5.10
2025-09-30 23:08:34 +08:00
ShirkNeko
c950705044 Manager: fmt
- Optimized homepage refresh logic and removed the caching mechanism
2025-09-29 17:17:19 +08:00
Rifat Azad
9e7aabf3f7 userspace/su: add ndk compatible su from kernelnosu
Co-authored-by: nampud <nampud@users.noreply.github.com>
2025-09-28 00:35:26 +08:00
ShirkNeko
a20a89da03 kernel: Revert partial changes 2025-09-27 23:04:14 +08:00
ShirkNeko
9551ca4fe8 kernel: fmt ,optimization Log 2025-09-27 21:12:02 +08:00
ShirkNeko
a2431d50ce kernel: Enhance the user space scanning functionality 2025-09-27 19:47:22 +08:00
ShirkNeko
8b74f7d466 manager: Redesign zygisk to ensure display accuracy 2025-09-26 23:28:27 +08:00
ShirkNeko
b5d9607e8e manager: Switch to matching mode to match the zygisk module
- bump dependencies
2025-09-26 20:14:27 +08:00
ShirkNeko
475b3998a1 manager: Removed SUSFS_UMOUNT_FOR_ZYGOTE_ISO_SERVICE and SUSFS_RUN_UMOUNT_FOR_CURRENT_MNT_NS, which are no longer used in susfs 1.5.10.
- bump susfs version 1.5.10
2025-09-25 21:57:31 +08:00
ShirkNeko
23ed4384e6 Revert "Unmount isolated process which forks from zygote unconditionally (#2747)"
This reverts commit 695e749e3e.
2025-09-25 16:13:07 +08:00
ShirkNeko
0af1ab2845 bump LKM build version 2025-09-24 22:45:12 +08:00
ShirkNeko
c664aa66af bump KSU_VERSION_API to 3.2.0 2025-09-24 22:34:47 +08:00
ShirkNeko
7a449345d1 kernel: fmt 2025-09-24 22:32:58 +08:00
Saksham
fa48b2fdaa feat: update to stable vitepress 2025-09-24 19:53:52 +05:30
ShirkNeko
f1f7c61aee kernel: Bump tracepoint_hooks to version v1.1
Remove `devpts_hook` and `execveat_hook` from `tracepoint_hooks`
2025-09-24 22:18:14 +08:00
ShirkNeko
ccc5cb74bf kernel: core_hook: intercept devpts via security_inode_permission LSM
`ksu handles devpts with selinux lsm hook` - aviraxp

- no, not yet, but yes we can, thats a good idea.

This change tries to do that, so instead of hooking pts_unix98_lookup or
devpts_get_priv, we just watch security_inode_permission, if its devpts,
pass it along to the original handler.

EDIT: define devpts super magic if its undefined
- yeah I aint gonna include a conditional include of a header just for this
- while we can just fully remove the macro and inline, readability loss is bad

Co-authored-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
2025-09-24 22:17:12 +08:00
Cloud_Yun
75fe8c9b6a kpm: remove incorrect "<" to fix compilation error (#418)
i'm so sorry

Signed-off-by: Cloud_Yun <1770669041@qq.com>
2025-09-24 21:48:03 +09:00
ShirkNeko
a12c78d213 Revert "kernel: throne_tracker: offload to kthread tiann #2632"
This reverts commit d5d2bb35d2.
2025-09-24 16:25:47 +08:00
backslashxx
6c145179d4 pullout envp 2025-09-24 16:17:38 +08:00
backslashxx
ac05038e64 move debug back up 2025-09-24 16:17:12 +08:00
ShirkNeko
d5d2bb35d2 kernel: throne_tracker: offload to kthread tiann #2632
Run throne_tracker() in kthread instead of blocking the caller.
Prevents full lockup during installation and removing the manager.

By default, first run remains synchronous for compatibility purposes
(FDE, FBEv1, FBEv2)

Features:
- looks and waits for manager UID in /data/system/packages.list
- run track_throne() in a kthread after the first synchronous run
- prevent duplicate thread creation with a single-instance check
- spinlock-on-d_lock based polling adressing possible race conditions.

Race conditions adressed
- single instance kthread lock, smp_mb()
- track_throne_function, packages.list, spinlock-on-d_lock based polling
- is_manager_apk, apk, spinlock-on-d_lock based polling

This is a squash of:
https://github.com/tiann/KernelSU/pull/2632

Original skeleton based on:
`kernelsu: move throne_tracker() to kthread`
`kernelsu: check locking before accessing files and dirs during searching manager`
`kernelsu: look for manager UID in /data/system/packages.list, not /data/system/packages.list.tmp`
0b05e927...8783badd

Co-Authored-By: backslashxx <118538522+backslashxx@users.noreply.github.com>
Co-Authored-By: Yaroslav Zviezda <10716792+acroreiser@users.noreply.github.com>
Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
2025-09-24 01:51:28 +08:00
ShirkNeko
cb01bf428d kernel: Simplify and remove user_arg_ptr ksu_handle_execveat_ksud
- Migrate `ksu_handle_execveat` to sucompat
2025-09-24 01:27:04 +08:00
ShirkNeko
7146210192 kernel: sys_execve bprm simplified
Co-authored-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
2025-09-23 23:58:41 +08:00
ShirkNeko
528df754a5 manager: bump dependencies 2025-09-23 22:54:15 +08:00
ShirkNeko
8a14f64964 kernel: sys_execve_kp remains the preferred choice for the first registration. 2025-09-23 21:22:34 +08:00
ShirkNeko
bf4e12ce80 ksud: Modified KPM to use the prctl system call instead of external execution. 2025-09-23 20:37:40 +08:00
ShirkNeko
5497c0004d Revert "ksud: Only start the monitor and load the module when KPM is enabled"
This reverts commit 3ed1d9aebc.
2025-09-23 18:40:58 +08:00
ShirkNeko
32baf8d9b0 ksud: Rename the output LKM patch file 2025-09-23 17:22:07 +08:00
ShirkNeko
763ce7e86c kernel ksud: Attempt registration with bprm_check_kp first. If it fails, fall back to sys_execve_kp.
Co-authored-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
Signed-off-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
2025-09-23 17:20:48 +08:00
5ec1cff
3a8ecf1253 ksud: magic_mount: make mount points read only
Signed-off-by: rsuntk <rsuntk@yukiprjkt.my.id>
2025-09-23 00:54:44 +08:00
Wang Han
7026c340b0 ksud: Update zip-extensions and set needed features for zip (#2592)
zip-extensions does not export time and deflate64 features now.
2025-09-23 00:54:30 +08:00
ShirkNeko
6dc803702b ksud: create our own new ramdisk when no compatible ramdisk found
Co-authored-by: rifsxd <rifat.44.azad.rifs@gmail.com>
2025-09-23 00:48:15 +08:00
backslashxx
c64d196a10 kernel: selinux: fix pointer mismatch with 32-bit ksud on 64-bit kernels
Since KernelSU Manager can now be built for 32-bit, theres this problematic
setup where userspace is 32-bit (armeabi-v7a) and kernel is 64bit (aarch64).

On 64-bit kernels with CONFIG_COMPAT=y, 32-bit userspace passes 32-bit pointers.
These values are interpreted as 64-bit pointers without proper casting and that
results in invalid or near-null memory access.

This patch adds proper compat-mode handling with the ff changes:
- introduce a dedicated struct (`sepol_compat_data`) using u32 fields
- use `compat_ptr()` to safely convert 32-bit user pointers to kernel pointers
- adding a runtime `ksu_is_compat` flag to dynamically select between struct layouts

This prevents a near-null pointer dereference when handling SELinux
policy updates from 32-bit ksud in a 64-bit kernel.

Truth table:

kernel 32 + ksud 32, struct is u32, no compat_ptr
kernel 64 + ksud 32, struct is u32, yes compat_ptr
kernel 64 + ksud 64, struct is u64, no compat_ptr

Preprocessor check

64BIT=y COMPAT=y: define both structs, select dynamically
64BIT=y COMPAT=n: struct u64
64BIT=n: struct u32

Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
2025-09-22 23:01:38 +08:00
backslashxx
c690d9c02c ksud: migrate ksud execution to security_bprm_check (tiann#2653)
This migrates ksud execution decision-making to bprm_check_security.
This requires passing proper argv and envp to a modified _ksud handler
aptly named 'ksu_handle_bprm_ksud'.

Introduces:
int ksu_handle_bprm_ksud(const char *filename, const char *argv1,
const char *envp, size_t envp_len)

which is adapted from:
int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
struct user_arg_ptr *argv,
struct user_arg_ptr *envp,
int *flags)

ksu_handle_bprm_ksud handles all the decision making, it decides when it is
time to apply_kernelsu_rules depending if it sees "second_stage".

For LSM hook, turns out we can pull out argv and envp from mm_struct.
The code in here explains itself on how to do it.

whole blob exists on arg_start to arg_end, so we just pull it out and grab next
array after the first null terminator.

as for envp, we pass the pointer then hunt for it when needed

My reasoning on adding a fallback on usercopy is that on some devices a fault
happens, and it copies garbled data. On my creation of this, I actually had to lock
that _nofault copy on a spinlock as a way to mimic preempt_disable/enable without
actually doing it. As per user reports, no failed _nofault copies anyway but we
have-to-have a fallback for resilience.

References:
- old version1 6efcd8193e
- old version2 37d5938e66
- bad usercopy #21

This now provides a small helper function, ksu_copy_from_user_retry, which explains
itself. First we attempt a _nofault copy, if that fails, we try plain.

With that, It also provides an inlined copy_from_user_nofault for < 5.8.

While using strncpy_from_user_nofault was considered, this wont do, this will
only copy up to the first \0.

devlog:
16e5dce9e7...16c1f5f521
28642e60d7...728de0c571

References:
https://elixir.bootlin.com/linux/v4.14.1/source/include/linux/mm_types.h#L429
https://elixir.bootlin.com/linux/v4.14.1/source/include/linux/lsm_hooks.h

Stale: https://github.com/tiann/KernelSU/pull/2653

Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
2025-09-22 23:01:38 +08:00
ShirkNeko
452fe3d508 uid_sanner: Ensure the /data/misc/user_uid/ directory is set to 777 permissions to prevent read/write issues. 2025-09-20 00:27:48 +08:00
ShirkNeko
e27d461eb0 manager: Reworking the cleanup functionality for the runtime environment
Fix the uid_scanner library filename in the build script
2025-09-19 23:02:38 +08:00
ShirkNeko
a77faa1fe2 Manager: Added functionality to clean up the user-mode scanning environment after execution
fmt ksud
2025-09-19 22:04:14 +08:00
ShirkNeko
9a9623f578 kernel: Use /data/user_de/ for rollback instead of packages.list
manager: Fix path and permission issues
2025-09-19 21:21:10 +08:00
ShirkNeko
cc1c66bb6f Add UID scanner functionality and related infrastructure
- Introduced a new module `uid_scanner` in userspace for managing UID scanning.
- Created a new GitHub Actions workflow for building the `user_scanner`.
- Implemented kernel communication in `throne_comm.c` and `throne_comm.h` to handle user space updates and rescan requests.
- Developed the `uid_scanner` daemon in C to scan user directories and manage UID whitelists.
- Added configuration management for the UID scanner with support for multiple users and auto-scanning.
- Implemented logging and error handling throughout the UID scanning process.
- Created necessary build files for the `user_scanner` JNI integration.
- Added a `.gitignore` file to exclude build artifacts.
2025-09-19 21:01:01 +08:00
Wang Han
695e749e3e Unmount isolated process which forks from zygote unconditionally (#2747)
Rethink about this patch, isolated process which directly forks from
zygote is just like normal app, so there is no reason apps won't crash
but Isolated process will. Also zygote reopens fd before actually fork,
so it should be fine.

This reverts commit 2a1741de96a789957555053cf5a397cbef1eb3e4.
2025-09-17 20:01:38 +08:00
生于生时 亡于亡刻
84c85ebe3c feat: Optimize ksud compilation products (#394)
Signed-off-by: Tools-app <localhost.hutao@gmail.com>
2025-09-17 20:01:27 +08:00
Cloud_Yun
ed7dc01fb2 kpm: fix compilation errors (#396)
Sorry, I made another mistake

Signed-off-by: Cloud_Yun <1770669041@qq.com>
2025-09-17 20:01:12 +08:00
Cloud_Yun
7d475e642f kpm: 改进可读性 (#392)
* kpm: improving readability
Honestly, this format is really messy

Signed-off-by: Cloud_Yun <1770669041@qq.com>

* kpm: fix missing int label
my bad (((

Signed-off-by: Cloud_Yun <1770669041@qq.com>

---------

Signed-off-by: Cloud_Yun <1770669041@qq.com>
2025-09-17 20:01:05 +08:00
ShirkNeko
cead5b03f4 Revert "manager: Optimized import, optimized all libsu shell calls, and fixed WebUI memory leaks #369
This reverts commit c3533861f2.
2025-09-17 20:00:51 +08:00
ShirkNeko
0c578e4518 [skip ci]: Reapply "manager: Optimized import, optimized all libsu shell calls, and fixed WebUI memory leaks Partial modification (#369)"
This reverts commit 37368fb41c.
2025-09-17 20:00:39 +08:00
NkBe
fad6420405 manager: Update zh-rTW strings (#388)
* manager: Update zh-rTW strings

* Setup default_signature
2025-09-12 14:12:05 +08:00
ShirkNeko
415555aef8 kernel: Add the real UID by parsing the UID from the /data/user_de/0/[app] directory fix #356]
Prioritize retrieving the application UID from /data/user_de. If this fails, fall back to retrieving it from packages.list.

Fix unstable application UID acquisition

Signed-off-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
2025-09-12 14:02:00 +08:00
ShirkNeko
f3e9033054 manager: Supplement the missing patch file format 2025-09-11 20:29:33 +08:00
由崎黑板
192323ad5c Add support for more kernel image name in KPM patcher (#386) 2025-09-11 20:18:02 +08:00
Cloud_Yun
6973ce6a1f manager: More standard working mode display (#384)
Actually, the working mode should be displayed here,
rather than the kernel type
This misled many people, leading them to misunderstand
the meaning of GKI

Signed-off-by: Cloud_Yun <1770669041@qq.com>
2025-09-10 22:32:58 +08:00
ShirkNeko
e8852223c4 manager: Optimize the overall layout of KPM patches 2025-09-10 22:05:30 +08:00
OukaroMF
42601b232c docs(zh): relocate SukiSU.svg to correct directory (#382)
- Move logo from docs/zh/guide/ to docs/zh/
- Remove obsolete path reference
- Standardize asset placement for localization

Co-authored-by: OukaroMF <OukaroMF@users.noreply.github.com>
2025-09-10 20:01:39 +08:00
ShirkNeko
cd8b6ab382 Manager: Added KPM patching functionality support. close #372
- Integrated KPM patching logic into KernelFlash and display KPM patching status.
- Updated Install to support KPM patching options.
- Implemented local and remote downloads for KPM tools.

Signed-off-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
2025-09-10 19:54:33 +08:00
ShirkNeko
3ed1d9aebc ksud: Only start the monitor and load the module when KPM is enabled
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
Co-authored-by: mihoy3rd <159522651+mihoy3rd@users.noreply.github.com>
2025-09-10 14:56:23 +08:00
ShirkNeko
d83fc2aec6 New Crowdin updates (#379)
* New translations strings.xml (Japanese)

* New translations strings.xml (Russian)
2025-09-09 14:31:49 +08:00
Saksham
098583f058 Delete Website/.github directory 2025-09-07 20:53:11 +05:30
NkBe
2521226745 docs: Update SukiSU logo (#381)
* docs: Add mini SukiSU logo/icon files

320x256 更符合大多项目使用标准

Co-Authored-By: OukaroMF <107784230+oukaromf@users.noreply.github.com>

* docs: Update project icon

Co-Authored-By: OukaroMF <107784230+oukaromf@users.noreply.github.com>

---------

Co-authored-by: OukaroMF <107784230+oukaromf@users.noreply.github.com>
2025-09-07 19:43:03 +05:30
ShirkNeko
942e5070f5 Manager: bump the agp version and ksp version. 2025-09-07 19:11:36 +08:00
Re*Index. (ot_inc)
6726828e1d Fix Japanese (#378)
* Fix Japanese

* Update strings.xml

* Update strings.xml

* Update strings.xml
2025-09-07 16:18:04 +08:00
ShirkNeko
4418ebadc4 Merge branch 'main' of https://github.com/SukiSU-Ultra/SukiSU-Ultra 2025-09-07 16:16:49 +08:00
ShirkNeko
37368fb41c Revert "manager: Optimized import, optimized all libsu shell calls, and fixed WebUI memory leaks Partial modification (#369)"
This reverts commit c3533861f2.

Resolved delayed access to globally mounted storage spaces

Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
2025-09-07 16:15:57 +08:00
OukaroMF
1e5db5d6bf docs: Add SukiSU logo/icon files (#377)
- Add SukiSU.svg to docs directory
- Add SukiSU.svg to docs/zh/guide directory
- These SVG files appear to be branding assets for the project
- Add SukiSU.svg to Website/docs/public directory
- This logo file will be used for website branding
- Maintains consistency with other SukiSU branding assets
2025-09-07 15:58:29 +08:00
ShirkNeko
067ced4a8c kernel: Reworking Dynamic Manager Index Configuration 2025-09-06 15:25:03 +08:00
nobody202222
41d21e994c fix 'for' loop problem (#376)
fix ‘for’ loop initial declarations are only allowed in c99 or c11 mode
2025-09-05 21:52:41 +08:00
TypeFlu
596dab1db8 refer links to sukisu-ultra 2025-09-04 15:26:46 +05:30
TypeFlu
71c0424512 Merge commit '49190feab6268d64bbb16e332f53d2a66f387d14' as 'Website' 2025-09-04 15:07:40 +05:30
TypeFlu
49190feab6 Squashed 'Website/' content from commit 820a8fc4
git-subtree-dir: Website
git-subtree-split: 820a8fc4c609fa2281312a6a75491add1c280711
2025-09-04 15:07:40 +05:30
rsuntk
9b37ec4a84 kernel: stop intercepting devpts inode permission via LSM
* Somehow, it just does not work properly. (sometimes)

Signed-off-by: rsuntk <rsuntk@yukiprjkt.my.id>
2025-09-04 16:25:27 +08:00
Wang Han
12f54b115c manager: Strip JNI debug logs on release build (#2732)
Add conditional logging to jni.c for debug builds.
2025-09-02 15:01:50 +08:00
ShirkNeko
5586f9ce30 manager: Optimize build configurations
bump Gradle version and dep
2025-09-01 16:25:25 +08:00
ShirkNeko
0789632efc New translations strings.xml (Vietnamese) (#370) 2025-09-01 15:17:17 +08:00
梦璃酱
c3533861f2 manager: Optimized import, optimized all libsu shell calls, and fixed WebUI memory leaks (#369)
* manager: simply optimize

* manager: optimize webui functions

* manager: detect selinux using libsu:io

* manager: optimize webui functions

* manager: use the default shell

* manager: optimize import

* manager: optimize shell builder

* manager: fix memory leaks

* manager: optimize magisk detection

* manager: use libsu

* manager: optimize webui

---------

Co-authored-by: 白彩恋 <shiro@oom-wg.dev>
2025-09-01 15:04:58 +08:00
dabao1955
662a2b1237 kernel: Removs extra strip for hook choice (#361)
* kernel: Removs extra strip for hook choice 

extra changes for #353

* kernel: Fix Makefile
2025-08-28 10:18:11 +08:00
rsuntk
436071a3f1 ksud: fix some warnings
warning: hiding a lifetime that's elided elsewhere is confusing
  --> src/sepolicy.rs:22:30
   |
22 | fn parse_bracket_objs(input: &str) -> IResult<&str, SeObject> {
   |                              ^^^^             ----  -------- the same lifetime is hidden here
   |                              |                |
   |                              |                the same lifetime is elided here
   |                              the lifetime is elided here

Signed-off-by: rsuntk <rsuntk@yukiprjkt.my.id>
2025-08-25 21:30:39 +08:00
ShirkNeko
ea602be270 kernel: Remove the ksu_ prefix from the dynamic manager signature. 2025-08-25 20:16:51 +08:00
ShirkNeko
8c8f344161 manager: Clean code & bump AGP version 2025-08-25 17:28:51 +08:00
WenHao2130
1af8a87876 workflows: Drop deploy-website.yml
Signed-off-by: WenHao2130 <wenhao2130@outlook.com>
2025-08-24 13:22:12 +08:00
WenHao2130
6640b5b7b6 website: Kill website
* It has been separated into SukiSU-Ultra/Website

Signed-off-by: WenHao2130 <wenhao2130@outlook.com>
2025-08-24 13:15:55 +08:00
468 changed files with 30494 additions and 26537 deletions

View File

@@ -1,137 +0,0 @@
name: GKI Kernel Build
on:
workflow_call:
inputs:
version_name:
required: true
type: string
description: >
With SUBLEVEL of kernel,
for example: android12-5.10.66
arch:
required: true
type: string
description: >
Build arch: aarch64/x86_64
debug:
required: false
type: boolean
default: true
manifest_name:
required: false
type: string
description: >
Local repo manifest xml path,
typically for AVD kernel build.
secrets:
BOOT_SIGN_KEY:
required: false
CHAT_ID:
required: false
BOT_TOKEN:
required: false
MESSAGE_THREAD_ID:
required: false
jobs:
build:
name: Build ${{ inputs.version_name }}
runs-on: ubuntu-22.04
steps:
- name: Maximize build space
uses: easimon/maximize-build-space@master
with:
root-reserve-mb: 8192
temp-reserve-mb: 2048
remove-dotnet: 'true'
remove-android: 'true'
remove-haskell: 'true'
remove-codeql: 'true'
- uses: actions/checkout@v4
with:
path: KernelSU
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: Setup kernel source
run: |
echo "Free space:"
df -h
cd $GITHUB_WORKSPACE
sudo apt-get install repo -y
mkdir android-kernel && cd android-kernel
repo init --depth=1 -u https://android.googlesource.com/kernel/manifest -m "$GITHUB_WORKSPACE/KernelSU/.github/manifests/${{ inputs.manifest_name }}" --repo-rev=v2.16
repo --version
repo --trace sync -c -j$(nproc --all) --no-tags
df -h
- name: Setup KernelSU
env:
PATCH_PATH: ${{ inputs.patch_path }}
IS_DEBUG_KERNEL: ${{ inputs.debug }}
run: |
cd $GITHUB_WORKSPACE/android-kernel
echo "[+] KernelSU setup"
GKI_ROOT=$(pwd)
echo "[+] GKI_ROOT: $GKI_ROOT"
echo "[+] Copy KernelSU driver to $GKI_ROOT/common/drivers"
ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $GKI_ROOT/common/drivers/kernelsu
echo "[+] Add KernelSU driver to Makefile"
DRIVER_MAKEFILE=$GKI_ROOT/common/drivers/Makefile
DRIVER_KCONFIG=$GKI_ROOT/common/drivers/Kconfig
grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "\nobj-\$(CONFIG_KSU) += kernelsu/\n" >> "$DRIVER_MAKEFILE"
grep -q "kernelsu" "$DRIVER_KCONFIG" || sed -i "/endmenu/i\\source \"drivers/kernelsu/Kconfig\"" "$DRIVER_KCONFIG"
echo "[+] Apply KernelSU patches"
cd $GKI_ROOT/common/ && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/$PATCH_PATH/*.patch || echo "[-] No patch found"
if [ "$IS_DEBUG_KERNEL" = "true" ]; then
echo "[+] Enable debug features for kernel"
printf "\nccflags-y += -DCONFIG_KSU_DEBUG\n" >> $GITHUB_WORKSPACE/KernelSU/kernel/Makefile
fi
repo status
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: Make working directory clean to avoid dirty
working-directory: android-kernel
run: |
rm common/android/abi_gki_protected_exports_* || echo "No protected exports!"
git config --global user.email "bot@kernelsu.org"
git config --global user.name "KernelSUBot"
cd common/ && git add -A && git commit -a -m "Add KernelSU"
repo status
- name: Build kernel
working-directory: android-kernel
run: |
if [ ! -z ${{ vars.EXPECTED_SIZE }} ] && [ ! -z ${{ vars.EXPECTED_HASH }} ]; then
export KSU_EXPECTED_SIZE=${{ vars.EXPECTED_SIZE }}
export KSU_EXPECTED_HASH=${{ vars.EXPECTED_HASH }}
fi
tools/bazel run --config=fast --config=stamp --lto=thin //common-modules/virtual-device:virtual_device_${{ inputs.arch }}_dist -- --dist_dir=dist
NAME=kernel-${{ inputs.arch }}-avd-${{ inputs.version_name }}-${{ env.kernelsu_version }}
TARGET_IMAGE=dist/bzImage
if [ ! -e $TARGET_IMAGE ]; then
TARGET_IMAGE=dist/Image
fi
mv $TARGET_IMAGE $NAME
echo "file_path=android-kernel/$NAME" >> $GITHUB_ENV
- name: Upload Kernel
uses: actions/upload-artifact@v4
with:
name: kernel-${{ inputs.arch }}-avd-${{ inputs.version_name }}-${{ env.kernelsu_version }}
path: "${{ env.file_path }}"

20
.github/workflows/build-gki-image.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: Build Android GKI Image
on:
workflow_call:
jobs:
build-a12-kernel:
uses: ./.github/workflows/build-kernel-a12.yml
secrets: inherit
build-a13-kernel:
uses: ./.github/workflows/build-kernel-a13.yml
secrets: inherit
build-a14-kernel:
uses: ./.github/workflows/build-kernel-a14.yml
secrets: inherit
build-a15-kernel:
uses: ./.github/workflows/build-kernel-a15.yml
secrets: inherit
build-a16-kernel:
uses: ./.github/workflows/build-kernel-a16.yml
secrets: inherit

111
.github/workflows/build-kernel-a12.yml vendored Normal file
View File

@@ -0,0 +1,111 @@
name: Build Kernel - Android 12
on:
# push:
# branches: ["main", "ci", "checkci"]
# paths:
# - ".github/workflows/deps/gki/build-kernel-a12.yml"
# - ".github/workflows/deps/gki/gki-kernel.yml"
# - ".github/scripts/build_a12.sh"
# - "kernel/**"
workflow_call:
inputs:
debug:
description: 'Build debug kernel'
required: false
type: boolean
default: false
workflow_dispatch:
inputs:
debug:
description: 'Build debug kernel'
required: false
type: boolean
default: false
jobs:
build-kernel:
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
strategy:
matrix:
include:
- sub_level: 209
os_patch_level: 2024-05
- sub_level: 218
os_patch_level: 2024-08
- sub_level: 226
os_patch_level: 2024-11
- sub_level: 233
os_patch_level: 2025-02
- sub_level: 236
os_patch_level: 2025-05
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
version: android12-5.10
version_name: android12-5.10.${{ matrix.sub_level }}
tag: android12-5.10-${{ matrix.os_patch_level }}
os_patch_level: ${{ matrix.os_patch_level }}
patch_path: "5.10"
debug: ${{ inputs.debug || false }}
upload-artifacts:
needs: build-kernel
runs-on: ubuntu-latest
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 }}
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 }}
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
- uses: actions/checkout@v4
with:
path: KernelSU
fetch-depth: 0
- name: List artifacts
run: |
tree
- name: Download prebuilt toolchain
run: |
AOSP_MIRROR=https://android.googlesource.com
BRANCH=main-kernel-build-2024
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
pip3 install telethon
- name: Set boot sign key
env:
BOOT_SIGN_KEY: ${{ secrets.BOOT_SIGN_KEY }}
run: |
if [ ! -z "$BOOT_SIGN_KEY" ]; then
echo "$BOOT_SIGN_KEY" > ./kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
fi
- name: Build boot images
run: |
export AVBTOOL=$GITHUB_WORKSPACE/kernel-build-tools/linux-x86/bin/avbtool
export GZIP=$GITHUB_WORKSPACE/build-tools/path/linux-x86/gzip
export LZ4=$GITHUB_WORKSPACE/build-tools/path/linux-x86/lz4
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) + 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@v4
with:
name: boot-images-android12
path: Image-android12*/*.img.gz

146
.github/workflows/build-kernel-a13.yml vendored Normal file
View File

@@ -0,0 +1,146 @@
name: Build Kernel - Android 13
on:
# push:
# branches: ["main", "ci", "checkci"]
# paths:
# - ".github/workflows/deps/gki/build-kernel-a13.yml"
# - ".github/workflows/deps/gki/gki-kernel.yml"
# - ".github/scripts/build_a13.sh"
# - "kernel/**"
workflow_call:
inputs:
debug:
description: 'Build debug kernel'
required: false
type: boolean
default: false
workflow_dispatch:
inputs:
debug:
description: 'Build debug kernel'
required: false
type: boolean
default: false
jobs:
build-kernel:
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
strategy:
matrix:
include:
- version: "5.10"
sub_level: 209
os_patch_level: 2024-05
- version: "5.10"
sub_level: 210
os_patch_level: 2024-06
- version: "5.10"
sub_level: 214
os_patch_level: 2024-07
- version: "5.10"
sub_level: 218
os_patch_level: 2024-08
- version: "5.10"
sub_level: 223
os_patch_level: 2024-11
- version: "5.10"
sub_level: 228
os_patch_level: 2025-01
- version: "5.10"
sub_level: 234
os_patch_level: 2025-03
- version: "5.15"
sub_level: 148
os_patch_level: 2024-05
- version: "5.15"
sub_level: 149
os_patch_level: 2024-07
- version: "5.15"
sub_level: 151
os_patch_level: 2024-08
- version: "5.15"
sub_level: 153
os_patch_level: 2024-09
- version: "5.15"
sub_level: 167
os_patch_level: 2024-11
- version: "5.15"
sub_level: 178
os_patch_level: 2024-11
- version: "5.15"
sub_level: 170
os_patch_level: 2025-01
- version: "5.15"
sub_level: 178
os_patch_level: 2025-03
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 }}
debug: ${{ inputs.debug || false }}
upload-artifacts:
needs: build-kernel
runs-on: ubuntu-latest
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 }}
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 }}
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
- uses: actions/checkout@v4
with:
path: KernelSU
fetch-depth: 0
- name: List artifacts
run: |
tree
- name: Download prebuilt toolchain
run: |
AOSP_MIRROR=https://android.googlesource.com
BRANCH=main-kernel-build-2024
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
pip3 install telethon
- name: Set boot sign key
env:
BOOT_SIGN_KEY: ${{ secrets.BOOT_SIGN_KEY }}
run: |
if [ ! -z "$BOOT_SIGN_KEY" ]; then
echo "$BOOT_SIGN_KEY" > ./kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
fi
- name: Build boot images
run: |
export AVBTOOL=$GITHUB_WORKSPACE/kernel-build-tools/linux-x86/bin/avbtool
export GZIP=$GITHUB_WORKSPACE/build-tools/path/linux-x86/gzip
export LZ4=$GITHUB_WORKSPACE/build-tools/path/linux-x86/lz4
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) + 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@v4
with:
name: boot-images-android13
path: Image-android13*/*.img.gz

158
.github/workflows/build-kernel-a14.yml vendored Normal file
View File

@@ -0,0 +1,158 @@
name: Build Kernel - Android 14
on:
# push:
# branches: ["main", "ci", "checkci"]
# paths:
# - ".github/workflows/deps/gki/build-kernel-a14.yml"
# - ".github/workflows/deps/gki/gki-kernel.yml"
# - ".github/scripts/build_a13.sh"
# - "kernel/**"
workflow_call:
inputs:
debug:
description: 'Build debug kernel'
required: false
type: boolean
default: false
workflow_dispatch:
inputs:
debug:
description: 'Build debug kernel'
required: false
type: boolean
default: false
jobs:
build-kernel:
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
strategy:
matrix:
include:
- version: "5.15"
sub_level: 148
os_patch_level: 2024-05
- version: "5.15"
sub_level: 149
os_patch_level: 2024-06
- version: "5.15"
sub_level: 153
os_patch_level: 2024-07
- version: "5.15"
sub_level: 158
os_patch_level: 2024-08
- version: "5.15"
sub_level: 164
os_patch_level: 2024-09
- version: "5.15"
sub_level: 167
os_patch_level: 2024-11
- version: "5.15"
sub_level: 170
os_patch_level: 2025-01
- version: "5.15"
sub_level: 178
os_patch_level: 2025-03
- version: "6.1"
sub_level: 75
os_patch_level: 2024-05
- version: "6.1"
sub_level: 78
os_patch_level: 2024-06
- version: "6.1"
sub_level: 84
os_patch_level: 2024-07
- version: "6.1"
sub_level: 90
os_patch_level: 2024-08
- version: "6.1"
sub_level: 93
os_patch_level: 2024-09
- version: "6.1"
sub_level: 99
os_patch_level: 2024-10
- version: "6.1"
sub_level: 112
os_patch_level: 2024-11
- version: "6.1"
sub_level: 115
os_patch_level: 2024-12
- version: "6.1"
sub_level: 118
os_patch_level: 2025-01
- version: "6.1"
sub_level: 128
os_patch_level: 2025-03
- version: "6.1"
sub_level: 134
os_patch_level: 2025-05
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
version: android14-${{ matrix.version }}
version_name: android14-${{ matrix.version }}.${{ matrix.sub_level }}
tag: android14-${{ matrix.version }}-${{ matrix.os_patch_level }}
os_patch_level: ${{ matrix.os_patch_level }}
patch_path: ${{ matrix.version }}
debug: ${{ inputs.debug || false }}
upload-artifacts:
needs: build-kernel
runs-on: ubuntu-latest
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 }}
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 }}
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
- uses: actions/checkout@v4
with:
path: KernelSU
fetch-depth: 0
- name: List artifacts
run: |
tree
- name: Download prebuilt toolchain
run: |
AOSP_MIRROR=https://android.googlesource.com
BRANCH=main-kernel-build-2024
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
pip3 install telethon
- name: Set boot sign key
env:
BOOT_SIGN_KEY: ${{ secrets.BOOT_SIGN_KEY }}
run: |
if [ ! -z "$BOOT_SIGN_KEY" ]; then
echo "$BOOT_SIGN_KEY" > ./kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
fi
- name: Build boot images
run: |
export AVBTOOL=$GITHUB_WORKSPACE/kernel-build-tools/linux-x86/bin/avbtool
export GZIP=$GITHUB_WORKSPACE/build-tools/path/linux-x86/gzip
export LZ4=$GITHUB_WORKSPACE/build-tools/path/linux-x86/lz4
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) + 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@v4
with:
name: boot-images-android14
path: Image-android14*/*.img.gz

131
.github/workflows/build-kernel-a15.yml vendored Normal file
View File

@@ -0,0 +1,131 @@
name: Build Kernel - Android 15
on:
# push:
# branches: ["main", "ci", "checkci"]
# paths:
# - ".github/workflows/deps/gki/build-kernel-a15.yml"
# - ".github/workflows/deps/gki/gki-kernel.yml"
# - ".github/scripts/build_a13.sh"
# - "kernel/**"
workflow_call:
inputs:
debug:
description: 'Build debug kernel'
required: false
type: boolean
default: false
workflow_dispatch:
inputs:
debug:
description: 'Build debug kernel'
required: false
type: boolean
default: false
jobs:
build-kernel:
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
strategy:
matrix:
include:
- version: "6.6"
sub_level: 30
os_patch_level: 2024-08
- version: "6.6"
sub_level: 46
os_patch_level: 2024-09
- version: "6.6"
sub_level: 50
os_patch_level: 2024-10
- version: "6.6"
sub_level: 56
os_patch_level: 2024-11
- version: "6.6"
sub_level: 57
os_patch_level: 2024-12
- version: "6.6"
sub_level: 58
os_patch_level: 2025-01
- version: "6.6"
sub_level: 66
os_patch_level: 2025-02
- version: "6.6"
sub_level: 77
os_patch_level: 2025-03
- version: "6.6"
sub_level: 82
os_patch_level: 2025-04
- version: "6.6"
sub_level: 87
os_patch_level: 2025-05
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
version: android15-${{ matrix.version }}
version_name: android15-${{ matrix.version }}.${{ matrix.sub_level }}
tag: android15-${{ matrix.version }}-${{ matrix.os_patch_level }}
os_patch_level: ${{ matrix.os_patch_level }}
patch_path: ${{ matrix.version }}
debug: ${{ inputs.debug || false }}
upload-artifacts:
needs: build-kernel
runs-on: ubuntu-latest
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 }}
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 }}
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
- uses: actions/checkout@v4
with:
path: KernelSU
fetch-depth: 0
- name: List artifacts
run: |
tree
- name: Download prebuilt toolchain
run: |
AOSP_MIRROR=https://android.googlesource.com
BRANCH=main-kernel-build-2024
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
pip3 install telethon
- name: Set boot sign key
env:
BOOT_SIGN_KEY: ${{ secrets.BOOT_SIGN_KEY }}
run: |
if [ ! -z "$BOOT_SIGN_KEY" ]; then
echo "$BOOT_SIGN_KEY" > ./kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
fi
- name: Build boot images
run: |
export AVBTOOL=$GITHUB_WORKSPACE/kernel-build-tools/linux-x86/bin/avbtool
export GZIP=$GITHUB_WORKSPACE/build-tools/path/linux-x86/gzip
export LZ4=$GITHUB_WORKSPACE/build-tools/path/linux-x86/lz4
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) + 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@v4
with:
name: boot-images-android15
path: Image-android15*/*.img.gz

104
.github/workflows/build-kernel-a16.yml vendored Normal file
View File

@@ -0,0 +1,104 @@
name: Build Kernel - Android 16
on:
# push:
# branches: ["main", "ci", "checkci"]
# paths:
# - ".github/workflows/deps/gki/build-kernel-a16.yml"
# - ".github/workflows/deps/gki/gki-kernel.yml"
# - ".github/scripts/build_a13.sh"
# - "kernel/**"
workflow_call:
inputs:
debug:
description: 'Build debug kernel'
required: false
type: boolean
default: false
workflow_dispatch:
inputs:
debug:
description: 'Build debug kernel'
required: false
type: boolean
default: false
jobs:
build-kernel:
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
strategy:
matrix:
include:
- version: "6.12"
sub_level: 38
os_patch_level: 2025-08
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
version: android16-${{ matrix.version }}
version_name: android16-${{ matrix.version }}.${{ matrix.sub_level }}
tag: android16-${{ matrix.version }}-${{ matrix.os_patch_level }}
os_patch_level: ${{ matrix.os_patch_level }}
patch_path: ${{ matrix.version }}
debug: ${{ inputs.debug || false }}
upload-artifacts:
needs: build-kernel
runs-on: ubuntu-latest
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 }}
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 }}
steps:
- name: Download artifacts
uses: actions/download-artifact@v6
- uses: actions/checkout@v5
with:
path: KernelSU
fetch-depth: 0
- name: List artifacts
run: |
tree
- name: Download prebuilt toolchain
run: |
AOSP_MIRROR=https://android.googlesource.com
BRANCH=main-kernel-build-2024
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
pip3 install telethon
- name: Set boot sign key
env:
BOOT_SIGN_KEY: ${{ secrets.BOOT_SIGN_KEY }}
run: |
if [ ! -z "$BOOT_SIGN_KEY" ]; then
echo "$BOOT_SIGN_KEY" > ./kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
fi
- name: Build boot images
run: |
export AVBTOOL=$GITHUB_WORKSPACE/kernel-build-tools/linux-x86/bin/avbtool
export GZIP=$GITHUB_WORKSPACE/build-tools/path/linux-x86/gzip
export LZ4=$GITHUB_WORKSPACE/build-tools/path/linux-x86/lz4
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) + 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@v5
with:
name: boot-images-android16
path: Image-android16*/*.img.gz

View File

@@ -1,74 +0,0 @@
name: Build LKM for KernelSU Local
on:
workflow_call:
inputs:
upload:
required: true
type: boolean
default: true
description: "Whether to upload to branch"
secrets:
# username:github_pat
TOKEN:
required: true
workflow_dispatch:
inputs:
upload:
required: true
type: boolean
default: true
description: "Whether to upload to branch"
jobs:
build-lkm:
strategy:
matrix:
include:
- version: "android12-5.10"
sub_level: 236
os_patch_level: 2025-05
- version: "android13-5.10"
sub_level: 234
os_patch_level: 2025-03
- version: "android13-5.15"
sub_level: 178
os_patch_level: 2025-03
- version: "android14-5.15"
sub_level: 178
os_patch_level: 2025-03
- version: "android14-6.1"
sub_level: 134
os_patch_level: 2025-05
- version: "android15-6.6"
sub_level: 87
os_patch_level: 2025-05
# uses: ./.github/workflows/gki-kernel-mock.yml when debugging
uses: ./.github/workflows/gki-kernel-local.yml
with:
version: ${{ matrix.version }}
version_name: ${{ matrix.version }}.${{ matrix.sub_level }}
tag: ${{ matrix.version }}-${{ matrix.os_patch_level }}
os_patch_level: ${{ matrix.os_patch_level }}
build_lkm: true
push-to-branch:
needs: [build-lkm]
runs-on: self-hosted
if: ${{ inputs.upload }}
steps:
- name: Download all workflow run artifacts
uses: actions/download-artifact@v4
with:
path: bin/
merge-multiple: true
- name: Push to branch LKM
run: |
cd bin
git config --global init.defaultBranch lkm
git init
git remote add origin https://${{ secrets.TOKEN }}@github.com/${{ github.repository }}
git config --local user.name "github-actions[bot]"
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
find . -type f
git add .
git commit -m "Upload LKM from ${{ github.sha }}" -m "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
git push --force --set-upstream origin lkm

View File

@@ -1,74 +1,21 @@
name: Build LKM for KernelSU
on:
workflow_call:
inputs:
upload:
required: true
type: boolean
default: true
description: "Whether to upload to branch"
secrets:
# username:github_pat
TOKEN:
required: true
workflow_dispatch:
inputs:
upload:
required: true
type: boolean
default: true
description: "Whether to upload to branch"
jobs:
build-lkm:
strategy:
fail-fast: false
matrix:
include:
- version: "android12-5.10"
sub_level: 237
os_patch_level: 2025-06
- version: "android13-5.10"
sub_level: 236
os_patch_level: 2025-05
- version: "android13-5.15"
sub_level: 180
os_patch_level: 2025-05
- version: "android14-5.15"
sub_level: 180
os_patch_level: 2025-05
- version: "android14-6.1"
sub_level: 138
os_patch_level: 2025-06
- version: "android15-6.6"
sub_level: 89
os_patch_level: 2025-06
# uses: ./.github/workflows/gki-kernel-mock.yml when debugging
uses: ./.github/workflows/gki-kernel.yml
kmi:
- android12-5.10
- android13-5.10
- android13-5.15
- android14-5.15
- android14-6.1
- android15-6.6
- android16-6.12
uses: ./.github/workflows/ddk-lkm.yml
with:
version: ${{ matrix.version }}
version_name: ${{ matrix.version }}.${{ matrix.sub_level }}
tag: ${{ matrix.version }}-${{ matrix.os_patch_level }}
os_patch_level: ${{ matrix.os_patch_level }}
build_lkm: true
push-to-branch:
needs: [build-lkm]
runs-on: ubuntu-latest
if: ${{ inputs.upload }}
steps:
- name: Download all workflow run artifacts
uses: actions/download-artifact@v4
with:
path: bin/
merge-multiple: true
- name: Push to branch LKM
run: |
cd bin
git config --global init.defaultBranch lkm
git init
git remote add origin https://${{ secrets.TOKEN }}@github.com/${{ github.repository }}
git config --local user.name "github-actions[bot]"
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
find . -type f
git add .
git commit -m "Upload LKM from ${{ github.sha }}" -m "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
git push --force --set-upstream origin lkm
kmi: ${{ matrix.kmi }}
ddk_release: '20251104'

View File

@@ -1,252 +0,0 @@
name: Build Manager Manual
on:
workflow_dispatch:
inputs:
build_lkm:
required: true
type: choice
default: "auto"
options:
- "true"
- "false"
- "auto"
description: "Whether to build lkm"
upload_lkm:
required: true
type: boolean
default: true
description: "Whether to upload lkm"
jobs:
check-build-lkm:
runs-on: self-hosted
outputs:
build_lkm: ${{ steps.check-build.outputs.build_lkm }}
upload_lkm: ${{ steps.check-build.outputs.upload_lkm }}
steps:
- name: check build
id: check-build
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ] && [ "${{ inputs.build_lkm }}" != "auto" ]; then
kernel_changed="${{ inputs.build_lkm }}"
else
kernel_changed=true
mkdir tmp
cd tmp
git config --global init.defaultBranch bot
git config --global user.name 'Bot'
git config --global user.email 'bot@github.shirkneko.io'
git init .
git remote add origin https://github.com/${{ github.repository }}
CURRENT_COMMIT="${{ github.event.head_commit.id }}"
git fetch origin $CURRENT_COMMIT --depth=1
git fetch origin lkm --depth=1
LKM_COMMIT="$(git log --format=%B -n 1 origin/lkm | head -n 1)"
LKM_COMMIT="${LKM_COMMIT#Upload LKM from }"
LKM_COMMIT=$(echo "$LKM_COMMIT" | tr -d '[:space:]')
echo "LKM_COMMIT=$LKM_COMMIT"
git fetch origin "$LKM_COMMIT" --depth=1
git diff --quiet "$LKM_COMMIT" "$CURRENT_COMMIT" -- kernel :!kernel/setup.sh .github/workflows/build-lkm-local.yml .github/workflows/build-kernel-*.yml && kernel_changed=false
cd ..
rm -rf tmp
fi
if [ "${{ github.event_name }}" == "push" ] && [ "${{ github.ref }}" == 'refs/heads/main' ]; then
need_upload=true
elif [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
need_upload="${{ inputs.upload_lkm }}"
else
need_upload=false
fi
echo "kernel changed: $kernel_changed"
echo "need upload: $need_upload"
echo "build_lkm=$kernel_changed" >> "$GITHUB_OUTPUT"
echo "upload_lkm=$need_upload" >> "$GITHUB_OUTPUT"
build-lkm:
needs: check-build-lkm
uses: ./.github/workflows/build-lkm-local.yml
if: ${{ needs.check-build-lkm.outputs.build_lkm == 'true' }}
with:
upload: ${{ needs.check-build-lkm.outputs.upload_lkm == 'true' }}
secrets: inherit
build-susfs:
if: ${{ always() }}
needs: [ check-build-lkm, build-lkm ]
strategy:
matrix:
include:
- target: aarch64-linux-android
os: ubuntu-latest
uses: ./.github/workflows/susfs.yml
with:
target: ${{ matrix.target }}
os: ${{ matrix.os }}
build-kpmmgr:
if: ${{ always() }}
needs: [ check-build-lkm, build-lkm ]
strategy:
matrix:
include:
- target: aarch64-linux-android
os: ubuntu-latest
uses: ./.github/workflows/kpmmgr.yml
with:
target: ${{ matrix.target }}
os: ${{ matrix.os }}
build-ksud:
if: ${{ always() }}
needs: [ check-build-lkm, build-lkm ]
strategy:
matrix:
include:
- target: aarch64-linux-android
os: ubuntu-latest
- target: x86_64-linux-android
os: ubuntu-latest
- target: armv7-linux-androideabi
os: ubuntu-latest
uses: ./.github/workflows/ksud.yml
with:
target: ${{ matrix.target }}
os: ${{ matrix.os }}
pack_lkm: true
pull_lkm: ${{ needs.check-build-lkm.outputs.build_lkm != 'true' }}
build-manager:
if: ${{ always() }}
needs: build-ksud
runs-on: self-hosted
defaults:
run:
working-directory: ./manager
steps:
- name: Checkout
uses: actions/checkout@v4
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 == 'refs/heads/susfs' || github.ref_type == 'tag' }}
run: |
if [ ! -z "${{ secrets.KEYSTORE }}" ]; then
{
echo KEYSTORE_PASSWORD='${{ secrets.KEYSTORE_PASSWORD }}'
echo KEY_ALIAS='${{ secrets.KEY_ALIAS }}'
echo KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}'
echo KEYSTORE_FILE='key.jks'
} >> gradle.properties
echo "${{ secrets.KEYSTORE }}" | base64 -d > key.jks
fi
- name: Download arm64 susfs
uses: actions/download-artifact@v4
with:
name: susfs-aarch64-linux-android
path: .
- name: Download arm64 kpmmgr
uses: actions/download-artifact@v4
with:
name: kpmmgr-aarch64-linux-android
path: .
- name: Download arm64 ksud
uses: actions/download-artifact@v4
with:
name: ksud-aarch64-linux-android
path: .
- name: Download x86_64 ksud
uses: actions/download-artifact@v4
with:
name: ksud-x86_64-linux-android
path: .
- name: Download arm ksud
uses: actions/download-artifact@v4
with:
name: ksud-armv7-linux-androideabi
path: .
- name: Copy ksud to app jniLibs
run: |
mkdir -p app/src/main/jniLibs/arm64-v8a
mkdir -p app/src/main/jniLibs/x86_64
mkdir -p app/src/main/jniLibs/armeabi-v7a
cp -f ../aarch64-linux-android/release/zakozako ../manager/app/src/main/jniLibs/arm64-v8a/libzakozako.so
cp -f ../x86_64-linux-android/release/zakozako ../manager/app/src/main/jniLibs/x86_64/libzakozako.so
cp -f ../armv7-linux-androideabi/release/zakozako ../manager/app/src/main/jniLibs/armeabi-v7a/libzakozako.so
- name: Copy kpmmgr to app jniLibs
run: |
mkdir -p app/src/main/jniLibs/arm64-v8a
cp -f ../arm64-v8a/kpmmgr ../manager/app/src/main/jniLibs/arm64-v8a/libkpmmgr.so
- name: Copy susfs to app jniLibs
run: |
mkdir -p app/src/main/jniLibs/arm64-v8a
cp -f ../arm64-v8a/zakozakozako ../manager/app/src/main/jniLibs/arm64-v8a/libzakozakozako.so
- name: Build with Gradle
run: |
export ANDROID_HOME=/root/.android/sdk
export PATH=$ANDROID_HOME/platform-tools:$ANDROID_HOME/tools:$ANDROID_HOME/tools/bin:$PATH
{
echo 'org.gradle.parallel=true'
echo 'org.gradle.vfs.watch=true'
echo 'org.gradle.jvmargs=-Xmx2048m'
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@v4
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
with:
name: manager
path: manager/app/build/outputs/apk/release/*.apk
- name: Upload mappings
uses: actions/upload-artifact@v4
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
with:
name: "mappings"
path: "manager/app/build/outputs/mapping/release/"
- name: Bot session cache
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
id: bot_session_cache
uses: actions/cache@v4
with:
path: scripts/ksubot.session
key: ${{ runner.os }}-bot-session
- name: Upload to telegram
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
env:
CHAT_ID: ${{ vars.CHAT_ID }}
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
MESSAGE_THREAD_ID: ${{ vars.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")
python3 $GITHUB_WORKSPACE/scripts/ksubot.py $APK
fi

View File

@@ -2,116 +2,42 @@ name: Build Manager
on:
push:
branches: [ "main", "ci" ]
branches: [ "main", "dev", "ci" ]
paths:
- '.github/workflows/build-manager.yml'
- '.github/workflows/build-lkm.yml'
- 'manager/**'
- 'kernel/**'
- 'userspace/ksud/**'
- 'userspace/susfs/**'
- 'userspace/kpmmgr/**'
- 'userspace/user_scanner/**'
pull_request:
branches: [ "main" ]
branches: [ "main", "dev" ]
paths:
- '.github/workflows/build-manager.yml'
- '.github/workflows/build-lkm.yml'
- 'manager/**'
- 'kernel/**'
- 'userspace/ksud/**'
workflow_call:
workflow_dispatch:
inputs:
build_lkm:
required: true
type: choice
default: "auto"
options:
- "true"
- "false"
- "auto"
description: "Whether to build lkm"
upload_lkm:
required: true
type: boolean
default: true
description: "Whether to upload lkm"
jobs:
check-build-lkm:
runs-on: ubuntu-latest
outputs:
build_lkm: ${{ steps.check-build.outputs.build_lkm }}
upload_lkm: ${{ steps.check-build.outputs.upload_lkm }}
steps:
- name: check build
id: check-build
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ] && [ "${{ inputs.build_lkm }}" != "auto" ]; then
kernel_changed="${{ inputs.build_lkm }}"
else
kernel_changed=true
mkdir tmp
cd tmp
git config --global init.defaultBranch bot
git config --global user.name 'Bot'
git config --global user.email 'bot@github.shirkneko.io'
git init .
git remote add origin https://github.com/${{ github.repository }}
CURRENT_COMMIT="${{ github.event.head_commit.id }}"
git fetch origin $CURRENT_COMMIT --depth=1
git fetch origin lkm --depth=1
LKM_COMMIT="$(git log --format=%B -n 1 origin/lkm | head -n 1)"
LKM_COMMIT="${LKM_COMMIT#Upload LKM from }"
LKM_COMMIT=$(echo "$LKM_COMMIT" | tr -d '[:space:]')
echo "LKM_COMMIT=$LKM_COMMIT"
git fetch origin "$LKM_COMMIT" --depth=1
git diff --quiet "$LKM_COMMIT" "$CURRENT_COMMIT" -- kernel :!kernel/setup.sh .github/workflows/build-lkm.yml .github/workflows/build-kernel-*.yml && kernel_changed=false
cd ..
rm -rf tmp
fi
if [ "${{ github.event_name }}" == "push" ] && [ "${{ github.ref }}" == 'refs/heads/main' ]; then
need_upload=true
elif [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
need_upload="${{ inputs.upload_lkm }}"
else
need_upload=false
fi
echo "kernel changed: $kernel_changed"
echo "need upload: $need_upload"
echo "build_lkm=$kernel_changed" >> "$GITHUB_OUTPUT"
echo "upload_lkm=$need_upload" >> "$GITHUB_OUTPUT"
build-lkm:
needs: check-build-lkm
uses: ./.github/workflows/build-lkm.yml
if: ${{ needs.check-build-lkm.outputs.build_lkm == 'true' }}
with:
upload: ${{ needs.check-build-lkm.outputs.upload_lkm == 'true' }}
secrets: inherit
build-susfs:
if: ${{ always() }}
needs: [ check-build-lkm, build-lkm ]
build-user_scanner:
needs: build-lkm
strategy:
matrix:
include:
- target: aarch64-linux-android
- target: All-linux-android
os: ubuntu-latest
uses: ./.github/workflows/susfs.yml
with:
target: ${{ matrix.target }}
os: ${{ matrix.os }}
build-kpmmgr:
if: ${{ always() }}
needs: [ check-build-lkm, build-lkm ]
strategy:
matrix:
include:
- target: aarch64-linux-android
os: ubuntu-latest
uses: ./.github/workflows/kpmmgr.yml
uses: ./.github/workflows/user_scanner.yml
with:
target: ${{ matrix.target }}
os: ${{ matrix.os }}
build-ksud:
if: ${{ always() }}
needs: [ check-build-lkm, build-lkm ]
needs: build-lkm
strategy:
matrix:
include:
@@ -125,13 +51,13 @@ jobs:
with:
target: ${{ matrix.target }}
os: ${{ matrix.os }}
pack_lkm: true
pull_lkm: ${{ needs.check-build-lkm.outputs.build_lkm != 'true' }}
build-manager:
if: ${{ always() }}
needs: build-ksud
runs-on: ubuntu-latest
strategy:
matrix:
spoofed: ["true","false"]
defaults:
run:
working-directory: ./manager
@@ -151,8 +77,27 @@ jobs:
echo "UPLOAD=false" >> $GITHUB_OUTPUT
fi
- name: Determine manager variant for telegram bot
id: determine
run: |
if [ "${{ matrix.spoofed }}" == "true" ]; then
echo "title=Spoofed-Manager" >> $GITHUB_OUTPUT
# maybe need a new var
echo "topicid=${{ vars.MESSAGE_SPOOFED_THREAD_ID }}" >> $GITHUB_OUTPUT
else
echo "title=Manager" >> $GITHUB_OUTPUT
echo "topicid=${{ vars.MESSAGE_THREAD_ID }}" >> $GITHUB_OUTPUT
fi
- name: Run randomizer
if: ${{ matrix.spoofed == 'true' }}
run: |
chmod +x randomizer
./randomizer
- name: Write key
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref == 'refs/heads/susfs' || github.ref_type == 'tag' }}
if: ${{ ( github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' )) || github.ref_type == 'tag' }}
run: |
if [ ! -z "${{ secrets.KEYSTORE }}" ]; then
{
@@ -176,16 +121,10 @@ jobs:
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Download arm64 susfs
- name: Download all userscanner artifacts
uses: actions/download-artifact@v4
with:
name: susfs-aarch64-linux-android
path: .
- name: Download arm64 kpmmgr
uses: actions/download-artifact@v4
with:
name: kpmmgr-aarch64-linux-android
name: userscanner-all-linux-android
path: .
- name: Download arm64 ksud
@@ -211,62 +150,47 @@ jobs:
mkdir -p app/src/main/jniLibs/arm64-v8a
mkdir -p app/src/main/jniLibs/x86_64
mkdir -p app/src/main/jniLibs/armeabi-v7a
cp -f ../aarch64-linux-android/release/zakozako ../manager/app/src/main/jniLibs/arm64-v8a/libzakozako.so
cp -f ../x86_64-linux-android/release/zakozako ../manager/app/src/main/jniLibs/x86_64/libzakozako.so
cp -f ../armv7-linux-androideabi/release/zakozako ../manager/app/src/main/jniLibs/armeabi-v7a/libzakozako.so
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
cp -f ../armv7-linux-androideabi/release/ksud ../manager/app/src/main/jniLibs/armeabi-v7a/libksud.so
- name: Copy kpmmgr to app jniLibs
- name: Copy user_scanner to app jniLibs
run: |
mkdir -p app/src/main/jniLibs/arm64-v8a
cp -f ../arm64-v8a/kpmmgr ../manager/app/src/main/jniLibs/arm64-v8a/libkpmmgr.so
- name: Copy susfs to app jniLibs
run: |
mkdir -p app/src/main/jniLibs/arm64-v8a
cp -f ../arm64-v8a/zakozakozako ../manager/app/src/main/jniLibs/arm64-v8a/libzakozakozako.so
mkdir -p app/src/main/jniLibs/x86_64
mkdir -p app/src/main/jniLibs/armeabi-v7a
cp -f ../arm64-v8a/uid_scanner ../manager/app/src/main/jniLibs/arm64-v8a/libuid_scanner.so
cp -f ../x86_64/uid_scanner ../manager/app/src/main/jniLibs/x86_64/libuid_scanner.so
cp -f ../armeabi-v7a/uid_scanner ../manager/app/src/main/jniLibs/armeabi-v7a/libuid_scanner.so
- name: Build with Gradle
run: |
{
echo 'org.gradle.parallel=true'
echo 'org.gradle.vfs.watch=true'
echo 'org.gradle.jvmargs=-Xmx2048m'
echo 'android.native.buildOutput=verbose'
} >> gradle.properties
sed -i 's/org.gradle.configuration-cache=true//g' gradle.properties
./gradlew clean assembleRelease
run: ./gradlew clean assembleRelease
- name: Upload build artifact
uses: actions/upload-artifact@v4
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 == 'refs/heads/dev' )) || github.ref_type == 'tag' }}
with:
name: manager
name: ${{ steps.determine.outputs.title }}
path: manager/app/build/outputs/apk/release/*.apk
- name: Upload mappings
uses: actions/upload-artifact@v4
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 == 'refs/heads/dev' )) || github.ref_type == 'tag' }}
with:
name: "mappings"
name: "${{ steps.determine.outputs.title }}-mappings"
path: "manager/app/build/outputs/mapping/release/"
- name: Bot session cache
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
id: bot_session_cache
uses: actions/cache@v4
with:
path: scripts/ksubot.session
key: ${{ runner.os }}-bot-session
- name: Upload to telegram
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
env:
CHAT_ID: ${{ vars.CHAT_ID }}
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
MESSAGE_THREAD_ID: ${{ vars.MESSAGE_THREAD_ID }}
MESSAGE_THREAD_ID: ${{ steps.determine.outputs.topicid }}
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
TITLE: ${{ steps.determine.outputs.title }}
BRANCH: ${{ github.ref_name }}
run: |
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
export VERSION=$(git rev-list --count HEAD)

53
.github/workflows/ddk-lkm.yml vendored Normal file
View File

@@ -0,0 +1,53 @@
name: Build KernelSU Kernel Module
on:
workflow_call:
inputs:
kmi:
description: 'KMI version'
required: true
type: string
ddk_release:
description: 'DDK release version'
required: false
default: '20251104'
type: string
jobs:
build-kernelsu-ko:
name: Build kernelsu.ko for ${{ inputs.kmi }}
runs-on: ubuntu-latest
container:
image: ghcr.io/ylarod/ddk:${{ inputs.kmi }}-${{ inputs.ddk_release }}
options: --privileged
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Build kernelsu.ko
run: |
git config --global --add safe.directory /__w/SukiSU-Ultra/SukiSU-Ultra
cd kernel
echo "=== Building kernelsu.ko for KMI: ${{ inputs.kmi }} ==="
CONFIG_KSU=m CONFIG_KSU_MANUAL_SU=y make
echo "=== Build completed ==="
# Create output directory in GitHub workspace
mkdir -p /github/workspace/out
# Copy with KMI-specific naming
OUTPUT_NAME="${{ inputs.kmi }}_kernelsu.ko"
cp kernelsu.ko "/github/workspace/out/$OUTPUT_NAME"
echo "Copied to: /github/workspace/out/$OUTPUT_NAME"
ls -la "/github/workspace/out/$OUTPUT_NAME"
echo "Size: $(du -h "/github/workspace/out/$OUTPUT_NAME" | cut -f1)"
llvm-strip -d "/github/workspace/out/$OUTPUT_NAME"
echo "Size after stripping: $(du -h "/github/workspace/out/$OUTPUT_NAME" | cut -f1)"
- name: Upload kernelsu.ko artifact
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.kmi }}-lkm
path: /github/workspace/out/${{ inputs.kmi }}_kernelsu.ko

View File

@@ -1,252 +0,0 @@
name: GKI Kernel Build Local
on:
workflow_call:
inputs:
version:
required: true
type: string
description: >
Output directory of gki,
for example: android12-5.10
version_name:
required: true
type: string
description: >
With SUBLEVEL of kernel,
for example: android12-5.10.66
tag:
required: true
type: string
description: >
Part of branch name of common kernel manifest,
for example: android12-5.10-2021-11
os_patch_level:
required: false
type: string
description: >
Patch level of common kernel manifest,
for example: 2021-11
default: 2022-05
patch_path:
required: false
type: string
description: >
Directory name of .github/patches/<patch_path>
for example: 5.10
use_cache:
required: false
type: boolean
default: true
embed_ksud:
required: false
type: string
default: ksud-aarch64-linux-android
description: >
Artifact name of prebuilt ksud to be embedded
for example: ksud-aarch64-linux-android
debug:
required: false
type: boolean
default: false
build_lkm:
required: false
type: boolean
default: false
secrets:
BOOT_SIGN_KEY:
required: false
CHAT_ID:
required: false
BOT_TOKEN:
required: false
MESSAGE_THREAD_ID:
required: false
jobs:
build:
name: Build ${{ inputs.version_name }}
runs-on: self-hosted
env:
CCACHE_COMPILERCHECK: "%compiler% -dumpmachine; %compiler% -dumpversion"
CCACHE_NOHASHDIR: "true"
CCACHE_HARDLINK: "true"
steps:
- uses: actions/checkout@v4
with:
path: KernelSU
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: Setup kernel source
run: |
echo "Free space:"
df -h
cd $GITHUB_WORKSPACE
sudo apt-get install repo -y
export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo'
mkdir android-kernel && cd android-kernel
repo init --depth=1 --u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/kernel/manifest -b common-${{ inputs.tag }} --repo-rev=v2.35
REMOTE_BRANCH=$(git ls-remote https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/kernel/common ${{ inputs.tag }})
DEFAULT_MANIFEST_PATH=.repo/manifests/default.xml
if grep -q deprecated <<< $REMOTE_BRANCH; then
echo "Found deprecated branch: ${{ inputs.tag }}"
sed -i 's/"${{ inputs.tag }}"/"deprecated\/${{ inputs.tag }}"/g' $DEFAULT_MANIFEST_PATH
cat $DEFAULT_MANIFEST_PATH
fi
repo --version
repo --trace sync -c -j$(nproc --all) --no-tags
df -h
- name: Setup KernelSU
env:
PATCH_PATH: ${{ inputs.patch_path }}
IS_DEBUG_KERNEL: ${{ inputs.debug }}
run: |
cd $GITHUB_WORKSPACE/android-kernel
echo "[+] KernelSU setup"
GKI_ROOT=$(pwd)
echo "[+] GKI_ROOT: $GKI_ROOT"
echo "[+] Copy KernelSU driver to $GKI_ROOT/common/drivers"
ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $GKI_ROOT/common/drivers/kernelsu
echo "[+] Add KernelSU driver to Makefile"
DRIVER_MAKEFILE=$GKI_ROOT/common/drivers/Makefile
DRIVER_KCONFIG=$GKI_ROOT/common/drivers/Kconfig
grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "\nobj-\$(CONFIG_KSU) += kernelsu/\n" >> "$DRIVER_MAKEFILE"
grep -q "kernelsu" "$DRIVER_KCONFIG" || sed -i "/endmenu/i\\source \"drivers/kernelsu/Kconfig\"" "$DRIVER_KCONFIG"
echo "[+] Apply Compilation Patches"
if [ ! -e build/build.sh ]; then
GLIBC_VERSION=$(ldd --version 2>/dev/null | head -n 1 | awk '{print $NF}')
echo "GLIBC_VERSION: $GLIBC_VERSION"
if [ "$(printf '%s\n' "2.38" "$GLIBC_VERSION" | sort -V | head -n1)" = "2.38" ]; then
echo "Patching resolve_btfids/Makefile"
cd $GKI_ROOT/common/ && sed -i '/\$(Q)\$(MAKE) -C \$(SUBCMD_SRC) OUTPUT=\$(abspath \$(dir \$@))\/ \$(abspath \$@)/s//$(Q)$(MAKE) -C $(SUBCMD_SRC) EXTRA_CFLAGS="$(CFLAGS)" OUTPUT=$(abspath $(dir $@))\/ $(abspath $@)/' tools/bpf/resolve_btfids/Makefile || echo "No patch needed."
fi
fi
if [ "$IS_DEBUG_KERNEL" = "true" ]; then
echo "[+] Enable debug features for kernel"
printf "\nccflags-y += -DCONFIG_KSU_DEBUG\n" >> $GITHUB_WORKSPACE/KernelSU/kernel/Makefile
fi
repo status
echo "[+] KernelSU setup done."
- name: Symbol magic
run: |
echo "[+] Export all symbol from abi_gki_aarch64.xml"
COMMON_ROOT=$GITHUB_WORKSPACE/android-kernel/common
KSU_ROOT=$GITHUB_WORKSPACE/KernelSU
ABI_XML=$COMMON_ROOT/android/abi_gki_aarch64.xml
SYMBOL_LIST=$COMMON_ROOT/android/abi_gki_aarch64
# python3 $KSU_ROOT/scripts/abi_gki_all.py $ABI_XML > $SYMBOL_LIST
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
with:
key: gki-kernel-aarch64-${{ inputs.version_name }}
max-size: 2G
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
- name: Setup for LKM
if: ${{ inputs.build_lkm == true }}
working-directory: android-kernel
run: |
pip install ast-grep-cli
sudo apt-get install llvm-15 -y
ast-grep -U -p '$$$ check_exports($$$) {$$$}' -r '' common/scripts/mod/modpost.c
ast-grep -U -p 'check_exports($$$);' -r '' common/scripts/mod/modpost.c
sed -i '/config KSU/,/help/{s/default y/default m/}' common/drivers/kernelsu/Kconfig
echo "drivers/kernelsu/kernelsu.ko" >> common/android/gki_aarch64_modules
# bazel build, android14-5.15, android14-6.1 use bazel
if [ ! -e build/build.sh ]; then
sed -i 's/needs unknown symbol/Dont abort when unknown symbol/g' build/kernel/*.sh || echo "No unknown symbol scripts found"
if [ -e common/modules.bzl ]; then
sed -i 's/_COMMON_GKI_MODULES_LIST = \[/_COMMON_GKI_MODULES_LIST = \[ "drivers\/kernelsu\/kernelsu.ko",/g' common/modules.bzl
fi
else
TARGET_FILE="build/kernel/build.sh"
if [ ! -e "$TARGET_FILE" ]; then
TARGET_FILE="build/build.sh"
fi
sed -i 's/needs unknown symbol/Dont abort when unknown symbol/g' $TARGET_FILE || echo "No unknown symbol in $TARGET_FILE"
sed -i 's/if ! diff -u "\${KERNEL_DIR}\/\${MODULES_ORDER}" "\${OUT_DIR}\/modules\.order"; then/if false; then/g' $TARGET_FILE
sed -i 's@${ROOT_DIR}/build/abi/compare_to_symbol_list@echo@g' $TARGET_FILE
sed -i 's/needs unknown symbol/Dont abort when unknown symbol/g' build/kernel/*.sh || echo "No unknown symbol scripts found"
fi
- name: Make working directory clean to avoid dirty
working-directory: android-kernel
run: |
if [ -e common/BUILD.bazel ]; then
sed -i '/^[[:space:]]*"protected_exports_list"[[:space:]]*:[[:space:]]*"android\/abi_gki_protected_exports_aarch64",$/d' common/BUILD.bazel
fi
rm common/android/abi_gki_protected_exports_* || echo "No protected exports!"
git config --global user.email "bot@kernelsu.org"
git config --global user.name "KernelSUBot"
cd common/ && git add -A && git commit -a -m "Add KernelSU"
repo status
- name: Build Kernel/LKM
working-directory: android-kernel
run: |
if [ ! -z ${{ vars.EXPECTED_SIZE }} ] && [ ! -z ${{ vars.EXPECTED_HASH }} ]; then
export KSU_EXPECTED_SIZE=${{ vars.EXPECTED_SIZE }}
export KSU_EXPECTED_HASH=${{ vars.EXPECTED_HASH }}
fi
if [ -e build/build.sh ]; then
LTO=thin BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh CC="/usr/bin/ccache clang"
else
tools/bazel run --disk_cache=/home/runner/.cache/bazel --config=fast --config=stamp --lto=thin //common:kernel_aarch64_dist -- --dist_dir=dist
fi
- name: Prepare artifacts
id: prepareArtifacts
run: |
OUTDIR=android-kernel/out/${{ inputs.version }}/dist
if [ ! -e $OUTDIR ]; then
OUTDIR=android-kernel/dist
fi
mkdir output
if [ "${{ inputs.build_lkm}}" = "true" ]; then
llvm-strip-15 -d $OUTDIR/kernelsu.ko
mv $OUTDIR/kernelsu.ko ./output/${{ inputs.version }}_kernelsu.ko
else
cp $OUTDIR/Image ./output/
cp $OUTDIR/Image.lz4 ./output/
git clone https://github.com/Kernel-SU/AnyKernel3
rm -rf ./AnyKernel3/.git
cp $OUTDIR/Image ./AnyKernel3/
fi
- name: Upload Image and Image.gz
uses: actions/upload-artifact@v4
if: ${{ inputs.build_lkm == false }}
with:
name: Image-${{ inputs.version_name }}_${{ inputs.os_patch_level }}
path: ./output/*
- name: Upload AnyKernel3
if: ${{ inputs.build_lkm == false }}
uses: actions/upload-artifact@v4
with:
name: AnyKernel3-${{ inputs.version_name }}_${{ inputs.os_patch_level }}
path: ./AnyKernel3/*
- name: Upload LKM
uses: actions/upload-artifact@v4
if: ${{ inputs.build_lkm == true }}
with:
name: ${{ inputs.version }}-lkm
path: ./output/*_kernelsu.ko

View File

@@ -1,79 +0,0 @@
name: GKI Kernel Build
on:
workflow_call:
inputs:
version:
required: true
type: string
description: >
Output directory of gki,
for example: android12-5.10
version_name:
required: true
type: string
description: >
With SUBLEVEL of kernel,
for example: android12-5.10.66
tag:
required: true
type: string
description: >
Part of branch name of common kernel manifest,
for example: android12-5.10-2021-11
os_patch_level:
required: false
type: string
description: >
Patch level of common kernel manifest,
for example: 2021-11
default: 2022-05
patch_path:
required: false
type: string
description: >
Directory name of .github/patches/<patch_path>
for example: 5.10
use_cache:
required: false
type: boolean
default: true
embed_ksud:
required: false
type: string
default: ksud-aarch64-linux-android
description: >
Artifact name of prebuilt ksud to be embedded
for example: ksud-aarch64-linux-android
debug:
required: false
type: boolean
default: false
build_lkm:
required: false
type: boolean
default: false
secrets:
BOOT_SIGN_KEY:
required: false
CHAT_ID:
required: false
BOT_TOKEN:
required: false
MESSAGE_THREAD_ID:
required: false
jobs:
mock_build:
name: Mock build ${{ inputs.version_name }}
runs-on: ubuntu-latest
steps:
- name: Create mocking ko
run: |
echo "${{ inputs.version }}_kernelsu.ko" > ${{ inputs.version }}_kernelsu.ko
- name: Upload LKM
uses: actions/upload-artifact@v4
if: ${{ inputs.build_lkm == true }}
with:
name: ${{ inputs.version }}-lkm
path: ./*_kernelsu.ko

View File

@@ -77,10 +77,10 @@ jobs:
with:
root-reserve-mb: 8192
temp-reserve-mb: 2048
remove-dotnet: 'true'
remove-android: 'true'
remove-haskell: 'true'
remove-codeql: 'true'
remove-dotnet: "true"
remove-android: "true"
remove-haskell: "true"
remove-codeql: "true"
- uses: actions/checkout@v4
with:
@@ -103,7 +103,7 @@ jobs:
cd $GITHUB_WORKSPACE
sudo apt-get install repo -y
mkdir android-kernel && cd android-kernel
repo init --depth=1 --u https://android.googlesource.com/kernel/manifest -b common-${{ inputs.tag }} --repo-rev=v2.35
repo init --depth=1 --u https://android.googlesource.com/kernel/manifest -b common-${{ inputs.tag }} --repo-rev=v2.16
REMOTE_BRANCH=$(git ls-remote https://android.googlesource.com/kernel/common ${{ inputs.tag }})
DEFAULT_MANIFEST_PATH=.repo/manifests/default.xml
if grep -q deprecated <<< $REMOTE_BRANCH; then
@@ -195,12 +195,35 @@ jobs:
sed -i 's/needs unknown symbol/Dont abort when unknown symbol/g' build/kernel/*.sh || echo "No unknown symbol scripts found"
fi
- name: Append ashmem exports if missing
if: startsWith(inputs.version, 'android16-6.12')
working-directory: android-kernel
run: |
FILE=common/drivers/staging/android/ashmem.c
if [[ -f "$FILE" ]] && ! grep -q 'is_ashmem_file' "$FILE"; then
cat >>"$FILE" <<'EOF'
bool is_ashmem_file(struct file *file) { return false; }
int ashmem_area_name(struct file *file, char *name) { return 0; }
long ashmem_area_size(struct file *file) { return 0; }
struct file *ashmem_area_vmfile(struct file *file) { return NULL; }
EXPORT_SYMBOL_GPL(is_ashmem_file);
EXPORT_SYMBOL_GPL(ashmem_area_name);
EXPORT_SYMBOL_GPL(ashmem_area_size);
EXPORT_SYMBOL_GPL(ashmem_area_vmfile);
EOF
fi
sed -i -E 's/\$\(CONFIG_ANDROID_BINDER_IPC_RUST\)/m/g' common/drivers/android/Makefile
- name: Make working directory clean to avoid dirty
working-directory: android-kernel
run: |
if [ -e common/BUILD.bazel ]; then
sed -i '/^[[:space:]]*"protected_exports_list"[[:space:]]*:[[:space:]]*"android\/abi_gki_protected_exports_aarch64",$/d' common/BUILD.bazel
# Fix bazel build error
if [ -f common/BUILD.bazel ]; then
[ -f android/abi_gki_protected_exports_aarch64 ] || sed -i '/^[[:space:]]*"protected_exports_list"[[:space:]]*:[[:space:]]*"android\/abi_gki_protected_exports_aarch64",$/d' common/BUILD.bazel
fi
rm common/android/abi_gki_protected_exports_* || echo "No protected exports!"
git config --global user.email "bot@kernelsu.org"
git config --global user.name "KernelSUBot"
@@ -216,9 +239,13 @@ jobs:
fi
if [ -e build/build.sh ]; then
LTO=thin BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh CC="/usr/bin/ccache clang"
else
if [ "${{ inputs.version }}" == "android16-6.12" ]; then
tools/bazel run --disk_cache=/home/runner/.cache/bazel --config=fast --config=stamp --lto=thin //common:kernel_aarch64_dist -- --destdir=dist
else
tools/bazel run --disk_cache=/home/runner/.cache/bazel --config=fast --config=stamp --lto=thin //common:kernel_aarch64_dist -- --dist_dir=dist
fi
fi
- name: Prepare artifacts
id: prepareArtifacts

View File

@@ -9,10 +9,6 @@ on:
required: false
type: string
default: ubuntu-latest
pull_lkm:
required: false
type: boolean
default: true
pack_lkm:
required: false
type: boolean
@@ -21,6 +17,8 @@ on:
required: false
type: boolean
default: true
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: ${{ inputs.os }}
@@ -29,24 +27,11 @@ jobs:
with:
fetch-depth: 0
- name: Pull lkms from branch
if: ${{ inputs.pack_lkm && inputs.pull_lkm }}
uses: actions/checkout@v4
with:
ref: lkm
path: lkm
- name: Download lkms from artifacts
if: ${{ inputs.pack_lkm && !inputs.pull_lkm }}
- name: Download artifacts
uses: actions/download-artifact@v4
- name: Prepare LKM files
if: ${{ inputs.pack_lkm && inputs.pull_lkm }}
run: |
cp lkm/*_kernelsu.ko ./userspace/ksud/bin/aarch64/
- name: Prepare LKM files
if: ${{ inputs.pack_lkm && !inputs.pull_lkm }}
- name: Prepare LKM fies
if: ${{ inputs.pack_lkm }}
run: |
cp android*-lkm/*_kernelsu.ko ./userspace/ksud/bin/aarch64/
@@ -55,10 +40,6 @@ jobs:
rustup update stable
rustup target add x86_64-apple-darwin
rustup target add aarch64-apple-darwin
- uses: Swatinem/rust-cache@v2
with:
workspaces: userspace/ksud
cache-targets: false
- name: Install cross
run: |
@@ -71,4 +52,4 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: ksud-${{ inputs.target }}
path: userspace/ksud/target/**/release/zakozako*
path: userspace/ksud/target/**/release/ksud*

View File

@@ -16,7 +16,7 @@ on:
jobs:
shellcheck:
runs-on: self-hosted
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

View File

@@ -1,40 +0,0 @@
name: Build susfs
on:
push:
branches: [ "mian" ]
paths:
- '.github/workflows/susfs.yml'
- 'userspace/susfs/**'
workflow_dispatch:
workflow_call:
inputs:
target:
required: true
type: string
os:
required: false
type: string
default: self-hosted
jobs:
build-susfs:
name: Build userspace susfs
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build susfs
working-directory: ./userspace/susfs
run: |
$ANDROID_NDK_HOME/ndk-build
- name: Upload a Build Artifact
uses: actions/upload-artifact@v4
with:
name: susfs-aarch64-linux-android
path: ./userspace/susfs/libs

View File

@@ -1,11 +1,11 @@
name: Build kpmmgr
name: Build user_scanner
on:
push:
branches: [ "mian" ]
paths:
- '.github/workflows/kpmmgr.yml'
- 'userspace/kpmmgr/**'
- '.github/workflows/user_scanner.yml'
- 'userspace/user_scanner/**'
workflow_dispatch:
workflow_call:
inputs:
@@ -18,8 +18,8 @@ on:
default: self-hosted
jobs:
build-susfs:
name: Build userspace kpmmgr
build-user_scanner:
name: Build userspace user_scanner
runs-on: ubuntu-latest
steps:
@@ -28,13 +28,13 @@ jobs:
with:
fetch-depth: 0
- name: Build kpmmgr
working-directory: ./userspace/kpmmgr
- name: Build user_scanner
working-directory: ./userspace/user_scanner
run: |
$ANDROID_NDK_HOME/ndk-build
- name: Upload a Build Artifact
uses: actions/upload-artifact@v4
with:
name: kpmmgr-aarch64-linux-android
path: ./userspace/kpmmgr/libs
name: userscanner-all-linux-android
path: ./userspace/user_scanner/libs

2
.gitignore vendored
View File

@@ -1,3 +1,3 @@
.idea
.vscode
CLAUDE.md
.DS_Store

89
Website/.gitignore vendored Normal file
View File

@@ -0,0 +1,89 @@
node_modules
pnpm-lock.yaml
package-lock.json
yarn.lock
.wrangler
.DS_Store
.vscode
.idea
.vite_opt_cache
# Build artifacts
docs/.vitepress/dist/
docs/.vitepress/cache/
docs/.vitepress/.temp/
dist/
# Generated files
docs/public/sw.js
docs/public/favicon*.png
docs/public/favicon.ico
docs/public/android-chrome-*.png
docs/public/apple-touch-icon*.png
docs/public/safari-pinned-tab.svg
docs/public/browserconfig.xml
docs/public/site.webmanifest
docs/public/manifest.webmanifest
docs/public/mstile-*.png
docs/public/favicons.html
favicon-data.json
# Logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Coverage directory used by tools like istanbul
coverage/
*.lcov
# Dependency directories
.pnpm-store/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Stores VSCode versions used for testing VSCode extensions
.vscode-test

14
Website/.prettierignore Normal file
View File

@@ -0,0 +1,14 @@
# Build artifacts
node_modules/
dist/
docs/.vitepress/cache/
docs/.vitepress/dist/
# Logs
*.log
# Lockfiles backup
pnpm-debug.log*
# Generated
.DS_Store

10
Website/.prettierrc.json Normal file
View File

@@ -0,0 +1,10 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"singleQuote": true,
"semi": false,
"trailingComma": "es5",
"printWidth": 100,
"tabWidth": 2,
"arrowParens": "always",
"endOfLine": "lf"
}

7
Website/README.md Normal file
View File

@@ -0,0 +1,7 @@
# SukiSU-Ultra Documentation
[![Website](https://img.shields.io/website?url=https%3A%2F%2Fsukisu.org&logo=Cloudflare&label=Cloudflare%20Pages&style=flat-square)](https://sukisu.org)
[![VitePress](https://img.shields.io/badge/VitePress-2.0.0--alpha.12-646cff?logo=vite&logoColor=white&style=flat-square)](https://vitepress.dev)
[![License](https://img.shields.io/badge/License-Multiple-blue?style=flat-square)](https://sukisu.org/guide/license)
[![Last Commit](https://img.shields.io/github/last-commit/sukisu-ultra/sukisu-ultra?style=flat-square)](https://github.com/sukisu-ultra/sukisu-ultra/commits/main)
[![GitHub Stars](https://img.shields.io/github/stars/sukisu-ultra/sukisu-ultra?style=flat-square)](https://github.com/sukisu-ultra/sukisu-ultra/stargazers)

18
Website/docs/.gitignore vendored Normal file
View File

@@ -0,0 +1,18 @@
/coverage
/src/client/shared.ts
/src/node/shared.ts
*.log
*.tgz
.DS_Store
.idea
.temp
.vite_opt_cache
.vscode
dist
cache
temp
examples-temp
node_modules
pnpm-global
TODOs.md
*.timestamp-*.mjs

View File

@@ -0,0 +1,248 @@
import { defineConfig } from 'vitepress'
import { groupIconMdPlugin, groupIconVitePlugin } from 'vitepress-plugin-group-icons'
import {
GitChangelog,
GitChangelogMarkdownSection,
} from '@nolebase/vitepress-plugin-git-changelog/vite'
import footnote from 'markdown-it-footnote'
import mark from 'markdown-it-mark'
import sub from 'markdown-it-sub'
import taskLists from 'markdown-it-task-lists'
export default defineConfig({
title: 'SukiSU-Ultra',
description: 'Next-Generation Android root solution.',
lastUpdated: true,
cleanUrls: true,
metaChunk: true,
// Global performance optimizations
cacheDir: './.vitepress/cache',
ignoreDeadLinks: false,
// Enhanced markdown with performance focus
markdown: {
math: true,
config(md) {
md.use(groupIconMdPlugin)
md.use(footnote)
md.use(mark)
md.use(sub)
md.use(taskLists)
},
linkify: true,
typographer: true,
lineNumbers: true,
image: {
lazyLoading: true,
},
toc: {
level: [1, 2, 3],
},
theme: {
light: 'github-light',
dark: 'github-dark',
},
},
sitemap: {
hostname: 'https://sukisu.org',
transformItems(items) {
return items
.filter((item) => !item.url.includes('404'))
.map((item) => ({
...item,
changefreq:
item.url === '/' ? 'daily' : item.url.includes('/guide/') ? 'weekly' : 'monthly',
priority: item.url === '/' ? 1.0 : item.url.includes('/guide/') ? 0.9 : 0.7,
}))
},
},
// Critical performance transformations
transformPageData(pageData) {
const canonicalUrl = `https://sukisu.org${pageData.relativePath}`
.replace(/index\.md$/, '')
.replace(/\.md$/, '')
pageData.frontmatter.head ??= []
pageData.frontmatter.head.push(
['link', { rel: 'canonical', href: canonicalUrl }],
['meta', { property: 'og:url', content: canonicalUrl }],
['link', { rel: 'preload', href: '/logo.svg', as: 'image' }]
)
return pageData
},
head: [
// Critical resource hints for global performance
['link', { rel: 'dns-prefetch', href: '//github.com' }],
['link', { rel: 'dns-prefetch', href: '//t.me' }],
['link', { rel: 'dns-prefetch', href: '//sukisu.org' }],
// Essential favicon setup - synced from /favicon during build/dev
['link', { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }],
['link', { rel: 'icon', type: 'image/svg+xml', href: '/favicon.svg' }],
['link', { rel: 'icon', type: 'image/png', sizes: '96x96', href: '/favicon-96x96.png' }],
['link', { rel: 'apple-touch-icon', sizes: '180x180', href: '/apple-touch-icon.png' }],
['link', { rel: 'mask-icon', href: '/safari-pinned-tab.svg', color: '#64edff' }],
// (Removed msapplication meta to avoid referencing non-existent files)
// Web App Manifest
['link', { rel: 'manifest', href: '/site.webmanifest' }],
// Theme and app configuration
['meta', { name: 'theme-color', content: '#64edff' }],
['meta', { name: 'application-name', content: 'SukiSU-Ultra' }],
['meta', { name: 'apple-mobile-web-app-title', content: 'SukiSU-Ultra' }],
['meta', { name: 'apple-mobile-web-app-capable', content: 'yes' }],
['meta', { name: 'apple-mobile-web-app-status-bar-style', content: 'default' }],
// Viewport and mobile optimization
[
'meta',
{ name: 'viewport', content: 'width=device-width, initial-scale=1.0, viewport-fit=cover' },
],
['meta', { name: 'format-detection', content: 'telephone=no' }],
['meta', { property: 'og:type', content: 'website' }],
['meta', { property: 'og:site_name', content: 'SukiSU-Ultra' }],
['meta', { property: 'og:url', content: 'https://sukisu.org/' }],
['meta', { property: 'og:locale', content: 'en_US' }],
['meta', { property: 'og:locale:alternate', content: 'zh_CN' }],
// Twitter optimization for global audience
['meta', { property: 'twitter:card', content: 'summary_large_image' }],
['meta', { property: 'twitter:site', content: '@sukisu_ultra' }],
['meta', { property: 'twitter:creator', content: '@sukisu_ultra' }],
// (Removed Twitter image as no PNG social image is provided)
// Additional SEO optimizations
[
'meta',
{
name: 'robots',
content: 'index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1',
},
],
['meta', { name: 'bingbot', content: 'index, follow' }],
['meta', { name: 'referrer', content: 'strict-origin-when-cross-origin' }],
// Global SEO optimization
[
'meta',
{
name: 'keywords',
content:
'Android root, KernelSU, SukiSU-Ultra, Android kernel, root management, 安卓 root, カーネル, рут',
},
],
['meta', { name: 'author', content: 'SukiSU-Ultra Team' }],
// Enhanced structured data for global search engines
[
'script',
{ type: 'application/ld+json' },
JSON.stringify({
'@context': 'https://schema.org',
'@type': 'SoftwareApplication',
name: 'SukiSU-Ultra',
description: 'Next-Generation Android Root Solution',
applicationCategory: 'SystemApplication',
operatingSystem: 'Android',
url: 'https://sukisu.org',
downloadUrl: 'https://github.com/sukisu-ultra/sukisu-ultra/releases',
supportingData: {
'@type': 'DataCatalog',
name: 'Compatibility Database',
},
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
author: {
'@type': 'Organization',
name: 'SukiSU-Ultra Team',
url: 'https://github.com/sukisu-ultra',
},
}),
],
// PWA optimization for global mobile users (manifest declared above)
['meta', { name: 'apple-mobile-web-app-capable', content: 'yes' }],
['meta', { name: 'apple-mobile-web-app-status-bar-style', content: 'black-translucent' }],
['meta', { name: 'apple-mobile-web-app-title', content: 'SukiSU-Ultra' }],
// Cloudflare Web Analytics
[
'script',
{
defer: '',
src: 'https://static.cloudflareinsights.com/beacon.min.js',
'data-cf-beacon': '{"token": "dcc5feef58bf4c56a170a99f4cec4798"}',
},
],
],
themeConfig: {
logo: { src: '/logo.svg', width: 24, height: 24 },
socialLinks: [
{ icon: 'github', link: 'https://github.com/sukisu-ultra/sukisu-ultra' },
{
icon: {
svg: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-brand-telegram"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M15 10l-4 4l6 6l4 -16l-18 7l4 2l2 6l3 -4" /></svg>',
},
link: 'https://t.me/sukiksu',
},
],
search: {
provider: 'local',
},
},
rewrites: {
'en/:rest*': ':rest*',
},
locales: {
root: {
label: 'English',
},
zh: {
label: '简体中文',
link: '/zh/',
},
},
vite: {
plugins: [
groupIconVitePlugin({
customIcon: {
bash: '<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 256 256"><g fill="none"><rect width="256" height="256" fill="#242938" rx="60"/><path fill="#242938" fill-rule="evenodd" d="m203.819 68.835l-63.14-37.48a23.79 23.79 0 0 0-24.361 0l-63.14 37.48C45.642 73.31 41 81.575 41 90.522v74.961c0 8.945 4.643 17.215 12.18 21.689l63.14 37.473a23.8 23.8 0 0 0 12.179 3.354a23.8 23.8 0 0 0 12.178-3.354l63.14-37.473c7.536-4.474 12.182-12.744 12.182-21.689v-74.96c0-8.948-4.646-17.214-12.18-21.688" clip-rule="evenodd"/><path fill="#fff" fill-rule="evenodd" d="m118.527 220.808l-63.14-37.474c-6.176-3.666-10.013-10.506-10.013-17.852V90.523c0-7.346 3.837-14.186 10.01-17.85l63.143-37.48a19.55 19.55 0 0 1 9.972-2.747c3.495 0 6.943.95 9.973 2.747l63.14 37.48c5.204 3.089 8.714 8.438 9.701 14.437c-2.094-4.469-6.817-5.684-12.32-2.47l-59.734 36.897c-7.448 4.354-12.94 9.24-12.945 18.221v73.604c-.004 5.378 2.168 8.861 5.504 9.871c-1.096.19-2.201.322-3.319.322a19.55 19.55 0 0 1-9.972-2.747m85.292-151.974l-63.14-37.478A23.8 23.8 0 0 0 128.499 28a23.8 23.8 0 0 0-12.181 3.356l-63.14 37.478C45.642 73.308 41 81.576 41 90.524v74.958c0 8.945 4.643 17.215 12.18 21.689l63.14 37.475A23.84 23.84 0 0 0 128.499 228a23.83 23.83 0 0 0 12.178-3.354l63.142-37.475c7.536-4.474 12.18-12.744 12.18-21.689V90.523c0-8.947-4.644-17.215-12.18-21.689" clip-rule="evenodd"/><path fill="#47b353" fill-rule="evenodd" d="m187.267 172.729l-15.722 9.41c-.417.243-.723.516-.726 1.017v4.114c0 .503.338.712.754.467l15.966-9.703c.416-.243.48-.708.483-1.209v-3.629c0-.5-.338-.71-.755-.467" clip-rule="evenodd"/><path fill="#242938" fill-rule="evenodd" d="M153.788 138.098c.509-.258.928.059.935.725l.053 5.439c2.277-.906 4.255-1.148 6.047-.734c.389.104.561.633.402 1.261l-1.197 4.82c-.093.364-.298.732-.545.961a1.3 1.3 0 0 1-.315.234a.7.7 0 0 1-.472.077c-.818-.185-2.763-.61-5.823.94c-3.21 1.625-4.333 4.414-4.311 6.484c.027 2.472 1.295 3.221 5.673 3.296c5.834.097 8.355 2.646 8.416 8.522c.06 5.77-3.02 11.966-7.732 15.763l.104 5.384c.006.648-.415 1.391-.924 1.649l-3.189 1.837c-.511.258-.93-.06-.937-.708l-.055-5.296c-2.731 1.135-5.499 1.409-7.267.699c-.333-.13-.476-.622-.344-1.182l1.156-4.868c.092-.384.295-.768.571-1.012q.147-.142.299-.219c.183-.092.362-.112.514-.055c1.905.642 4.342.342 6.685-.844c2.977-1.506 4.968-4.542 4.937-7.558c-.029-2.737-1.51-3.874-5.113-3.901c-4.586.013-8.861-.891-8.932-7.642c-.057-5.558 2.833-11.342 7.408-14.999l-.057-5.435c-.007-.668.401-1.403.926-1.667z" clip-rule="evenodd"/></g></svg>',
},
}),
GitChangelog({ repoURL: () => 'https://github.com/SukiSU-Ultra/Website' }),
GitChangelogMarkdownSection({
exclude: (id) => id.endsWith('index.md'),
sections: { disableContributors: true },
}),
],
build: {
minify: 'terser',
chunkSizeWarningLimit: 800,
assetsInlineLimit: 8192,
target: 'esnext',
cssCodeSplit: true,
sourcemap: false,
},
server: {
fs: {
allow: ['..'],
},
},
},
})

View File

@@ -0,0 +1,195 @@
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useData } from 'vitepress'
const props = defineProps({
shareText: {
type: String,
default: undefined,
},
copiedText: {
type: String,
default: undefined,
},
includeQuery: {
type: Boolean,
default: false,
},
includeHash: {
type: Boolean,
default: false,
},
copiedTimeout: {
type: Number,
default: 2000,
},
})
defineOptions({ name: 'ArticleShare' })
const copied = ref(false)
const isClient = typeof window !== 'undefined' && typeof document !== 'undefined'
const { theme, lang } = useData()
const defaultShareText = computed(() =>
lang.value?.toLowerCase().startsWith('zh') ? '分享链接' : 'Share link'
)
const defaultCopiedText = computed(() =>
lang.value?.toLowerCase().startsWith('zh') ? '已复制!' : 'Copied!'
)
const defaultCopyFailedText = computed(() =>
lang.value?.toLowerCase().startsWith('zh') ? '复制链接失败:' : 'Failed to copy link:'
)
const i18nShareText = computed(
() => props.shareText ?? (theme.value as any)?.articleShare?.shareText ?? defaultShareText.value
)
const i18nCopiedText = computed(
() =>
props.copiedText ?? (theme.value as any)?.articleShare?.copiedText ?? defaultCopiedText.value
)
const i18nCopyFailedText = computed(
() => (theme.value as any)?.articleShare?.copyFailed ?? defaultCopyFailedText.value
)
const shareLink = computed(() => {
if (!isClient) return ''
const { origin, pathname, search, hash } = window.location
const finalSearch = props.includeQuery ? search : ''
const finalHash = props.includeHash ? hash : ''
return `${origin}${pathname}${finalSearch}${finalHash}`
})
async function copyToClipboard() {
if (copied.value || !isClient) return
try {
if (navigator.clipboard) {
await navigator.clipboard.writeText(shareLink.value)
} else {
const input = document.createElement('input')
input.setAttribute('readonly', 'readonly')
input.setAttribute('value', shareLink.value)
document.body.appendChild(input)
input.select()
document.execCommand('copy')
document.body.removeChild(input)
}
copied.value = true
setTimeout(() => {
copied.value = false
}, props.copiedTimeout)
} catch (error) {
console.error(i18nCopyFailedText.value, error)
}
}
const shareIconSvg = `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8"></path>
<polyline points="16 6 12 2 8 6"></polyline>
<line x1="12" y1="2" x2="12" y2="15"></line>
</svg>
`
const copiedIconSvg = `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M20 6 9 17l-5-5"></path>
</svg>
`
</script>
<template>
<div class="article-share">
<button
:class="['article-share__button', { copied: copied }]"
:aria-label="copied ? i18nCopiedText : i18nShareText"
aria-live="polite"
@click="copyToClipboard"
>
<div v-if="!copied" class="content-wrapper">
<span class="icon" v-html="shareIconSvg"></span>
{{ i18nShareText }}
</div>
<div v-else class="content-wrapper">
<span class="icon" v-html="copiedIconSvg"></span>
{{ i18nCopiedText }}
</div>
</button>
</div>
</template>
<style scoped>
.article-share {
padding: 14px 0;
}
.article-share__button {
display: flex;
justify-content: center;
align-items: center;
font-weight: 500;
font-size: 14px;
position: relative;
z-index: 1;
transition: all 0.4s var(--ease-out-cubic, cubic-bezier(0.33, 1, 0.68, 1));
cursor: pointer;
border: 1px solid transparent;
border-radius: 14px;
padding: 7px 14px;
width: 100%;
overflow: hidden;
color: var(--vp-c-text-1, #333);
background-color: var(--vp-c-bg-alt, #f6f6f7);
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.02);
will-change: transform, box-shadow;
}
.article-share__button::before {
content: '';
position: absolute;
top: 0;
left: -100%;
z-index: -1;
transition: left 0.6s ease;
background-color: var(--vp-c-brand-soft, #ddf4ff);
width: 100%;
height: 100%;
}
.article-share__button:hover {
transform: translateY(-1px);
border-color: var(--vp-c-brand-soft, #ddf4ff);
background-color: var(--vp-c-brand-soft, #ddf4ff);
}
.article-share__button:active {
transform: scale(0.9);
}
.article-share__button.copied {
color: var(--vp-c-brand-1, #007acc);
background-color: var(--vp-c-brand-soft, #ddf4ff);
}
.article-share__button.copied::before {
left: 0;
background-color: var(--vp-c-brand-soft, #ddf4ff);
}
.content-wrapper {
display: flex;
align-items: center;
justify-content: center;
}
.icon {
display: inline-flex;
align-items: center;
margin-right: 6px;
}
</style>

View File

@@ -0,0 +1,12 @@
<script setup lang="ts">
import confetti from 'canvas-confetti'
const media = window.matchMedia('(prefers-reduced-motion: reduce)')
if (!media.matches) {
confetti({
particleCount: 100,
spread: 170,
origin: { y: 0.6 },
})
}
</script>

View File

@@ -0,0 +1,150 @@
<script setup>
import { onBeforeUnmount, onMounted, ref, computed } from 'vue'
const showBackTop = ref(false) // 初始状态设为false
const scrollProgress = ref(0)
// 圆形进度条计算
const radius = 42
const circumference = computed(() => 2 * Math.PI * radius)
function scrollToTop() {
window.scrollTo({
top: 0,
behavior: 'smooth',
})
}
// 使用更高效的节流函数
function throttle(fn, delay = 50) {
let timer = null
return function (...args) {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
}, delay)
}
}
}
const updateScrollProgress = () => {
const { scrollY, innerHeight } = window
const { scrollHeight } = document.documentElement
const totalScroll = scrollHeight - innerHeight
scrollProgress.value = totalScroll > 0 ? Math.min(scrollY / totalScroll, 1) : 0
}
const handleScroll = throttle(() => {
// 当滚动超过100px时显示否则隐藏
const shouldShow = window.scrollY > 100
showBackTop.value = shouldShow
updateScrollProgress()
})
onMounted(() => {
window.addEventListener('scroll', handleScroll)
updateScrollProgress()
})
onBeforeUnmount(() => {
window.removeEventListener('scroll', handleScroll)
})
</script>
<template>
<Transition name="fade">
<div class="back-top-container" v-show="showBackTop">
<svg class="progress-ring" viewBox="0 0 100 100">
<circle class="progress-ring-background" cx="50" cy="50" r="42" />
<circle
class="progress-ring-circle"
cx="50"
cy="50"
r="42"
:style="{ 'stroke-dashoffset': circumference - scrollProgress * circumference }"
/>
</svg>
<div class="vitepress-backTop-main" title="返回顶部" @click="scrollToTop()">
<svg class="icon" viewBox="0 0 1024 1024">
<path
d="M752.736 431.063C757.159 140.575 520.41 8.97 504.518 0.41V0l-0.45 0.205-0.41-0.205v0.41c-15.934 8.56-252.723 140.165-248.259 430.653-48.21 31.457-98.713 87.368-90.685 184.074 8.028 96.666 101.007 160.768 136.601 157.287 35.595-3.482 25.232-30.31 25.232-30.31l12.206-50.095s52.47 80.569 69.304 80.528c15.114-1.23 87-0.123 95.6 0h0.82c8.602-0.123 80.486-1.23 95.6 0 16.794 0 69.305-80.528 69.305-80.528l12.165 50.094s-10.322 26.83 25.272 30.31c35.595 3.482 128.574-60.62 136.602-157.286 8.028-96.665-42.475-152.617-90.685-184.074z m-248.669-4.26c-6.758-0.123-94.781-3.359-102.891-107.192 2.95-98.714 95.97-107.438 102.891-107.93 6.964 0.492 99.943 9.216 102.892 107.93-8.11 103.833-96.174 107.07-102.892 107.192z m-52.019 500.531c0 11.838-9.42 21.382-21.012 21.382a21.217 21.217 0 0 1-21.054-21.34V821.74c0-11.797 9.421-21.382 21.054-21.382 11.591 0 21.012 9.585 21.012 21.382v105.635z m77.333 57.222a21.504 21.504 0 0 1-21.34 21.626 21.504 21.504 0 0 1-21.34-21.626V827.474c0-11.96 9.543-21.668 21.299-21.668 11.796 0 21.38 9.708 21.38 21.668v157.082z m71.147-82.043c0 11.796-9.42 21.34-21.053 21.34a21.217 21.217 0 0 1-21.013-21.34v-75.367c0-11.755 9.421-21.299 21.013-21.299 11.632 0 21.053 9.544 21.053 21.3v75.366z"
fill="#FFF"
/>
</svg>
</div>
</div>
</Transition>
</template>
<style scoped>
.back-top-container {
position: fixed;
bottom: 20px;
right: 20px;
width: 60px;
height: 60px;
z-index: 999;
}
.vitepress-backTop-main {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
cursor: pointer;
width: 44px;
height: 44px;
border-radius: 50%;
background-color: #3eaf7c;
padding: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
display: flex;
align-items: center;
justify-content: center;
z-index: 2;
transition: background-color 0.2s ease;
}
.vitepress-backTop-main:hover {
background-color: #71cda3;
}
.progress-ring {
position: absolute;
width: 100%;
height: 100%;
transform: rotate(-90deg);
z-index: 1;
}
.progress-ring-background {
fill: none;
stroke: rgba(62, 175, 124, 0.15);
stroke-width: 3;
}
.progress-ring-circle {
fill: none;
stroke: #3eaf7c;
stroke-width: 3;
stroke-dasharray: 264; /* 2 * π * 42 */
stroke-linecap: round;
transition: stroke-dashoffset 0.15s ease-out;
}
.icon {
width: 24px;
height: 24px;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>

View File

@@ -0,0 +1,33 @@
// .vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme'
import { NolebaseGitChangelogPlugin } from '@nolebase/vitepress-plugin-git-changelog/client'
import 'virtual:group-icons.css'
import { h, onMounted } from 'vue'
import './style/style.css'
import ArticleShare from './components/ArticleShare.vue'
import backtotop from './components/backtotop.vue'
import '@nolebase/vitepress-plugin-git-changelog/client/style.css'
export default {
extends: DefaultTheme,
Layout: () => {
return h(DefaultTheme.Layout, null, {
'aside-outline-before': () => h(ArticleShare),
'doc-footer-before': () => h(backtotop),
})
},
enhanceApp({ app }) {
app.use(NolebaseGitChangelogPlugin)
// Register service worker in production for offline support and caching
if (
typeof window !== 'undefined' &&
'serviceWorker' in navigator &&
(import.meta as any).env?.PROD
) {
onMounted(() => {
navigator.serviceWorker.register('/sw.js').catch(() => {})
})
}
},
}

View File

@@ -0,0 +1,192 @@
/* .vitepress/theme/style/custom-block.css */
/* 深浅色卡 */
:root {
--custom-block-info-left: #cccccc;
--custom-block-info-bg: #fafafa;
--custom-block-tip-left: #009400;
--custom-block-tip-bg: #e6f6e6;
--custom-block-warning-left: #e6a700;
--custom-block-warning-bg: #fff8e6;
--custom-block-danger-left: #e13238;
--custom-block-danger-bg: #ffebec;
--custom-block-note-left: #4cb3d4;
--custom-block-note-bg: #eef9fd;
--custom-block-important-left: #a371f7;
--custom-block-important-bg: #f4eefe;
--custom-block-caution-left: #e0575b;
--custom-block-caution-bg: #fde4e8;
}
.dark {
--custom-block-info-left: #cccccc;
--custom-block-info-bg: #474748;
--custom-block-tip-left: #009400;
--custom-block-tip-bg: #003100;
--custom-block-warning-left: #e6a700;
--custom-block-warning-bg: #4d3800;
--custom-block-danger-left: #e13238;
--custom-block-danger-bg: #4b1113;
--custom-block-note-left: #4cb3d4;
--custom-block-note-bg: #193c47;
--custom-block-important-left: #a371f7;
--custom-block-important-bg: #230555;
--custom-block-caution-left: #e0575b;
--custom-block-caution-bg: #391c22;
}
/* 标题字体大小 */
.custom-block-title {
font-size: 16px;
}
/* info容器:背景色、左侧 */
.custom-block.info {
border-left: 5px solid var(--custom-block-info-left);
background-color: var(--custom-block-info-bg);
}
/* info容器:svg图 */
.custom-block.info [class*='custom-block-title']::before {
content: '';
background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-11v6h2v-6h-2zm0-4v2h2V7h-2z' fill='%23ccc'/%3E%3C/svg%3E");
width: 20px;
height: 20px;
display: inline-block;
vertical-align: middle;
position: relative;
margin-right: 4px;
left: -5px;
top: -1px;
}
/* 提示容器:边框色、背景色、左侧 */
.custom-block.tip {
/* border-color: var(--custom-block-tip); */
border-left: 5px solid var(--custom-block-tip-left);
background-color: var(--custom-block-tip-bg);
}
/* 提示容器:svg图 */
.custom-block.tip [class*='custom-block-title']::before {
content: '';
background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23009400' d='M7.941 18c-.297-1.273-1.637-2.314-2.187-3a8 8 0 1 1 12.49.002c-.55.685-1.888 1.726-2.185 2.998H7.94zM16 20v1a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-1h8zm-3-9.995V6l-4.5 6.005H11v4l4.5-6H13z'/%3E%3C/svg%3E");
width: 20px;
height: 20px;
display: inline-block;
vertical-align: middle;
position: relative;
margin-right: 4px;
left: -5px;
top: -2px;
}
/* 警告容器:背景色、左侧 */
.custom-block.warning {
border-left: 5px solid var(--custom-block-warning-left);
background-color: var(--custom-block-warning-bg);
}
/* 警告容器:svg图 */
.custom-block.warning [class*='custom-block-title']::before {
content: '';
background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Cpath d='M576.286 752.57v-95.425q0-7.031-4.771-11.802t-11.3-4.772h-96.43q-6.528 0-11.3 4.772t-4.77 11.802v95.424q0 7.031 4.77 11.803t11.3 4.77h96.43q6.528 0 11.3-4.77t4.77-11.803zm-1.005-187.836 9.04-230.524q0-6.027-5.022-9.543-6.529-5.524-12.053-5.524H456.754q-5.524 0-12.053 5.524-5.022 3.516-5.022 10.547l8.538 229.52q0 5.023 5.022 8.287t12.053 3.265h92.913q7.032 0 11.803-3.265t5.273-8.287zM568.25 95.65l385.714 707.142q17.578 31.641-1.004 63.282-8.538 14.564-23.354 23.102t-31.892 8.538H126.286q-17.076 0-31.892-8.538T71.04 866.074q-18.582-31.641-1.004-63.282L455.75 95.65q8.538-15.57 23.605-24.61T512 62t32.645 9.04 23.605 24.61z' fill='%23e6a700'/%3E%3C/svg%3E");
width: 20px;
height: 20px;
display: inline-block;
vertical-align: middle;
position: relative;
margin-right: 4px;
left: -5px;
}
/* 危险容器:背景色、左侧 */
.custom-block.danger {
border-left: 5px solid var(--custom-block-danger-left);
background-color: var(--custom-block-danger-bg);
}
/* 危险容器:svg图 */
.custom-block.danger [class*='custom-block-title']::before {
content: '';
background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2c5.523 0 10 4.477 10 10v3.764a2 2 0 0 1-1.106 1.789L18 19v1a3 3 0 0 1-2.824 2.995L14.95 23a2.5 2.5 0 0 0 .044-.33L15 22.5V22a2 2 0 0 0-1.85-1.995L13 20h-2a2 2 0 0 0-1.995 1.85L9 22v.5c0 .171.017.339.05.5H9a3 3 0 0 1-3-3v-1l-2.894-1.447A2 2 0 0 1 2 15.763V12C2 6.477 6.477 2 12 2zm-4 9a2 2 0 1 0 0 4 2 2 0 0 0 0-4zm8 0a2 2 0 1 0 0 4 2 2 0 0 0 0-4z' fill='%23e13238'/%3E%3C/svg%3E");
width: 20px;
height: 20px;
display: inline-block;
vertical-align: middle;
position: relative;
margin-right: 4px;
left: -5px;
top: -1px;
}
/* 提醒容器:背景色、左侧 */
.custom-block.note {
border-left: 5px solid var(--custom-block-note-left);
background-color: var(--custom-block-note-bg);
}
/* 提醒容器:svg图 */
.custom-block.note [class*='custom-block-title']::before {
content: '';
background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-11v6h2v-6h-2zm0-4v2h2V7h-2z' fill='%234cb3d4'/%3E%3C/svg%3E");
width: 20px;
height: 20px;
display: inline-block;
vertical-align: middle;
position: relative;
margin-right: 4px;
left: -5px;
top: -1px;
}
/* 重要容器:背景色、左侧 */
.custom-block.important {
border-left: 5px solid var(--custom-block-important-left);
background-color: var(--custom-block-important-bg);
}
/* 重要容器:svg图 */
.custom-block.important [class*='custom-block-title']::before {
content: '';
background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Cpath d='M512 981.333a84.992 84.992 0 0 1-84.907-84.906h169.814A84.992 84.992 0 0 1 512 981.333zm384-128H128v-42.666l85.333-85.334v-256A298.325 298.325 0 0 1 448 177.92V128a64 64 0 0 1 128 0v49.92a298.325 298.325 0 0 1 234.667 291.413v256L896 810.667v42.666zm-426.667-256v85.334h85.334v-85.334h-85.334zm0-256V512h85.334V341.333h-85.334z' fill='%23a371f7'/%3E%3C/svg%3E");
width: 20px;
height: 20px;
display: inline-block;
vertical-align: middle;
position: relative;
margin-right: 4px;
left: -5px;
top: -1px;
}
/* 注意容器:背景色、左侧 */
.custom-block.caution {
border-left: 5px solid var(--custom-block-caution-left);
background-color: var(--custom-block-caution-bg);
}
/* 注意容器:svg图 */
.custom-block.caution [class*='custom-block-title']::before {
content: '';
background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2c5.523 0 10 4.477 10 10v3.764a2 2 0 0 1-1.106 1.789L18 19v1a3 3 0 0 1-2.824 2.995L14.95 23a2.5 2.5 0 0 0 .044-.33L15 22.5V22a2 2 0 0 0-1.85-1.995L13 20h-2a2 2 0 0 0-1.995 1.85L9 22v.5c0 .171.017.339.05.5H9a3 3 0 0 1-3-3v-1l-2.894-1.447A2 2 0 0 1 2 15.763V12C2 6.477 6.477 2 12 2zm-4 9a2 2 0 1 0 0 4 2 2 0 0 0 0-4zm8 0a2 2 0 1 0 0 4 2 2 0 0 0 0-4z' fill='%23e13238'/%3E%3C/svg%3E");
width: 20px;
height: 20px;
display: inline-block;
vertical-align: middle;
position: relative;
margin-right: 4px;
left: -5px;
top: -1px;
}

View File

@@ -0,0 +1,125 @@
#app a:focus-visible,
#app button:focus-visible,
#app input[type='checkbox']:focus-visible {
--at-apply: outline-1 outline-primary ring-2 ring-primary;
}
.VPSidebar::-webkit-scrollbar {
background: transparent;
height: 8px;
width: 8px;
margin-right: 8px;
}
#app > div > div.VPLocalNav > div > div > div.outline {
outline-style: none !important;
}
.vp-doc .color-swatch {
display: inline-block;
width: 0.85em;
height: 0.85em;
min-width: 12px;
min-height: 12px;
font-size: inherit;
border: 0;
border-radius: 2px;
margin: 0 3px 0 6px;
cursor: pointer;
}
.medium-zoom-overlay {
z-index: 20;
}
.medium-zoom-image {
z-index: 21;
}
@keyframes slide-enter {
0% {
transform: translateY(10px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 100;
}
}
@media (prefers-reduced-motion: no-preference) {
html:not(.no-sliding) [slide-enter],
html:not(.no-sliding) .slide-enter,
html:not(.no-sliding) .main > div > *,
html:not(.no-sliding) #VPContent > div > div.VPFeatures.VPHomeFeatures > *,
html:not(.no-sliding) .TeamPage > *,
html:not(.no-sliding) .VPHomeHero > * {
--enter-stage: 0;
--enter-step: 90ms;
--enter-initial: 0ms;
animation: slide-enter 1s both 1;
animation-delay: calc(var(--enter-initial) + var(--enter-stage) * var(--enter-step));
}
.main > div > *:nth-child(1) {
--enter-stage: 1;
}
.main > div > *:nth-child(2) {
--enter-stage: 2;
}
.main > div > *:nth-child(3) {
--enter-stage: 3;
}
.main > div > *:nth-child(4) {
--enter-stage: 4;
}
.main > div > *:nth-child(5) {
--enter-stage: 5;
}
.main > div > *:nth-child(6) {
--enter-stage: 6;
}
.main > div > *:nth-child(7) {
--enter-stage: 7;
}
.main > div > *:nth-child(8) {
--enter-stage: 8;
}
.main > div > *:nth-child(9) {
--enter-stage: 9;
}
.main > div > *:nth-child(10) {
--enter-stage: 10;
}
.main > div > *:nth-child(11) {
--enter-stage: 11;
}
.main > div > *:nth-child(12) {
--enter-stage: 12;
}
.main > div > *:nth-child(13) {
--enter-stage: 13;
}
.main > div > *:nth-child(14) {
--enter-stage: 14;
}
.main > div > *:nth-child(15) {
--enter-stage: 15;
}
.main > div > *:nth-child(16) {
--enter-stage: 16;
}
.main > div > *:nth-child(17) {
--enter-stage: 17;
}
.main > div > *:nth-child(18) {
--enter-stage: 18;
}
.main > div > *:nth-child(19) {
--enter-stage: 19;
}
.main > div > *:nth-child(20) {
--enter-stage: 20;
}
}

View File

@@ -0,0 +1,158 @@
@import './custom-block.css';
@import './doc-fade-in.css';
:root:where(:lang(fa)) {
--vp-font-family-base:
'Vazirmatn', 'Inter', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji',
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
}
:root {
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe 30%, #41d1ff);
--vp-home-hero-image-background-image: linear-gradient(-45deg, #bd34fe 50%, #47caff 50%);
--vp-home-hero-image-filter: blur(44px);
/* Enhanced brand color for better contrast */
--vp-c-brand-1: #1e40af;
--vp-c-brand-2: #2563eb;
--vp-c-brand-3: #3b82f6;
--vp-c-brand-soft: rgba(30, 64, 175, 0.14);
/* Button contrast improvements */
--vp-button-brand-bg: #1e40af;
--vp-button-brand-text: #ffffff;
--vp-button-brand-hover-bg: #1d4ed8;
--vp-button-brand-hover-text: #ffffff;
--vp-button-brand-active-bg: #1e3a8a;
--vp-button-brand-active-text: #ffffff;
}
/* Dark mode color overrides for better contrast */
.dark:root {
--vp-c-brand-1: #60a5fa;
--vp-c-brand-2: #3b82f6;
--vp-c-brand-3: #2563eb;
--vp-c-brand-soft: rgba(96, 165, 250, 0.16);
--vp-button-brand-bg: #3b82f6;
--vp-button-brand-text: #000000;
--vp-button-brand-hover-bg: #60a5fa;
--vp-button-brand-hover-text: #000000;
--vp-button-brand-active-bg: #2563eb;
--vp-button-brand-active-text: #000000;
}
@media (min-width: 640px) {
:root {
--vp-home-hero-image-filter: blur(56px);
}
}
@media (min-width: 960px) {
:root {
--vp-home-hero-image-filter: blur(68px);
}
}
.VPHero .VPImage {
filter: drop-shadow(-2px 4px 6px rgba(0, 0, 0, 0.2));
padding: 18px;
}
/* used in reference/default-theme-search */
img[src='/search.png'] {
width: 100%;
aspect-ratio: 1 / 1;
}
/* Enhanced button contrast for accessibility */
.VPButton.brand {
background-color: var(--vp-button-brand-bg) !important;
color: var(--vp-button-brand-text) !important;
border: none;
font-weight: 600;
text-shadow: none;
}
.VPButton.brand:hover {
background-color: var(--vp-button-brand-hover-bg) !important;
color: var(--vp-button-brand-hover-text) !important;
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(30, 64, 175, 0.4);
}
.VPButton.brand:active {
background-color: var(--vp-button-brand-active-bg) !important;
color: var(--vp-button-brand-active-text) !important;
transform: translateY(0);
}
/* Dark mode support for buttons */
.dark .VPButton.brand {
background-color: #3b82f6 !important;
color: #000000 !important;
}
.dark .VPButton.brand:hover {
background-color: #60a5fa !important;
color: #000000 !important;
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
}
.dark .VPButton.brand:active {
background-color: #2563eb !important;
color: #000000 !important;
}
/* Ensure proper contrast for all text elements */
.VPButton.brand .text {
color: inherit !important;
}
/* Focus states for accessibility */
.VPButton.brand:focus-visible {
outline: 2px solid #ffffff;
outline-offset: 2px;
}
.dark .VPButton.brand:focus-visible {
outline: 2px solid #000000;
outline-offset: 2px;
}
@font-face {
font-family: 'HarmonyOS Sans SC';
src: url('/HarmonyOS_Sans_SC.ttf') format('truetype');
}
body {
font-family: 'HarmonyOS Sans SC', sans-serif;
line-height: 1.8;
letter-spacing: 0.05em;
word-spacing: 0.05em;
}
p,
li,
a,
span,
div,
h1,
h2,
h3,
h4,
h5,
h6 {
word-break: break-word;
text-justify: inter-ideograph;
-ms-text-autospace: ideograph-alpha;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
pre,
code {
letter-spacing: normal;
word-spacing: normal;
}

101
Website/docs/config.ts Normal file
View File

@@ -0,0 +1,101 @@
import { defineConfig, type DefaultTheme } from 'vitepress'
import { groupIconMdPlugin, groupIconVitePlugin } from 'vitepress-plugin-group-icons'
export default defineConfig({
lang: 'en-US',
description:
'Next-Generation Android Root Solution - Advanced kernel-based root management for Android devices with KernelSU integration',
themeConfig: {
nav: nav(),
sidebar: {
'/': { base: '/', items: sidebar() },
},
search: { options: searchOptions() },
editLink: {
pattern: 'https://github.com/sukisu-ultra/sukisu-ultra/edit/main/docs/:path',
text: 'Edit this page on GitHub',
},
docFooter: {
prev: 'Previous',
next: 'Next',
},
outline: {
label: 'On this page',
},
lastUpdated: {
text: 'Last updated',
},
notFound: {
title: 'Page Not Found',
quote: "Sorry, we couldn't find what you're looking for.",
linkLabel: 'Go to home',
linkText: 'Take me home',
},
langMenuLabel: 'Languages',
returnToTopLabel: 'Return to top',
sidebarMenuLabel: 'Menu',
darkModeSwitchLabel: 'Theme',
lightModeSwitchTitle: 'Switch to light theme',
darkModeSwitchTitle: 'Switch to dark theme',
skipToContentLabel: 'Skip to content',
},
})
function nav(): DefaultTheme.NavItem[] {
return [
{ text: 'Home', link: '/' },
{
text: 'Getting Started',
items: [
{ text: 'Introduction', link: '/guide/' },
{ text: 'Installation', link: '/guide/installation' },
{ text: 'Compatibility', link: '/guide/compatibility' },
{ text: 'Links', link: '/guide/links' },
{ text: 'license', link: '/guide/license' },
],
},
]
}
function sidebar(): DefaultTheme.SidebarItem[] {
return [
{
text: 'Getting Started',
items: [
{ text: 'Introduction', link: '/guide/' },
{ text: 'Installation', link: '/guide/installation' },
{ text: 'Compatibility', link: '/guide/compatibility' },
{ text: 'Links', link: '/guide/links' },
{ text: 'license', link: '/guide/license' },
],
},
]
}
function searchOptions(): Partial<DefaultTheme.LocalSearchOptions> {
return {
translations: {
button: {
buttonText: 'Search docs',
buttonAriaLabel: 'Search docs',
},
modal: {
noResultsText: 'No results found',
resetButtonTitle: 'Clear query',
footer: {
selectText: 'Select',
navigateText: 'Navigate',
closeText: 'Close',
},
},
},
}
}

View File

@@ -0,0 +1,23 @@
# Compatibility Status
::: info KernelSU
KernelSU (versions prior to v0.9.5) officially supports Android GKI 2.0 devices (kernel 5.10+)
:::
::: warning Legacy Kernel Support
Older kernels (4.4+) are also compatible, but the kernel must be built manually
:::
::: tip Extended Compatibility
SukiSu-Ultra can support 3.x kernels (3.4-3.18) through additional back ports
:::
## Architecture Support
Currently supports the following processor architectures:
| Architecture | Support Level | Notes |
| --------------- | ------------------ | --------------------------- |
| **arm64-v8a** | ✅ Full Support | Primary target architecture |
| **armeabi-v7a** | ✅ Basic Support | Bare minimum functionality |
| **X86_64** | 🟡 Partial Support | Some devices supported |

View File

@@ -0,0 +1,85 @@
# Introduction
Welcome to SukiSU-Ultra, the next-generation Android root solution that provides advanced kernel-based root management for Android devices.
## What is SukiSU-Ultra?
SukiSU-Ultra is a modern, secure, and powerful root solution designed specifically for Android devices. It offers kernel-level root access management with enhanced security features and improved compatibility.
## Key Features
### 🔒 Kernel-based su and root access management
Secure root access management at the kernel level, providing better security and performance compared to traditional solutions.
### 🚫 Not based on OverlayFS module system
Built on Magic Mount technology from 5ec1cff, offering a more stable and reliable foundation.
### 📱 App Profile
Advanced application profiling system that allows you to lock root privileges in a controlled environment.
### 🔧 Enhanced Device Support
Bringing back support for non-GKI/GKI 1.0 devices, ensuring compatibility with older Android devices.
### ⚙️ Extensive Customization
Comprehensive customization options to tailor the root experience to your specific needs.
### 🔌 KPM Kernel Module Support
Full KernelPatch Module (KPM) functionality for advanced kernel modifications and enhancements.
## Why Choose SukiSU-Ultra?
- **Security First**: Advanced security features protect your device and data
- **Modern Architecture**: Built with modern Android security models in mind
- **Wide Compatibility**: Supports both GKI and non-GKI devices
- **Active Development**: Continuously updated with latest Android versions
- **Community Driven**: Open source with active community support
## Getting Started
Ready to get started with SukiSU-Ultra? Follow our step-by-step guide:
1. **[Installation](./installation)** - Learn how to install SukiSU-Ultra on your device
2. **[Compatibility](./compatibility)** - Check device compatibility requirements
3. **[Links](./links)** - Find additional resources and downloads
## System Requirements
Before installing SukiSU-Ultra, ensure your device meets these requirements:
- **Android Version**: Android 8.0 (API 26) or higher
- **Bootloader**: Unlocked bootloader
- **Recovery**: Custom recovery (TWRP recommended)
- **Storage**: At least 100MB free space
- **Knowledge**: Basic understanding of Android modding
## Safety Notice
::: danger Important
⚠️ **Rooting your device can void your warranty and may cause permanent damage if done incorrectly.**
Always:
- Create a full backup before proceeding
- Ensure your device is compatible
- Follow instructions carefully
- Have a recovery plan ready
:::
## Support
Need help? We're here to assist:
- **📖 Documentation**: Comprehensive guides and tutorials
- **💬 Community**: Active community forums and chat
- **🐛 Bug Reports**: GitHub issue tracker
- **📧 Direct Support**: Contact developers for critical issues
---
**Ready to unlock the full potential of your Android device?** Start with our [installation guide](./installation) and join thousands of users who trust SukiSU-Ultra for their root needs.

View File

@@ -0,0 +1,121 @@
# Installation Guide
This guide provides comprehensive instructions for installing SukiSU-Ultra on your Android device. Please follow the steps carefully.
## Prerequisites
Before you begin, ensure you have the following:
- [ ] A compatible device. Check the [Compatibility Guide](./compatibility.md) for details.
- [ ] Unlocked bootloader.
- [ ] Custom recovery installed, such as TWRP.
- [ ] Basic knowledge of flashing custom ROMs and kernels.
- [ ] Your device's kernel source or a compatible pre-built kernel.
## Installation Methods
There are several ways to install SukiSU-Ultra, depending on your device and preference.
### Method 1: Using Pre-built GKI Packages
This is the recommended method for devices with Generic Kernel Image (GKI) 2.0, such as many Xiaomi, Redmi, and Samsung models.[^1]
[^1]: This method is not suitable for devices from manufacturers that heavily modify the kernel, like Meizu, OnePlus, Realme, and Oppo.
#### Steps:
1. **Download GKI Build**: Visit our [resources section](./links.md) to find the appropriate GKI build for your device's kernel version. Download the `.zip` file that includes `AnyKernel3` in its name.
2. **Flash via Recovery**:
- [ ] Boot your device into TWRP recovery.
- [ ] Select "Install".
- [ ] Navigate to the downloaded `AnyKernel3` zip file and select it.
- [ ] Swipe to confirm the flash.
- [ ] Once flashing is complete, reboot your system.
3. **Verify Installation**:
- [ ] Install the SukiSU-Ultra Manager app.
- [ ] Open the app and check if root access is granted and working correctly.
- [ ] You can also verify the new kernel version in your device's settings.
::: details File Format Guide
The `.zip` archive without a suffix is uncompressed. The `.gz` suffix indicates compression used for specific models.
:::
### Method 2: Custom Build for OnePlus Devices
For OnePlus devices, you'll need to create a custom build.
#### Steps:
1. **Gather Device Information**: You will need:
- Your kernel version (e.g., `5.10`, `5.15`).
- Your processor's codename.
- The branch and configuration files from the OnePlus open-source kernel repository.
2. **Create Custom Build**: Use the link in our [resources section](./links.md) to generate a custom build with your device's information.
3. **Flash the Build**:
- [ ] Download the generated `AnyKernel3` zip file.
- [ ] Boot into recovery.
- [ ] Flash the zip file.
- [ ] Reboot and verify the installation.
### Method 3: Manual Kernel Integration (Advanced)
This method is for advanced users who are building a kernel from source.
#### Integration Scripts:
- **Main Branch (GKI)**:
```sh [bash]
curl -LSs "https://raw.githubusercontent.com/SukiSU-Ultra/SukiSU-Ultra/main/kernel/setup.sh" | bash -s main
```
- **Non-GKI Branch**:
```sh [bash]
curl -LSs "https://raw.githubusercontent.com/SukiSU-Ultra/SukiSU-Ultra/main/kernel/setup.sh" | bash -s nongki
```
- **SUSFS-Dev Branch (Recommended)**:
```sh [bash]
curl -LSs "https://raw.githubusercontent.com/SukiSU-Ultra/SukiSU-Ultra/main/kernel/setup.sh" | bash -s susfs-main
```
::: warning Required Kernel Configs
For KPM support, you must enable `CONFIG_KPM=y`.
For non-GKI devices, you also need to enable `CONFIG_KALLSYMS=y` and `CONFIG_KALLSYMS_ALL=y`.
:::
## Post-Installation
### Maintaining Root After OTA Updates
To keep root access after an Over-the-Air (OTA) update, follow these steps ==before rebooting==.
1. **Flash to Inactive Slot**:
- [ ] After the OTA update is downloaded and installed, **do not reboot**.
- [ ] Open the SukiSU-Ultra Manager.
- [ ] Go to the flashing/patching interface.
- [ ] Select your `AnyKernel3` kernel zip file.
- [ ] Choose to install it to the inactive slot.
- [ ] Once flashed, you can safely reboot.
2. **Alternative: LKM Mode**: You can also use LKM mode to install to the unused slot after an OTA.
::: tip
For non-GKI devices, the safest method to retain root after an OTA is to use TWRP to flash the kernel again.
:::
## Verification Checklist
After installation, please verify the following:
- [ ] **Manager App**: The SukiSU-Ultra Manager app opens and shows a successful root status.
- [ ] **Root Access**: Root checker apps confirm that root access is working.
- [ ] **Kernel Version**: The kernel version in `Settings > About Phone` reflects the SukiSU-Ultra kernel.
## Troubleshooting
If you encounter any issues:
1. Double-check the [Compatibility Guide](./compatibility.md).
2. Visit our [GitHub repository](https://github.com/sukisu-ultra/sukisu-ultra) for issues and solutions.
3. Join our [Telegram community](https://t.me/sukiksu) for live support.
::: danger Safety Reminder
⚠️ **Always have a backup!** Keep a copy of your original `boot.img` and be prepared to restore your device if something goes wrong.
:::

View File

@@ -0,0 +1,77 @@
# License
## 📄 Software Licensing
### Kernel Components
::: info GPL-2.0 License
The files in the "kernel" directory are under GPL-2.0-only license
:::
**License:** [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
### Application Core
::: tip GPL-3.0 License
All other parts (except mentioned below) are under GPL-3.0 or later license
:::
**License:** [GPL-3.0 or later](https://www.gnu.org/licenses/gpl-3.0.html)
## Artwork & Brand Assets
### Launcher Icons & Character Art
::: warning Copyright Notice
Special licensing requirements for anime character artwork
:::
The images of the files `ic_launcher(?!.*alt.*).*` with anime character emoticons have specific copyright terms:
**Copyright Holders:**
- **Anime Character Art:** [五十根大虾仁](https://space.bilibili.com/370927)
- **Brand Intellectual Property:** [明风OuO](https://space.bilibili.com/274939213)
- **Vectorization:** @MiRinChan
**License Requirements:**
1. **Creative Commons License:** [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.txt)
2. **Author Authorization:** Required from both copyright holders
3. **Attribution:** Must credit all contributors listed above
::: details Usage Requirements
Before using these artistic assets, you must:
- Comply with Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International license
- Obtain authorization from both original authors for use of artistic content
- Provide proper attribution to all contributors
:::
## 📋 License Summary
| Component | License | Notes |
| -------------------- | ------------------------------------------------------------------------- | ------------------------------------- |
| **Kernel Files** | [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) | Files in `/kernel/` directory |
| **Application Code** | [GPL-3.0+](https://www.gnu.org/licenses/gpl-3.0.html) | Main application components |
| **Character Art** | [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/) | + Author authorization required |
| **Brand Assets** | Mixed Licensing | See specific attribution requirements |
## 🔗 License Links
- **GPL-2.0:** [Full License Text](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- **GPL-3.0:** [Full License Text](https://www.gnu.org/licenses/gpl-3.0.html)
- **CC BY-NC-SA 4.0:** [Full License Text](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.txt)
## 📞 Licensing Questions
For questions about licensing or usage permissions:
1. **Code Licensing:** Refer to respective GPL license terms
2. **Artwork Usage:** Contact original authors for authorization
3. **Commercial Use:** Review CC BY-NC-SA 4.0 restrictions
4. **Distribution:** Ensure compliance with all applicable licenses
::: tip Compliance Note
When redistributing or modifying SukiSU-Ultra, ensure you comply with all applicable licenses and attribution requirements for each component.
:::

View File

@@ -0,0 +1,77 @@
# More Links
## 🌐 Translation & Localization
::: info Contribute Translations
If you need to submit a translation for the manager, please visit our Crowdin project
:::
**Translation Platform:** [Crowdin - SukiSU-Ultra](https://crowdin.com/project/SukiSU-Ultra)
## 🔧 Projects & Builds
Projects compiled based on Sukisu and susfs:
### GKI Builds
::: tip Universal GKI Support
Generic Kernel Image builds with KernelSU and SUSFS integration
:::
**Repository:** [GKI_KernelSU_SUSFS](https://github.com/ShirkNeko/GKI_KernelSU_SUSFS)
### OnePlus Builds
::: tip Device-Specific Builds
Automated OnePlus kernel builds with MKSU and SUSFS
:::
**Repository:** [Action_OnePlus_MKSU_SUSFS](https://github.com/ShirkNeko/Action_OnePlus_MKSU_SUSFS)
## 📱 Community & Support
### Telegram Community
::: info Join Our Community
Connect with other users, get support, and stay updated
:::
**Main Group:** [Tg Group](https://t.me/sukiksu)
### Test Builds
::: warning Experimental Builds
Test builds are experimental and may be unstable
:::
**Test Builds Channel:** [Latest Test Build](https://t.me/Sukiksu/7114)
## Downloads & Releases
### Official Releases
::: tip Stable Releases
Download the latest stable versions from our GitHub releases
:::
**GitHub Releases:** [SukiSU-Ultra Releases](https://github.com/sukisu-ultra/sukisu-ultra/releases)
### Issue Reporting
::: info Bug Reports & Feature Requests
Report bugs or request new features on our GitHub repository
:::
**GitHub Issues:** [Report Issues](https://github.com/sukisu-ultra/sukisu-ultra/issues)
## 🔗 Quick Links Summary
| Resource | Link | Description |
| ------------------ | ---------------------------------------------------------------------------- | ---------------------- |
| **Translations** | [Crowdin](https://crowdin.com/project/SukiSU-Ultra) | Submit translations |
| **Telegram Group** | [t.me/sukiksu](https://t.me/sukiksu) | Community support |
| **Test Builds** | [Test Channel](https://t.me/Sukiksu/7114) | Experimental builds |
| **Releases** | [GitHub Releases](https://github.com/sukisu-ultra/sukisu-ultra/releases) | Stable downloads |
| **Issues** | [GitHub Issues](https://github.com/sukisu-ultra/sukisu-ultra/issues) | Bug reports |
| **GKI Builds** | [GKI Repository](https://github.com/ShirkNeko/GKI_KernelSU_SUSFS) | Universal builds |
| **OnePlus Builds** | [OnePlus Repository](https://github.com/ShirkNeko/Action_OnePlus_MKSU_SUSFS) | Device-specific builds |

37
Website/docs/en/index.md Normal file
View File

@@ -0,0 +1,37 @@
---
layout: home
hero:
name: 'SukiSU-Ultra'
text: 'Next-Generation Android Root Solution'
tagline: Advanced kernel-based root management for Android devices
image:
src: /logo.svg
alt: SukiSU-Ultra
actions:
- theme: brand
text: Get Started
link: /guide/
- theme: alt
text: View on GitHub
link: https://github.com/sukisu-ultra/sukisu-ultra
features:
- title: Kernel-based su and root access management
details: Secure root access management at the kernel level.
- title: Not based on OverlayFS module system
details: Based on Magic Mount from 5ec1cff.
- title: App Profile
details: Lock root privileges in a cage.
- title: Bringing back non-GKI/GKI 1.0 support
details: Enhanced compatibility for older devices.
- title: More customization
details: Extensive customization options available.
- title: Support for KPM kernel modules
details: Full KernelPatch Module functionality.
---

Binary file not shown.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 200 KiB

View File

@@ -0,0 +1,60 @@
# Global headers for security and performance
/*
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Strict-Transport-Security: "max-age=31536000; includeSubDomains; preload"
Permissions-Policy: "camera=(), microphone=(), geolocation=()"
Content-Security-Policy: "default-src 'self'; script-src 'self' https://static.cloudflareinsights.com; img-src 'self' data: https:; style-src 'self' 'unsafe-inline'; font-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'"
# Cache static assets for maximum performance
/assets/*
Cache-Control: public, max-age=31536000, immutable
/*.js
Cache-Control: public, max-age=31536000, immutable
/*.css
Cache-Control: public, max-age=31536000, immutable
/*.woff2
Cache-Control: public, max-age=31536000, immutable
/*.woff
Cache-Control: public, max-age=31536000, immutable
# Images - 30 days cache
/*.svg
Cache-Control: public, max-age=2592000
/*.png
Cache-Control: public, max-age=2592000
/*.jpg
Cache-Control: public, max-age=2592000
/*.jpeg
Cache-Control: public, max-age=2592000
/*.webp
Cache-Control: public, max-age=2592000
/*.avif
Cache-Control: public, max-age=2592000
/*.ico
Cache-Control: public, max-age=2592000
# Manifest and service worker
/site.webmanifest
Cache-Control: public, max-age=86400
/sw.js
Cache-Control: public, max-age=0, must-revalidate
# Offline page and HTML caching
/*.html
Cache-Control: public, max-age=60, must-revalidate
/offline.html
Cache-Control: public, max-age=3600

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 58 KiB

View File

@@ -0,0 +1,535 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="512"
height="512"
viewBox="0 0 512 512"
version="1.1"
id="svg1"
xml:space="preserve"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
sodipodi:docname="zako.optizmism.svg"
inkscape:export-filename="zako.plain.svg"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#999999"
borderopacity="1"
inkscape:showpageshadow="2"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
showguides="false"
inkscape:zoom="2"
inkscape:cx="219"
inkscape:cy="370"
inkscape:window-width="1280"
inkscape:window-height="702"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
showgrid="false"><inkscape:page
x="0"
y="0"
width="512"
height="512"
id="page2"
margin="0"
bleed="0" /></sodipodi:namedview><defs
id="defs1"><inkscape:path-effect
effect="simplify"
id="path-effect79"
is_visible="true"
lpeversion="1.3"
threshold="32.467532"
steps="1"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false" /><inkscape:path-effect
effect="simplify"
id="path-effect78"
is_visible="true"
lpeversion="1.3"
threshold="32.467532"
steps="1"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false" /><inkscape:path-effect
effect="simplify"
id="path-effect77"
is_visible="true"
lpeversion="1.3"
threshold="32.467532"
steps="1"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false" /><inkscape:path-effect
effect="simplify"
id="path-effect76"
is_visible="true"
lpeversion="1.3"
threshold="32.467532"
steps="1"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false" /><inkscape:path-effect
effect="simplify"
id="path-effect75"
is_visible="true"
lpeversion="1.3"
threshold="32.467532"
steps="1"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false" /><inkscape:path-effect
effect="simplify"
id="path-effect61"
is_visible="true"
lpeversion="1.3"
threshold="32.467532"
steps="1"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false" /><inkscape:path-effect
effect="simplify"
id="path-effect42"
is_visible="true"
lpeversion="1.3"
threshold="32.467532"
steps="1"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false" /></defs><g
inkscape:label="main"
inkscape:groupmode="layer"
id="layer1"><path
style="display:inline;opacity:1;fill:#fff9f6;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 164.23888,424.64081 -31.07097,26.05282 c 0,0 -5.19317,18.17613 25.96589,28.93342 31.15907,10.7573 213.29123,1.48377 213.29123,1.48377 0,0 52.30272,11.87012 80.86519,-37.09413 -0.37094,0.74188 -8.90259,19.28895 -8.90259,19.28895 l 1.48377,19.28894 c 0,0 57.73516,-9.41425 30.45647,-148.95524 4.19672,-9.44262 8.39344,-15.21311 8.39344,-15.21311 l -3.14754,-21.77049 c 0,0 5.65758,-40.33533 7.88323,-45.52851 2.22564,-5.19317 9.64447,-11.12823 9.64447,-11.12823 0,0 -2.78206,-20.40177 -6.67694,-26.15136 -0.74189,-3.33847 6.86241,-35.05395 2.04017,-58.05231 -7.04788,-11.87012 -4.82223,-11.87012 -18.918,-25.59495 0,0.37094 8.90259,-44.88389 -0.74188,-73.446367 -2.96753,0 -32.27189,-10.757296 -96.81567,23.740241 -0.37094,1.112824 -26.33683,-30.046242 -153.56969,-15.950474 -0.74188,0 -43.40012,-37.836009 -66.76942,-40.432598 -1.11283,-0.370941 -22.62742,-4.080354 -25.22401,48.964247 0,1.112824 -44.14201,15.950474 -56.01213,64.914721 -11.87012,48.96425 -11.128238,80.86519 -11.128238,80.86519 0,0 -18.904912,27.6632 -9.798121,25.03308 5.346826,-1.54421 4.975885,23.56023 4.975885,23.56023 l -2.225648,39.31977 c 0,0 -14.466709,35.23942 -14.83765,59.72155 -0.370942,24.48212 -0.741883,34.12659 4.822236,48.5933 5.564119,14.46671 20.772711,46.7386 42.658245,63.06002 8.902591,0.37094 18.918001,1.8547 18.918001,1.8547 l 3.70942,-20.77271 c 0,0 18.918,15.95048 32.27189,14.83765 13.35388,-1.11282 -0.74189,-0.74188 -0.74189,-0.74188 l -13.72482,-17.80518 z"
id="path2"
sodipodi:nodetypes="ccscccccccscccccccccscsccsscccsccc"
inkscape:label="整个人的边框" /><path
id="path91"
style="opacity:1;fill:#93d4fa;fill-opacity:1;stroke:#4c4f59;stroke-width:6.9;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 133.91016,110.16992 -69.738285,47.48047 18.263976,30.75433 -31.617492,55.67536 28.5625,17.0625 14.837891,-1.48438 2.226562,-55.64062 2.577791,-4.39109 18.193697,-21.94485 23.74023,-49.70703 z"
sodipodi:nodetypes="ccccccccccc" /><path
style="display:inline;opacity:1;fill:#ace0fe;fill-opacity:1;stroke:#4c4f59;stroke-width:6.54357;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 217.01397,405.82758 c 0,0 7.41728,-25.94462 41.16595,-27.07265 33.74866,-1.12802 53.77534,4.1361 53.77534,4.1361 0,0 11.12594,6.39215 17.80149,14.66435 6.67557,8.2722 28.92743,40.60895 41.53682,48.88115 12.60939,8.27219 15.20545,15.41636 15.20545,15.41636 l -1.85433,11.28027 c 0,0 -14.83458,10.15224 -30.78175,11.65627 -15.94717,1.50404 -147.60404,0 -147.60404,0 l -30.04002,-3.00807"
id="path71"
inkscape:label="衣服底色" /><path
style="fill:#ffffff;fill-opacity:1;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
d="m 363.54127,444.68178 c 0,0 -6.89429,4.06586 -4.86135,6.8059 2.03293,2.74004 5.92201,3.44715 5.92201,3.44715 0,0 4.5962,0.26516 5.12653,-3.53554 0.53033,-3.8007 -3.00521,-6.8059 -3.00521,-6.8059"
id="path60" /><path
style="fill:#ffffff;fill-opacity:1;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
d="m 349.67678,459.82583 c 0,0 4.5,-7.25 7,-5.5 2.5,1.75 -4.25,7.25 -4.25,7.25"
id="path59" /><path
id="path73-8"
style="fill:#ffffff;stroke-width:8.7;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
d="m 228.96985,465.10941 a 8.0341015,5.6995392 0 0 1 -8.0341,5.69953 8.0341015,5.6995392 0 0 1 -8.03411,-5.69953 8.0341015,5.6995392 0 0 1 8.03411,-5.69954 8.0341015,5.6995392 0 0 1 8.0341,5.69954 z" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#6c9cb2;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 220.85246,408.91803 c -0.22678,0.7374 0.77024,1.47887 0.20184,0.3709 -0.55918,-1.08999 0.45864,1.0858 0.58075,1.39596 2.10089,5.33666 1.96407,11.16153 3.60742,16.6426 0.30205,1.00744 0.58829,2.039 0.5936,3.09874"
id="path75"
inkscape:path-effect="#path-effect75"
inkscape:original-d="m 220.85246,408.91803 c 0.0874,0.34973 -0.0874,1.13662 0.26229,1.04918 0.34973,-0.0874 -0.42351,-1.37161 -0.26229,-1.04918 2.70315,5.4063 2.32215,10.60009 3.67213,16 0.44415,1.77662 1.31148,3.74741 1.31148,5.5082" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#6c9cb2;stroke-width:6.9;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 225.57377,436.98361 c -1.22213,4.37272 0.0774,9.22771 2.41807,12.85195 2.34183,3.626 0.85866,8.30929 2.56554,12.06608 1.71568,3.77616 2.21068,8.39349 -0.30117,12.16042 -1.9802,2.96963 -5.23922,5.13567 -6.38674,8.61546 0,0 -0.0736,0.66095 -0.0736,0.66095"
id="path76"
inkscape:path-effect="#path-effect76"
inkscape:original-d="m 225.57377,436.98361 c -1.27879,3.14891 0.64852,9.42818 3.40984,14.95082 0.92316,1.84632 0.76302,8.34571 1.57377,9.96721 1.05661,2.11323 2.18032,6.57378 1.31147,9.18033 -1.55473,4.66419 -8.07296,8.77008 -8.07296,12.2565"
sodipodi:nodetypes="csssc" /><path
style="opacity:1;fill:#fbf3ef;fill-opacity:1;stroke:none;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 259.14754,381.90164 c 0,0 8.91803,15.47541 9.18033,20.98361 0.26229,5.50819 32.26229,-1.83607 32.26229,-1.83607 0,0 -4.45901,-16.78688 -7.34426,-19.40983 -2.88524,-2.62296 -34.09836,0.26229 -34.09836,0.26229 z"
id="path89" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#6c9cb2;stroke-width:4.6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 247.86885,386.36066 c 0.62439,0.76152 1.31219,1.32242 0.35251,0.10604 -0.98535,-1.24891 -0.63523,-0.56343 0.0935,0.24171 1.40155,1.54849 2.30926,3.40606 3.10338,5.34166 1.48771,3.62621 2.15649,7.53104 4.02075,11.02472 1.24886,2.3404 2.74915,4.53757 3.97084,6.89242"
id="path77"
inkscape:path-effect="#path-effect77"
inkscape:original-d="m 247.86885,386.36066 c 3.34102,3.56326 -3.68025,-4.79705 1.83607,2.09836 1.23825,1.54782 3.18087,7.73986 3.67213,9.70492 1.00623,4.02493 4.53306,8.80383 6.03279,11.80327" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#6c9cb2;stroke-width:4.6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 306.62295,386.88525 c 1.62958,6.07854 4.04229,11.93568 6.81967,17.57377"
id="path78"
inkscape:path-effect="#path-effect78"
inkscape:original-d="m 306.62295,386.88525 c 1.57569,6.03983 4.44925,12.83291 6.81967,17.57377" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#6c9cb2;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 335.73771,431.21312 c 0.7696,3.76393 3.24862,7.26774 5.48726,10.89168 2.09754,3.39553 3.33574,7.13199 4.87926,10.7955 2.06975,4.91248 6.75146,8.7424 7.699,13.95386 0.92029,5.06165 5.24206,8.89669 5.27874,14.19502"
id="path79"
inkscape:path-effect="#path-effect79"
inkscape:original-d="m 335.73771,431.21312 c -1.15649,1.03916 3.66917,4.97179 4.45901,8.13114 0.96754,3.87016 3.8848,6.88344 4.72131,10.22951 1.09547,4.38186 5.88097,12.49359 8.39345,16.2623 0.80744,1.21116 0.89968,3.11084 1.57377,4.45901 1.7539,3.50782 4.19672,6.9619 4.19672,10.7541" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#494d55;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 258.62295,384.2623 c 0,0 8.13115,6.81967 11.27869,27.01639"
id="path80" /><path
style="opacity:1;fill:#fbf3ef;fill-opacity:1;stroke:#4c4f59;stroke-width:6.9;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 127.23285,329.0249 c 0,0 -2.59659,60.46343 13.72483,75.30108 8.16071,-8.16071 10.01541,-10.38636 10.01541,-10.38636 l 12.24107,8.53165 5.19317,-4.45129 2.22565,-19.65989 5.19318,-10.01542 5.93506,-12.24106 -8.53165,-8.53165 -15.95047,-19.28894 -3.33848,-4.82224 -4.45129,9.27353 c 0,0 -12.24106,0 -15.95048,-2.59659 -3.70941,-2.59658 -6.306,-1.11282 -6.306,-1.11282 z"
id="path90" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#494d55;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 291.67213,381.37705 c 0,0 7.08197,6.55738 10.22951,26.4918"
id="path81" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#494d55;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 270.16393,404.19672 c 0,0 16.00001,-3.93442 27.80328,-2.62295"
id="path82" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#494d55;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 253.90164,417.83607 c 0,0 37.2459,-13.11476 69.77049,-9.18033 2.09836,3.67213 5.77049,16.78688 -5.77049,20.98361 -4.72131,0 -19.14754,-1.57378 -22.55738,-0.5246 -3.40983,1.04919 -12.59016,0.5246 -18.36065,4.45902 -5.77049,3.93443 -14.68853,8.91803 -18.36066,3.14754 -3.67213,-5.77049 -4.72131,-12.32787 -4.72131,-12.32787 z"
id="path83" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#494d55;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 276.45902,482.62295 c 0,0 -9.70492,-1.57377 1.04918,-46.42623"
id="path84" /><path
style="opacity:1;fill:#fcf6fa;fill-opacity:1;stroke:#494d55;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 287.21312,432.78689 6.29508,50.88524 13.90164,-0.78688 -6.81968,-54.03279 z"
id="path88" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#494d55;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 287.73771,430.95082 5.77049,50.88525"
id="path85" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#494d55;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 300.32787,428.06557 c 0,0 2.09836,37.7705 7.34426,52.98361"
id="path86" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#494d55;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 313.18033,431.21312 c 0,0 7.60656,27.54098 10.22951,35.93442 2.62295,8.39344 -8.13115,15.73771 -8.13115,15.73771"
id="path87" /><path
style="opacity:1;fill:#bce4fd;fill-opacity:1;stroke:none;stroke-width:8.7;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 164.23888,424.64081 -31.07097,26.05282 5.00771,13.72483 20.95818,15.20859 17.08508,2.15431 -11.1287,-20.55238 -1.54637,-22.78395 z"
id="path74" /><path
id="path73"
style="opacity:1;fill:#ffffff;stroke-width:8.7;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
d="m 163.81755,451.10144 a 8.0341015,5.6995392 0 0 1 -8.0341,5.69954 8.0341015,5.6995392 0 0 1 -8.0341,-5.69954 8.0341015,5.6995392 0 0 1 8.0341,-5.69954 8.0341015,5.6995392 0 0 1 8.0341,5.69954 z" /><path
style="opacity:1;fill:#fff9f6;fill-opacity:1;stroke:none;stroke-width:8.7;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 338.36066,376.13115 c 0,0 1.83605,30.95081 -6.29509,51.40983 2.88525,1.04918 14.48107,0.26606 26.91267,-7.34238 12.4316,-7.60844 11.38242,-22.03467 11.38242,-22.03467 l 2.09836,28.85246 c 0,0 24.31867,-28.09873 24.2249,-52.60674 -0.0938,-24.50801 -1.66753,-26.08178 -1.66753,-26.08178 l -11.83407,-1.12685 z"
id="path72" /><path
style="opacity:1;fill:#fde9e7;fill-opacity:1;stroke:none;stroke-width:2.845;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 339.7822,389.85927 c 0,0 38.20695,-7.78977 56.38307,-25.96589 5.56412,8.53165 8.16071,32.64283 8.16071,32.64283 l 2.59659,12.98294 16.32141,-62.68907 -6.67694,-5.19318 -5.93506,-17.43424 c 0,0 -15.20859,15.2086 -27.44966,22.99836 -12.24106,7.78977 -34.12659,19.28895 -34.12659,19.28895 l -10.7573,3.70941 z"
id="path70" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#c3b4b0;stroke-width:2.845;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 347.01555,369.64297 c 0,0 2.22565,10.01541 -1.8547,19.84536 -4.08036,9.82994 -5.00771,9.459 -5.00771,9.459"
id="path69" /><path
style="opacity:1;fill:#fde9e7;fill-opacity:1;stroke:none;stroke-width:6.945;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 380.85246,480 c 0,0 44.59016,-17.31147 59.27869,-87.08197 6.81967,-2.62295 34.09836,-14.68852 39.34426,-25.70491 2.62295,-9.96722 -3.67213,-32 -3.67213,-32 l -24.65574,0.52459 -26.7541,4.72131 -4.72131,11.54098 -8.39344,52.45902 -13.11475,28.32787 -15.73771,36.19672 z"
id="path68" /><path
style="fill:none;fill-opacity:1;stroke:#4c4f59;stroke-width:8.74203;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 147.6556,277.03379 c 0,0 -11.12655,104.13607 127.58449,103.38689 138.71104,-0.74917 149.83759,-100.39017 149.83759,-100.39017"
id="path41"
inkscape:label="脸蛋" /><path
style="opacity:1;fill:#fff9f6;fill-opacity:1;stroke:none;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 123.27869,147.93443 304.78688,21.50819 -24.65573,-40.39344 c 0,0 44.06557,-58.754098 50.88524,-60.327868 6.81967,-1.573771 15.73771,-9.967214 15.73771,-9.967214 l -13.11476,-3.672131 -77.11475,22.032787 c 0,0 -122.7541,-33.57377 -168.39344,-6.295082 -45.63935,27.278689 -69.7705,46.163938 -69.7705,46.163938 z"
id="path33"
inkscape:label="头发底色2" /><path
style="fill:#fde9e7;fill-opacity:1;stroke:none;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 331.44501,66.651771 16.22882,30.84274 47.82991,31.367399 6.30629,1.07795 26.88325,-35.335399 -32.10312,-22.211018 -18.88524,5.245901 -30.42623,-11.540983 z"
id="path35"
inkscape:label="头发部件111" /><path
style="opacity:1;fill:#ace0fe;fill-opacity:1;stroke:none;stroke-width:14.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 431.03375,175.82616 17.06329,-17.0633 50.44802,71.96261 -5.93506,17.80518 -33.38472,18.54706 -12.612,-16.32142 17.80518,-11.12823 z"
id="path29"
inkscape:label="蓝色发卡上" /><path
style="opacity:1;fill:#ace0fe;fill-opacity:1;stroke:#4c4f59;stroke-width:6.945;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 465.90223,261.88453 c 0,0 35.61036,54.52837 2.96753,73.44637 -25.22401,4.08036 -48.22237,2.22565 -48.22237,2.22565 l 10.38636,-26.33683 21.51459,-41.91636 z"
id="path66"
inkscape:label="蓝色发卡下" /><path
style="opacity:1;fill:#febdc7;fill-opacity:1;stroke:none;stroke-width:4.6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 471.86885,57.704918 c 0,0 17.04918,68.983602 -11.01639,110.426232 -7.34426,0.26229 -9.18033,-10.49181 -9.18033,-10.49181 l 2.09836,-6.55737 -1.04918,-9.18033 2.36066,-10.7541 1.83606,-5.5082 -6.29508,-6.03278 -6.55738,-5.2459 -2.88524,-5.24591 2.88524,-5.2459 -2.62295,-5.245899 -4.19672,-2.885246 -3.14754,-1.57377 5.2459,-11.540984 11.80328,-7.344262 z"
id="path64" /><path
id="path57"
style="opacity:1;fill:#ff1c1c;fill-opacity:0.0509804;stroke-width:3.92397;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
d="m 244.26691,326.81357 a 35.587568,21.480417 0 0 1 -35.58757,21.48042 35.587568,21.480417 0 0 1 -35.58757,-21.48042 35.587568,21.480417 0 0 1 35.58757,-21.48042 35.587568,21.480417 0 0 1 35.58757,21.48042 z" /><path
id="path57-1"
style="fill:#ff1c1c;fill-opacity:0.05044398;stroke-width:3.65169;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
d="m 355.20429,336.75188 a 31.611719,20.942554 0 0 1 -31.61171,20.94255 31.611719,20.942554 0 0 1 -31.61172,-20.94255 31.611719,20.942554 0 0 1 31.61172,-20.94255 31.611719,20.942554 0 0 1 31.61171,20.94255 z" /><path
style="display:inline;opacity:1;fill:#fbf3ef;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 188.32787,343.60656 c 0,0 12.06557,-28.32787 15.7377,6.29508 5.24591,-8.91803 9.96722,-17.31148 17.31148,-8.39344 6.81967,2.09836 15.21311,7.34426 4.72131,22.03278 -10.4918,14.68853 16.33814,-18.37136 15.445,-1.63289 -0.72099,13.51206 -24.52214,46.81129 -24.52214,46.81129 0,0 -6.33782,64.18547 -33.41466,70.23144 -36.5485,8.16089 -12.06558,-103.86885 -12.06558,-103.86885 z"
id="path1"
sodipodi:nodetypes="cccsscscc"
inkscape:label="右手" /><path
id="path5"
style="fill:#fbe7e5;stroke-width:10.4;stroke-linecap:round;stroke-miterlimit:1.3;paint-order:fill markers stroke;fill-opacity:0.40581462"
inkscape:label="右手踝阴影"
d="m 193.63133,383.92419 a 12.612,12.241061 0 0 1 -12.612,12.24107 12.612,12.241061 0 0 1 -12.612,-12.24107 12.612,12.241061 0 0 1 12.612,-12.24106 12.612,12.241061 0 0 1 12.612,12.24106 z" /><path
style="fill:#fee4e0;fill-opacity:0.42411327;stroke:none;stroke-width:10.4;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 179.09741,356.52608 14.09576,-20.77271 7.04789,1.48377 0.74188,13.72482 11.49918,-11.49918 9.27353,4.08036 8.53165,5.93506 -5.56412,14.83765 13.72483,-4.82224 -3.33847,17.80518 -47.85143,-27.44965 z"
id="path9"
inkscape:label="右手手指阴影" /><path
style="display:inline;fill:none;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 188.32787,343.60656 c 0,0 12.06557,-28.32787 15.7377,6.29508 5.24591,-8.91803 9.96722,-17.31148 17.31148,-8.39344 6.81967,2.09836 15.21311,7.34426 4.72131,22.03278 -10.4918,14.68853 16.33814,-18.37136 15.445,-1.63289 -0.72099,13.51206 -24.52214,46.81129 -24.52214,46.81129 0,0 -6.33782,64.18547 -33.41466,70.23144 -36.5485,8.16089 -12.06558,-103.86885 -12.06558,-103.86885 z"
id="path1-6"
sodipodi:nodetypes="cccsscscc"
inkscape:label="右手遮挡" /><path
style="opacity:1;fill:#fff9f6;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 137.44262,123.2787 c 0,0 49.33852,-48.649769 86.97684,-58.734919 0.10513,0.76769 -120.16719,-122.15824 -86.97684,58.734919 z"
id="path3"
inkscape:label="头发部件19 左猫耳" /><path
style="fill:#fde9e7;fill-opacity:1;stroke-width:1.18016;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
d="m 198.85246,42 -63.6342,39.016573 3.84123,40.939237 L 184.82787,87 224,64.5 Z"
id="path58"
sodipodi:nodetypes="cccccc" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0.465732;stroke:#a18f90;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
id="path4"
d="m 404.96447,131.7729 c 0.52512,-0.76931 1.0357,-1.54875 1.57536,-2.30793 2.82418,-3.97291 5.82035,-7.82036 8.67758,-11.76948 2.39309,-3.30762 3.93978,-5.54326 6.29133,-8.89998 5.32612,-7.58044 11.18023,-14.760796 17.20894,-21.78699 3.02173,-3.55064 6.06655,-7.098864 9.47662,-10.289082 1.96198,-1.835492 4.21906,-3.672787 6.27415,-5.392122 5.10823,-4.357455 10.66931,-8.109574 16.22169,-11.862072 0,0 -2.92504,-1.864176 -2.92504,-1.864176 v 0 c -5.41592,3.900149 -10.90348,7.705144 -15.99184,12.040062 -1.99887,1.645368 -4.44389,3.611151 -6.36286,5.369248 -3.45237,3.162941 -6.48944,6.731577 -9.48752,10.316639 -5.95526,7.087894 -11.63254,14.399231 -17.00034,21.944173 -5.47138,7.72885 -10.96322,15.45542 -17.11251,22.66867 z"
inkscape:label="头发部件18" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0.465732;stroke:#a18f90;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
id="path6"
d="m 431.7055,96.885136 c 0.68345,-0.01683 1.36993,0.008 2.05351,0.03239 1.26616,0.04274 2.52519,0.175792 3.77564,0.374299 1.34943,0.219358 2.67703,0.547853 3.99756,0.89747 1.30448,0.342355 2.58658,0.760225 3.8587,1.206247 0.34787,0.132122 0.88919,0.332358 1.23164,0.483411 0.1893,0.0835 0.73774,0.373687 0.5597,0.268307 -4.92017,-2.912189 -2.83776,-1.86942 -2.01609,-0.911603 0.4665,0.942833 -0.25414,1.810973 -0.83258,2.515753 -1.05305,1.11546 -2.37988,1.92349 -3.65077,2.76486 -0.70455,0.52564 -1.84263,0.99551 -2.02707,1.9792 -0.13577,0.72412 0.14689,1.00706 0.45808,1.64499 0.25805,0.31484 0.49646,0.64686 0.77415,0.94453 0.63085,0.67625 1.54885,1.45348 2.25243,2.03623 1.28413,1.06359 2.61277,2.07518 3.92585,3.10243 2.22765,1.73231 4.46676,3.44711 6.4408,5.4696 1.24472,1.36548 2.33589,2.86124 3.10757,4.54226 0.57402,1.31239 0.61894,2.68201 0.46471,4.08008 -0.15236,1.542 -1.01177,2.74753 -1.96982,3.90485 -1.25092,1.39253 -2.70297,2.57966 -3.98322,3.94302 -0.61776,0.76458 -1.19371,1.60995 -1.3359,2.60746 -0.0756,0.53059 -0.0152,0.87319 0.031,1.40055 0.18192,1.34638 0.59785,2.64226 1.03422,3.92358 0.46172,1.36123 1.10075,2.65093 1.71056,3.94949 0.57934,1.12566 0.88081,2.32829 0.97901,3.58284 0.0285,1.01273 -0.14083,2.01608 -0.35002,3.00302 -0.18321,0.8594 -0.39147,1.62037 -0.92358,2.32955 -0.69384,0.72591 -1.52468,1.30006 -2.31082,1.91913 0,0 3.13155,1.96912 3.13155,1.96912 v 0 c 0.80747,-0.64335 1.66352,-1.23803 2.37418,-1.9921 0.58364,-0.77755 0.80933,-1.52536 1.00495,-2.4688 0.21825,-1.01967 0.38801,-2.05558 0.38421,-3.10149 -0.0761,-1.29512 -0.34601,-2.55043 -0.93895,-3.71574 -0.60728,-1.2882 -1.24849,-2.56502 -1.72185,-3.91075 -0.43768,-1.25837 -0.85635,-2.529 -1.07055,-3.84806 -0.053,-0.43231 -0.12968,-0.85315 -0.0855,-1.29165 0.0948,-0.94059 0.64999,-1.73394 1.21835,-2.45227 1.27656,-1.3752 2.72864,-2.57131 3.98645,-3.96542 1.00742,-1.20382 1.92485,-2.46496 2.104,-4.07351 0.17452,-1.45227 0.1673,-2.88462 -0.39573,-4.26425 -0.74413,-1.73945 -1.85028,-3.26977 -3.10544,-4.6809 -0.76822,-0.80351 -0.91233,-0.98548 -1.76144,-1.74089 -1.5106,-1.3439 -3.15419,-2.52947 -4.72414,-3.80078 -1.30934,-1.02359 -2.63319,-2.03185 -3.9193,-3.08473 -0.71006,-0.5813 -1.57278,-1.30278 -2.22387,-1.96185 -0.27049,-0.2738 -0.51217,-0.57463 -0.76826,-0.86194 -0.2502,-0.39692 -0.62512,-0.79772 -0.57512,-1.31981 0.0792,-0.82671 1.33713,-1.38331 1.899,-1.81756 1.29884,-0.86671 2.65474,-1.69887 3.73107,-2.84377 0.6873,-0.83746 1.4042,-1.79633 1.075,-2.93575 -0.0816,-0.13585 -0.14456,-0.28482 -0.24481,-0.40755 -0.1097,-0.13429 -0.23095,-0.26613 -0.3791,-0.356228 -1.82458,-1.109627 -3.48552,-2.166773 -5.4739,-2.822822 -1.27815,-0.438878 -2.56689,-0.847162 -3.87638,-1.183261 -1.32827,-0.341807 -2.66392,-0.6605 -4.021,-0.867076 -1.26646,-0.185139 -2.54065,-0.306124 -3.82011,-0.354118 -0.68835,-0.02484 -1.39159,-0.0088 -2.07079,-0.120664 z"
inkscape:label="头发部件17" /><path
style="display:inline;opacity:1;fill:#1a1a1a;fill-opacity:0.465732;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
id="path7"
d="m 472.56515,132.89174 c 0.0148,0.77317 -0.10076,1.54619 -0.19578,2.31209 -0.22663,1.66469 -0.65036,3.29152 -1.09324,4.90909 -0.61155,2.16519 -1.31643,4.30298 -2.07388,6.4211 -0.85906,2.40245 -1.88628,4.73722 -3.04362,7.0095 -1.12519,2.18837 -2.40662,4.28829 -3.77255,6.3331 -1.20044,1.78353 -2.51232,3.48695 -3.85961,5.16088 -0.77567,0.94691 -1.56273,1.88443 -2.34905,2.82249 0,0 3.09439,1.85764 3.09439,1.85764 v 0 c 0.78058,-0.94434 1.56325,-1.88703 2.331,-2.84187 1.33972,-1.69155 2.6509,-3.40675 3.84535,-5.20534 1.36483,-2.06191 2.64248,-4.17929 3.77385,-6.37958 1.16439,-2.28454 2.19746,-4.6314 3.07763,-7.04092 0.77266,-2.11878 1.49327,-4.25705 2.12518,-6.4224 0.46749,-1.62041 0.91079,-3.25003 1.1854,-4.9163 0.11547,-0.76691 0.21504,-1.53597 0.32143,-2.30416 z"
inkscape:label="头发部件16" /><path
style="display:inline;opacity:1;fill:#fff9f6;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 322.62295,86.032787 c 0,0 75.43341,26.120553 110.16394,89.180323 33.44261,60.72132 33.04918,62.42623 33.04918,62.42623 0,0 0.52459,8.39345 -19.93443,11.54099 -2.62295,0 14.68852,30.95082 19.93443,37.2459 -14.68853,7.34426 -16.78689,8.91803 -16.78689,8.91803 0,0 6.29508,7.86885 4.72131,15.73771 -17.31147,-0.52459 -22.55738,-1.04918 -22.55738,-1.04918 0,0 -4.19672,17.31147 -15.7377,33.04918 C 410.22951,333.11475 410.22951,320 410.22951,320 c 0,0 -24.13115,36.72131 -72.39344,41.44262 -1.57377,-2.62295 12.59016,-14.16393 17.83606,-28.32787 -11.54098,1.57377 -14.68852,2.09836 -14.68852,2.09836 l 10.4918,-16.78688 c 0,0 11.01639,-24.13115 9.44262,-28.32787 -1.04918,-2.62295 -32,-57.70492 -32,-57.70492 0,0 -24.65573,33.04918 -43.54098,49.83607 -6.81967,-4.19672 -13.63934,-14.68853 -13.63934,-14.68853 l -12.59017,11.54099 c 0,0 -48.43778,-50.76436 -42.0945,-90.18318 -3.14754,12.06557 0.12729,56.60941 -5.6432,62.3799 -5.24591,-2.09836 -16.2623,-14.68853 -14.16394,-40.91803 -0.52459,-0.52459 -29.90164,41.44262 -29.90164,41.44262 0,0 -4.19672,48.78688 16.2623,73.44262 1.57377,2.62295 -1.57377,16.2623 -31.47541,-2.62295 1.04918,-1.57377 -1.04918,9.96721 -1.04918,9.96721 0,0 -46.68853,2.09836 -45.63935,-60.85245 -2.62295,-2.62296 -13.639341,34.09836 -13.639341,34.09836 0,0 -24.131151,-32 -0.52459,-92.85246 11.803281,-30.42623 23.344261,-52.85246 31.934421,-67.67213 8.59017,-14.81968 14.22951,-22.03279 14.22951,-22.03279"
id="path8"
sodipodi:nodetypes="csccccccccccccccccccccccccccssc"
inkscape:label="头发部件15 头发底色" /><path
id="path36"
style="fill:#fffdfc;stroke-width:7.4278;stroke-linecap:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
inkscape:label="头发打光"
d="m 355.67214,146.88524 a 91.803276,41.967213 0 0 1 -91.80327,41.96721 91.803276,41.967213 0 0 1 -91.80328,-41.96721 91.803276,41.967213 0 0 1 91.80328,-41.96721 91.803276,41.967213 0 0 1 91.80327,41.96721 z" /><path
style="fill:#fde9e7;fill-opacity:1;stroke:none;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 349.37705,329.44262 c 0,0 71.34426,-41.96721 78.68852,-91.27868 0,1.04918 26.22951,28.32786 26.22951,28.32786 l 11.54099,24.13115 -15.73771,7.34426 2.09836,13.63935 -22.03279,-1.04918 -12.59016,30.42623 -12.59016,-17.83607 -23.08197,26.22951 -45.11475,14.68852 z"
id="path37"
inkscape:label="头发阴影"
sodipodi:nodetypes="cccccccccccc" /><path
style="fill:#fde9e7;fill-opacity:1;stroke:none;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 325.2459,144.78689 c 0,0 10.49181,44.06557 2.09836,78.68852 0,10.4918 33.57377,60.85246 33.57377,60.85246 0,0 14.68853,-71.34426 -25.18032,-132.19672 -8.39345,-5.2459 -10.49181,-7.34426 -10.49181,-7.34426 z"
id="path38"
inkscape:label="头发阴影2" /><path
style="fill:#fde9e7;fill-opacity:1;stroke:none;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 186.7541,166.81967 23.08197,1.04918 c 0,0 -14.68853,26.22951 -13.63935,46.16394 -2.09836,-3.14754 -22.03279,31.47541 -22.03279,31.47541 0,0 -9.44262,-14.68853 -3.14754,-50.36066 9.44263,-16.78688 15.73771,-28.32787 15.73771,-28.32787 z"
id="path39"
inkscape:label="头发阴影" /><path
id="path36-5"
style="fill:#fffdfc;stroke-width:6.94619;stroke-linecap:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
inkscape:label="头发打光"
transform="matrix(0.99965843,-0.02613486,0,1,0,0)"
d="m 340.28017,112.23744 a 80.289719,41.967213 0 0 1 -80.28972,41.96721 80.289719,41.967213 0 0 1 -80.28972,-41.96721 80.289719,41.967213 0 0 1 80.28972,-41.967211 80.289719,41.967213 0 0 1 80.28972,41.967211 z" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#a18f90;stroke-width:7.7;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 138.62295,122.4918 c 0,0 53.63935,-52.983604 92.98361,-58.229505"
id="path65"
sodipodi:nodetypes="cc" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#c3b4b0;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 436.45902,268.06557 c 0,0 3.67213,18.36066 -2.62295,42.49181"
id="path17"
inkscape:label="头发部件7" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#c3b4b0;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 418.09836,305.83607 -8.91803,17.83606"
id="path16"
inkscape:label="头发部件8" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#c3b4b0;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 377.70492,300.59016 c 0,0 2.62295,12.06558 -22.03279,32"
id="path15"
inkscape:label="头发部件9" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#c3b4b0;stroke-width:4.2;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 284.32787,97.573771 c 0,0 12.06557,39.344259 -27.80328,119.081969 0.52459,0 53.5082,-38.81967 56.13115,-89.18033"
id="path10"
inkscape:label="头发部件14" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#c3b4b0;stroke-width:5.1;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 272.78689,87.081967 c 0,0 13.63934,-8.393442 18.88524,-0.52459 17.17267,10.839383 13.03281,30.236103 24.19672,44.393443 1.79263,1.85342 7.1718,-0.78131 7.80328,1.77049 4.88126,19.72513 14.81582,50.80617 4.32401,100.11764"
id="path11"
sodipodi:nodetypes="csssc"
inkscape:label="头发部件13" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#c3b4b0;stroke-width:4.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 171.00392,241.8537 c 0,0 -28.56248,-60.09248 92.36438,-147.634619 2.22564,0.741882 -59.35061,54.157419 -66.02755,111.282379"
id="path12"
inkscape:label="头发部件12" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#c3b4b0;stroke-width:3;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 327.34426,143.7377 c 0,0 25.18033,20.45902 32,65.57378"
id="path13"
inkscape:label="头发部件11" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 362.4918,268.59016 -3.14754,19.93443"
id="path14"
inkscape:label="头发部件10" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 421.77049,344.13115 c 0,0 -2.62295,58.22951 -33.57377,111.7377 -30.95082,53.5082 38.29508,15.73771 38.29508,15.73771"
id="path18"
inkscape:label="头发部件6" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 395.01639,348.32787 12.06558,60.32787"
id="path19"
inkscape:label="头发部件5" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 371.93443,423.86885 c 0,0 30.95082,-25.70492 24.65573,-73.96721"
id="path20"
inkscape:label="头发部件4" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 332.06557,427.54098 c 0,0 36.72132,1.57377 38.81968,-29.37705"
id="path21"
inkscape:label="头发部件3" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 372.45902,427.01639 -2.09836,-28.85246"
id="path22"
inkscape:label="头发部件2" /><path
style="fill:#93cefc;fill-opacity:1;stroke:#4d4e59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 377.50929,228.61046 c 0,0 24.13115,1.57377 24.13115,10.49181 -0.52459,3.67213 -11.54099,17.83606 -23.60656,18.88524 -2.09836,-1.57377 -0.52459,-29.37705 -0.52459,-29.37705 z"
id="path34"
sodipodi:nodetypes="cccc"
inkscape:label="兔子发卡后" /><path
style="opacity:1;fill:#fffdfe;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 350.95082,235.54098 c 0,0 -6.55738,-22.03278 1.04918,-22.03278 7.60656,0 13.37705,13.90164 13.37705,13.90164 0,0 5.05941,-17.72738 9.96722,-15.21311 11.79758,6.04389 3.40983,21.77048 3.40983,21.77048 0,0 18.62295,25.96722 -12.06558,27.27869 -30.16717,1.28919 -15.7377,-25.70492 -15.7377,-25.70492 z"
id="path24"
sodipodi:nodetypes="cscscsc"
inkscape:label="兔子发卡" /><path
style="display:inline;opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 332.06557,425.96721 c 0,0 10.49181,-25.18032 6.29509,-49.83606"
id="path23"
inkscape:label="头发部件" /><path
style="display:inline;opacity:1;fill:#e85240;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 192.2623,268.85246 c 0,0 -15.47541,22.03279 -2.62296,35.40984 42.7541,0.26229 43.27869,0.52459 43.27869,0.52459 0,0 11.27869,-8.39345 5.5082,-32 -25.44262,-9.96722 -46.16393,-3.93443 -46.16393,-3.93443 z"
id="path25"
inkscape:label="左眼白" /><path
style="opacity:1;fill:#fbb579;fill-opacity:1;stroke:none;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 188.06557,301.11475 c -0.44151,-8.78192 13.4528,-14.01636 22.29509,-14.42623 8.67244,-0.402 23.2398,3.38526 23.08196,12.06558 -0.0775,4.26198 -11.54098,5.5082 -11.54098,5.5082 0,0 -33.2673,8.16555 -33.83607,-3.14755 z"
id="path27"
sodipodi:nodetypes="saacs"
inkscape:label="左眼瞳" /><path
id="path26"
style="display:inline;opacity:1;fill:#ffffff;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
inkscape:label="眼光"
d="m 217.96721,273.04919 a 7.8688526,7.0819674 0 0 1 -7.86885,7.08197 7.8688526,7.0819674 0 0 1 -7.86885,-7.08197 7.8688526,7.0819674 0 0 1 7.86885,-7.08196 7.8688526,7.0819674 0 0 1 7.86885,7.08196 z" /><path
style="fill:none;fill-opacity:1;stroke:#ebc2bf;stroke-width:2.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 174.16393,245.5082 c 15.08644,-4.76649 31.53934,-7.45293 47.09358,-3.51527 3.29779,0.83486 6.51821,1.99257 9.56216,3.51527"
id="path42"
inkscape:path-effect="#path-effect42"
inkscape:original-d="m 174.16393,245.5082 c 11.60252,-3.79212 36.99244,-9.83166 56.65574,0"
transform="translate(0,4)" /><path
style="opacity:1;fill:#fde9e7;fill-opacity:1;stroke:none;stroke-width:6.945;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 477.77235,132.79697 c 0,0 13.35388,10.01542 14.83765,17.43424 1.48376,7.41883 1.48376,57.4959 1.48376,57.4959 l -4.45129,1.11282 -30.78813,-37.46507 c 0,0 8.90259,-14.46671 11.12824,-22.62741 2.22565,-8.16071 7.78977,-15.95048 7.78977,-15.95048 z"
id="path67" /><path
style="fill:#e85240;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 192.2623,268.85246 c 0,0 -15.47541,22.03279 -2.62296,35.40984 42.7541,0.26229 43.27869,0.52459 43.27869,0.52459 0,0 11.27869,-8.39345 5.5082,-32 -25.44262,-9.96722 -46.16393,-3.93443 -46.16393,-3.93443 z"
id="path25-9"
inkscape:label="左眼遮挡上" /><path
style="display:inline;fill:#e85240;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 325.52138,272.81871 c 17.02505,1.06627 38.81967,23.08196 17.83607,48.26229 -1.57377,0.52459 -48.98481,-5.30599 -49.57378,-9.18033 -0.80561,-5.29953 -7.95666,-41.56799 31.73771,-39.08196 z"
id="path40"
sodipodi:nodetypes="scss"
inkscape:label="右眼白" /><path
style="fill:#fbb579;fill-opacity:1;stroke:none;stroke-width:7.14054;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 293.04592,306.32136 c 2.55323,-8.53469 20.43105,-9.52962 30.78942,-7.36618 10.1594,2.12188 25.66784,9.9581 22.45763,18.22228 -1.5762,4.05766 -15.25453,1.93723 -15.25453,1.93723 0,0 -41.28165,-1.79873 -37.99252,-12.79333 z"
id="path27-0"
sodipodi:nodetypes="saacs"
inkscape:label="左眼瞳" /><path
style="display:inline;fill:none;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 325.52138,272.81871 c 17.02505,1.06627 38.81967,23.08196 17.83607,48.26229 -1.57377,0.52459 -48.98481,-5.30599 -49.57378,-9.18033 -0.80561,-5.29953 -7.95666,-41.56799 31.73771,-39.08196 z"
id="path40-2"
sodipodi:nodetypes="scss"
inkscape:label="右眼遮挡上" /><path
style="fill:none;fill-opacity:1;stroke:#ebc2bf;stroke-width:2.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 309.32819,258.43459 c 0,0 26.2295,-5.2459 36.72131,4.19672"
id="path43" /><path
id="path26-9"
style="display:inline;fill:#ffffff;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
inkscape:label="眼光"
d="m 329.6342,284.99301 a 7.8688526,7.0819674 0 0 1 -7.86885,7.08197 7.8688526,7.0819674 0 0 1 -7.86885,-7.08197 7.8688526,7.0819674 0 0 1 7.86885,-7.08197 7.8688526,7.0819674 0 0 1 7.86885,7.08197 z" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#4c4f59;stroke-width:14.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 170.4918,266.4918 c 0,0 32,-19.93442 70.29509,-2.09836"
id="path28"
inkscape:label="眉毛" /><path
style="fill:none;fill-opacity:1;stroke:#4c4f59;stroke-width:14.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 292.9971,274.17683 c 0,0 35.55098,-12.55026 69.08832,13.13797"
id="path28-2"
inkscape:label="眉毛" /><path
style="display:inline;opacity:1;fill:none;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 431.03375,176.1971 18.17612,-17.43424 41.54542,54.15742"
id="path30"
inkscape:label="蓝色发卡遮挡上" /><path
style="opacity:1;fill:none;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 454.0321,267.44865 43.21466,-23.92571"
id="path31"
sodipodi:nodetypes="cc"
inkscape:label="蓝色发卡遮挡下" /><path
style="display:inline;fill:#fff9f6;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 164.23888,424.64081 -31.07097,26.05282 c 0,0 -5.19317,18.17613 25.96589,28.93342 31.15907,10.7573 213.29123,1.48377 213.29123,1.48377 0,0 52.30272,11.87012 80.86519,-37.09413 -0.37094,0.74188 -8.90259,19.28895 -8.90259,19.28895 l 1.48377,19.28894 c 0,0 57.73516,-9.41425 30.45647,-148.95524 4.19672,-9.44262 8.39344,-15.21311 8.39344,-15.21311 l -3.14754,-21.77049 c 0,0 5.65758,-40.33533 7.88323,-45.52851 2.22564,-5.19317 8.51558,-6.35116 9.64447,-11.12823 2.06907,-8.75561 -2.78206,-20.40177 -6.67694,-26.15136 -0.74189,-3.33847 6.86241,-35.05395 2.04017,-58.05231 -7.04788,-11.87012 -4.82223,-11.87012 -18.918,-25.59495 0,0.37094 8.90259,-44.88389 -0.74188,-73.446367 -2.96753,0 -32.27189,-10.757296 -96.81567,23.740241 -0.37094,1.112824 -26.33683,-30.046242 -153.56969,-15.950474 -0.74188,0 -43.40012,-37.836009 -66.76942,-40.432598 -1.11283,-0.370941 -22.62742,-4.080354 -25.22401,48.964247 0,1.112824 -44.14201,15.950474 -56.01213,64.914721 -11.87012,48.96425 -11.128238,80.86519 -11.128238,80.86519 0,0 -18.904912,27.6632 -9.798121,25.03308 5.346826,-1.54421 4.975885,23.56023 4.975885,23.56023 l -2.225648,39.31977 c 0,0 -14.466709,35.23942 -14.83765,59.72155 -0.370942,24.48212 -0.741883,34.12659 4.822236,48.5933 5.564119,14.46671 20.772711,46.7386 42.658245,63.06002 8.902591,0.37094 18.918001,1.8547 18.918001,1.8547 l 3.70942,-20.77271 c 0,0 18.918,15.95048 32.27189,14.83765 13.35388,-1.11282 -0.74189,-0.74188 -0.74189,-0.74188 l -13.72482,-17.80518 z"
id="path2-4"
sodipodi:nodetypes="ccscccccccsaccccccccscsccsscccsccc"
inkscape:label="上发层" /><path
style="fill:none;fill-opacity:1;stroke:#c3b4b0;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 197.5082,220.06557 18.36065,-12.32786"
id="path46" /><path
style="fill:none;fill-opacity:1;stroke:#c3b4b0;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 327.54114,234.24941 c 0,0 -6.27192,4.90452 -15.85821,-0.991"
id="path47"
sodipodi:nodetypes="cc" /><path
style="display:inline;fill:none;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 322.62295,86.03279 c 0,0 75.43341,26.12055 110.16394,89.18032 33.44261,60.72132 33.04918,62.42623 33.04918,62.42623 0,0 0.52459,8.39345 -19.93443,11.54099 -2.62295,0 14.68852,30.95082 19.93443,37.2459 -14.68853,7.34426 -16.78689,8.91803 -16.78689,8.91803 0,0 6.29508,7.86885 4.72131,15.73771 -17.31147,-0.52459 -22.55738,-1.04918 -22.55738,-1.04918 0,0 -4.19672,17.31147 -15.7377,33.04918 C 410.22951,333.11475 410.22951,320 410.22951,320 c 0,0 -24.13115,36.72131 -72.39344,41.44262 -1.57377,-2.62295 12.59016,-14.16393 17.83606,-28.32787 -11.54098,1.57377 -14.68852,2.09836 -14.68852,2.09836 l 10.4918,-16.78688 c 0,0 11.01639,-24.13115 9.44262,-28.32787 -1.04918,-2.62295 -32,-57.70492 -32,-57.70492 0,0 -24.65573,33.04918 -43.54098,49.83607 -6.81967,-4.19672 -13.63934,-14.68853 -13.63934,-14.68853 l -12.59017,11.54099 c 0,0 -48.43778,-50.76436 -42.0945,-90.18318 -3.14754,12.06557 0.12729,56.60941 -5.6432,62.3799 -5.24591,-2.09836 -16.2623,-14.68853 -14.16394,-40.91803 -0.52459,-0.52459 -29.90164,41.44262 -29.90164,41.44262 0,0 -4.19672,48.78688 16.2623,73.44262 1.57377,2.62295 -1.57377,16.2623 -31.47541,-2.62295 1.04918,-1.57377 -1.04918,9.96721 -1.04918,9.96721 0,0 -46.68853,2.09836 -45.63935,-60.85245 -2.62295,-2.62296 -13.63934,34.09836 -13.63934,34.09836 0,0 -24.13115,-32 -0.52459,-92.85246 11.80328,-30.42623 23.34426,-52.85246 31.93442,-67.67213 8.59017,-14.81968 14.22951,-22.03279 14.22951,-22.03279"
id="path8-0"
sodipodi:nodetypes="csccccccccccccccccccccccccccssc"
inkscape:label="头发部件15 头发底色" /><path
id="path44-3"
style="fill:#a88a8f;stroke:#4c4f59;stroke-width:2.8623;stroke-linecap:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
d="m 216.29183,255.53888 a 8.8904896,7.4928694 0 0 1 -8.89049,7.49287 8.8904896,7.4928694 0 0 1 -8.89049,-7.49287 8.8904896,7.4928694 0 0 1 8.89049,-7.49287 8.8904896,7.4928694 0 0 1 8.89049,7.49287 z" /><path
id="path44"
style="fill:#a88a8f;stroke:#4c4f59;stroke-width:2.8623;stroke-linecap:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
d="m 336.16933,270.5473 a 8.8904896,7.4928694 0 0 1 -8.89049,7.49287 8.8904896,7.4928694 0 0 1 -8.89049,-7.49287 8.8904896,7.4928694 0 0 1 8.89049,-7.49287 8.8904896,7.4928694 0 0 1 8.89049,7.49287 z" /><path
style="opacity:1;fill:none;fill-opacity:0;stroke:#a18f90;stroke-width:10.4;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 318.7189,85.461784 c 0,0 50.44801,17.063296 76.78484,43.400126 26.33683,26.33683 32.64283,39.31978 32.64283,39.31978"
id="path32"
inkscape:label="上方头发边缘加厚" /><path
style="fill:none;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 186.7541,224.52459 10.4918,1.04918"
id="path45" /><path
style="opacity:1;fill:#fcbeb5;fill-opacity:1;stroke:#e99c9b;stroke-width:3.4;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 250.94176,349.98308 c 0,0 -13.91029,-8.90259 -10.0154,-16.69235 3.89488,-7.78977 17.80517,-4.4513 17.80517,-4.4513 0,0 12.98295,-1.29829 20.03083,-3.89488 7.04788,-2.59659 9.64447,5.0077 9.64447,5.0077 0,0 4.76461,6.06544 -4.26583,16.50689 -5.93505,6.86241 -21.14364,7.04788 -21.14364,7.04788"
id="path48"
sodipodi:nodetypes="cscscsc" /><path
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#e99c9b;stroke-width:1.8;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 276.20884,325.76493 c 0,0 4.35031,3.01904 5.37456,7.95235 0.57119,0.10629 3.33355,-3.08729 2.97647,-6.87263 -0.67968,-1.48531 -8.35103,-1.07972 -8.35103,-1.07972 z"
id="path49" /><path
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#e99c9b;stroke-width:1.8;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 245.0067,329.39584 -4.17308,2.78206 -0.0927,6.0278 -0.0956,-0.0355 7.07328,-8.8174 z"
id="path50"
sodipodi:nodetypes="cccccc" /><path
style="fill:none;fill-opacity:1;stroke:#e99c9b;stroke-width:3.4;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 250.94176,349.98308 c 0,0 -13.91029,-8.90259 -10.0154,-16.69235 3.89488,-7.78977 17.80517,-4.4513 17.80517,-4.4513 0,0 12.98295,-1.29829 20.03083,-3.89488 7.04788,-2.59659 9.64447,5.0077 9.64447,5.0077 0,0 4.76461,6.06544 -4.26583,16.50689 -5.93505,6.86241 -21.14364,7.04788 -21.14364,7.04788"
id="path48-2"
sodipodi:nodetypes="cscscsc" /><path
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#e89493;stroke-width:2.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 190.84928,314.92913 6.12053,15.02312"
id="path51" /><path
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#e89493;stroke-width:2.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 204.94505,316.96931 5.56412,14.28124"
id="path52" /><path
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#e89493;stroke-width:2.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 217.92799,317.34025 7.41883,16.50689"
id="path53" /><path
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#e89493;stroke-width:2.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 300.64789,328.46849 6.86242,18.17612"
id="path54" /><path
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#e89493;stroke-width:2.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 312.70348,329.21037 6.67695,17.0633"
id="path55" /><path
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#e89493;stroke-width:2.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 326.24284,328.65396 7.04788,17.99065"
id="path56" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#e49589;stroke-width:4.6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 218.4918,348.98361 c -1.87307,1.30472 -3.33608,3.11401 -4.70333,4.91603 -1.02497,1.35089 -2.00187,2.75003 -2.77208,4.2643"
id="path61"
inkscape:path-effect="#path-effect61"
inkscape:original-d="m 218.4918,348.98361 c -1.70592,0.99645 -5.82749,5.88449 -7.47541,9.18033"
transform="rotate(-3.3120949,219.55256,344.63259)" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#4c4f59;stroke-width:3.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 127.47541,375.08197 c 0,0 -14.42623,-19.14754 -12.06557,-59.54099"
id="path92" /><path
style="opacity:1;fill:#ffffff;fill-opacity:0.734285;stroke:#c1545a;stroke-width:7.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 136.39344,322.09836 c 0,0 9.44263,-18.88525 -4.19672,-39.86885 -3.14754,-0.52459 27.80328,-27.80328 5.2459,-77.11476 -1.57377,0.52459 23.60656,-55.60655 -24.13115,-82.88524 -4.19672,-8.39344 -45.639336,-69.245904 -89.180316,13.11475 0,11.54099 -1.04918,36.19672 -1.04918,36.19672 0,0 -14.6885299,38.81968 -6.29509,71.86886 2.09837,3.14754 -20.9835999,49.83606 11.0164,106.4918 0.52459,0.52459 -16.78689,57.70492 12.59016,82.88525 1.04918,4.72131 13.63935,33.57377 42.49181,39.34426 12.59016,0.52459 19.409826,-0.52459 19.409826,-0.52459 0,0 31.47541,-4.72131 47.73771,-67.14754 -2.09836,-27.80328 -4.19672,-50.36066 -11.0164,-70.81968"
id="path93" /><path
id="path101"
style="opacity:1;fill:#ffffff;fill-opacity:0.734285;stroke:#000000;stroke-width:9;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 109.69769,219.48859 c 0,0 -15.208592,-11.87012 -21.143652,-19.65989 m -37.09413,20.03083 22.25648,-21.88553 m 0.37094,-14.09577 5.93506,41.91636 m -35.23942,-24.11118 56.012132,-4.82224 m 11.12824,-17.43424 -19.288952,0.37094 m -0.37094,-0.74188 -1.48376,-29.6753 m -38.94883,3.33847 37.836,-2.96753 m -24.85306,-11.49918 0.74188,39.69072"
inkscape:label="杂" /><path
id="path111"
style="opacity:1;fill:#ffffff;fill-opacity:0.734285;stroke:#000000;stroke-width:9;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 58.507798,352.28556 54.157422,-3.33847 m -46.367662,-13.72483 35.610372,-2.96753 m -21.514602,-32.27189 2.59659,33.38472 m -18.918,-16.32142 37.094122,-3.33847 m 1.48377,18.54706 0.74188,-33.75565 m -0.37094,0.37094 -40.803542,2.22565 m 0,-0.37094 4.4513,33.38471 m 27.44965,-48.22237 3.33847,-14.4667 m 0,-1.48377 -27.44965,1.48377 m -1.48377,14.83765 0.74188,-20.03083"
inkscape:label="鱼" /><path
d="m 69.453989,376.46984 c -4.220665,0.22086 -8.079406,1.8518 -10.783191,4.54882 -2.980547,2.98155 -4.241957,7.10139 -3.534076,11.54824 0.904812,5.67433 4.763552,11.7394 11.384623,17.90216 1.405115,1.30393 2.39508,2.14912 4.390984,3.74184 3.507462,2.79468 6.679618,5.01174 11.04931,7.70876 1.559468,0.96838 4.635815,2.76496 5.796096,3.38931 l 0.335314,0.18263 0.48966,-0.26758 c 1.783005,-0.98111 4.960482,-2.86264 6.844609,-4.05189 7.126702,-4.49782 12.832312,-9.01266 17.063632,-13.50625 6.86057,-7.28827 9.77725,-14.38543 8.43068,-20.49298 -0.93142,-4.20475 -4.04502,-7.68327 -8.46261,-9.45012 -1.90011,-0.76026 -3.74699,-1.15525 -5.83869,-1.24869 -2.7091,-0.12316 -5.37562,0.33977 -7.91973,1.37185 -4.332435,1.75413 -7.951675,5.17315 -10.229661,9.66674 -0.159681,0.3143 -0.308701,0.59038 -0.329985,0.60737 -0.0692,0.0553 -0.143707,-0.051 -0.431122,-0.62859 -0.681263,-1.35913 -2.01719,-3.3341 -3.065699,-4.52331 -1.07513,-1.22747 -2.804909,-2.72251 -4.092931,-3.54224 -3.326503,-2.11937 -7.222503,-3.15569 -11.097213,-2.95607 z"
id="path1-4"
style="fill:#d96477;fill-opacity:1;stroke:none;stroke-width:0.00475452" /></g></svg>

After

Width:  |  Height:  |  Size: 60 KiB

View File

@@ -0,0 +1,80 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Offline | SukiSU-Ultra</title>
<meta name="theme-color" content="#64edff" />
<style>
html,
body {
height: 100%;
margin: 0;
font-family:
system-ui,
-apple-system,
Segoe UI,
Roboto,
Ubuntu,
Cantarell,
'Noto Sans',
sans-serif;
}
.wrap {
min-height: 100%;
display: grid;
place-items: center;
padding: 2rem;
}
.card {
max-width: 560px;
background: #fff;
color: #111;
border-radius: 12px;
box-shadow: 0 6px 30px rgba(0, 0, 0, 0.06);
padding: 24px;
}
.card h1 {
margin: 0 0 8px;
font-size: 1.4rem;
}
.card p {
margin: 0.5rem 0;
line-height: 1.5;
}
.muted {
color: #666;
font-size: 0.9rem;
}
.actions {
margin-top: 1rem;
display: flex;
gap: 0.75rem;
}
.btn {
padding: 0.6rem 0.9rem;
border-radius: 8px;
border: 1px solid #d0d0d0;
background: #f7f7f7;
color: #111;
text-decoration: none;
}
</style>
</head>
<body>
<div class="wrap">
<div class="card">
<h1>You're offline</h1>
<p>We couldn't load this page because your device has no internet connection.</p>
<p class="muted">
When you're back online, try again. Some pages you visited before may still work from
cache.
</p>
<div class="actions">
<a class="btn" href="/">Go to home</a>
<a class="btn" href="/guide/">Docs guide</a>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,76 @@
User-agent: *
Allow: /
Disallow: /admin/
Disallow: /.git/
Disallow: /node_modules/
Disallow: /api/
Disallow: /.vitepress/
# Sitemap
Sitemap: https://sukisu.org/sitemap.xml
# Crawl-delay for high-traffic optimization
Crawl-delay: 0.5
# Major search engines (global optimization)
User-agent: Googlebot
Allow: /
Crawl-delay: 0.5
User-agent: Bingbot
Allow: /
Crawl-delay: 1
User-agent: Slurp
Allow: /
Crawl-delay: 1
User-agent: DuckDuckBot
Allow: /
Crawl-delay: 0.5
User-agent: Baiduspider
Allow: /
Crawl-delay: 2
# Asian search engines (for China, Japan, etc.)
User-agent: YandexBot
Allow: /
Crawl-delay: 1
User-agent: NaverBot
Allow: /
Crawl-delay: 1
User-agent: SogouSpider
Allow: /
Crawl-delay: 2
# Block resource-intensive bots for performance
User-agent: AhrefsBot
Disallow: /
User-agent: MJ12bot
Disallow: /
User-agent: SemrushBot
Disallow: /
User-agent: DotBot
Disallow: /
# Block AI training crawlers to save bandwidth
User-agent: GPTBot
Disallow: /
User-agent: ChatGPT-User
Disallow: /
User-agent: CCBot
Disallow: /
User-agent: anthropic-ai
Disallow: /
User-agent: Claude-Web
Disallow: /

View File

@@ -0,0 +1,535 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="512"
height="512"
viewBox="0 0 512 512"
version="1.1"
id="svg1"
xml:space="preserve"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
sodipodi:docname="zako.optizmism.svg"
inkscape:export-filename="zako.plain.svg"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#999999"
borderopacity="1"
inkscape:showpageshadow="2"
inkscape:pageopacity="1"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
showguides="false"
inkscape:zoom="2"
inkscape:cx="219"
inkscape:cy="370"
inkscape:window-width="1280"
inkscape:window-height="702"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
showgrid="false"><inkscape:page
x="0"
y="0"
width="512"
height="512"
id="page2"
margin="0"
bleed="0" /></sodipodi:namedview><defs
id="defs1"><inkscape:path-effect
effect="simplify"
id="path-effect79"
is_visible="true"
lpeversion="1.3"
threshold="32.467532"
steps="1"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false" /><inkscape:path-effect
effect="simplify"
id="path-effect78"
is_visible="true"
lpeversion="1.3"
threshold="32.467532"
steps="1"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false" /><inkscape:path-effect
effect="simplify"
id="path-effect77"
is_visible="true"
lpeversion="1.3"
threshold="32.467532"
steps="1"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false" /><inkscape:path-effect
effect="simplify"
id="path-effect76"
is_visible="true"
lpeversion="1.3"
threshold="32.467532"
steps="1"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false" /><inkscape:path-effect
effect="simplify"
id="path-effect75"
is_visible="true"
lpeversion="1.3"
threshold="32.467532"
steps="1"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false" /><inkscape:path-effect
effect="simplify"
id="path-effect61"
is_visible="true"
lpeversion="1.3"
threshold="32.467532"
steps="1"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false" /><inkscape:path-effect
effect="simplify"
id="path-effect42"
is_visible="true"
lpeversion="1.3"
threshold="32.467532"
steps="1"
smooth_angles="360"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false" /></defs><g
inkscape:label="main"
inkscape:groupmode="layer"
id="layer1"><path
style="display:inline;opacity:1;fill:#fff9f6;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 164.23888,424.64081 -31.07097,26.05282 c 0,0 -5.19317,18.17613 25.96589,28.93342 31.15907,10.7573 213.29123,1.48377 213.29123,1.48377 0,0 52.30272,11.87012 80.86519,-37.09413 -0.37094,0.74188 -8.90259,19.28895 -8.90259,19.28895 l 1.48377,19.28894 c 0,0 57.73516,-9.41425 30.45647,-148.95524 4.19672,-9.44262 8.39344,-15.21311 8.39344,-15.21311 l -3.14754,-21.77049 c 0,0 5.65758,-40.33533 7.88323,-45.52851 2.22564,-5.19317 9.64447,-11.12823 9.64447,-11.12823 0,0 -2.78206,-20.40177 -6.67694,-26.15136 -0.74189,-3.33847 6.86241,-35.05395 2.04017,-58.05231 -7.04788,-11.87012 -4.82223,-11.87012 -18.918,-25.59495 0,0.37094 8.90259,-44.88389 -0.74188,-73.446367 -2.96753,0 -32.27189,-10.757296 -96.81567,23.740241 -0.37094,1.112824 -26.33683,-30.046242 -153.56969,-15.950474 -0.74188,0 -43.40012,-37.836009 -66.76942,-40.432598 -1.11283,-0.370941 -22.62742,-4.080354 -25.22401,48.964247 0,1.112824 -44.14201,15.950474 -56.01213,64.914721 -11.87012,48.96425 -11.128238,80.86519 -11.128238,80.86519 0,0 -18.904912,27.6632 -9.798121,25.03308 5.346826,-1.54421 4.975885,23.56023 4.975885,23.56023 l -2.225648,39.31977 c 0,0 -14.466709,35.23942 -14.83765,59.72155 -0.370942,24.48212 -0.741883,34.12659 4.822236,48.5933 5.564119,14.46671 20.772711,46.7386 42.658245,63.06002 8.902591,0.37094 18.918001,1.8547 18.918001,1.8547 l 3.70942,-20.77271 c 0,0 18.918,15.95048 32.27189,14.83765 13.35388,-1.11282 -0.74189,-0.74188 -0.74189,-0.74188 l -13.72482,-17.80518 z"
id="path2"
sodipodi:nodetypes="ccscccccccscccccccccscsccsscccsccc"
inkscape:label="整个人的边框" /><path
id="path91"
style="opacity:1;fill:#93d4fa;fill-opacity:1;stroke:#4c4f59;stroke-width:6.9;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 133.91016,110.16992 -69.738285,47.48047 18.263976,30.75433 -31.617492,55.67536 28.5625,17.0625 14.837891,-1.48438 2.226562,-55.64062 2.577791,-4.39109 18.193697,-21.94485 23.74023,-49.70703 z"
sodipodi:nodetypes="ccccccccccc" /><path
style="display:inline;opacity:1;fill:#ace0fe;fill-opacity:1;stroke:#4c4f59;stroke-width:6.54357;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 217.01397,405.82758 c 0,0 7.41728,-25.94462 41.16595,-27.07265 33.74866,-1.12802 53.77534,4.1361 53.77534,4.1361 0,0 11.12594,6.39215 17.80149,14.66435 6.67557,8.2722 28.92743,40.60895 41.53682,48.88115 12.60939,8.27219 15.20545,15.41636 15.20545,15.41636 l -1.85433,11.28027 c 0,0 -14.83458,10.15224 -30.78175,11.65627 -15.94717,1.50404 -147.60404,0 -147.60404,0 l -30.04002,-3.00807"
id="path71"
inkscape:label="衣服底色" /><path
style="fill:#ffffff;fill-opacity:1;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
d="m 363.54127,444.68178 c 0,0 -6.89429,4.06586 -4.86135,6.8059 2.03293,2.74004 5.92201,3.44715 5.92201,3.44715 0,0 4.5962,0.26516 5.12653,-3.53554 0.53033,-3.8007 -3.00521,-6.8059 -3.00521,-6.8059"
id="path60" /><path
style="fill:#ffffff;fill-opacity:1;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
d="m 349.67678,459.82583 c 0,0 4.5,-7.25 7,-5.5 2.5,1.75 -4.25,7.25 -4.25,7.25"
id="path59" /><path
id="path73-8"
style="fill:#ffffff;stroke-width:8.7;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
d="m 228.96985,465.10941 a 8.0341015,5.6995392 0 0 1 -8.0341,5.69953 8.0341015,5.6995392 0 0 1 -8.03411,-5.69953 8.0341015,5.6995392 0 0 1 8.03411,-5.69954 8.0341015,5.6995392 0 0 1 8.0341,5.69954 z" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#6c9cb2;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 220.85246,408.91803 c -0.22678,0.7374 0.77024,1.47887 0.20184,0.3709 -0.55918,-1.08999 0.45864,1.0858 0.58075,1.39596 2.10089,5.33666 1.96407,11.16153 3.60742,16.6426 0.30205,1.00744 0.58829,2.039 0.5936,3.09874"
id="path75"
inkscape:path-effect="#path-effect75"
inkscape:original-d="m 220.85246,408.91803 c 0.0874,0.34973 -0.0874,1.13662 0.26229,1.04918 0.34973,-0.0874 -0.42351,-1.37161 -0.26229,-1.04918 2.70315,5.4063 2.32215,10.60009 3.67213,16 0.44415,1.77662 1.31148,3.74741 1.31148,5.5082" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#6c9cb2;stroke-width:6.9;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 225.57377,436.98361 c -1.22213,4.37272 0.0774,9.22771 2.41807,12.85195 2.34183,3.626 0.85866,8.30929 2.56554,12.06608 1.71568,3.77616 2.21068,8.39349 -0.30117,12.16042 -1.9802,2.96963 -5.23922,5.13567 -6.38674,8.61546 0,0 -0.0736,0.66095 -0.0736,0.66095"
id="path76"
inkscape:path-effect="#path-effect76"
inkscape:original-d="m 225.57377,436.98361 c -1.27879,3.14891 0.64852,9.42818 3.40984,14.95082 0.92316,1.84632 0.76302,8.34571 1.57377,9.96721 1.05661,2.11323 2.18032,6.57378 1.31147,9.18033 -1.55473,4.66419 -8.07296,8.77008 -8.07296,12.2565"
sodipodi:nodetypes="csssc" /><path
style="opacity:1;fill:#fbf3ef;fill-opacity:1;stroke:none;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 259.14754,381.90164 c 0,0 8.91803,15.47541 9.18033,20.98361 0.26229,5.50819 32.26229,-1.83607 32.26229,-1.83607 0,0 -4.45901,-16.78688 -7.34426,-19.40983 -2.88524,-2.62296 -34.09836,0.26229 -34.09836,0.26229 z"
id="path89" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#6c9cb2;stroke-width:4.6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 247.86885,386.36066 c 0.62439,0.76152 1.31219,1.32242 0.35251,0.10604 -0.98535,-1.24891 -0.63523,-0.56343 0.0935,0.24171 1.40155,1.54849 2.30926,3.40606 3.10338,5.34166 1.48771,3.62621 2.15649,7.53104 4.02075,11.02472 1.24886,2.3404 2.74915,4.53757 3.97084,6.89242"
id="path77"
inkscape:path-effect="#path-effect77"
inkscape:original-d="m 247.86885,386.36066 c 3.34102,3.56326 -3.68025,-4.79705 1.83607,2.09836 1.23825,1.54782 3.18087,7.73986 3.67213,9.70492 1.00623,4.02493 4.53306,8.80383 6.03279,11.80327" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#6c9cb2;stroke-width:4.6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 306.62295,386.88525 c 1.62958,6.07854 4.04229,11.93568 6.81967,17.57377"
id="path78"
inkscape:path-effect="#path-effect78"
inkscape:original-d="m 306.62295,386.88525 c 1.57569,6.03983 4.44925,12.83291 6.81967,17.57377" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#6c9cb2;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 335.73771,431.21312 c 0.7696,3.76393 3.24862,7.26774 5.48726,10.89168 2.09754,3.39553 3.33574,7.13199 4.87926,10.7955 2.06975,4.91248 6.75146,8.7424 7.699,13.95386 0.92029,5.06165 5.24206,8.89669 5.27874,14.19502"
id="path79"
inkscape:path-effect="#path-effect79"
inkscape:original-d="m 335.73771,431.21312 c -1.15649,1.03916 3.66917,4.97179 4.45901,8.13114 0.96754,3.87016 3.8848,6.88344 4.72131,10.22951 1.09547,4.38186 5.88097,12.49359 8.39345,16.2623 0.80744,1.21116 0.89968,3.11084 1.57377,4.45901 1.7539,3.50782 4.19672,6.9619 4.19672,10.7541" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#494d55;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 258.62295,384.2623 c 0,0 8.13115,6.81967 11.27869,27.01639"
id="path80" /><path
style="opacity:1;fill:#fbf3ef;fill-opacity:1;stroke:#4c4f59;stroke-width:6.9;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 127.23285,329.0249 c 0,0 -2.59659,60.46343 13.72483,75.30108 8.16071,-8.16071 10.01541,-10.38636 10.01541,-10.38636 l 12.24107,8.53165 5.19317,-4.45129 2.22565,-19.65989 5.19318,-10.01542 5.93506,-12.24106 -8.53165,-8.53165 -15.95047,-19.28894 -3.33848,-4.82224 -4.45129,9.27353 c 0,0 -12.24106,0 -15.95048,-2.59659 -3.70941,-2.59658 -6.306,-1.11282 -6.306,-1.11282 z"
id="path90" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#494d55;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 291.67213,381.37705 c 0,0 7.08197,6.55738 10.22951,26.4918"
id="path81" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#494d55;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 270.16393,404.19672 c 0,0 16.00001,-3.93442 27.80328,-2.62295"
id="path82" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#494d55;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 253.90164,417.83607 c 0,0 37.2459,-13.11476 69.77049,-9.18033 2.09836,3.67213 5.77049,16.78688 -5.77049,20.98361 -4.72131,0 -19.14754,-1.57378 -22.55738,-0.5246 -3.40983,1.04919 -12.59016,0.5246 -18.36065,4.45902 -5.77049,3.93443 -14.68853,8.91803 -18.36066,3.14754 -3.67213,-5.77049 -4.72131,-12.32787 -4.72131,-12.32787 z"
id="path83" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#494d55;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 276.45902,482.62295 c 0,0 -9.70492,-1.57377 1.04918,-46.42623"
id="path84" /><path
style="opacity:1;fill:#fcf6fa;fill-opacity:1;stroke:#494d55;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 287.21312,432.78689 6.29508,50.88524 13.90164,-0.78688 -6.81968,-54.03279 z"
id="path88" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#494d55;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 287.73771,430.95082 5.77049,50.88525"
id="path85" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#494d55;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 300.32787,428.06557 c 0,0 2.09836,37.7705 7.34426,52.98361"
id="path86" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#494d55;stroke-width:5.3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 313.18033,431.21312 c 0,0 7.60656,27.54098 10.22951,35.93442 2.62295,8.39344 -8.13115,15.73771 -8.13115,15.73771"
id="path87" /><path
style="opacity:1;fill:#bce4fd;fill-opacity:1;stroke:none;stroke-width:8.7;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 164.23888,424.64081 -31.07097,26.05282 5.00771,13.72483 20.95818,15.20859 17.08508,2.15431 -11.1287,-20.55238 -1.54637,-22.78395 z"
id="path74" /><path
id="path73"
style="opacity:1;fill:#ffffff;stroke-width:8.7;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
d="m 163.81755,451.10144 a 8.0341015,5.6995392 0 0 1 -8.0341,5.69954 8.0341015,5.6995392 0 0 1 -8.0341,-5.69954 8.0341015,5.6995392 0 0 1 8.0341,-5.69954 8.0341015,5.6995392 0 0 1 8.0341,5.69954 z" /><path
style="opacity:1;fill:#fff9f6;fill-opacity:1;stroke:none;stroke-width:8.7;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 338.36066,376.13115 c 0,0 1.83605,30.95081 -6.29509,51.40983 2.88525,1.04918 14.48107,0.26606 26.91267,-7.34238 12.4316,-7.60844 11.38242,-22.03467 11.38242,-22.03467 l 2.09836,28.85246 c 0,0 24.31867,-28.09873 24.2249,-52.60674 -0.0938,-24.50801 -1.66753,-26.08178 -1.66753,-26.08178 l -11.83407,-1.12685 z"
id="path72" /><path
style="opacity:1;fill:#fde9e7;fill-opacity:1;stroke:none;stroke-width:2.845;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 339.7822,389.85927 c 0,0 38.20695,-7.78977 56.38307,-25.96589 5.56412,8.53165 8.16071,32.64283 8.16071,32.64283 l 2.59659,12.98294 16.32141,-62.68907 -6.67694,-5.19318 -5.93506,-17.43424 c 0,0 -15.20859,15.2086 -27.44966,22.99836 -12.24106,7.78977 -34.12659,19.28895 -34.12659,19.28895 l -10.7573,3.70941 z"
id="path70" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#c3b4b0;stroke-width:2.845;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 347.01555,369.64297 c 0,0 2.22565,10.01541 -1.8547,19.84536 -4.08036,9.82994 -5.00771,9.459 -5.00771,9.459"
id="path69" /><path
style="opacity:1;fill:#fde9e7;fill-opacity:1;stroke:none;stroke-width:6.945;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 380.85246,480 c 0,0 44.59016,-17.31147 59.27869,-87.08197 6.81967,-2.62295 34.09836,-14.68852 39.34426,-25.70491 2.62295,-9.96722 -3.67213,-32 -3.67213,-32 l -24.65574,0.52459 -26.7541,4.72131 -4.72131,11.54098 -8.39344,52.45902 -13.11475,28.32787 -15.73771,36.19672 z"
id="path68" /><path
style="fill:none;fill-opacity:1;stroke:#4c4f59;stroke-width:8.74203;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 147.6556,277.03379 c 0,0 -11.12655,104.13607 127.58449,103.38689 138.71104,-0.74917 149.83759,-100.39017 149.83759,-100.39017"
id="path41"
inkscape:label="脸蛋" /><path
style="opacity:1;fill:#fff9f6;fill-opacity:1;stroke:none;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 123.27869,147.93443 304.78688,21.50819 -24.65573,-40.39344 c 0,0 44.06557,-58.754098 50.88524,-60.327868 6.81967,-1.573771 15.73771,-9.967214 15.73771,-9.967214 l -13.11476,-3.672131 -77.11475,22.032787 c 0,0 -122.7541,-33.57377 -168.39344,-6.295082 -45.63935,27.278689 -69.7705,46.163938 -69.7705,46.163938 z"
id="path33"
inkscape:label="头发底色2" /><path
style="fill:#fde9e7;fill-opacity:1;stroke:none;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 331.44501,66.651771 16.22882,30.84274 47.82991,31.367399 6.30629,1.07795 26.88325,-35.335399 -32.10312,-22.211018 -18.88524,5.245901 -30.42623,-11.540983 z"
id="path35"
inkscape:label="头发部件111" /><path
style="opacity:1;fill:#ace0fe;fill-opacity:1;stroke:none;stroke-width:14.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 431.03375,175.82616 17.06329,-17.0633 50.44802,71.96261 -5.93506,17.80518 -33.38472,18.54706 -12.612,-16.32142 17.80518,-11.12823 z"
id="path29"
inkscape:label="蓝色发卡上" /><path
style="opacity:1;fill:#ace0fe;fill-opacity:1;stroke:#4c4f59;stroke-width:6.945;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 465.90223,261.88453 c 0,0 35.61036,54.52837 2.96753,73.44637 -25.22401,4.08036 -48.22237,2.22565 -48.22237,2.22565 l 10.38636,-26.33683 21.51459,-41.91636 z"
id="path66"
inkscape:label="蓝色发卡下" /><path
style="opacity:1;fill:#febdc7;fill-opacity:1;stroke:none;stroke-width:4.6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 471.86885,57.704918 c 0,0 17.04918,68.983602 -11.01639,110.426232 -7.34426,0.26229 -9.18033,-10.49181 -9.18033,-10.49181 l 2.09836,-6.55737 -1.04918,-9.18033 2.36066,-10.7541 1.83606,-5.5082 -6.29508,-6.03278 -6.55738,-5.2459 -2.88524,-5.24591 2.88524,-5.2459 -2.62295,-5.245899 -4.19672,-2.885246 -3.14754,-1.57377 5.2459,-11.540984 11.80328,-7.344262 z"
id="path64" /><path
id="path57"
style="opacity:1;fill:#ff1c1c;fill-opacity:0.0509804;stroke-width:3.92397;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
d="m 244.26691,326.81357 a 35.587568,21.480417 0 0 1 -35.58757,21.48042 35.587568,21.480417 0 0 1 -35.58757,-21.48042 35.587568,21.480417 0 0 1 35.58757,-21.48042 35.587568,21.480417 0 0 1 35.58757,21.48042 z" /><path
id="path57-1"
style="fill:#ff1c1c;fill-opacity:0.05044398;stroke-width:3.65169;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
d="m 355.20429,336.75188 a 31.611719,20.942554 0 0 1 -31.61171,20.94255 31.611719,20.942554 0 0 1 -31.61172,-20.94255 31.611719,20.942554 0 0 1 31.61172,-20.94255 31.611719,20.942554 0 0 1 31.61171,20.94255 z" /><path
style="display:inline;opacity:1;fill:#fbf3ef;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 188.32787,343.60656 c 0,0 12.06557,-28.32787 15.7377,6.29508 5.24591,-8.91803 9.96722,-17.31148 17.31148,-8.39344 6.81967,2.09836 15.21311,7.34426 4.72131,22.03278 -10.4918,14.68853 16.33814,-18.37136 15.445,-1.63289 -0.72099,13.51206 -24.52214,46.81129 -24.52214,46.81129 0,0 -6.33782,64.18547 -33.41466,70.23144 -36.5485,8.16089 -12.06558,-103.86885 -12.06558,-103.86885 z"
id="path1"
sodipodi:nodetypes="cccsscscc"
inkscape:label="右手" /><path
id="path5"
style="fill:#fbe7e5;stroke-width:10.4;stroke-linecap:round;stroke-miterlimit:1.3;paint-order:fill markers stroke;fill-opacity:0.40581462"
inkscape:label="右手踝阴影"
d="m 193.63133,383.92419 a 12.612,12.241061 0 0 1 -12.612,12.24107 12.612,12.241061 0 0 1 -12.612,-12.24107 12.612,12.241061 0 0 1 12.612,-12.24106 12.612,12.241061 0 0 1 12.612,12.24106 z" /><path
style="fill:#fee4e0;fill-opacity:0.42411327;stroke:none;stroke-width:10.4;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 179.09741,356.52608 14.09576,-20.77271 7.04789,1.48377 0.74188,13.72482 11.49918,-11.49918 9.27353,4.08036 8.53165,5.93506 -5.56412,14.83765 13.72483,-4.82224 -3.33847,17.80518 -47.85143,-27.44965 z"
id="path9"
inkscape:label="右手手指阴影" /><path
style="display:inline;fill:none;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 188.32787,343.60656 c 0,0 12.06557,-28.32787 15.7377,6.29508 5.24591,-8.91803 9.96722,-17.31148 17.31148,-8.39344 6.81967,2.09836 15.21311,7.34426 4.72131,22.03278 -10.4918,14.68853 16.33814,-18.37136 15.445,-1.63289 -0.72099,13.51206 -24.52214,46.81129 -24.52214,46.81129 0,0 -6.33782,64.18547 -33.41466,70.23144 -36.5485,8.16089 -12.06558,-103.86885 -12.06558,-103.86885 z"
id="path1-6"
sodipodi:nodetypes="cccsscscc"
inkscape:label="右手遮挡" /><path
style="opacity:1;fill:#fff9f6;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 137.44262,123.2787 c 0,0 49.33852,-48.649769 86.97684,-58.734919 0.10513,0.76769 -120.16719,-122.15824 -86.97684,58.734919 z"
id="path3"
inkscape:label="头发部件19 左猫耳" /><path
style="fill:#fde9e7;fill-opacity:1;stroke-width:1.18016;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
d="m 198.85246,42 -63.6342,39.016573 3.84123,40.939237 L 184.82787,87 224,64.5 Z"
id="path58"
sodipodi:nodetypes="cccccc" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0.465732;stroke:#a18f90;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
id="path4"
d="m 404.96447,131.7729 c 0.52512,-0.76931 1.0357,-1.54875 1.57536,-2.30793 2.82418,-3.97291 5.82035,-7.82036 8.67758,-11.76948 2.39309,-3.30762 3.93978,-5.54326 6.29133,-8.89998 5.32612,-7.58044 11.18023,-14.760796 17.20894,-21.78699 3.02173,-3.55064 6.06655,-7.098864 9.47662,-10.289082 1.96198,-1.835492 4.21906,-3.672787 6.27415,-5.392122 5.10823,-4.357455 10.66931,-8.109574 16.22169,-11.862072 0,0 -2.92504,-1.864176 -2.92504,-1.864176 v 0 c -5.41592,3.900149 -10.90348,7.705144 -15.99184,12.040062 -1.99887,1.645368 -4.44389,3.611151 -6.36286,5.369248 -3.45237,3.162941 -6.48944,6.731577 -9.48752,10.316639 -5.95526,7.087894 -11.63254,14.399231 -17.00034,21.944173 -5.47138,7.72885 -10.96322,15.45542 -17.11251,22.66867 z"
inkscape:label="头发部件18" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0.465732;stroke:#a18f90;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
id="path6"
d="m 431.7055,96.885136 c 0.68345,-0.01683 1.36993,0.008 2.05351,0.03239 1.26616,0.04274 2.52519,0.175792 3.77564,0.374299 1.34943,0.219358 2.67703,0.547853 3.99756,0.89747 1.30448,0.342355 2.58658,0.760225 3.8587,1.206247 0.34787,0.132122 0.88919,0.332358 1.23164,0.483411 0.1893,0.0835 0.73774,0.373687 0.5597,0.268307 -4.92017,-2.912189 -2.83776,-1.86942 -2.01609,-0.911603 0.4665,0.942833 -0.25414,1.810973 -0.83258,2.515753 -1.05305,1.11546 -2.37988,1.92349 -3.65077,2.76486 -0.70455,0.52564 -1.84263,0.99551 -2.02707,1.9792 -0.13577,0.72412 0.14689,1.00706 0.45808,1.64499 0.25805,0.31484 0.49646,0.64686 0.77415,0.94453 0.63085,0.67625 1.54885,1.45348 2.25243,2.03623 1.28413,1.06359 2.61277,2.07518 3.92585,3.10243 2.22765,1.73231 4.46676,3.44711 6.4408,5.4696 1.24472,1.36548 2.33589,2.86124 3.10757,4.54226 0.57402,1.31239 0.61894,2.68201 0.46471,4.08008 -0.15236,1.542 -1.01177,2.74753 -1.96982,3.90485 -1.25092,1.39253 -2.70297,2.57966 -3.98322,3.94302 -0.61776,0.76458 -1.19371,1.60995 -1.3359,2.60746 -0.0756,0.53059 -0.0152,0.87319 0.031,1.40055 0.18192,1.34638 0.59785,2.64226 1.03422,3.92358 0.46172,1.36123 1.10075,2.65093 1.71056,3.94949 0.57934,1.12566 0.88081,2.32829 0.97901,3.58284 0.0285,1.01273 -0.14083,2.01608 -0.35002,3.00302 -0.18321,0.8594 -0.39147,1.62037 -0.92358,2.32955 -0.69384,0.72591 -1.52468,1.30006 -2.31082,1.91913 0,0 3.13155,1.96912 3.13155,1.96912 v 0 c 0.80747,-0.64335 1.66352,-1.23803 2.37418,-1.9921 0.58364,-0.77755 0.80933,-1.52536 1.00495,-2.4688 0.21825,-1.01967 0.38801,-2.05558 0.38421,-3.10149 -0.0761,-1.29512 -0.34601,-2.55043 -0.93895,-3.71574 -0.60728,-1.2882 -1.24849,-2.56502 -1.72185,-3.91075 -0.43768,-1.25837 -0.85635,-2.529 -1.07055,-3.84806 -0.053,-0.43231 -0.12968,-0.85315 -0.0855,-1.29165 0.0948,-0.94059 0.64999,-1.73394 1.21835,-2.45227 1.27656,-1.3752 2.72864,-2.57131 3.98645,-3.96542 1.00742,-1.20382 1.92485,-2.46496 2.104,-4.07351 0.17452,-1.45227 0.1673,-2.88462 -0.39573,-4.26425 -0.74413,-1.73945 -1.85028,-3.26977 -3.10544,-4.6809 -0.76822,-0.80351 -0.91233,-0.98548 -1.76144,-1.74089 -1.5106,-1.3439 -3.15419,-2.52947 -4.72414,-3.80078 -1.30934,-1.02359 -2.63319,-2.03185 -3.9193,-3.08473 -0.71006,-0.5813 -1.57278,-1.30278 -2.22387,-1.96185 -0.27049,-0.2738 -0.51217,-0.57463 -0.76826,-0.86194 -0.2502,-0.39692 -0.62512,-0.79772 -0.57512,-1.31981 0.0792,-0.82671 1.33713,-1.38331 1.899,-1.81756 1.29884,-0.86671 2.65474,-1.69887 3.73107,-2.84377 0.6873,-0.83746 1.4042,-1.79633 1.075,-2.93575 -0.0816,-0.13585 -0.14456,-0.28482 -0.24481,-0.40755 -0.1097,-0.13429 -0.23095,-0.26613 -0.3791,-0.356228 -1.82458,-1.109627 -3.48552,-2.166773 -5.4739,-2.822822 -1.27815,-0.438878 -2.56689,-0.847162 -3.87638,-1.183261 -1.32827,-0.341807 -2.66392,-0.6605 -4.021,-0.867076 -1.26646,-0.185139 -2.54065,-0.306124 -3.82011,-0.354118 -0.68835,-0.02484 -1.39159,-0.0088 -2.07079,-0.120664 z"
inkscape:label="头发部件17" /><path
style="display:inline;opacity:1;fill:#1a1a1a;fill-opacity:0.465732;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
id="path7"
d="m 472.56515,132.89174 c 0.0148,0.77317 -0.10076,1.54619 -0.19578,2.31209 -0.22663,1.66469 -0.65036,3.29152 -1.09324,4.90909 -0.61155,2.16519 -1.31643,4.30298 -2.07388,6.4211 -0.85906,2.40245 -1.88628,4.73722 -3.04362,7.0095 -1.12519,2.18837 -2.40662,4.28829 -3.77255,6.3331 -1.20044,1.78353 -2.51232,3.48695 -3.85961,5.16088 -0.77567,0.94691 -1.56273,1.88443 -2.34905,2.82249 0,0 3.09439,1.85764 3.09439,1.85764 v 0 c 0.78058,-0.94434 1.56325,-1.88703 2.331,-2.84187 1.33972,-1.69155 2.6509,-3.40675 3.84535,-5.20534 1.36483,-2.06191 2.64248,-4.17929 3.77385,-6.37958 1.16439,-2.28454 2.19746,-4.6314 3.07763,-7.04092 0.77266,-2.11878 1.49327,-4.25705 2.12518,-6.4224 0.46749,-1.62041 0.91079,-3.25003 1.1854,-4.9163 0.11547,-0.76691 0.21504,-1.53597 0.32143,-2.30416 z"
inkscape:label="头发部件16" /><path
style="display:inline;opacity:1;fill:#fff9f6;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 322.62295,86.032787 c 0,0 75.43341,26.120553 110.16394,89.180323 33.44261,60.72132 33.04918,62.42623 33.04918,62.42623 0,0 0.52459,8.39345 -19.93443,11.54099 -2.62295,0 14.68852,30.95082 19.93443,37.2459 -14.68853,7.34426 -16.78689,8.91803 -16.78689,8.91803 0,0 6.29508,7.86885 4.72131,15.73771 -17.31147,-0.52459 -22.55738,-1.04918 -22.55738,-1.04918 0,0 -4.19672,17.31147 -15.7377,33.04918 C 410.22951,333.11475 410.22951,320 410.22951,320 c 0,0 -24.13115,36.72131 -72.39344,41.44262 -1.57377,-2.62295 12.59016,-14.16393 17.83606,-28.32787 -11.54098,1.57377 -14.68852,2.09836 -14.68852,2.09836 l 10.4918,-16.78688 c 0,0 11.01639,-24.13115 9.44262,-28.32787 -1.04918,-2.62295 -32,-57.70492 -32,-57.70492 0,0 -24.65573,33.04918 -43.54098,49.83607 -6.81967,-4.19672 -13.63934,-14.68853 -13.63934,-14.68853 l -12.59017,11.54099 c 0,0 -48.43778,-50.76436 -42.0945,-90.18318 -3.14754,12.06557 0.12729,56.60941 -5.6432,62.3799 -5.24591,-2.09836 -16.2623,-14.68853 -14.16394,-40.91803 -0.52459,-0.52459 -29.90164,41.44262 -29.90164,41.44262 0,0 -4.19672,48.78688 16.2623,73.44262 1.57377,2.62295 -1.57377,16.2623 -31.47541,-2.62295 1.04918,-1.57377 -1.04918,9.96721 -1.04918,9.96721 0,0 -46.68853,2.09836 -45.63935,-60.85245 -2.62295,-2.62296 -13.639341,34.09836 -13.639341,34.09836 0,0 -24.131151,-32 -0.52459,-92.85246 11.803281,-30.42623 23.344261,-52.85246 31.934421,-67.67213 8.59017,-14.81968 14.22951,-22.03279 14.22951,-22.03279"
id="path8"
sodipodi:nodetypes="csccccccccccccccccccccccccccssc"
inkscape:label="头发部件15 头发底色" /><path
id="path36"
style="fill:#fffdfc;stroke-width:7.4278;stroke-linecap:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
inkscape:label="头发打光"
d="m 355.67214,146.88524 a 91.803276,41.967213 0 0 1 -91.80327,41.96721 91.803276,41.967213 0 0 1 -91.80328,-41.96721 91.803276,41.967213 0 0 1 91.80328,-41.96721 91.803276,41.967213 0 0 1 91.80327,41.96721 z" /><path
style="fill:#fde9e7;fill-opacity:1;stroke:none;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 349.37705,329.44262 c 0,0 71.34426,-41.96721 78.68852,-91.27868 0,1.04918 26.22951,28.32786 26.22951,28.32786 l 11.54099,24.13115 -15.73771,7.34426 2.09836,13.63935 -22.03279,-1.04918 -12.59016,30.42623 -12.59016,-17.83607 -23.08197,26.22951 -45.11475,14.68852 z"
id="path37"
inkscape:label="头发阴影"
sodipodi:nodetypes="cccccccccccc" /><path
style="fill:#fde9e7;fill-opacity:1;stroke:none;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 325.2459,144.78689 c 0,0 10.49181,44.06557 2.09836,78.68852 0,10.4918 33.57377,60.85246 33.57377,60.85246 0,0 14.68853,-71.34426 -25.18032,-132.19672 -8.39345,-5.2459 -10.49181,-7.34426 -10.49181,-7.34426 z"
id="path38"
inkscape:label="头发阴影2" /><path
style="fill:#fde9e7;fill-opacity:1;stroke:none;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 186.7541,166.81967 23.08197,1.04918 c 0,0 -14.68853,26.22951 -13.63935,46.16394 -2.09836,-3.14754 -22.03279,31.47541 -22.03279,31.47541 0,0 -9.44262,-14.68853 -3.14754,-50.36066 9.44263,-16.78688 15.73771,-28.32787 15.73771,-28.32787 z"
id="path39"
inkscape:label="头发阴影" /><path
id="path36-5"
style="fill:#fffdfc;stroke-width:6.94619;stroke-linecap:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
inkscape:label="头发打光"
transform="matrix(0.99965843,-0.02613486,0,1,0,0)"
d="m 340.28017,112.23744 a 80.289719,41.967213 0 0 1 -80.28972,41.96721 80.289719,41.967213 0 0 1 -80.28972,-41.96721 80.289719,41.967213 0 0 1 80.28972,-41.967211 80.289719,41.967213 0 0 1 80.28972,41.967211 z" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#a18f90;stroke-width:7.7;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 138.62295,122.4918 c 0,0 53.63935,-52.983604 92.98361,-58.229505"
id="path65"
sodipodi:nodetypes="cc" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#c3b4b0;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 436.45902,268.06557 c 0,0 3.67213,18.36066 -2.62295,42.49181"
id="path17"
inkscape:label="头发部件7" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#c3b4b0;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 418.09836,305.83607 -8.91803,17.83606"
id="path16"
inkscape:label="头发部件8" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#c3b4b0;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 377.70492,300.59016 c 0,0 2.62295,12.06558 -22.03279,32"
id="path15"
inkscape:label="头发部件9" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#c3b4b0;stroke-width:4.2;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 284.32787,97.573771 c 0,0 12.06557,39.344259 -27.80328,119.081969 0.52459,0 53.5082,-38.81967 56.13115,-89.18033"
id="path10"
inkscape:label="头发部件14" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#c3b4b0;stroke-width:5.1;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 272.78689,87.081967 c 0,0 13.63934,-8.393442 18.88524,-0.52459 17.17267,10.839383 13.03281,30.236103 24.19672,44.393443 1.79263,1.85342 7.1718,-0.78131 7.80328,1.77049 4.88126,19.72513 14.81582,50.80617 4.32401,100.11764"
id="path11"
sodipodi:nodetypes="csssc"
inkscape:label="头发部件13" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#c3b4b0;stroke-width:4.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 171.00392,241.8537 c 0,0 -28.56248,-60.09248 92.36438,-147.634619 2.22564,0.741882 -59.35061,54.157419 -66.02755,111.282379"
id="path12"
inkscape:label="头发部件12" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#c3b4b0;stroke-width:3;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 327.34426,143.7377 c 0,0 25.18033,20.45902 32,65.57378"
id="path13"
inkscape:label="头发部件11" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 362.4918,268.59016 -3.14754,19.93443"
id="path14"
inkscape:label="头发部件10" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 421.77049,344.13115 c 0,0 -2.62295,58.22951 -33.57377,111.7377 -30.95082,53.5082 38.29508,15.73771 38.29508,15.73771"
id="path18"
inkscape:label="头发部件6" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 395.01639,348.32787 12.06558,60.32787"
id="path19"
inkscape:label="头发部件5" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 371.93443,423.86885 c 0,0 30.95082,-25.70492 24.65573,-73.96721"
id="path20"
inkscape:label="头发部件4" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 332.06557,427.54098 c 0,0 36.72132,1.57377 38.81968,-29.37705"
id="path21"
inkscape:label="头发部件3" /><path
style="opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 372.45902,427.01639 -2.09836,-28.85246"
id="path22"
inkscape:label="头发部件2" /><path
style="fill:#93cefc;fill-opacity:1;stroke:#4d4e59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 377.50929,228.61046 c 0,0 24.13115,1.57377 24.13115,10.49181 -0.52459,3.67213 -11.54099,17.83606 -23.60656,18.88524 -2.09836,-1.57377 -0.52459,-29.37705 -0.52459,-29.37705 z"
id="path34"
sodipodi:nodetypes="cccc"
inkscape:label="兔子发卡后" /><path
style="opacity:1;fill:#fffdfe;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 350.95082,235.54098 c 0,0 -6.55738,-22.03278 1.04918,-22.03278 7.60656,0 13.37705,13.90164 13.37705,13.90164 0,0 5.05941,-17.72738 9.96722,-15.21311 11.79758,6.04389 3.40983,21.77048 3.40983,21.77048 0,0 18.62295,25.96722 -12.06558,27.27869 -30.16717,1.28919 -15.7377,-25.70492 -15.7377,-25.70492 z"
id="path24"
sodipodi:nodetypes="cscscsc"
inkscape:label="兔子发卡" /><path
style="display:inline;opacity:1;fill:#1a1a1a;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 332.06557,425.96721 c 0,0 10.49181,-25.18032 6.29509,-49.83606"
id="path23"
inkscape:label="头发部件" /><path
style="display:inline;opacity:1;fill:#e85240;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 192.2623,268.85246 c 0,0 -15.47541,22.03279 -2.62296,35.40984 42.7541,0.26229 43.27869,0.52459 43.27869,0.52459 0,0 11.27869,-8.39345 5.5082,-32 -25.44262,-9.96722 -46.16393,-3.93443 -46.16393,-3.93443 z"
id="path25"
inkscape:label="左眼白" /><path
style="opacity:1;fill:#fbb579;fill-opacity:1;stroke:none;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 188.06557,301.11475 c -0.44151,-8.78192 13.4528,-14.01636 22.29509,-14.42623 8.67244,-0.402 23.2398,3.38526 23.08196,12.06558 -0.0775,4.26198 -11.54098,5.5082 -11.54098,5.5082 0,0 -33.2673,8.16555 -33.83607,-3.14755 z"
id="path27"
sodipodi:nodetypes="saacs"
inkscape:label="左眼瞳" /><path
id="path26"
style="display:inline;opacity:1;fill:#ffffff;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
inkscape:label="眼光"
d="m 217.96721,273.04919 a 7.8688526,7.0819674 0 0 1 -7.86885,7.08197 7.8688526,7.0819674 0 0 1 -7.86885,-7.08197 7.8688526,7.0819674 0 0 1 7.86885,-7.08196 7.8688526,7.0819674 0 0 1 7.86885,7.08196 z" /><path
style="fill:none;fill-opacity:1;stroke:#ebc2bf;stroke-width:2.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 174.16393,245.5082 c 15.08644,-4.76649 31.53934,-7.45293 47.09358,-3.51527 3.29779,0.83486 6.51821,1.99257 9.56216,3.51527"
id="path42"
inkscape:path-effect="#path-effect42"
inkscape:original-d="m 174.16393,245.5082 c 11.60252,-3.79212 36.99244,-9.83166 56.65574,0"
transform="translate(0,4)" /><path
style="opacity:1;fill:#fde9e7;fill-opacity:1;stroke:none;stroke-width:6.945;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 477.77235,132.79697 c 0,0 13.35388,10.01542 14.83765,17.43424 1.48376,7.41883 1.48376,57.4959 1.48376,57.4959 l -4.45129,1.11282 -30.78813,-37.46507 c 0,0 8.90259,-14.46671 11.12824,-22.62741 2.22565,-8.16071 7.78977,-15.95048 7.78977,-15.95048 z"
id="path67" /><path
style="fill:#e85240;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 192.2623,268.85246 c 0,0 -15.47541,22.03279 -2.62296,35.40984 42.7541,0.26229 43.27869,0.52459 43.27869,0.52459 0,0 11.27869,-8.39345 5.5082,-32 -25.44262,-9.96722 -46.16393,-3.93443 -46.16393,-3.93443 z"
id="path25-9"
inkscape:label="左眼遮挡上" /><path
style="display:inline;fill:#e85240;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 325.52138,272.81871 c 17.02505,1.06627 38.81967,23.08196 17.83607,48.26229 -1.57377,0.52459 -48.98481,-5.30599 -49.57378,-9.18033 -0.80561,-5.29953 -7.95666,-41.56799 31.73771,-39.08196 z"
id="path40"
sodipodi:nodetypes="scss"
inkscape:label="右眼白" /><path
style="fill:#fbb579;fill-opacity:1;stroke:none;stroke-width:7.14054;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 293.04592,306.32136 c 2.55323,-8.53469 20.43105,-9.52962 30.78942,-7.36618 10.1594,2.12188 25.66784,9.9581 22.45763,18.22228 -1.5762,4.05766 -15.25453,1.93723 -15.25453,1.93723 0,0 -41.28165,-1.79873 -37.99252,-12.79333 z"
id="path27-0"
sodipodi:nodetypes="saacs"
inkscape:label="左眼瞳" /><path
style="display:inline;fill:none;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 325.52138,272.81871 c 17.02505,1.06627 38.81967,23.08196 17.83607,48.26229 -1.57377,0.52459 -48.98481,-5.30599 -49.57378,-9.18033 -0.80561,-5.29953 -7.95666,-41.56799 31.73771,-39.08196 z"
id="path40-2"
sodipodi:nodetypes="scss"
inkscape:label="右眼遮挡上" /><path
style="fill:none;fill-opacity:1;stroke:#ebc2bf;stroke-width:2.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 309.32819,258.43459 c 0,0 26.2295,-5.2459 36.72131,4.19672"
id="path43" /><path
id="path26-9"
style="display:inline;fill:#ffffff;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
inkscape:label="眼光"
d="m 329.6342,284.99301 a 7.8688526,7.0819674 0 0 1 -7.86885,7.08197 7.8688526,7.0819674 0 0 1 -7.86885,-7.08197 7.8688526,7.0819674 0 0 1 7.86885,-7.08197 7.8688526,7.0819674 0 0 1 7.86885,7.08197 z" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#4c4f59;stroke-width:14.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 170.4918,266.4918 c 0,0 32,-19.93442 70.29509,-2.09836"
id="path28"
inkscape:label="眉毛" /><path
style="fill:none;fill-opacity:1;stroke:#4c4f59;stroke-width:14.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 292.9971,274.17683 c 0,0 35.55098,-12.55026 69.08832,13.13797"
id="path28-2"
inkscape:label="眉毛" /><path
style="display:inline;opacity:1;fill:none;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 431.03375,176.1971 18.17612,-17.43424 41.54542,54.15742"
id="path30"
inkscape:label="蓝色发卡遮挡上" /><path
style="opacity:1;fill:none;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 454.0321,267.44865 43.21466,-23.92571"
id="path31"
sodipodi:nodetypes="cc"
inkscape:label="蓝色发卡遮挡下" /><path
style="display:inline;fill:#fff9f6;fill-opacity:0;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 164.23888,424.64081 -31.07097,26.05282 c 0,0 -5.19317,18.17613 25.96589,28.93342 31.15907,10.7573 213.29123,1.48377 213.29123,1.48377 0,0 52.30272,11.87012 80.86519,-37.09413 -0.37094,0.74188 -8.90259,19.28895 -8.90259,19.28895 l 1.48377,19.28894 c 0,0 57.73516,-9.41425 30.45647,-148.95524 4.19672,-9.44262 8.39344,-15.21311 8.39344,-15.21311 l -3.14754,-21.77049 c 0,0 5.65758,-40.33533 7.88323,-45.52851 2.22564,-5.19317 8.51558,-6.35116 9.64447,-11.12823 2.06907,-8.75561 -2.78206,-20.40177 -6.67694,-26.15136 -0.74189,-3.33847 6.86241,-35.05395 2.04017,-58.05231 -7.04788,-11.87012 -4.82223,-11.87012 -18.918,-25.59495 0,0.37094 8.90259,-44.88389 -0.74188,-73.446367 -2.96753,0 -32.27189,-10.757296 -96.81567,23.740241 -0.37094,1.112824 -26.33683,-30.046242 -153.56969,-15.950474 -0.74188,0 -43.40012,-37.836009 -66.76942,-40.432598 -1.11283,-0.370941 -22.62742,-4.080354 -25.22401,48.964247 0,1.112824 -44.14201,15.950474 -56.01213,64.914721 -11.87012,48.96425 -11.128238,80.86519 -11.128238,80.86519 0,0 -18.904912,27.6632 -9.798121,25.03308 5.346826,-1.54421 4.975885,23.56023 4.975885,23.56023 l -2.225648,39.31977 c 0,0 -14.466709,35.23942 -14.83765,59.72155 -0.370942,24.48212 -0.741883,34.12659 4.822236,48.5933 5.564119,14.46671 20.772711,46.7386 42.658245,63.06002 8.902591,0.37094 18.918001,1.8547 18.918001,1.8547 l 3.70942,-20.77271 c 0,0 18.918,15.95048 32.27189,14.83765 13.35388,-1.11282 -0.74189,-0.74188 -0.74189,-0.74188 l -13.72482,-17.80518 z"
id="path2-4"
sodipodi:nodetypes="ccscccccccsaccccccccscsccsscccsccc"
inkscape:label="上发层" /><path
style="fill:none;fill-opacity:1;stroke:#c3b4b0;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 197.5082,220.06557 18.36065,-12.32786"
id="path46" /><path
style="fill:none;fill-opacity:1;stroke:#c3b4b0;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 327.54114,234.24941 c 0,0 -6.27192,4.90452 -15.85821,-0.991"
id="path47"
sodipodi:nodetypes="cc" /><path
style="display:inline;fill:none;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 322.62295,86.03279 c 0,0 75.43341,26.12055 110.16394,89.18032 33.44261,60.72132 33.04918,62.42623 33.04918,62.42623 0,0 0.52459,8.39345 -19.93443,11.54099 -2.62295,0 14.68852,30.95082 19.93443,37.2459 -14.68853,7.34426 -16.78689,8.91803 -16.78689,8.91803 0,0 6.29508,7.86885 4.72131,15.73771 -17.31147,-0.52459 -22.55738,-1.04918 -22.55738,-1.04918 0,0 -4.19672,17.31147 -15.7377,33.04918 C 410.22951,333.11475 410.22951,320 410.22951,320 c 0,0 -24.13115,36.72131 -72.39344,41.44262 -1.57377,-2.62295 12.59016,-14.16393 17.83606,-28.32787 -11.54098,1.57377 -14.68852,2.09836 -14.68852,2.09836 l 10.4918,-16.78688 c 0,0 11.01639,-24.13115 9.44262,-28.32787 -1.04918,-2.62295 -32,-57.70492 -32,-57.70492 0,0 -24.65573,33.04918 -43.54098,49.83607 -6.81967,-4.19672 -13.63934,-14.68853 -13.63934,-14.68853 l -12.59017,11.54099 c 0,0 -48.43778,-50.76436 -42.0945,-90.18318 -3.14754,12.06557 0.12729,56.60941 -5.6432,62.3799 -5.24591,-2.09836 -16.2623,-14.68853 -14.16394,-40.91803 -0.52459,-0.52459 -29.90164,41.44262 -29.90164,41.44262 0,0 -4.19672,48.78688 16.2623,73.44262 1.57377,2.62295 -1.57377,16.2623 -31.47541,-2.62295 1.04918,-1.57377 -1.04918,9.96721 -1.04918,9.96721 0,0 -46.68853,2.09836 -45.63935,-60.85245 -2.62295,-2.62296 -13.63934,34.09836 -13.63934,34.09836 0,0 -24.13115,-32 -0.52459,-92.85246 11.80328,-30.42623 23.34426,-52.85246 31.93442,-67.67213 8.59017,-14.81968 14.22951,-22.03279 14.22951,-22.03279"
id="path8-0"
sodipodi:nodetypes="csccccccccccccccccccccccccccssc"
inkscape:label="头发部件15 头发底色" /><path
id="path44-3"
style="fill:#a88a8f;stroke:#4c4f59;stroke-width:2.8623;stroke-linecap:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
d="m 216.29183,255.53888 a 8.8904896,7.4928694 0 0 1 -8.89049,7.49287 8.8904896,7.4928694 0 0 1 -8.89049,-7.49287 8.8904896,7.4928694 0 0 1 8.89049,-7.49287 8.8904896,7.4928694 0 0 1 8.89049,7.49287 z" /><path
id="path44"
style="fill:#a88a8f;stroke:#4c4f59;stroke-width:2.8623;stroke-linecap:round;stroke-miterlimit:1.3;paint-order:fill markers stroke"
d="m 336.16933,270.5473 a 8.8904896,7.4928694 0 0 1 -8.89049,7.49287 8.8904896,7.4928694 0 0 1 -8.89049,-7.49287 8.8904896,7.4928694 0 0 1 8.89049,-7.49287 8.8904896,7.4928694 0 0 1 8.89049,7.49287 z" /><path
style="opacity:1;fill:none;fill-opacity:0;stroke:#a18f90;stroke-width:10.4;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 318.7189,85.461784 c 0,0 50.44801,17.063296 76.78484,43.400126 26.33683,26.33683 32.64283,39.31978 32.64283,39.31978"
id="path32"
inkscape:label="上方头发边缘加厚" /><path
style="fill:none;fill-opacity:1;stroke:#4c4f59;stroke-width:6.5;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 186.7541,224.52459 10.4918,1.04918"
id="path45" /><path
style="opacity:1;fill:#fcbeb5;fill-opacity:1;stroke:#e99c9b;stroke-width:3.4;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 250.94176,349.98308 c 0,0 -13.91029,-8.90259 -10.0154,-16.69235 3.89488,-7.78977 17.80517,-4.4513 17.80517,-4.4513 0,0 12.98295,-1.29829 20.03083,-3.89488 7.04788,-2.59659 9.64447,5.0077 9.64447,5.0077 0,0 4.76461,6.06544 -4.26583,16.50689 -5.93505,6.86241 -21.14364,7.04788 -21.14364,7.04788"
id="path48"
sodipodi:nodetypes="cscscsc" /><path
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#e99c9b;stroke-width:1.8;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 276.20884,325.76493 c 0,0 4.35031,3.01904 5.37456,7.95235 0.57119,0.10629 3.33355,-3.08729 2.97647,-6.87263 -0.67968,-1.48531 -8.35103,-1.07972 -8.35103,-1.07972 z"
id="path49" /><path
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#e99c9b;stroke-width:1.8;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 245.0067,329.39584 -4.17308,2.78206 -0.0927,6.0278 -0.0956,-0.0355 7.07328,-8.8174 z"
id="path50"
sodipodi:nodetypes="cccccc" /><path
style="fill:none;fill-opacity:1;stroke:#e99c9b;stroke-width:3.4;stroke-linecap:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 250.94176,349.98308 c 0,0 -13.91029,-8.90259 -10.0154,-16.69235 3.89488,-7.78977 17.80517,-4.4513 17.80517,-4.4513 0,0 12.98295,-1.29829 20.03083,-3.89488 7.04788,-2.59659 9.64447,5.0077 9.64447,5.0077 0,0 4.76461,6.06544 -4.26583,16.50689 -5.93505,6.86241 -21.14364,7.04788 -21.14364,7.04788"
id="path48-2"
sodipodi:nodetypes="cscscsc" /><path
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#e89493;stroke-width:2.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 190.84928,314.92913 6.12053,15.02312"
id="path51" /><path
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#e89493;stroke-width:2.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 204.94505,316.96931 5.56412,14.28124"
id="path52" /><path
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#e89493;stroke-width:2.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 217.92799,317.34025 7.41883,16.50689"
id="path53" /><path
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#e89493;stroke-width:2.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 300.64789,328.46849 6.86242,18.17612"
id="path54" /><path
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#e89493;stroke-width:2.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 312.70348,329.21037 6.67695,17.0633"
id="path55" /><path
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#e89493;stroke-width:2.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 326.24284,328.65396 7.04788,17.99065"
id="path56" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#e49589;stroke-width:4.6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 218.4918,348.98361 c -1.87307,1.30472 -3.33608,3.11401 -4.70333,4.91603 -1.02497,1.35089 -2.00187,2.75003 -2.77208,4.2643"
id="path61"
inkscape:path-effect="#path-effect61"
inkscape:original-d="m 218.4918,348.98361 c -1.70592,0.99645 -5.82749,5.88449 -7.47541,9.18033"
transform="rotate(-3.3120949,219.55256,344.63259)" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#4c4f59;stroke-width:3.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 127.47541,375.08197 c 0,0 -14.42623,-19.14754 -12.06557,-59.54099"
id="path92" /><path
style="opacity:1;fill:#ffffff;fill-opacity:0.734285;stroke:#c1545a;stroke-width:7.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 136.39344,322.09836 c 0,0 9.44263,-18.88525 -4.19672,-39.86885 -3.14754,-0.52459 27.80328,-27.80328 5.2459,-77.11476 -1.57377,0.52459 23.60656,-55.60655 -24.13115,-82.88524 -4.19672,-8.39344 -45.639336,-69.245904 -89.180316,13.11475 0,11.54099 -1.04918,36.19672 -1.04918,36.19672 0,0 -14.6885299,38.81968 -6.29509,71.86886 2.09837,3.14754 -20.9835999,49.83606 11.0164,106.4918 0.52459,0.52459 -16.78689,57.70492 12.59016,82.88525 1.04918,4.72131 13.63935,33.57377 42.49181,39.34426 12.59016,0.52459 19.409826,-0.52459 19.409826,-0.52459 0,0 31.47541,-4.72131 47.73771,-67.14754 -2.09836,-27.80328 -4.19672,-50.36066 -11.0164,-70.81968"
id="path93" /><path
id="path101"
style="opacity:1;fill:#ffffff;fill-opacity:0.734285;stroke:#000000;stroke-width:9;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 109.69769,219.48859 c 0,0 -15.208592,-11.87012 -21.143652,-19.65989 m -37.09413,20.03083 22.25648,-21.88553 m 0.37094,-14.09577 5.93506,41.91636 m -35.23942,-24.11118 56.012132,-4.82224 m 11.12824,-17.43424 -19.288952,0.37094 m -0.37094,-0.74188 -1.48376,-29.6753 m -38.94883,3.33847 37.836,-2.96753 m -24.85306,-11.49918 0.74188,39.69072"
inkscape:label="杂" /><path
id="path111"
style="opacity:1;fill:#ffffff;fill-opacity:0.734285;stroke:#000000;stroke-width:9;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 58.507798,352.28556 54.157422,-3.33847 m -46.367662,-13.72483 35.610372,-2.96753 m -21.514602,-32.27189 2.59659,33.38472 m -18.918,-16.32142 37.094122,-3.33847 m 1.48377,18.54706 0.74188,-33.75565 m -0.37094,0.37094 -40.803542,2.22565 m 0,-0.37094 4.4513,33.38471 m 27.44965,-48.22237 3.33847,-14.4667 m 0,-1.48377 -27.44965,1.48377 m -1.48377,14.83765 0.74188,-20.03083"
inkscape:label="鱼" /><path
d="m 69.453989,376.46984 c -4.220665,0.22086 -8.079406,1.8518 -10.783191,4.54882 -2.980547,2.98155 -4.241957,7.10139 -3.534076,11.54824 0.904812,5.67433 4.763552,11.7394 11.384623,17.90216 1.405115,1.30393 2.39508,2.14912 4.390984,3.74184 3.507462,2.79468 6.679618,5.01174 11.04931,7.70876 1.559468,0.96838 4.635815,2.76496 5.796096,3.38931 l 0.335314,0.18263 0.48966,-0.26758 c 1.783005,-0.98111 4.960482,-2.86264 6.844609,-4.05189 7.126702,-4.49782 12.832312,-9.01266 17.063632,-13.50625 6.86057,-7.28827 9.77725,-14.38543 8.43068,-20.49298 -0.93142,-4.20475 -4.04502,-7.68327 -8.46261,-9.45012 -1.90011,-0.76026 -3.74699,-1.15525 -5.83869,-1.24869 -2.7091,-0.12316 -5.37562,0.33977 -7.91973,1.37185 -4.332435,1.75413 -7.951675,5.17315 -10.229661,9.66674 -0.159681,0.3143 -0.308701,0.59038 -0.329985,0.60737 -0.0692,0.0553 -0.143707,-0.051 -0.431122,-0.62859 -0.681263,-1.35913 -2.01719,-3.3341 -3.065699,-4.52331 -1.07513,-1.22747 -2.804909,-2.72251 -4.092931,-3.54224 -3.326503,-2.11937 -7.222503,-3.15569 -11.097213,-2.95607 z"
id="path1-4"
style="fill:#d96477;fill-opacity:1;stroke:none;stroke-width:0.00475452" /></g></svg>

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

101
Website/docs/zh/config.ts Normal file
View File

@@ -0,0 +1,101 @@
import { defineConfig, type DefaultTheme } from 'vitepress'
export default defineConfig({
lang: 'zh-Hans',
description: '下一代 Android Root 解决方案 - Android 上的内核级的高级 root 方案',
themeConfig: {
nav: nav(),
sidebar: {
'/zh/': { base: '/zh/', items: sidebar() },
},
search: { options: searchOptions() },
editLink: {
pattern: 'https://github.com/sukisu-ultra/sukisu-ultra/edit/main/docs/:path',
text: '在 GitHub 上编辑此页面',
},
docFooter: {
prev: '上一页',
next: '下一页',
},
outline: {
label: '页面导航',
},
lastUpdated: {
text: '最后更新于',
},
notFound: {
title: '页面未找到',
quote: '抱歉,我们无法找到您要查找的页面。',
linkLabel: '前往首页',
linkText: '带我回首页',
},
langMenuLabel: '多语言',
returnToTopLabel: '回到顶部',
sidebarMenuLabel: '菜单',
darkModeSwitchLabel: '主题',
lightModeSwitchTitle: '切换到浅色模式',
darkModeSwitchTitle: '切换到深色模式',
skipToContentLabel: '跳转到内容',
},
})
function nav(): DefaultTheme.NavItem[] {
return [
{ text: '首页', link: '/zh/' },
{
text: '开始使用',
items: [
{ text: '介绍', link: '/zh/guide/' },
{ text: '安装', link: '/zh/guide/installation' },
{ text: '集成', link: '/zh/guide/how-to-integrate' },
{ text: '兼容性', link: '/zh/guide/compatibility' },
{ text: '链接', link: '/zh/guide/links' },
{ text: '许可', link: '/zh/guide/license' },
],
},
]
}
function sidebar(): DefaultTheme.SidebarItem[] {
return [
{
text: '开始使用',
items: [
{ text: '介绍', link: '/guide/' },
{ text: '安装', link: '/guide/installation' },
{ text: '集成', link: '/guide/how-to-integrate' },
{ text: '兼容性', link: '/guide/compatibility' },
{ text: '链接', link: '/guide/links' },
{ text: '许可', link: '/guide/license' },
],
},
]
}
function searchOptions(): Partial<DefaultTheme.LocalSearchOptions> {
return {
translations: {
button: {
buttonText: '搜索文档',
buttonAriaLabel: '搜索文档',
},
modal: {
noResultsText: '无法找到相关结果',
resetButtonTitle: '清除查询条件',
footer: {
selectText: '选择',
navigateText: '切换',
closeText: '关闭',
},
},
},
}
}

View File

@@ -0,0 +1,23 @@
# 兼容性状态
::: info KernelSU
KernelSUv0.9.5 之前的版本)官方支持 Android GKI 2.0 设备(内核 5.10+
:::
::: warning 传统内核支持
较旧的内核4.4+)也兼容,但内核必须手动构建
:::
::: tip 扩展兼容性
SukiSU-Ultra 可以通过额外的反向移植支持 3.x 内核3.4-3.18
:::
## 架构支持
目前支持以下处理器架构:
| 架构 | 支持级别 | 备注 |
| --------------- | :---------: | -----------: |
| **arm64-v8a** | ✅ 完全支持 | 主要目标架构 |
| **armeabi-v7a** | ✅ 基础支持 | 最低功能要求 |
| **X86_64** | 🟡 部分支持 | 支持部分设备 |

View File

@@ -0,0 +1,94 @@
# 集成指导
SukiSU 可以集成到 GKI 和 non-GKI 内核中,并且已反向移植到 4.14 版本。
<!-- 应该是 3.4 版本,但 backslashxx 的 syscall manual hook 无法在 SukiSU 中使用-->
有些 OEM 定制可能导致多达 50% 的内核代码超出内核树代码,而非来自上游 Linux 内核或 ACK。因此non-GKI 内核的定制特性导致了严重的内核碎片化,而且我们缺乏构建它们的通用方法。因此,我们无法提供 non-GKI 内核的启动映像。
前提条件:开源的、可启动的内核。
## Hook 方法
1. **KPROBES hook:**
- GKI kernels 的默认 hook 方法。
- 需要 `# CONFIG_KSU_MANUAL_HOOK is not set`(未设定) & `CONFIG_KPROBES=y`
- 用作可加载的内核模块 (LKM).
2. **Manual hook:**
<!-- - backslashxx's syscall manual hook: https://github.com/backslashxx/KernelSU/issues/5 (v1.5 version is not available at the moment, if you want to use it, please use v1.4 version, or standard KernelSU hooks)-->
- 需要 `CONFIG_KSU_MANUAL_HOOK=y`
- 需要 [`guide/how-to-integrate.md`](how-to-integrate.md)
- 需要 [https://github.com/~](https://github.com/tiann/KernelSU/blob/main/website/docs/guide/how-to-integrate-for-non-gki.md#manually-modify-the-kernel-source)
3. **Tracepoint Hook:**
- 自 SukiSU commit [49b01aad](https://github.com/SukiSU-Ultra/SukiSU-Ultra/commit/49b01aad74bcca6dba5a8a2e053bb54b648eb124) 引入的 hook 方法
- 需要 `CONFIG_KSU_TRACEPOINT_HOOK=y`
- 需要 [`guide/tracepoint-hook.md`](tracepoint-hook.md)
<!-- This part refer to [rsuntk/KernelSU](https://github.com/rsuntk/KernelSU). -->
如果您能够构建可启动内核,有两种方法可以将 KernelSU 集成到内核源代码中:
1. 使用 `kprobe` 自动集成
2. 手动集成
## 与 kprobe 集成
适用:
- GKI 内核
不适用:
- non-GKI 内核
KernelSU 使用 kprobe 机制来做内核的相关 hook如果 _kprobe_ 可以在你编译的内核中正常运行,那么推荐用这个方法来集成。
请参阅此文档 [https://github.com/~](https://github.com/tiann/KernelSU/blob/main/website/docs/guide/how-to-integrate-for-non-gki.md#integrate-with-kprobe)。虽然标题为“适用于 non-GKI”但仅适用于 GKI。
替换 KernelSU 添加到内核源代码树的步骤的执行命令为:
```sh [bash]
curl -LSs "https://raw.githubusercontent.com/SukiSU-Ultra/SukiSU-Ultra/main/kernel/setup.sh" | bash -s main
```
## 手动修改内核源代码
适用:
- GKI 内核
- non-GKI 内核
请参考此文档 [https://github.com/~ (non-GKI 内核集成)](https://github.com/tiann/KernelSU/blob/main/website/docs/guide/how-to-integrate-for-non-gki.md#manually-modify-the-kernel-source) 和 [https://github.com/~ (GKI 内核构建)](https://kernelsu.org/zh_CN/guide/how-to-build.html) 进行手动集成。虽然第一个链接的标题是“适用于 non-GKI”但它也适用于 GKI。两者都可以正常工作。
还有另一种集成方法,但是仍在开发中。
<!-- 这是 backslashxx 的syscall manual hook但目前无法使用。 -->
将 KernelSUSukiSU添加到内核源代码树的步骤的运行命令将被替换为
### GKI 内核
```sh [bash]
curl -LSs "https://raw.githubusercontent.com/SukiSU-Ultra/SukiSU-Ultra/main/kernel/setup.sh" | bash -s main
```
### non-GKI 内核
```sh [bash]
curl -LSs "https://raw.githubusercontent.com/SukiSU-Ultra/SukiSU-Ultra/main/kernel/setup.sh" | bash -s nongki
```
### 带有 susfs 的 GKI / non-GKI 内核(实验)
```sh [bash]
curl -LSs "https://raw.githubusercontent.com/SukiSU-Ultra/SukiSU-Ultra/main/kernel/setup.sh" | bash -s susfs-{{branch}}
```
分支:
- `main` (susfs-main)
- `test` (susfs-test)
- 版本号 (例如: susfs-1.5.7, 你需要在 [分支](https://github.com/SukiSU-Ultra/SukiSU-Ultra/branches) 里找到它)

View File

@@ -0,0 +1,35 @@
# 什么是 SukiSU-Ultra
一个 Android 上基于内核的 root 方案,由 [`tiann/KernelSU`](https://github.com/tiann/KernelSU) 分叉而来,添加了一些有趣的变更。
## 特性
1. 基于内核的 su 和权限管理。
2. 基于 Magic Mount 的模块系统。
3. App Profile: 把 Root 权限关进笼子里。
4. 支持 non-GKI 与 GKI 1.0。
5. KPM 支持
6. 可调整管理器外观,可自定义 susfs 配置。
## 如何安装
了解如何在您的设备上 **[安装](./installation)** SukiSU-Ultra
## 如何集成
阅读 **[集成](./how-to-integrate.md)** 将 SukiSU 集成到你的内核中
## 了解兼容性
检查设备 **[兼容性](./compatibility)** 要求
## 资源获取
查找其他资源和 **[下载](./links)**
## 获取支持
需要帮助?我们在这里为您提供帮助:
- **错误报告**: [GitHub Issues](https://github.com/SukiSU-Ultra/SukiSU-Ultra/issues)
- **直接支持**: 联系开发者处理关键问题

View File

@@ -0,0 +1,149 @@
# 安装参考
::: details 将会了解 SukiSU-Ultra 安装过程
[[toc]]
:::
::: danger 警告
**Root 您的设备可能会使保修失效,如果操作不当可能会造成永久性损坏。**
请务必在继续之前创建完整备份,阅读文档确保与您的设备兼容,遵循文档参考,准备好恢复计划
:::
## 通用 GKI
请**全部**参考 [KernelSU 安装指南](https://kernelsu.org/zh_CN/guide/installation.html)
1. 适用于 GKI 2.0 设备,如小米、红米、三星等(不包括内核修改的制造商,如魅族、一加、真我和 OPPO
2. 在[更多链接](./links)中查找 GKI 构建。找到设备内核版本,然后下载并使用 TWRP 或内核刷写工具刷入带有 `AnyKernel3` 后缀的
zip 文件。
3. 无后缀的 `.zip` 档案是未压缩的,`gz` 后缀是特定型号使用的压缩格式。
## 一加设备
使用[更多链接](./links)部分提到的链接,用您的设备信息创建自定义构建,然后刷入带有 AnyKernel3 后缀的 zip 文件。
::: details 展开
- 只需要填写内核版本的前两部分,如 `5.10``5.15``6.1``6.6`
- 请自行搜索处理器代号,通常是不含数字的英文字母。
- 可以从一加开源内核仓库中找到分支和配置文件。
- 第三方 Recovery推荐 TWRP
:::
## 开始安装
### 通用 GKI 安装
::: tip
适用于 GKI 2.0 设备,如小米、红米、三星等(不包括内核修改的制造商,如魅族、一加、真我和 OPPO
:::
#### 步骤:
1. 下载 GKI 构建文件
从我们的[资源部分](./links)查找 GKI 构建。查找您设备的内核版本并下载带有 `AnyKernel3` 后缀的 `zip` 文件。
2. 通过 Recovery 刷入
启动到 `TWRP recovery`,选择 **Install**,导航到下载的 `AnyKernel3 zip` 文件,滑动刷入后重启系统
3. [验证安装](#验证)
::: details 文件格式说明
无后缀的 `.zip` 档案是未压缩的,`gz` 后缀是特定型号使用的压缩格式。
:::
### 一加设备安装
1. 获取设备信息
- 内核版本(前两部分,例如 `5.10``5.15``6.1``6.6`
- 处理器代号(通常是不含数字的英文)
- 来自一加开源内核仓库的分支和配置文件
2. 创建自定义构建
使用我们[资源部分](./links)中提到的链接,用您的设备信息创建自定义构建。
3. 刷入构建
下载生成的带有 AnyKernel3 后缀的 zip 文件,启动到 `TWRP recovery`,选择 **Install**,导航到下载的 `AnyKernel3 zip` 文件,滑动刷入后重启系统
::: tip
您只需要填写内核版本的前两部分。自行搜索处理器代号
:::
### 手动内核集成
面向希望将 SukiSU Ultra 集成到自己内核构建中的高级用户
#### 主分支GKI
```sh [bash]
curl -LSs "https://raw.githubusercontent.com/SukiSU-Ultra/SukiSU-Ultra/main/kernel/setup.sh" | bash -s main
```
#### 非 GKI 分支
```sh [bash]
curl -LSs "https://raw.githubusercontent.com/SukiSU-Ultra/SukiSU-Ultra/main/kernel/setup.sh" | bash -s nongki
```
#### SUSFS-Dev 分支(推荐)
```sh [bash]
curl -LSs "https://raw.githubusercontent.com/SukiSU-Ultra/SukiSU-Ultra/main/kernel/setup.sh" | bash -s susfs-dev
```
```bash
curl -LSs "https://raw.githubusercontent.com/SukiSU-Ultra/SukiSU-Ultra/main/kernel/setup.sh" | bash -s susfs-main
```
::: warning 必需的内核配置
为了支持 KPM添加 `CONFIG_KPM=y`
对于非 GKI 设备,还要添加 `CONFIG_KALLSYMS=y` 和 `CONFIG_KALLSYMS_ALL=y`
:::
## 安装后设置
### 系统更新时保持 Root
> [!IMPORTANT]
> 如何在 OTA 更新后保持 root 访问权限:
#### 步骤:
1. 系统更新后重启前
- OTA 安装后不要立即重启,将 SukiSU Ultra 安装到第二插槽
- 打开 SukiSU Ultra 管理器,在**刷入/修补内核**界面选择 **GKI/non_GKI install**,选择您的 `AnyKernel3` 内核 `zip` 文件,选择与当前运行插槽相对的插槽然后刷入重启。
2. 替代方案LKM 模式
使用 [LKM 模式](#通用-gki) 在 OTA 后安装到未使用的插槽。
::: warning 警告
**非 GKI 设备注意事项:** 此方法不支持所有非 GKI 设备。对于非 GKI 设备,使用 TWRP 是最安全的方法。
:::
## 验证
安装后,验证一切是否正常工作,
- 打开 SukiSU Ultra 管理器检查 root 工作状态
- 使用 root 权限的应用程序来验证 root 访问是否工作正常
- 在设置 -> 关于手机中检查内核版本
## 需要帮助?
如果在安装过程中遇到问题:
1. 查看我们的[兼容性指南](./compatibility)了解设备要求
2. 访问我们的 [GitHub 仓库](https://github.com/sukisu-ultra/sukisu-ultra)获取支持
3. 加入我们的 [Telegram 社区](https://t.me/sukiksu)获取帮助
::: danger 安全提醒
**始终有备用计划!** 保留您的原始 `boot.img/init_boot.img` 并知道如何在出现问题时恢复设备。
:::

View File

@@ -0,0 +1,77 @@
# 许可证
## 软件许可
### 内核组件
::: info GPL-2.0 许可证
"kernel" 目录中的文件采用 GPL-2.0-only 许可证
:::
**许可证:** [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
### 应用程序核心
::: tip GPL-3.0 许可证
所有其他部分(除下述特别说明外)采用 GPL-3.0 或更高版本许可证
:::
**许可证:** [GPL-3.0 或更高版本](https://www.gnu.org/licenses/gpl-3.0.html)
## 艺术作品与品牌资产
### 启动器图标与角色艺术
::: warning 版权声明
动画角色艺术作品有特殊许可要求
:::
包含动画角色表情的文件 `ic_launcher(?!.*alt.*).*` 图像有特定的版权条款:
**版权持有者:**
- **动画角色艺术:** [怡子曰曰](https://space.bilibili.com/10545509)
- **品牌知识产权:** [明风OuO](https://space.bilibili.com/274939213)
- **矢量化制作:** @MiRinChan
**许可要求:**
1. **知识共享许可证:** [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.txt)
2. **作者授权:** 需要获得两位版权持有者的授权
3. **署名要求:** 必须署名上述所有贡献者
::: details 使用要求
在使用这些艺术资产之前,您必须:
- 遵守知识共享署名-非商业性使用-相同方式共享 4.0 国际许可证
- 获得两位原作者对艺术内容使用的授权
- 为所有贡献者提供适当的署名
:::
## 摘要
| 组件 | 许可证 | 备注 |
| ---------------- | ------------------------------------------------------------------------- | ----------------------- |
| **内核文件** | [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) | `/kernel/` 目录中的文件 |
| **应用程序代码** | [GPL-3.0+](https://www.gnu.org/licenses/gpl-3.0.html) | 主要应用程序组件 |
| **角色艺术** | [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/) | + 需要作者授权 |
| **品牌资产** | 混合许可 | 查看具体署名要求 |
## 链接
- **GPL-2.0** [完整许可证文本](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- **GPL-3.0** [完整许可证文本](https://www.gnu.org/licenses/gpl-3.0.html)
- **CC BY-NC-SA 4.0** [完整许可证文本](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.txt)
## 问题
关于许可证或使用权限的问题:
1. **代码许可:** 参考相应的 GPL 许可证条款
2. **艺术作品使用:** 联系原作者获取授权
3. **商业使用:** 查看 CC BY-NC-SA 4.0 限制条款
4. **分发:** 确保遵守所有适用的许可证
::: tip 合规提示
在重新分发或修改 SukiSU-Ultra 时,请确保遵守各个组件的所有适用许可证和署名要求。
:::

View File

@@ -0,0 +1,71 @@
# 更多链接
## 参与翻译
::: info 贡献翻译
如果您需要为管理器提交翻译,请访问我们的 Crowdin 项目
:::
**翻译平台:** [Crowdin - SukiSU-Ultra](https://crowdin.com/project/SukiSU-Ultra)
## 项目与构建
基于 Sukisu 和 susfs 编译的项目:
### GKI 构建
::: tip 通用 GKI 支持
集成 KernelSU 和 SUSFS 的通用内核映像构建
:::
**仓库:** [GKI_KernelSU_SUSFS](https://github.com/ShirkNeko/GKI_KernelSU_SUSFS)
### OnePlus 构建
::: tip 设备特定构建
带有 MKSU 和 SUSFS 的自动化 OnePlus 内核构建
:::
**仓库:** [Action_OnePlus_MKSU_SUSFS](https://github.com/ShirkNeko/Action_OnePlus_MKSU_SUSFS)
## 社区与支持
### Telegram 社区
> 与其他用户联系,获取支持并保持更新
**主群组:** [Tg Group](https://t.me/sukiksu)
### 测试构建
::: warning 实验性构建
测试构建是实验性的,可能不稳定
:::
**测试构建频道:** [最新测试构建](https://t.me/Sukiksu/7114)
## 下载与发布
### 官方发布
> 从我们的 GitHub 发布页面下载最新稳定版本
**GitHub 发布:** [SukiSU-Ultra 发布](https://github.com/sukisu-ultra/sukisu-ultra/releases)
### 问题报告
> 在我们的 GitHub 仓库上报告错误或请求新功能
**GitHub 问题:** [报告问题](https://github.com/sukisu-ultra/sukisu-ultra/issues)
## 快速链接汇总
| 资源 | 链接 | 描述 |
| ----------------- | :--------------------------------------------------------------------: | -----------: |
| **翻译** | [Crowdin](https://crowdin.com/project/SukiSU-Ultra) | 提交翻译 |
| **Telegram 群组** | [t.me/sukiksu](https://t.me/sukiksu) | 社区支持 |
| **测试构建** | [测试频道](https://t.me/Sukiksu/7114) | 实验性构建 |
| **发布** | [GitHub 发布](https://github.com/sukisu-ultra/sukisu-ultra/releases) | 稳定下载 |
| **问题** | [GitHub 问题](https://github.com/sukisu-ultra/sukisu-ultra/issues) | 错误报告 |
| **GKI 构建** | [GKI 仓库](https://github.com/ShirkNeko/GKI_KernelSU_SUSFS) | 通用构建 |
| **OnePlus 构建** | [OnePlus 仓库](https://github.com/ShirkNeko/Action_OnePlus_MKSU_SUSFS) | 设备特定构建 |

View File

@@ -0,0 +1,266 @@
# Tracepoint Hook 集成
## 介绍
自 commit [49b01aad](https://github.com/SukiSU-Ultra/SukiSU-Ultra/commit/49b01aad74bcca6dba5a8a2e053bb54b648eb124) 起SukiSU 引入了 Tracepoint Hook
**该 Hook 理论上相比于 Kprobes Hook性能开销更小但次于 Manual Hook / Syscall Hook**
::: warning
目前 Tracepoint Hook 在 6.x 设备上并不稳定,请勿使用,否则可能出现无法开机或无法获取 `ROOT` 权限等问题。
:::
> [!NOTE]
> 本教程参考了 [backslashxx/KernelSU#5](https://github.com/backslashxx/KernelSU/issues/5) 的 syscall hook v1.4 版本钩子,以及原版 KernelSU 的 [Manual Hook](https://kernelsu.org/guide/how-to-integrate-for-non-gki.html#manually-modify-the-kernel-source)
## 在内核中放置 TP 钩子
::: code-group
```diff[exec.c]
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -78,6 +78,10 @@
#include <trace/hooks/sched.h>
#endif
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+#include <../drivers/kernelsu/ksu_trace.h>
+#endif
+
EXPORT_TRACEPOINT_SYMBOL_GPL(task_rename);
static int bprm_creds_from_file(struct linux_binprm *bprm);
@@ -2037,6 +2041,9 @@ static int do_execve(struct filename *filename,
{
struct user_arg_ptr argv = { .ptr.native = __argv };
struct user_arg_ptr envp = { .ptr.native = __envp };
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+ trace_ksu_trace_execveat_hook((int *)AT_FDCWD, &filename, &argv, &envp, 0);
+#endif
return do_execveat_common(AT_FDCWD, filename, argv, envp, 0);
}
@@ -2064,6 +2071,9 @@ static int compat_do_execve(struct filename *filename,
.is_compat = true,
.ptr.compat = __envp,
};
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+ trace_ksu_trace_execveat_sucompat_hook((int *)AT_FDCWD, &filename, NULL, NULL, NULL); /* 32-bit su */
+#endif
return do_execveat_common(AT_FDCWD, filename, argv, envp, 0);
}
```
```diff[open.c]
--- a/fs/open.c
+++ b/fs/open.c
@@ -37,6 +37,10 @@
#include "internal.h"
#include <trace/hooks/syscall_check.h>
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+#include <../drivers/kernelsu/ksu_trace.h>
+#endif
+
int do_truncate(struct user_namespace *mnt_userns, struct dentry *dentry,
loff_t length, unsigned int time_attrs, struct file *filp)
{
@@ -468,6 +472,9 @@ static long do_faccessat(int dfd, const char __user *filename, int mode, int fla
SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
{
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+ trace_ksu_trace_faccessat_hook(&dfd, &filename, &mode, NULL);
+#endif
return do_faccessat(dfd, filename, mode, 0);
}
```
```diff[read_write.c]
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -25,6 +25,10 @@
#include <linux/uaccess.h>
#include <asm/unistd.h>
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+#include <../drivers/kernelsu/ksu_trace.h>
+#endif
+
const struct file_operations generic_ro_fops = {
.llseek = generic_file_llseek,
.read_iter = generic_file_read_iter,
@@ -630,6 +634,9 @@ ssize_t ksys_read(unsigned int fd, char __user *buf, size_t count)
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
{
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+ trace_ksu_trace_sys_read_hook(fd, &buf, &count);
+#endif
return ksys_read(fd, buf, count);
}
```
```diff[stat.c]
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -24,6 +24,10 @@
#include "internal.h"
#include "mount.h"
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+#include <../drivers/kernelsu/ksu_trace.h>
+#endif
+
/**
* generic_fillattr - Fill in the basic attributes from the inode struct
* @mnt_userns: user namespace of the mount the inode was found from
@@ -408,6 +412,10 @@ SYSCALL_DEFINE4(newfstatat, int, dfd, const char __user *, filename,
struct kstat stat;
int error;
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+ trace_ksu_trace_stat_hook(&dfd, &filename, &flag);
+#endif
+
error = vfs_fstatat(dfd, filename, &stat, flag);
if (error)
return error;
@@ -559,6 +567,10 @@ SYSCALL_DEFINE4(fstatat64, int, dfd, const char __user *, filename,
struct kstat stat;
int error;
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+ trace_ksu_trace_stat_hook(&dfd, &filename, &flag); /* 32-bit su support */
+#endif
+
error = vfs_fstatat(dfd, filename, &stat, flag);
if (error)
return error;
```
:::
通常是要改四个地方:
1. compat_do_execve通常位于 `fs/exec.c`
2. do_faccessat通常位于 `/fs/open.c`
3. sys_read通常位于 `fs/read_write.c`
4. newfstatat SYSCALL通常位于 `fs/stat.c`
如果没有 do_faccessat 方法,可以找 faccessat 的 SYSCALL 定义(对于早于 4.17 的内核)
```diff
--- a/fs/open.c
+++ b/fs/open.c
@@ -31,6 +31,9 @@
#include <linux/ima.h>
#include <linux/dnotify.h>
#include <linux/compat.h>
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+#include <../drivers/kernelsu/ksu_trace.h>
+#endif
#include "internal.h"
@@ -369,6 +372,9 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
int res;
unsigned int lookup_flags = LOOKUP_FOLLOW;
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+ trace_ksu_trace_faccessat_hook(&dfd, &filename, &mode, NULL);
+#endif
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
return -EINVAL;
```
如果没有 sys_read 方法,并且 4.14 及以下需要修改 read 的 SYSCALL 定义
```diff
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -25,6 +25,11 @@
#include <linux/uaccess.h>
#include <asm/unistd.h>
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+#include <../drivers/kernelsu/ksu_trace.h>
+#endif
+
+
const struct file_operations generic_ro_fops = {
.llseek = generic_file_llseek,
.read_iter = generic_file_read_iter,
@@ -575,6 +580,9 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
if (f.file) {
loff_t pos = file_pos_read(f.file);
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+ trace_ksu_trace_sys_read_hook(fd, &buf, &count);
+#endif
ret = vfs_read(f.file, buf, count, &pos);
if (ret >= 0)
file_pos_write(f.file, pos);
```
## 安全模式
要使用 KernelSU 内置的安全模式,你还需要修改 `drivers/input/input.c` 中的 input_handle_event 方法:
```diff
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -26,6 +26,10 @@
#include "input-compat.h"
#include "input-poller.h"
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+#include <../../drivers/kernelsu/ksu_trace.h>
+#endif
+
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("Input core");
MODULE_LICENSE("GPL");
@@ -451,6 +455,10 @@ void input_event(struct input_dev *dev,
{
unsigned long flags;
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+ trace_ksu_trace_input_hook(&type, &code, &value);
+#endif
+
if (is_event_supported(type, dev->evbit, EV_MAX)) {
spin_lock_irqsave(&dev->event_lock, flags);
```
## pm 命令执行失败?
你需要修改 `drivers/tty/pty.c`
```diff
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -31,6 +31,10 @@
#include <linux/compat.h>
#include "tty.h"
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+#include <../../drivers/kernelsu/ksu_trace.h>
+#endif
+
#undef TTY_DEBUG_HANGUP
#ifdef TTY_DEBUG_HANGUP
# define tty_debug_hangup(tty, f, args...) tty_debug(tty, f, ##args)
@@ -707,6 +711,10 @@ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
{
struct tty_struct *tty;
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+ trace_ksu_trace_devpts_hook((struct inode *)file->f_path.dentry->d_inode);
+#endif
+
mutex_lock(&devpts_mutex);
tty = devpts_get_priv(file->f_path.dentry);
mutex_unlock(&devpts_mutex);
```

37
Website/docs/zh/index.md Normal file
View File

@@ -0,0 +1,37 @@
---
layout: home
hero:
name: 'SukiSU-Ultra'
text: '下一代 Android Root 解决方案'
tagline: Android 上的内核级的高级 root 方案
image:
src: /logo.svg
alt: SukiSU-Ultra
actions:
- theme: brand
text: 开始使用
link: /zh/guide/
- theme: alt
text: 在 GitHub 上查看
link: https://github.com/sukisu-ultra/sukisu-ultra
features:
- title: 内核级的 su 和 root 权限管理
details: 在内核进行安全的 root 权限管理。
- title: 不基于 OverlayFS 的模块系统
details: 模块系统基于来自 5ec1cff 的 Magic Mount。
- title: App Profile
details: 把 root 权限关进笼子里。
- title: 重新支持非 GKI 与 GKI 1.0 内核
details: 增强对旧设备的兼容性。
- title: 更多自定义选项
details: 提供广泛的自定义选项。
- title: 支持 KPM
details: 完整的基于 KernelPatch 的 KPM 功能。
---

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
Website/favicon/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 58 KiB

View File

@@ -0,0 +1,26 @@
{
"name": "SukiSU",
"short_name": "SukiSU",
"icons": [
{
"src": "/favicon.svg",
"type": "image/svg+xml",
"purpose": "any"
},
{
"src": "/web-app-manifest-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/web-app-manifest-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
],
"theme_color": "#000000",
"background_color": "#000000",
"display": "standalone"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

57
Website/package.json Normal file
View File

@@ -0,0 +1,57 @@
{
"name": "sukisu-ultra-docs",
"version": "2.0.0",
"description": "SukiSU-Ultra Documentation - Next-Generation Android Root Solution",
"type": "module",
"scripts": {
"dev": "tsx scripts/rebuild-ico.ts && tsx scripts/sync-favicons.ts && vitepress dev docs --host",
"build": "tsx scripts/sync-favicons.ts && vitepress build docs && pnpm build:sw:dist",
"preview": "vitepress preview docs",
"build:sw": "tsc scripts/sw.ts --target ES2022 --lib ES2022,WebWorker --outDir docs/public --skipLibCheck",
"build:sw:dist": "tsc scripts/sw.ts --target ES2022 --lib ES2022,WebWorker --outDir docs/.vitepress/dist --skipLibCheck",
"build:scripts": "pnpm build:sw",
"type-check": "tsc --noEmit",
"format": "prettier --write .",
"format:check": "prettier --check ."
},
"keywords": [
"android",
"root",
"kernelsu",
"sukisu",
"documentation",
"vitepress"
],
"repository": {
"type": "git",
"url": "https://github.com/sukisu-ultra/sukisu-ultra.git"
},
"homepage": "https://sukisu.org",
"bugs": {
"url": "https://github.com/sukisu-ultra/sukisu-ultra/issues"
},
"devDependencies": {
"@types/node": "^24.3.0",
"@types/serviceworker": "^0.0.152",
"markdown-it-footnote": "^4.0.0",
"markdown-it-mark": "^4.0.0",
"markdown-it-mathjax3": "^4.3.2",
"markdown-it-sub": "^2.0.0",
"markdown-it-task-lists": "^2.1.1",
"prettier": "^3.6.2",
"terser": "^5.44.0",
"ts-node": "^10.9.2",
"tsx": "^4.20.5",
"typescript": "^5.9.2",
"vitepress": "1.6.4",
"vue": "^3.5.21"
},
"engines": {
"node": ">=22"
},
"packageManager": "pnpm@10.17.1",
"dependencies": {
"@nolebase/vitepress-plugin-git-changelog": "^2.18.2",
"vitepress-plugin-group-icons": "^1.6.3"
}
}

View File

@@ -0,0 +1,6 @@
packages:
- docs
- .
onlyBuiltDependencies:
- esbuild

207
Website/scripts/sw.ts Normal file
View File

@@ -0,0 +1,207 @@
/// <reference lib="webworker" />
const CACHE_NAME: string = 'sukisu-ultra-v2.0'
const STATIC_CACHE: string = 'sukisu-static-v2.0'
const RUNTIME_CACHE: string = 'sukisu-runtime-v2.0'
const IMAGE_CACHE: string = 'sukisu-images-v2.0'
const CRITICAL_ASSETS: string[] = [
'/',
'/guide/',
'/guide/installation',
'/guide/compatibility',
'/zh/',
'/zh/guide/',
'/logo.svg',
'/favicon.ico',
'/offline.html',
]
const CACHE_STRATEGIES: {
static: string[]
images: string[]
documents: string[]
} = {
static: ['.css', '.js', '.woff2', '.woff', '.ttf', '.otf'],
images: ['.png', '.jpg', '.jpeg', '.svg', '.webp', '.avif', '.gif', '.ico'],
documents: ['.html', '.json', '.xml'],
}
self.addEventListener('install', (event: ExtendableEvent) => {
event.waitUntil(
(async (): Promise<void> => {
const cache: Cache = await caches.open(STATIC_CACHE)
try {
await cache.addAll(CRITICAL_ASSETS)
} catch (error) {
console.warn('Failed to cache some assets:', error)
}
;(self as any).skipWaiting()
})()
)
})
self.addEventListener('activate', (event: ExtendableEvent) => {
event.waitUntil(
(async (): Promise<void> => {
const cacheNames: string[] = await caches.keys()
const validCaches: string[] = [STATIC_CACHE, RUNTIME_CACHE, IMAGE_CACHE, CACHE_NAME]
await Promise.all(
cacheNames
.filter((name: string) => !validCaches.includes(name))
.map((name: string) => caches.delete(name))
)
;(self as any).clients.claim()
})()
)
})
self.addEventListener('fetch', (event: FetchEvent) => {
const { request } = event
const url: URL = new URL(request.url)
if (request.method !== 'GET' || url.origin !== location.origin) return
if (url.pathname.startsWith('/api/')) return
event.respondWith(handleRequest(request, url))
})
async function handleRequest(request: Request, url: URL): Promise<Response> {
const isStatic: boolean = CACHE_STRATEGIES.static.some((ext: string) =>
url.pathname.endsWith(ext)
)
const isImage: boolean = CACHE_STRATEGIES.images.some((ext: string) => url.pathname.endsWith(ext))
const isDocument: boolean =
CACHE_STRATEGIES.documents.some((ext: string) => url.pathname.endsWith(ext)) ||
url.pathname.endsWith('/')
try {
if (isStatic) {
return await handleStatic(request)
} else if (isImage) {
return await handleImage(request)
} else if (isDocument) {
return await handleDocument(request)
} else {
return await handleDefault(request)
}
} catch (error) {
return await handleOffline(request)
}
}
async function handleStatic(request: Request): Promise<Response> {
const cache: Cache = await caches.open(STATIC_CACHE)
const cached: Response | undefined = await cache.match(request)
if (cached) {
fetch(request)
.then((response: Response) => {
if (response.ok) cache.put(request, response.clone())
})
.catch(() => {})
return cached
}
const response: Response = await fetch(request)
if (response.ok) {
cache.put(request, response.clone())
}
return response
}
async function handleImage(request: Request): Promise<Response> {
const cache: Cache = await caches.open(IMAGE_CACHE)
const cached: Response | undefined = await cache.match(request)
if (cached) return cached
const response: Response = await fetch(request)
if (response.ok) {
cache.put(request, response.clone())
}
return response
}
async function handleDocument(request: Request): Promise<Response> {
const cache: Cache = await caches.open(RUNTIME_CACHE)
try {
const response: Response = await fetch(request)
if (response.ok) {
cache.put(request, response.clone())
}
return response
} catch (error) {
const cached: Response | undefined = await cache.match(request)
if (cached) return cached
if (request.mode === 'navigate') {
const offlinePage: Response | undefined = await caches.match('/offline.html')
if (offlinePage) return offlinePage
}
throw error
}
}
async function handleDefault(request: Request): Promise<Response> {
const cache: Cache = await caches.open(RUNTIME_CACHE)
try {
const response: Response = await fetch(request)
if (response.ok) {
cache.put(request, response.clone())
}
return response
} catch (error) {
const cached: Response | undefined = await cache.match(request)
if (cached) return cached
throw error
}
}
async function handleOffline(request: Request): Promise<Response> {
const cache: Cache = await caches.open(STATIC_CACHE)
if (request.mode === 'navigate') {
const offlinePage: Response | undefined = await caches.match('/offline.html')
if (offlinePage) return offlinePage
}
return new Response('Offline', {
status: 503,
statusText: 'Service Unavailable',
headers: new Headers({
'Content-Type': 'text/plain',
}),
})
}
self.addEventListener('sync', (event: any) => {
if (event.tag === 'data-sync') {
event.waitUntil(syncData())
}
})
async function syncData(): Promise<void> {
try {
console.log('Syncing application data...')
} catch (error) {
console.error('Data sync failed:', error)
}
}
interface PerformanceMessage {
type: string
name: string
}
self.addEventListener('message', (event: MessageEvent) => {
const data = event.data as PerformanceMessage
if (data && data.type === 'PERFORMANCE_MARK') {
performance.mark(data.name)
}
})

View File

@@ -0,0 +1,38 @@
import fs from 'fs'
import path from 'path'
import { fileURLToPath } from 'url'
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const srcDir = path.join(__dirname, '../favicon')
const dstDir = path.join(__dirname, '../docs/public')
function ensureDir(dir: string) {
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })
}
function copyAll(src: string, dst: string) {
ensureDir(dst)
const entries = fs.readdirSync(src, { withFileTypes: true })
let count = 0
for (const entry of entries) {
const s = path.join(src, entry.name)
const d = path.join(dst, entry.name)
if (entry.isDirectory()) {
copyAll(s, d)
} else if (entry.isFile()) {
fs.copyFileSync(s, d)
count++
}
}
return count
}
if (!fs.existsSync(srcDir)) {
console.warn('Favicons source folder not found:', srcDir)
process.exit(0)
}
const copied = copyAll(srcDir, dstDir)
console.log(`✅ Synced ${copied} favicon file(s) from \'favicon\' to docs/public`)

25
Website/tsconfig.json Normal file
View File

@@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"outDir": "./dist",
"rootDir": "./",
"types": ["node", "serviceworker"],
"lib": ["ES2022", "WebWorker"],
"ignoreDeprecations": "5.0"
},
"ts-node": {
"esm": true,
"experimentalSpecifierResolution": "node"
},
"include": ["scripts/**/*"],
"exclude": ["node_modules", "dist", "docs/.vitepress/dist"]
}

11
Website/wrangler.toml Normal file
View File

@@ -0,0 +1,11 @@
# Cloudflare Pages Configuration for SukiSU-Ultra
name = "sukisu-ultra-docs"
compatibility_date = "2025-08-04"
compatibility_flags = ["nodejs_compat"]
pages_build_output_dir = "docs/.vitepress/dist"
[env.production]
name = "sukisu-ultra-docs"
[env.preview]
name = "sukisu-ultra-docs-preview"

View File

@@ -1,6 +1,6 @@
<img align='right' src='zakomonochrome-128.svg' width='100px' alt="logo">
# SukiSU Ultra
<img align='right' src='SukiSU-mini.svg' width='220px' alt="sukisu logo">
**English** | [简体中文](./zh/README.md) | [日本語](./ja/README.md) | [Türkçe](./tr/README.md)

183
docs/SukiSU-mini.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 185 KiB

188
docs/SukiSU.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 200 KiB

View File

@@ -44,7 +44,7 @@ Generally need to modify the `do_execve` and `compat_do_execve` methods in `fs/e
.ptr.compat = __envp,
};
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+ trace_ksu_trace_execveat_sucompat_hook((int *)AT_FDCWD, &filename, NULL, NULL, NULL); /* 32-bit su */
+ trace_ksu_trace_execveat_hook((int *)AT_FDCWD, &filename, &argv, &envp, 0); // 32-bit su and 32-on-64 support
+#endif
return do_execveat_common(AT_FDCWD, filename, argv, envp, 0);
}
@@ -237,34 +237,3 @@ Need to modify the `input_event` method in `drivers/input/input.c`, not `input_h
spin_lock_irqsave(&dev->event_lock, flags);
```
### devpts Hook (`pty.c`)
Need to modify the `pts_unix98_lookup` method in `drivers/tty/pty.c`
```patch
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -31,6 +31,10 @@
#include <linux/compat.h>
#include "tty.h"
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+#include <../../drivers/kernelsu/ksu_trace.h>
+#endif
+
#undef TTY_DEBUG_HANGUP
#ifdef TTY_DEBUG_HANGUP
# define tty_debug_hangup(tty, f, args...) tty_debug(tty, f, ##args)
@@ -707,6 +711,10 @@ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
{
struct tty_struct *tty;
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+ trace_ksu_trace_devpts_hook((struct inode *)file->f_path.dentry->d_inode);
+#endif
+
mutex_lock(&devpts_mutex);
tty = devpts_get_priv(file->f_path.dentry);
mutex_unlock(&devpts_mutex);
```

View File

@@ -1,4 +1,6 @@
# SukiSU Ultra
<img align='right' src='SukiSU-mini.svg' width='220px' alt="sukisu logo">
[English](../README.md) | [简体中文](../zh/README.md) | **日本語** | [Türkçe](../tr/README.md)

183
docs/ja/SukiSU-mini.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 185 KiB

View File

@@ -1,4 +1,6 @@
# SukiSU Ultra
<img align='right' src='SukiSU-mini.svg' width='250px' alt="sukisu logo">
[English](../README.md) | [简体中文](../zh/README.md) | [日本語](../ja/README.md) | **Türkçe**

183
docs/tr/SukiSU-mini.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 185 KiB

View File

@@ -1,6 +1,6 @@
<img align='right' src='zakomonochrome-128.svg' width='100px' alt="logo">
# SukiSU Ultra
<img align='right' src='SukiSU-mini.svg' width='220px' alt="sukisu logo">
[English](../README.md) | **简体中文** | [日本語](../ja/README.md) | [Türkçe](../tr/README.md)

183
docs/zh/SukiSU-mini.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 185 KiB

188
docs/zh/SukiSU.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 200 KiB

View File

@@ -44,7 +44,7 @@
.ptr.compat = __envp,
};
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+ trace_ksu_trace_execveat_sucompat_hook((int *)AT_FDCWD, &filename, NULL, NULL, NULL); /* 32-bit su */
+ trace_ksu_trace_execveat_hook((int *)AT_FDCWD, &filename, &argv, &envp, 0)); // 32-bit su and 32-on-64 support
+#endif
return do_execveat_common(AT_FDCWD, filename, argv, envp, 0);
}
@@ -237,34 +237,3 @@
spin_lock_irqsave(&dev->event_lock, flags);
```
### devpts 钩子 (`pty.c`)
需要修改 `drivers/tty/pty.c``pts_unix98_lookup` 方法
```patch
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -31,6 +31,10 @@
#include <linux/compat.h>
#include "tty.h"
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+#include <../../drivers/kernelsu/ksu_trace.h>
+#endif
+
#undef TTY_DEBUG_HANGUP
#ifdef TTY_DEBUG_HANGUP
# define tty_debug_hangup(tty, f, args...) tty_debug(tty, f, ##args)
@@ -707,6 +711,10 @@ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
{
struct tty_struct *tty;
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
+ trace_ksu_trace_devpts_hook((struct inode *)file->f_path.dentry->d_inode);
+#endif
+
mutex_lock(&devpts_mutex);
tty = devpts_get_priv(file->f_path.dentry);
mutex_unlock(&devpts_mutex);
```

View File

@@ -1,65 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="128"
height="128"
viewBox="0 0 128 128"
version="1.1"
id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="zakomonochrome-128.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#999999"
borderopacity="1"
inkscape:showpageshadow="2"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="2.6185048"
inkscape:cx="59.957881"
inkscape:cy="71.032903"
inkscape:window-width="1280"
inkscape:window-height="696"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="图层 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;paint-order:fill markers stroke;fill-opacity:1"
id="rect1"
width="128"
height="128"
x="0"
y="0"
rx="7.772471"
ry="7.772471" />
<path
id="path101"
style="fill:#ffffff;fill-opacity:0.734285;stroke:#000000;stroke-width:4.27504;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 42.510282,81.796052 c 0,0 -7.224141,-5.638356 -10.043315,-9.338525 M 14.847106,81.97224 25.41902,71.576535 m 0.17619,-6.695549 2.819179,19.910444 M 11.675534,73.338532 38.281518,71.047931 M 43.567475,62.7666 34.40515,62.942814 M 34.22896,62.590425 33.524162,48.494537 m -18.500855,1.58577 17.972249,-1.409582 m -11.8053,-5.462154 0.352397,18.853251"
inkscape:label="杂" />
<path
id="path111"
style="fill:#ffffff;fill-opacity:0.734285;stroke:#000000;stroke-width:3.94824;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="M 55.912937,82.876745 79.671596,81.412163 M 59.330273,75.391135 74.952411,74.089291 m -9.43837,-14.157553 1.139102,14.645756 m -8.299247,-7.160159 16.273048,-1.464569 m 0.650926,8.136525 0.325472,-14.808482 m -0.162747,0.162739 -17.900363,0.976379 m 0,-0.162738 1.952774,14.645756 m 12.042061,-21.154974 1.464576,-6.346492 m 0,-0.650928 -12.042063,0.650928 m -0.650918,6.509218 0.325459,-8.787441"
inkscape:label="鱼" />
<path
d="m 95.08569,51.121163 c -1.90515,0.116064 -3.64694,0.97349 -4.86738,2.391307 -1.34538,1.56738 -1.91476,3.733159 -1.59523,6.070852 0.40842,2.982962 2.1502,6.17135 5.13887,9.411078 0.63424,0.68546 1.08109,1.129773 1.98202,1.967071 1.58321,1.469144 3.01507,2.634638 4.9875,4.052454 0.70392,0.50905 2.09253,1.453525 2.61627,1.781734 l 0.15133,0.09594 0.22103,-0.140663 c 0.80481,-0.515755 2.23909,-1.504852 3.08956,-2.130057 3.21689,-2.364488 5.79232,-4.737902 7.70228,-7.100167 3.09676,-3.831409 4.4133,-7.562359 3.80549,-10.773058 -0.42043,-2.210414 -1.82588,-4.039057 -3.81992,-4.967887 -0.85767,-0.399664 -1.69132,-0.607312 -2.6355,-0.656431 -1.22285,-0.0647 -2.42648,0.178619 -3.57485,0.721182 -1.95561,0.922124 -3.58927,2.719503 -4.61752,5.081755 -0.072,0.165235 -0.1394,0.310355 -0.14895,0.319295 -0.0312,0.02902 -0.0648,-0.02679 -0.19458,-0.330457 -0.30752,-0.714476 -0.91055,-1.752718 -1.38382,-2.377871 -0.4853,-0.645282 -1.2661,-1.431214 -1.84749,-1.862143 -1.50155,-1.114153 -3.26013,-1.658924 -5.00914,-1.553996 z"
id="path1-4"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.00231605" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -56,8 +56,8 @@ ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
#CompactNamespaces: false # Unknown to clang-format-4.0
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
@@ -501,7 +501,7 @@ IncludeCategories:
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
#IndentPPDirectives: None # Unknown to clang-format-5.0
IndentWidth: 8
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
@@ -511,7 +511,7 @@ MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0
ObjCBlockIndentWidth: 8
ObjCBlockIndentWidth: 4
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
@@ -543,6 +543,6 @@ SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp03
TabWidth: 8
UseTab: Always
TabWidth: 4
UseTab: Never
...

22
kernel/.gitignore vendored Normal file
View File

@@ -0,0 +1,22 @@
.cache/
.thinlto-cache/
compile_commands.json
*.ko
*.o
*.mod
*.lds
*.mod.o
.*.o*
.*.mod*
*.ko*
*.mod.c
*.symvers*
*.order
.*.ko.cmd
.tmp_versions/
libs/
obj/
CLAUDE.md
.ddk-version
.vscode/settings.json

11
kernel/.vscode/c_cpp_properties.json vendored Normal file
View File

@@ -0,0 +1,11 @@
{
"configurations": [
{
"name": "Linux",
"cStandard": "c11",
"intelliSenseMode": "gcc-arm64",
"compileCommands": "${workspaceFolder}/compile_commands.json"
}
],
"version": 4
}

92
kernel/.vscode/generate_compdb.py vendored Normal file
View File

@@ -0,0 +1,92 @@
#!/usr/bin/env python3
from __future__ import print_function, division
import argparse
import fnmatch
import functools
import json
import math
import multiprocessing
import os
import re
import sys
CMD_VAR_RE = re.compile(r'^\s*(?:saved)?cmd_(\S+)\s*:=\s*(.+)\s*$', re.MULTILINE)
SOURCE_VAR_RE = re.compile(r'^\s*source_(\S+)\s*:=\s*(.+)\s*$', re.MULTILINE)
def print_progress_bar(progress):
progress_bar = '[' + '|' * int(50 * progress) + '-' * int(50 * (1.0 - progress)) + ']'
print('\r', progress_bar, "{0:.1%}".format(progress), end='\r', file=sys.stderr)
def parse_cmd_file(out_dir, cmdfile_path):
with open(cmdfile_path, 'r') as cmdfile:
cmdfile_content = cmdfile.read()
commands = { match.group(1): match.group(2) for match in CMD_VAR_RE.finditer(cmdfile_content) }
sources = { match.group(1): match.group(2) for match in SOURCE_VAR_RE.finditer(cmdfile_content) }
return [{
'directory': out_dir,
'command': commands[o_file_name],
'file': source,
'output': o_file_name
} for o_file_name, source in sources.items()]
def gen_compile_commands(cmd_file_search_path, out_dir):
print("Building *.o.cmd file list...", file=sys.stderr)
out_dir = os.path.abspath(out_dir)
if not cmd_file_search_path:
cmd_file_search_path = [out_dir]
cmd_files = []
for search_path in cmd_file_search_path:
if (os.path.isdir(search_path)):
for cur_dir, subdir, files in os.walk(search_path):
cmd_files.extend(os.path.join(cur_dir, cmdfile_name) for cmdfile_name in fnmatch.filter(files, '*.o.cmd'))
else:
cmd_files.extend(search_path)
if not cmd_files:
print("No *.o.cmd files found in", ", ".join(cmd_file_search_path), file=sys.stderr)
return
print("Parsing *.o.cmd files...", file=sys.stderr)
n_processed = 0
print_progress_bar(0)
compdb = []
pool = multiprocessing.Pool()
try:
for compdb_chunk in pool.imap_unordered(functools.partial(parse_cmd_file, out_dir), cmd_files, chunksize=int(math.sqrt(len(cmd_files)))):
compdb.extend(compdb_chunk)
n_processed += 1
print_progress_bar(n_processed / len(cmd_files))
finally:
pool.terminate()
pool.join()
print(file=sys.stderr)
print("Writing compile_commands.json...", file=sys.stderr)
with open('compile_commands.json', 'w') as compdb_file:
json.dump(compdb, compdb_file, indent=1)
def main():
cmd_parser = argparse.ArgumentParser()
cmd_parser.add_argument('-O', '--out-dir', type=str, default=os.getcwd(), help="Build output directory")
cmd_parser.add_argument('cmd_file_search_path', nargs='*', help="*.cmd file search path")
gen_compile_commands(**vars(cmd_parser.parse_args()))
if __name__ == '__main__':
main()

16
kernel/.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,16 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Generate compile_commands.json",
"type": "process",
"command": "python",
"args": [
"${workspaceRoot}/.vscode/generate_compdb.py"
],
"problemMatcher": []
}
]
}

View File

@@ -2,7 +2,6 @@ menu "KernelSU"
config KSU
tristate "KernelSU function support"
depends on OVERLAY_FS
default y
help
Enable kernel-level root privileges on Android System.
@@ -16,6 +15,13 @@ config KSU_DEBUG
help
Enable KernelSU debug mode.
config KSU_MANUAL_SU
bool "Use manual su"
depends on KSU
default y
help
Use manual su and authorize the corresponding command line and application via prctl
config KPM
bool "Enable SukiSU KPM"
depends on KSU && 64BIT
@@ -27,31 +33,10 @@ config KPM
select KALLSYMS
select KALLSYMS_ALL
choice
prompt "KernelSU hook type"
depends on KSU
default KSU_KPROBES_HOOK
help
Hook type for KernelSU
config KSU_KPROBES_HOOK
bool "Hook KernelSU with Kprobes"
depends on KPROBES
help
If enabled, Hook required KernelSU syscalls with Kernel-probe.
config KSU_TRACEPOINT_HOOK
bool "Hook KernelSU with Tracepoint"
depends on TRACEPOINTS
help
If enabled, Hook required KernelSU syscalls with Tracepoint.
config KSU_MANUAL_HOOK
bool "Hook KernelSU manually"
depends on KSU != m
help
If enabled, Hook required KernelSU syscalls with manually-patched function.
endchoice
endmenu

View File

@@ -1,16 +1,28 @@
kernelsu-objs := ksu.o
kernelsu-objs += allowlist.o
kernelsu-objs += app_profile.o
kernelsu-objs += dynamic_manager.o
kernelsu-objs += apk_sign.o
kernelsu-objs += sucompat.o
kernelsu-objs += syscall_hook_manager.o
kernelsu-objs += throne_tracker.o
kernelsu-objs += core_hook.o
kernelsu-objs += pkg_observer.o
kernelsu-objs += throne_tracker.o
kernelsu-objs += umount_manager.o
kernelsu-objs += setuid_hook.o
kernelsu-objs += kernel_umount.o
kernelsu-objs += supercalls.o
kernelsu-objs += feature.o
kernelsu-objs += ksud.o
kernelsu-objs += embed_ksud.o
kernelsu-objs += kernel_compat.o
kernelsu-objs += seccomp_cache.o
kernelsu-objs += file_wrapper.o
kernelsu-objs += throne_comm.o
kernelsu-objs += sulog.o
ifeq ($(CONFIG_KSU_TRACEPOINT_HOOK), y)
kernelsu-objs += ksu_trace.o
ifeq ($(CONFIG_KSU_MANUAL_SU), y)
ccflags-y += -DCONFIG_KSU_MANUAL_SU
kernelsu-objs += manual_su.o
endif
kernelsu-objs += selinux/selinux.o
@@ -20,46 +32,62 @@ ccflags-y += -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm-generic/errno.h
obj-$(CONFIG_KSU) += kernelsu.o
obj-$(CONFIG_KSU_TRACEPOINT_HOOK) += ksu_trace_export.o
obj-$(CONFIG_KPM) += kpm/
REPO_OWNER := SukiSU-Ultra
REPO_NAME := SukiSU-Ultra
REPO_BRANCH := main
KSU_VERSION_API := 3.1.9
KSU_VERSION_API := 4.0.0
GIT_BIN := /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin git
CURL_BIN := /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin curl
KDIR := $(KDIR)
MDIR := $(realpath $(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
ifneq ($(KDIR),)
$(info -- KDIR: $(KDIR))
$(info -- MDIR: $(MDIR))
endif
KSU_GITHUB_VERSION := $(shell $(CURL_BIN) -s "https://api.github.com/repos/$(REPO_OWNER)/$(REPO_NAME)/releases/latest" | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
KSU_GITHUB_VERSION_COMMIT := $(shell $(CURL_BIN) -sI "https://api.github.com/repos/$(REPO_OWNER)/$(REPO_NAME)/commits?sha=$(REPO_BRANCH)&per_page=1" | grep -i "link:" | sed -n 's/.*page=\([0-9]*\)>; rel="last".*/\1/p')
LOCAL_GIT_EXISTS := $(shell test -e $(srctree)/$(src)/../.git && echo 1 || echo 0)
ifeq ($(findstring $(srctree),$(src)),$(srctree))
KSU_SRC := $(src)
else
KSU_SRC := $(srctree)/$(src)
endif
ifneq ($(shell test -e $(KSU_SRC)/../.git && echo "in-tree"),in-tree)
KSU_SRC := $(MDIR)
endif
LOCAL_GIT_EXISTS := $(shell test -e $(KSU_SRC)/../.git && echo 1 || echo 0)
define get_ksu_version_full
v$1-$(shell cd $(srctree)/$(src); $(GIT_BIN) rev-parse --short=8 HEAD)@$(shell cd $(srctree)/$(src); $(GIT_BIN) rev-parse --abbrev-ref HEAD)
v$1-$(shell cd $(KSU_SRC); $(GIT_BIN) rev-parse --short=8 HEAD)@$(shell cd $(KSU_SRC); $(GIT_BIN) rev-parse --abbrev-ref HEAD)
endef
ifeq ($(KSU_GITHUB_VERSION_COMMIT),)
ifeq ($(LOCAL_GIT_EXISTS),1)
$(shell cd $(srctree)/$(src); [ -f ../.git/shallow ] && $(GIT_BIN) fetch --unshallow)
KSU_LOCAL_VERSION := $(shell cd $(srctree)/$(src); $(GIT_BIN) rev-list --count $(REPO_BRANCH))
KSU_VERSION := $(shell expr 10000 + $(KSU_LOCAL_VERSION) + 700)
$(shell cd $(KSU_SRC); [ -f ../.git/shallow ] && $(GIT_BIN) fetch --unshallow)
KSU_LOCAL_VERSION := $(shell cd $(KSU_SRC); $(GIT_BIN) rev-list --count $(REPO_BRANCH))
KSU_VERSION := $(shell expr 40000 + $(KSU_LOCAL_VERSION) - 2815)
$(info -- $(REPO_NAME) version (local .git): $(KSU_VERSION))
else
KSU_VERSION := 13000
$(warning -- Could not fetch version online or via local .git! Using fallback version: $(KSU_VERSION))
endif
else
KSU_VERSION := $(shell expr 10000 + $(KSU_GITHUB_VERSION_COMMIT) + 700)
KSU_VERSION := $(shell expr 40000 + $(KSU_GITHUB_VERSION_COMMIT) - 2815)
$(info -- $(REPO_NAME) version (GitHub): $(KSU_VERSION))
endif
ifeq ($(KSU_GITHUB_VERSION),)
ifeq ($(LOCAL_GIT_EXISTS),1)
$(shell cd $(srctree)/$(src); [ -f ../.git/shallow ] && $(GIT_BIN) fetch --unshallow)
$(shell cd $(KSU_SRC); [ -f ../.git/shallow ] && $(GIT_BIN) fetch --unshallow)
KSU_VERSION_FULL := $(call get_ksu_version_full,$(KSU_VERSION_API))
$(info -- $(REPO_NAME) version (local .git): $(KSU_VERSION_FULL))
$(info -- $(REPO_NAME) Formatted version (local .git): $(KSU_VERSION))
@@ -68,7 +96,7 @@ ifeq ($(KSU_GITHUB_VERSION),)
$(warning -- $(REPO_NAME) version: $(KSU_VERSION_FULL))
endif
else
$(shell cd $(srctree)/$(src); [ -f ../.git/shallow ] && $(GIT_BIN) fetch --unshallow)
$(shell cd $(KSU_SRC); [ -f ../.git/shallow ] && $(GIT_BIN) fetch --unshallow)
KSU_VERSION_FULL := $(call get_ksu_version_full,$(KSU_GITHUB_VERSION))
$(info -- $(REPO_NAME) version (Github): $(KSU_VERSION_FULL))
endif
@@ -92,14 +120,13 @@ ccflags-y += -DKSU_MANAGER_PACKAGE=\"$(KSU_MANAGER_PACKAGE)\"
$(info -- SukiSU Manager package name: $(KSU_MANAGER_PACKAGE))
endif
$(info -- Supported Unofficial Manager: 5ec1cff (GKI) ShirkNeko udochina (GKI and KPM))
ifeq ($(strip $(CONFIG_KSU_KPROBES_HOOK)),y)
$(info -- SukiSU: CONFIG_KSU_KPROBES_HOOK)
else ifeq ($(strip $(CONFIG_KSU_TRACEPOINT_HOOK)),y)
$(info -- SukiSU: CONFIG_KSU_TRACEPOINT_HOOK)
else ifeq ($(strip $(CONFIG_KSU_MANUAL_HOOK)),y)
$(info -- SukiSU: CONFIG_KSU_MANUAL_HOOK)
ifeq ($(CONFIG_KSU_MANUAL_HOOK), y)
ccflags-y += -DKSU_MANUAL_HOOK
$(info -- SukiSU: KSU_MANUAL_HOOK Temporarily discontinued)
else
ccflags-y += -DKSU_KPROBES_HOOK
ccflags-y += -DKSU_TP_HOOK
$(info -- SukiSU: KSU_TRACEPOINT_HOOK)
endif
KERNEL_VERSION := $(VERSION).$(PATCHLEVEL)
@@ -116,14 +143,30 @@ endif
$(info -- KERNEL_VERSION: $(KERNEL_VERSION))
$(info -- KERNEL_TYPE: $(KERNEL_TYPE))
$(info -- KERNEL_VERSION: $(KERNEL_VERSION))
ifeq ($(CONFIG_KPM),y)
ifeq ($(CONFIG_KPM), y)
$(info -- KPM is enabled)
else
$(info -- KPM is disabled)
endif
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function
# Check new vfs_getattr()
ifeq ($(shell grep -A1 "^int vfs_getattr" $(srctree)/fs/stat.c | grep -q "query_flags" ; echo $$?),0)
ccflags-y += -DKSU_HAS_NEW_VFS_GETATTR
endif
# Function proc_ops check
ifeq ($(shell grep -q "struct proc_ops " $(srctree)/include/linux/proc_fs.h; echo $$?),0)
ccflags-y += -DKSU_COMPAT_HAS_PROC_OPS
endif
ccflags-y += -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat -Wno-missing-prototypes
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function -Wno-unused-variable
all:
make -C $(KDIR) M=$(MDIR) modules
compdb:
python3 $(MDIR)/.vscode/generate_compdb.py -O $(KDIR) $(MDIR)
clean:
make -C $(KDIR) M=$(MDIR) clean
# Keep a new line here!! Because someone may append config

View File

@@ -1,3 +1,5 @@
#include <linux/mutex.h>
#include <linux/task_work.h>
#include <linux/capability.h>
#include <linux/compiler.h>
#include <linux/fs.h>
@@ -8,14 +10,16 @@
#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 "ksu.h"
#include "klog.h" // IWYU pragma: keep
#include "ksud.h"
#include "selinux/selinux.h"
#include "kernel_compat.h"
#include "allowlist.h"
#include "manager.h"
#include "syscall_hook_manager.h"
#define FILE_MAGIC 0x7f4b5355 // ' KSU', u32
#define FILE_FORMAT_VERSION 3 // u32
@@ -29,7 +33,10 @@ static DEFINE_MUTEX(allowlist_mutex);
static struct root_profile default_root_profile;
static struct non_root_profile default_non_root_profile;
static int allow_list_arr[PAGE_SIZE / sizeof(int)] __read_mostly __aligned(PAGE_SIZE);
void persistent_allow_list(void);
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)
@@ -61,7 +68,7 @@ static void remove_uid_from_arr(uid_t uid)
kfree(temp_arr);
}
static void init_default_profiles()
static void init_default_profiles(void)
{
kernel_cap_t full_cap = CAP_FULL_SET;
@@ -90,11 +97,6 @@ static uint8_t allow_list_bitmap[PAGE_SIZE] __read_mostly __aligned(PAGE_SIZE);
#define KERNEL_SU_ALLOWLIST "/data/adb/ksu/.allowlist"
static struct work_struct ksu_save_work;
static struct work_struct ksu_load_work;
bool persistent_allow_list(void);
void ksu_show_allow_list(void)
{
struct perm_data *p = NULL;
@@ -108,7 +110,7 @@ void ksu_show_allow_list(void)
}
#ifdef CONFIG_KSU_DEBUG
static void ksu_grant_root_to_shell()
static void ksu_grant_root_to_shell(void)
{
struct app_profile profile = {
.version = KSU_APP_PROFILE_VER,
@@ -116,7 +118,8 @@ static void ksu_grant_root_to_shell()
.current_uid = 2000,
};
strcpy(profile.key, "com.android.shell");
strcpy(profile.rp_config.profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN);
strcpy(profile.rp_config.profile.selinux_domain,
KSU_DEFAULT_SELINUX_DOMAIN);
ksu_set_app_profile(&profile, false);
}
#endif
@@ -142,9 +145,10 @@ exit:
return found;
}
static inline bool forbid_system_uid(uid_t uid) {
#define SHELL_UID 2000
#define SYSTEM_UID 1000
static inline bool forbid_system_uid(uid_t uid)
{
#define SHELL_UID 2000
#define SYSTEM_UID 1000
return uid < SHELL_UID && uid != SYSTEM_UID;
}
@@ -218,9 +222,11 @@ bool ksu_set_app_profile(struct app_profile *profile, bool persist)
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);
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));
allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] &=
~(1 << (profile->current_uid % BITS_PER_BYTE));
} else {
if (profile->allow_su) {
/*
@@ -252,8 +258,11 @@ out:
sizeof(default_root_profile));
}
if (persist)
if (persist) {
persistent_allow_list();
// FIXME: use a new flag
ksu_mark_running_process();
}
return result;
}
@@ -262,23 +271,20 @@ bool __ksu_is_allow_uid(uid_t uid)
{
int i;
if (unlikely(uid == 0)) {
// already root, but only allow our domain.
return is_ksu_domain();
}
if (forbid_system_uid(uid)) {
// do not bother going through the list if it's system
return false;
}
if (likely(ksu_is_manager_uid_valid()) && unlikely(ksu_get_manager_uid() == uid)) {
if (likely(ksu_is_manager_uid_valid()) &&
unlikely(ksu_get_manager_uid() == uid)) {
// manager is always allowed!
return true;
}
if (likely(uid <= BITMAP_UID_MAX)) {
return !!(allow_list_bitmap[uid / BITS_PER_BYTE] & (1 << (uid % BITS_PER_BYTE)));
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)
@@ -289,10 +295,20 @@ bool __ksu_is_allow_uid(uid_t uid)
return false;
}
bool __ksu_is_allow_uid_for_current(uid_t uid)
{
if (unlikely(uid == 0)) {
// already root, but only allow our domain.
return is_ksu_domain();
}
return __ksu_is_allow_uid(uid);
}
bool ksu_uid_should_umount(uid_t uid)
{
struct app_profile profile = { .current_uid = uid };
if (likely(ksu_is_manager_uid_valid()) && unlikely(ksu_get_manager_uid() == uid)) {
if (likely(ksu_is_manager_uid_valid()) &&
unlikely(ksu_get_manager_uid() == uid)) {
// we should not umount on manager!
return false;
}
@@ -349,7 +365,7 @@ bool ksu_get_allow_list(int *array, int *length, bool allow)
return true;
}
void do_save_allow_list(struct work_struct *work)
static void do_persistent_allow_list(struct callback_head *_cb)
{
u32 magic = FILE_MAGIC;
u32 version = FILE_FORMAT_VERSION;
@@ -357,41 +373,64 @@ void do_save_allow_list(struct work_struct *work)
struct list_head *pos = NULL;
loff_t off = 0;
mutex_lock(&allowlist_mutex);
struct file *fp =
ksu_filp_open_compat(KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT | O_TRUNC, 0644);
filp_open(KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (IS_ERR(fp)) {
pr_err("save_allow_list create file failed: %ld\n", PTR_ERR(fp));
return;
goto unlock;
}
// store magic and version
if (ksu_kernel_write_compat(fp, &magic, sizeof(magic), &off) !=
sizeof(magic)) {
if (kernel_write(fp, &magic, sizeof(magic), &off) != sizeof(magic)) {
pr_err("save_allow_list write magic failed.\n");
goto exit;
goto close_file;
}
if (ksu_kernel_write_compat(fp, &version, sizeof(version), &off) !=
sizeof(version)) {
if (kernel_write(fp, &version, sizeof(version), &off) != sizeof(version)) {
pr_err("save_allow_list write version failed.\n");
goto exit;
goto close_file;
}
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
pr_info("save allow list, name: %s uid :%d, allow: %d\n",
p->profile.key, p->profile.current_uid,
p->profile.allow_su);
p->profile.key, p->profile.current_uid, p->profile.allow_su);
ksu_kernel_write_compat(fp, &p->profile, sizeof(p->profile),
&off);
kernel_write(fp, &p->profile, sizeof(p->profile), &off);
}
exit:
close_file:
filp_close(fp, 0);
unlock:
mutex_unlock(&allowlist_mutex);
kfree(_cb);
}
void do_load_allow_list(struct work_struct *work)
void persistent_allow_list()
{
struct task_struct *tsk;
tsk = get_pid_task(find_vpid(1), PIDTYPE_PID);
if (!tsk) {
pr_err("save_allow_list find init task err\n");
return;
}
struct callback_head *cb =
kzalloc(sizeof(struct callback_head), GFP_KERNEL);
if (!cb) {
pr_err("save_allow_list alloc cb err\b");
goto put_task;
}
cb->func = do_persistent_allow_list;
task_work_add(tsk, cb, TWA_RESUME);
put_task:
put_task_struct(tsk);
}
void ksu_load_allow_list()
{
loff_t off = 0;
ssize_t ret = 0;
@@ -405,22 +444,20 @@ void do_load_allow_list(struct work_struct *work)
#endif
// load allowlist now!
fp = ksu_filp_open_compat(KERNEL_SU_ALLOWLIST, O_RDONLY, 0);
fp = filp_open(KERNEL_SU_ALLOWLIST, O_RDONLY, 0);
if (IS_ERR(fp)) {
pr_err("load_allow_list open file failed: %ld\n", PTR_ERR(fp));
return;
}
// verify magic
if (ksu_kernel_read_compat(fp, &magic, sizeof(magic), &off) !=
sizeof(magic) ||
if (kernel_read(fp, &magic, sizeof(magic), &off) != sizeof(magic) ||
magic != FILE_MAGIC) {
pr_err("allowlist file invalid: %d!\n", magic);
goto exit;
}
if (ksu_kernel_read_compat(fp, &version, sizeof(version), &off) !=
sizeof(version)) {
if (kernel_read(fp, &version, sizeof(version), &off) != sizeof(version)) {
pr_err("allowlist read version: %d failed\n", version);
goto exit;
}
@@ -430,16 +467,15 @@ void do_load_allow_list(struct work_struct *work)
while (true) {
struct app_profile profile;
ret = ksu_kernel_read_compat(fp, &profile, sizeof(profile),
&off);
ret = kernel_read(fp, &profile, sizeof(profile), &off);
if (ret <= 0) {
pr_info("load_allow_list read err: %zd\n", ret);
break;
}
pr_info("load_allow_uid, name: %s, uid: %d, allow: %d\n",
profile.key, profile.current_uid, profile.allow_su);
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);
}
@@ -448,11 +484,17 @@ exit:
filp_close(fp, 0);
}
void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *), void *data)
void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *),
void *data)
{
struct perm_data *np = NULL;
struct perm_data *n = NULL;
if (!ksu_boot_completed) {
pr_info("boot not completed, skip prune\n");
return;
}
bool modified = false;
// TODO: use RCU!
mutex_lock(&allowlist_mutex);
@@ -466,7 +508,8 @@ void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *), void *data
pr_info("prune uid: %d, package: %s\n", uid, package);
list_del(&np->list);
if (likely(uid <= BITMAP_UID_MAX)) {
allow_list_bitmap[uid / BITS_PER_BYTE] &= ~(1 << (uid % BITS_PER_BYTE));
allow_list_bitmap[uid / BITS_PER_BYTE] &=
~(1 << (uid % BITS_PER_BYTE));
}
remove_uid_from_arr(uid);
smp_mb();
@@ -480,17 +523,6 @@ void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *), void *data
}
}
// make sure allow list works cross boot
bool persistent_allow_list(void)
{
return ksu_queue_work(&ksu_save_work);
}
bool ksu_load_allow_list(void)
{
return ksu_queue_work(&ksu_load_work);
}
void ksu_allowlist_init(void)
{
int i;
@@ -503,9 +535,6 @@ void ksu_allowlist_init(void)
INIT_LIST_HEAD(&allow_list);
INIT_WORK(&ksu_save_work, do_save_allow_list);
INIT_WORK(&ksu_load_work, do_load_allow_list);
init_default_profiles();
}
@@ -514,8 +543,6 @@ void ksu_allowlist_exit(void)
struct perm_data *np = NULL;
struct perm_data *n = NULL;
do_save_allow_list(NULL);
// free allowlist
mutex_lock(&allowlist_mutex);
list_for_each_entry_safe (np, n, &allow_list, list) {
@@ -524,3 +551,81 @@ void ksu_allowlist_exit(void)
}
mutex_unlock(&allowlist_mutex);
}
#ifdef CONFIG_KSU_MANUAL_SU
bool ksu_temp_grant_root_once(uid_t uid)
{
struct app_profile profile = {
.version = KSU_APP_PROFILE_VER,
.allow_su = true,
.current_uid = uid,
};
const char *default_key = "com.temp.once";
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);
if (p->profile.current_uid == uid) {
strcpy(profile.key, p->profile.key);
found = true;
break;
}
}
if (!found) {
strcpy(profile.key, default_key);
}
profile.rp_config.profile.uid = default_root_profile.uid;
profile.rp_config.profile.gid = default_root_profile.gid;
profile.rp_config.profile.groups_count = default_root_profile.groups_count;
memcpy(profile.rp_config.profile.groups, default_root_profile.groups, sizeof(default_root_profile.groups));
memcpy(&profile.rp_config.profile.capabilities, &default_root_profile.capabilities, sizeof(default_root_profile.capabilities));
profile.rp_config.profile.namespaces = default_root_profile.namespaces;
strcpy(profile.rp_config.profile.selinux_domain, default_root_profile.selinux_domain);
bool ok = ksu_set_app_profile(&profile, false);
if (ok)
pr_info("pending_root: UID=%d granted and persisted\n", uid);
return ok;
}
void ksu_temp_revoke_root_once(uid_t uid)
{
struct app_profile profile = {
.version = KSU_APP_PROFILE_VER,
.allow_su = false,
.current_uid = uid,
};
const char *default_key = "com.temp.once";
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);
if (p->profile.current_uid == uid) {
strcpy(profile.key, p->profile.key);
found = true;
break;
}
}
if (!found) {
strcpy(profile.key, default_key);
}
profile.nrp_config.profile.umount_modules = default_non_root_profile.umount_modules;
strcpy(profile.rp_config.profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN);
ksu_set_app_profile(&profile, false);
persistent_allow_list();
pr_info("pending_root: UID=%d removed and persist updated\n", uid);
}
#endif

View File

@@ -2,19 +2,29 @@
#define __KSU_H_ALLOWLIST
#include <linux/types.h>
#include "ksu.h"
#include <linux/uidgid.h>
#include "app_profile.h"
#define PER_USER_RANGE 100000
#define FIRST_APPLICATION_UID 10000
#define LAST_APPLICATION_UID 19999
void ksu_allowlist_init(void);
void ksu_allowlist_exit(void);
bool ksu_load_allow_list(void);
void ksu_load_allow_list(void);
void ksu_show_allow_list(void);
// Check if the uid is in allow list
bool __ksu_is_allow_uid(uid_t uid);
#define ksu_is_allow_uid(uid) unlikely(__ksu_is_allow_uid(uid))
// Check if the uid is in allow list, or current is ksu domain root
bool __ksu_is_allow_uid_for_current(uid_t uid);
#define ksu_is_allow_uid_for_current(uid) unlikely(__ksu_is_allow_uid_for_current(uid))
bool ksu_get_allow_list(int *array, int *length, bool allow);
void ksu_prune_allowlist(bool (*is_uid_exist)(uid_t, char *, void *), void *data);
@@ -24,4 +34,16 @@ 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);
static inline bool is_appuid(uid_t uid)
{
uid_t appid = uid % PER_USER_RANGE;
return appid >= FIRST_APPLICATION_UID && appid <= LAST_APPLICATION_UID;
}
#ifdef CONFIG_KSU_MANUAL_SU
bool ksu_temp_grant_root_once(uid_t uid);
void ksu_temp_revoke_root_once(uid_t uid);
#endif
#endif

View File

@@ -17,7 +17,6 @@
#include "apk_sign.h"
#include "dynamic_manager.h"
#include "klog.h" // IWYU pragma: keep
#include "kernel_compat.h"
#include "manager_sign.h"
struct sdesc {
@@ -25,12 +24,8 @@ struct sdesc {
char ctx[];
};
static struct apk_sign_key {
unsigned size;
const char *sha256;
} apk_sign_keys[] = {
static apk_sign_key_t apk_sign_keys[] = {
{EXPECTED_SIZE_SHIRKNEKO, EXPECTED_HASH_SHIRKNEKO}, // ShirkNeko/SukiSU
{EXPECTED_SIZE_OTHER, EXPECTED_HASH_OTHER}, // Dynamic Sign
#ifdef EXPECTED_SIZE
{EXPECTED_SIZE, EXPECTED_HASH}, // Custom
#endif
@@ -82,39 +77,87 @@ static int ksu_sha256(const unsigned char *data, unsigned int datalen,
crypto_free_shash(alg);
return ret;
}
static struct dynamic_sign_key dynamic_sign = DYNAMIC_SIGN_DEFAULT_CONFIG;
static bool check_dynamic_sign(struct file *fp, u32 size4, loff_t *pos, int *matched_index)
{
struct dynamic_sign_key current_dynamic_key = dynamic_sign;
if (ksu_get_dynamic_manager_config(&current_dynamic_key.size, &current_dynamic_key.hash)) {
pr_debug("Using dynamic manager config: size=0x%x, hash=%.16s...\n",
current_dynamic_key.size, current_dynamic_key.hash);
}
if (size4 != current_dynamic_key.size) {
return false;
}
#define CERT_MAX_LENGTH 1024
char cert[CERT_MAX_LENGTH];
if (size4 > CERT_MAX_LENGTH) {
pr_info("cert length overlimit\n");
return false;
}
kernel_read(fp, cert, size4, pos);
unsigned char digest[SHA256_DIGEST_SIZE];
if (ksu_sha256(cert, size4, digest) < 0) {
pr_info("sha256 error\n");
return false;
}
char hash_str[SHA256_DIGEST_SIZE * 2 + 1];
hash_str[SHA256_DIGEST_SIZE * 2] = '\0';
bin2hex(hash_str, digest, SHA256_DIGEST_SIZE);
pr_info("sha256: %s, expected: %s, index: dynamic\n", hash_str, current_dynamic_key.hash);
if (strcmp(current_dynamic_key.hash, hash_str) == 0) {
if (matched_index) {
*matched_index = DYNAMIC_SIGN_INDEX;
}
return true;
}
return false;
}
static bool check_block(struct file *fp, u32 *size4, loff_t *pos, u32 *offset, int *matched_index)
{
int i;
struct apk_sign_key sign_key;
apk_sign_key_t sign_key;
bool signature_valid = false;
ksu_kernel_read_compat(fp, size4, 0x4, pos); // signer-sequence length
ksu_kernel_read_compat(fp, size4, 0x4, pos); // signer length
ksu_kernel_read_compat(fp, size4, 0x4, pos); // signed data length
kernel_read(fp, size4, 0x4, pos); // signer-sequence length
kernel_read(fp, size4, 0x4, pos); // signer length
kernel_read(fp, size4, 0x4, pos); // signed data length
*offset += 0x4 * 3;
ksu_kernel_read_compat(fp, size4, 0x4, pos); // digests-sequence length
kernel_read(fp, size4, 0x4, pos); // digests-sequence length
*pos += *size4;
*offset += 0x4 + *size4;
ksu_kernel_read_compat(fp, size4, 0x4, pos); // certificates length
ksu_kernel_read_compat(fp, size4, 0x4, pos); // certificate length
kernel_read(fp, size4, 0x4, pos); // certificates length
kernel_read(fp, size4, 0x4, pos); // certificate length
*offset += 0x4 * 2;
if (ksu_is_dynamic_manager_enabled()) {
loff_t temp_pos = *pos;
if (check_dynamic_sign(fp, *size4, &temp_pos, matched_index)) {
*pos = temp_pos;
*offset += *size4;
return true;
}
}
for (i = 0; i < ARRAY_SIZE(apk_sign_keys); i++) {
sign_key = apk_sign_keys[i];
if (i == 1) { // Dynamic Sign indexing
unsigned int size;
const char *hash;
if (ksu_get_dynamic_manager_config(&size, &hash)) {
sign_key.size = size;
sign_key.sha256 = hash;
}
}
if (*size4 != sign_key.size)
continue;
*offset += *size4;
@@ -125,9 +168,9 @@ static bool check_block(struct file *fp, u32 *size4, loff_t *pos, u32 *offset, i
pr_info("cert length overlimit\n");
return false;
}
ksu_kernel_read_compat(fp, cert, *size4, pos);
kernel_read(fp, cert, *size4, pos);
unsigned char digest[SHA256_DIGEST_SIZE];
if (IS_ERR(ksu_sha256(cert, *size4, digest))) {
if (ksu_sha256(cert, *size4, digest) < 0 ) {
pr_info("sha256 error\n");
return false;
}
@@ -171,7 +214,7 @@ static bool has_v1_signature_file(struct file *fp)
loff_t pos = 0;
while (ksu_kernel_read_compat(fp, &header,
while (kernel_read(fp, &header,
sizeof(struct zip_entry_header), &pos) ==
sizeof(struct zip_entry_header)) {
if (header.signature != 0x04034b50) {
@@ -181,12 +224,13 @@ static bool has_v1_signature_file(struct file *fp)
// Read the entry file name
if (header.file_name_length == sizeof(MANIFEST) - 1) {
char fileName[sizeof(MANIFEST)];
ksu_kernel_read_compat(fp, fileName,
kernel_read(fp, fileName,
header.file_name_length, &pos);
fileName[header.file_name_length] = '\0';
// Check if the entry matches META-INF/MANIFEST.MF
if (strncmp(MANIFEST, fileName, sizeof(MANIFEST) - 1) == 0) {
if (strncmp(MANIFEST, fileName, sizeof(MANIFEST) - 1) ==
0) {
return true;
}
} else {
@@ -206,14 +250,16 @@ static __always_inline bool check_v2_signature(char *path, bool check_multi_mana
unsigned char buffer[0x11] = { 0 };
u32 size4;
u64 size8, size_of_block;
loff_t pos;
bool v2_signing_valid = false;
int v2_signing_blocks = 0;
bool v3_signing_exist = false;
bool v3_1_signing_exist = false;
int matched_index = -1;
int i;
struct file *fp = ksu_filp_open_compat(path, O_RDONLY, 0);
struct file *fp = filp_open(path, O_RDONLY, 0);
if (IS_ERR(fp)) {
pr_err("open %s error.\n", path);
return false;
@@ -232,10 +278,10 @@ static __always_inline bool check_v2_signature(char *path, bool check_multi_mana
for (i = 0;; ++i) {
unsigned short n;
pos = generic_file_llseek(fp, -i - 2, SEEK_END);
ksu_kernel_read_compat(fp, &n, 2, &pos);
kernel_read(fp, &n, 2, &pos);
if (n == i) {
pos -= 22;
ksu_kernel_read_compat(fp, &size4, 4, &pos);
kernel_read(fp, &size4, 4, &pos);
if ((size4 ^ 0xcafebabeu) == 0xccfbf1eeu) {
break;
}
@@ -248,17 +294,17 @@ static __always_inline bool check_v2_signature(char *path, bool check_multi_mana
pos += 12;
// offset
ksu_kernel_read_compat(fp, &size4, 0x4, &pos);
kernel_read(fp, &size4, 0x4, &pos);
pos = size4 - 0x18;
ksu_kernel_read_compat(fp, &size8, 0x8, &pos);
ksu_kernel_read_compat(fp, buffer, 0x10, &pos);
kernel_read(fp, &size8, 0x8, &pos);
kernel_read(fp, buffer, 0x10, &pos);
if (strcmp((char *)buffer, "APK Sig Block 42")) {
goto clean;
}
pos = size4 - (size8 + 0x8);
ksu_kernel_read_compat(fp, &size_of_block, 0x8, &pos);
kernel_read(fp, &size_of_block, 0x8, &pos);
if (size_of_block != size8) {
goto clean;
}
@@ -267,12 +313,12 @@ static __always_inline bool check_v2_signature(char *path, bool check_multi_mana
while (loop_count++ < 10) {
uint32_t id;
uint32_t offset;
ksu_kernel_read_compat(fp, &size8, 0x8,
kernel_read(fp, &size8, 0x8,
&pos); // sequence length
if (size8 == size_of_block) {
break;
}
ksu_kernel_read_compat(fp, &id, 0x4, &pos); // id
kernel_read(fp, &id, 0x4, &pos); // id
offset = 4;
if (id == 0x7109871au) {
v2_signing_blocks++;
@@ -326,8 +372,8 @@ clean:
}
if (check_multi_manager) {
// 0: ShirkNeko/SukiSU, 1: Dynamic Sign
if (matched_index == 0 || matched_index == 1) {
// 0: ShirkNeko/SukiSU, DYNAMIC_SIGN_INDEX : Dynamic Sign
if (matched_index == 0 || matched_index == DYNAMIC_SIGN_INDEX) {
pr_info("Multi-manager APK detected (dynamic_manager enabled): signature_index=%d\n", matched_index);
return true;
}
@@ -369,7 +415,7 @@ bool is_manager_apk(char *path)
return check_v2_signature(path, false, NULL);
}
bool ksu_is_dynamic_manager_apk(char *path, int *signature_index)
bool is_dynamic_manager_apk(char *path, int *signature_index)
{
return check_v2_signature(path, true, signature_index);
}

View File

@@ -6,4 +6,6 @@
bool is_manager_apk(char *path);
bool is_dynamic_manager_apk(char *path, int *signature_index);
#endif

302
kernel/app_profile.c Normal file
View File

@@ -0,0 +1,302 @@
#include <linux/capability.h>
#include <linux/cred.h>
#include <linux/sched.h>
#include <linux/sched/signal.h>
#include <linux/seccomp.h>
#include <linux/thread_info.h>
#include <linux/uidgid.h>
#include <linux/version.h>
#include "objsec.h"
#include "allowlist.h"
#include "app_profile.h"
#include "klog.h" // IWYU pragma: keep
#include "selinux/selinux.h"
#include "syscall_hook_manager.h"
#include "sucompat.h"
#include "sulog.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION (6, 7, 0)
static struct group_info root_groups = { .usage = REFCOUNT_INIT(2), };
#else
static struct group_info root_groups = { .usage = ATOMIC_INIT(2) };
#endif
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;
}
group_info->gid[i] = kgid;
}
groups_sort(group_info);
set_groups(cred, group_info);
put_group_info(group_info);
}
void disable_seccomp(void)
{
assert_spin_locked(&current->sighand->siglock);
// disable seccomp
#if defined(CONFIG_GENERIC_ENTRY) && \
LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
clear_syscall_work(SECCOMP);
#else
clear_thread_flag(TIF_SECCOMP);
#endif
#ifdef CONFIG_SECCOMP
current->seccomp.mode = 0;
current->seccomp.filter = NULL;
atomic_set(&current->seccomp.filter_count, 0);
#else
#endif
}
void escape_with_root_profile(void)
{
struct cred *cred;
struct task_struct *p = current;
struct task_struct *t;
cred = prepare_creds();
if (!cred) {
pr_warn("prepare_creds failed!\n");
return;
}
if (cred->euid.val == 0) {
pr_warn("Already root, don't escape!\n");
#if __SULOG_GATE
ksu_sulog_report_su_grant(current_euid().val, NULL, "escape_to_root_failed");
#endif
abort_creds(cred);
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;
cred->securebits = 0;
BUILD_BUG_ON(sizeof(profile->capabilities.effective) !=
sizeof(kernel_cap_t));
// setup capabilities
// we need CAP_DAC_READ_SEARCH becuase `/data/adb/ksud` is not accessible for non root process
// we add it here but don't add it to cap_inhertiable, it would be dropped automaticly after exec!
u64 cap_for_ksud =
profile->capabilities.effective | CAP_DAC_READ_SEARCH;
memcpy(&cred->cap_effective, &cap_for_ksud,
sizeof(cred->cap_effective));
memcpy(&cred->cap_permitted, &profile->capabilities.effective,
sizeof(cred->cap_permitted));
memcpy(&cred->cap_bset, &profile->capabilities.effective,
sizeof(cred->cap_bset));
setup_groups(profile, cred);
commit_creds(cred);
// Refer to kernel/seccomp.c: seccomp_set_mode_strict
// When disabling Seccomp, ensure that current->sighand->siglock is held during the operation.
spin_lock_irq(&current->sighand->siglock);
disable_seccomp();
spin_unlock_irq(&current->sighand->siglock);
setup_selinux(profile->selinux_domain);
#if __SULOG_GATE
ksu_sulog_report_su_grant(current_euid().val, NULL, "escape_to_root");
#endif
for_each_thread (p, t) {
ksu_set_task_tracepoint_flag(t);
}
}
#ifdef CONFIG_KSU_MANUAL_SU
#include "ksud.h"
#ifndef DEVPTS_SUPER_MAGIC
#define DEVPTS_SUPER_MAGIC 0x1cd1
#endif
static int __manual_su_handle_devpts(struct inode *inode)
{
if (!current->mm) {
return 0;
}
uid_t uid = current_uid().val;
if (uid % 100000 < 10000) {
// not untrusted_app, ignore it
return 0;
}
if (likely(!ksu_is_allow_uid_for_current(uid)))
return 0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) || defined(KSU_OPTIONAL_SELINUX_INODE)
struct inode_security_struct *sec = selinux_inode(inode);
#else
struct inode_security_struct *sec =
(struct inode_security_struct *)inode->i_security;
#endif
if (ksu_file_sid && sec)
sec->sid = ksu_file_sid;
return 0;
}
static void disable_seccomp_for_task(struct task_struct *tsk)
{
assert_spin_locked(&tsk->sighand->siglock);
#ifdef CONFIG_SECCOMP
if (tsk->seccomp.mode == SECCOMP_MODE_DISABLED && !tsk->seccomp.filter)
return;
#endif
clear_tsk_thread_flag(tsk, TIF_SECCOMP);
#ifdef CONFIG_SECCOMP
tsk->seccomp.mode = SECCOMP_MODE_DISABLED;
if (tsk->seccomp.filter) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
seccomp_filter_release(tsk);
#else
put_seccomp_filter(tsk);
tsk->seccomp.filter = NULL;
#endif
}
#endif
}
void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid)
{
struct cred *newcreds;
struct task_struct *target_task;
unsigned long flags;
struct task_struct *p = current;
struct task_struct *t;
pr_info("cmd_su: escape_to_root_for_cmd_su called for UID: %d, PID: %d\n", target_uid, target_pid);
// Find target task by PID
rcu_read_lock();
target_task = pid_task(find_vpid(target_pid), PIDTYPE_PID);
if (!target_task) {
rcu_read_unlock();
pr_err("cmd_su: target task not found for PID: %d\n", target_pid);
#if __SULOG_GATE
ksu_sulog_report_su_grant(target_uid, "cmd_su", "target_not_found");
#endif
return;
}
get_task_struct(target_task);
rcu_read_unlock();
if (task_uid(target_task).val == 0) {
pr_warn("cmd_su: target task is already root, PID: %d\n", target_pid);
put_task_struct(target_task);
return;
}
newcreds = prepare_kernel_cred(target_task);
if (newcreds == NULL) {
pr_err("cmd_su: failed to allocate new cred for PID: %d\n", target_pid);
#if __SULOG_GATE
ksu_sulog_report_su_grant(target_uid, "cmd_su", "cred_alloc_failed");
#endif
put_task_struct(target_task);
return;
}
struct root_profile *profile = ksu_get_root_profile(target_uid);
newcreds->uid.val = profile->uid;
newcreds->suid.val = profile->uid;
newcreds->euid.val = profile->uid;
newcreds->fsuid.val = profile->uid;
newcreds->gid.val = profile->gid;
newcreds->fsgid.val = profile->gid;
newcreds->sgid.val = profile->gid;
newcreds->egid.val = profile->gid;
newcreds->securebits = 0;
u64 cap_for_cmd_su = profile->capabilities.effective | CAP_DAC_READ_SEARCH | CAP_SETUID | CAP_SETGID;
memcpy(&newcreds->cap_effective, &cap_for_cmd_su, sizeof(newcreds->cap_effective));
memcpy(&newcreds->cap_permitted, &profile->capabilities.effective, sizeof(newcreds->cap_permitted));
memcpy(&newcreds->cap_bset, &profile->capabilities.effective, sizeof(newcreds->cap_bset));
setup_groups(profile, newcreds);
task_lock(target_task);
const struct cred *old_creds = get_task_cred(target_task);
rcu_assign_pointer(target_task->real_cred, newcreds);
rcu_assign_pointer(target_task->cred, get_cred(newcreds));
task_unlock(target_task);
if (target_task->sighand) {
spin_lock_irqsave(&target_task->sighand->siglock, flags);
disable_seccomp_for_task(target_task);
spin_unlock_irqrestore(&target_task->sighand->siglock, flags);
}
setup_selinux(profile->selinux_domain);
put_cred(old_creds);
wake_up_process(target_task);
if (target_task->signal->tty) {
struct inode *inode = target_task->signal->tty->driver_data;
if (inode && inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC) {
__manual_su_handle_devpts(inode);
}
}
put_task_struct(target_task);
#if __SULOG_GATE
ksu_sulog_report_su_grant(target_uid, "cmd_su", "manual_escalation");
#endif
for_each_thread (p, t) {
ksu_set_task_tracepoint_flag(t);
}
pr_info("cmd_su: privilege escalation completed for UID: %d, PID: %d\n", target_uid, target_pid);
}
#endif

70
kernel/app_profile.h Normal file
View File

@@ -0,0 +1,70 @@
#ifndef __KSU_H_APP_PROFILE
#define __KSU_H_APP_PROFILE
#include <linux/types.h>
// Forward declarations
struct cred;
#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;
};
};
// Escalate current process to root with the appropriate profile
void escape_with_root_profile(void);
void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid);
void disable_seccomp(void);
#endif

View File

@@ -18,10 +18,8 @@
#define __PT_SP_REG sp
#define __PT_IP_REG pc
#define PRCTL_SYMBOL "__arm64_sys_prctl"
#define REBOOT_SYMBOL "__arm64_sys_reboot"
#define SYS_READ_SYMBOL "__arm64_sys_read"
#define SYS_NEWFSTATAT_SYMBOL "__arm64_sys_newfstatat"
#define SYS_FACCESSAT_SYMBOL "__arm64_sys_faccessat"
#define SYS_EXECVE_SYMBOL "__arm64_sys_execve"
#elif defined(__x86_64__)
@@ -39,10 +37,8 @@
#define __PT_RC_REG ax
#define __PT_SP_REG sp
#define __PT_IP_REG ip
#define PRCTL_SYMBOL "__x64_sys_prctl"
#define REBOOT_SYMBOL "__x64_sys_reboot"
#define SYS_READ_SYMBOL "__x64_sys_read"
#define SYS_NEWFSTATAT_SYMBOL "__x64_sys_newfstatat"
#define SYS_FACCESSAT_SYMBOL "__x64_sys_faccessat"
#define SYS_EXECVE_SYMBOL "__x64_sys_execve"
#else

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