tiann / KernelSU

A Kernel based root solution for Android
https://kernelsu.org
GNU General Public License v3.0
9.23k stars 1.5k forks source link

[Feature] 允許在不關閉 kprobes 下使用手動集成 #1048

Closed supechicken closed 9 months ago

supechicken commented 9 months ago

Is your feature request related to a problem? Please describe.

背景是這樣的,我的內核在開啟 kprobes 下 kernelsu 不能正常工作(情況和 #887 一樣, manager 顯示工作中但 root 和模塊都用不了,dmesg 裡能看到 KernelSU: prctl reply error)。 如果關掉 kprobes 只用手動集成會導致 bootloop(可能有些內核模塊依賴於kprobes?)

我現在在用的方法是 CONFIG_KPROBES=y 外加手動集成。雖說解決了 kernelsu 不能工作的問題,但ksud裡一些依賴於 CONFIG_KPROBES 判斷的功能部分仍然不能正常工作(雖然 CONFIG_KPROBES=y,但 kernelsu 實際上是工作於手動集成下),比如 safe mode input hook 的停止邏輯:

static void stop_input_hook()
{
    static bool input_hook_stopped = false;
    if (input_hook_stopped) {
        return;
    }
    input_hook_stopped = true;
#ifdef CONFIG_KPROBES
    bool ret = schedule_work(&stop_input_hook_work);
    pr_info("unregister input kprobe: %d!\n", ret);
#else
    ksu_input_hook = false;
    pr_info("stop input_hook\n");
#endif
}

這導致了一些奇奇怪怪的問題,比如在調整音量的時候 safe mode 突然就開了(stop_input_hook 只處理了 kprobe 的部分,導致開機後 hook 沒有停止),雖然影響不大但有點煩。

日誌(如果需要的話):KernelSU_bugreport_2023-10-16_15_32.tar.gz

Describe the solution you'd like.

在 kconfig 裡添加一個獨立的選項控制集成方式(像 CONFIG_KSU_KPROBES, depends_on CONFIG_KPROBES

Describe alternatives you've considered.

如果有需要的話可用 sed 刪除所有 if statement,只留下 else 的部分

Additional context

tiann commented 9 months ago

我的內核在開啟 kprobes 下 kernelsu 不能正常工作

如果關掉 kprobes 只用手動集成會導致 bootloop

这两个是自相矛盾的,建议你查明开启 kprobes 后不工作的原因;如果你开 kprobe + kernelsu 能正常开机,那么说明你 kprobe 功能正常;我们只有在开了 kprobe 系统 bootloop 的情况下才推荐关闭 kprobe。

https://github.com/tiann/KernelSU/issues/887#issuecomment-1684685592 表明,kprobe 的符号不对,可能是 do_execve_common 符号有所不同,你可以换个试试。

tiann commented 9 months ago

你可以在 /proc/kallsyms 中确认符号

supechicken commented 9 months ago

剛試了 kernelsu + kprobes,情況和 #887 一樣,看不到 kprobes 錯誤但抓到了 permission error:

[   37.481957] KernelSU: renameat: packages.list.tmp -> packages.list, new path: /system/packages.list
[   37.482091] logd: start watching /data/system/packages.list ...
[   37.482115] KernelSU: do_update_uid, open /data/system/packages.list failed: -13

(關 selinux 和 chmod 0777 不起作用,加上重啟系統會重設檔案權限)

嘗試在 termux 調用 su 會出現 exec: /system/bin/su: not found (正常來說如果 su 不存在的話 termux 會有自己的錯誤信息,而不是這樣的 shell 錯誤,證明 kernelsu 是有在工作的)

在 issue 裏搜了一遍,發現可能是内核有安全機制的原因,但在 logcat.txt 和 dmesg.txt 裏看不出來

這是剛開機什麽都沒做導出的日誌: KernelSU_bugreport_2023-10-16_18_04.tar.gz

這是嘗試調用 su 後的日誌: KernelSU_bugreport_2023-10-16_18_11.tar.gz

tiann commented 9 months ago

还是我上面说的问题,do_execveat_common kprobe 失败;如果你不想调查原因,以下是一个简单的处理方法:

结合 kprobe 和手动修改源码,但只修改 fs/exec.c 里面 ksu_handle_execve 那部分,其他用 kprobe。

supechicken commented 9 months ago

感謝建議!

在加了 ksu_handle_execve 之後大部分的 app 都能正常授權了,唯獨 adb shell 和 revanced manager 不行, 是還有其他 kprobe 失敗了嗎?

还是我上面说的问题,do_execveat_common kprobe 失败

我在 liveboot 的 dmesg 裡找到了相關的錯誤(從 kernelsu 的 bug tarball 裡找不到,應該是被覆蓋了),印證了您的說法:

6,421,1349254,-,caller=T1;KernelSU: ksu_lsm_hook_init
6,422,1374236,-,caller=T1;KernelSU: sucompat: execve_kp: -2
6,423,1384970,-,caller=T1;KernelSU: sucompat: newfstatat_kp: 0
6,424,1395487,-,caller=T1;KernelSU: sucompat: faccessat_kp: 0
6,425,1420422,-,caller=T1;KernelSU: ksud: execve_kp: -2
6,426,1430647,-,caller=T1;KernelSU: ksud: vfs_read_kp: 0
6,427,1444621,-,caller=T1;KernelSU: ksud: input_handle_event_kp: 0

kprobe 的符号不对,可能是 do_execve_common 符号有所不同,你可以换个试试。

我在 kallsyms 裡找不到 do_execve_common 或者 do_execveat_common,只找到了這些:

0000000000000000 T do_execve_file
0000000000000000 t __do_execve_file.llvm.10451029662658543295
0000000000000000 T do_execve
0000000000000000 T do_execveat

還有一個問題,如果要更換符號的話是要從這裡改嗎: https://github.com/tiann/KernelSU/blob/1f1d4d454e9e5d2d108792bc1f3aae76671054b3/kernel/ksud.c#L473-L482

(Edit) 改成這樣沒用:

static struct kprobe execve_kp = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
        .symbol_name = "do_execveat_common",
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
        .symbol_name = "do_execve_file",
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
        .symbol_name = "__do_execve_file",
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
        .symbol_name = "do_execveat_common",
#endif
        .pre_handler = execve_handler_pre,
};
supechicken commented 9 months ago

對了,忘記附 log 了 liveboot.log kallsyms.txt KernelSU_bugreport_2023-10-17_22_19.tar.gz

supechicken commented 9 months ago

kprobe 的問題在 fs/exec.c 加了 EXPORT_SYMBOL(__do_execve_file) 之後解決了, 然而這次的問題是重啟掉allowlist... (把 .allowlist 刪掉解決)

在加了 ksu_handle_execve 之後大部分的 app 都能正常授權了,唯獨 adb shell 和 revanced manager 不行,

在用了 #668 的 workaround 之後正常了,與 #668 不同的是這次 kprobe 沒報錯

KernelSU: ksu_lsm_hook_init
KernelSU: sucompat: execve_kp: 0
KernelSU: sucompat: newfstatat_kp: 0
KernelSU: sucompat: faccessat_kp: 0
KernelSU: ksud: execve_kp: 0
KernelSU: ksud: vfs_read_kp: 0
KernelSU: ksud: input_handle_event_kp: 0

KernelSU_bugreport_2023-10-19_09_00.tar.gz

tiann commented 9 months ago

没报错其他正常吗?

supechicken commented 9 months ago

没报错其他正常吗?

除了上述有些 app 看不到 su 之外其他都正常