#include #include #include #include #include #include #include #include "klog.h" // IWYU pragma: keep #include "kernel_compat.h" extern struct task_struct init_task; // mnt_ns context switch for environment that android_init->nsproxy->mnt_ns != init_task.nsproxy->mnt_ns, such as WSA struct ksu_ns_fs_saved { struct nsproxy *ns; struct fs_struct *fs; }; static void ksu_save_ns_fs(struct ksu_ns_fs_saved *ns_fs_saved) { ns_fs_saved->ns = current->nsproxy; ns_fs_saved->fs = current->fs; } static void ksu_load_ns_fs(struct ksu_ns_fs_saved *ns_fs_saved) { current->nsproxy = ns_fs_saved->ns; current->fs = ns_fs_saved->fs; } static bool android_context_saved_checked = false; static bool android_context_saved_enabled = false; static struct ksu_ns_fs_saved android_context_saved; void ksu_android_ns_fs_check() { if (android_context_saved_checked) return; android_context_saved_checked = true; task_lock(current); if (current->nsproxy && current->fs && current->nsproxy->mnt_ns != init_task.nsproxy->mnt_ns) { android_context_saved_enabled = true; #ifdef CONFIG_KSU_DEBUG pr_info("android context saved enabled due to init mnt_ns(%p) != android mnt_ns(%p)\n", current->nsproxy->mnt_ns, init_task.nsproxy->mnt_ns); #endif ksu_save_ns_fs(&android_context_saved); } else { pr_info("android context saved disabled\n"); } task_unlock(current); } struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode) { // switch mnt_ns even if current is not wq_worker, to ensure what we open is the correct file in android mnt_ns, rather than user created mnt_ns struct ksu_ns_fs_saved saved; if (android_context_saved_enabled) { #ifdef CONFIG_KSU_DEBUG pr_info("start switch current nsproxy and fs to android context\n"); #endif task_lock(current); ksu_save_ns_fs(&saved); ksu_load_ns_fs(&android_context_saved); task_unlock(current); } struct file *fp = filp_open(filename, flags, mode); if (android_context_saved_enabled) { task_lock(current); ksu_load_ns_fs(&saved); task_unlock(current); #ifdef CONFIG_KSU_DEBUG pr_info("switch current nsproxy and fs back to saved successfully\n"); #endif } return fp; } ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count, loff_t *pos) { return kernel_read(p, buf, count, pos); } ssize_t ksu_kernel_write_compat(struct file *p, const void *buf, size_t count, loff_t *pos) { return kernel_write(p, buf, count, pos); } long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr, long count) { return strncpy_from_user_nofault(dst, unsafe_addr, count); } struct action_cache { DECLARE_BITMAP(allow_native, SECCOMP_ARCH_NATIVE_NR); #ifdef SECCOMP_ARCH_COMPAT DECLARE_BITMAP(allow_compat, SECCOMP_ARCH_COMPAT_NR); #endif }; struct seccomp_filter { refcount_t refs; refcount_t users; bool log; #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) bool wait_killable_recv; #endif struct action_cache cache; struct seccomp_filter *prev; struct bpf_prog *prog; struct notification *notif; struct mutex notify_lock; wait_queue_head_t wqh; }; void ksu_seccomp_clear_cache(struct seccomp_filter *filter, int nr) { if (!filter) { return; } if (nr >= 0 && nr < SECCOMP_ARCH_NATIVE_NR) { clear_bit(nr, filter->cache.allow_native); } #ifdef SECCOMP_ARCH_COMPAT if (nr >= 0 && nr < SECCOMP_ARCH_COMPAT_NR) { clear_bit(nr, filter->cache.allow_compat); } #endif } void ksu_seccomp_allow_cache(struct seccomp_filter *filter, int nr) { if (!filter) { return; } if (nr >= 0 && nr < SECCOMP_ARCH_NATIVE_NR) { set_bit(nr, filter->cache.allow_native); } #ifdef SECCOMP_ARCH_COMPAT if (nr >= 0 && nr < SECCOMP_ARCH_COMPAT_NR) { set_bit(nr, filter->cache.allow_compat); } #endif }