[
  {
    "path": "README.md",
    "content": "# WSA-Kernel-SU\n\n## Intro\n\nThis is a kernel module to provide `/system/xbin/su` to Android Kernel (especially to WSA).\nThis is the best root solution if hiding is required. When GKI is ready, kernelsu is definitely the next generation of root.\n\nOnly works on 4.17+ kernel (both WSA and GKI is 5.0+). For older kernel, you can refer to the [origin repo](https://git.zx2c4.com/kernel-assisted-superuser).\n\n## How it works\n- Replace syscall `newfstatat`, `faccessat` and `execve` on `/system/xbin/su` to `/system/bin/sh`\n- When `execve` on `/system/xbin/su`, change SELinux to permissive, set all kinds of uids and gids to 0 and permit all capabilities\n- Set SELinux context `su` to permissive\n- Set the selinux context of the current process to `u:r:su:s0`\n\n## License\nGPLv2\n\n## Credits\nJason A. Donenfeld for the original implementation\n"
  },
  {
    "path": "drivers/base/superuser/Kconfig",
    "content": "menu \"Super User Options\"\nconfig ASSISTED_SUPERUSER\n\tbool \"Kernel-assisted superuser\"\n\tselect SECURITY_SELINUX_DEVELOP if SECURITY_SELINUX\n\thelp\n\t  This driver gives trivial root access by typing `su` in a\n\t  shell. It is a security disaster, and nobody should enable\n\t  this catastrophe of a driver.\n\n\t  Say N here unless you have a vendetta against kittens.\n\nconfig HIDE_ASSISTED_SUPERUSER\n\tbool \"hide Kernel-assisted superuser\"\n    depends on ASSISTED_SUPERUSER\n\thelp\n\tWhen this option is on, only processes with uid/gid=0/2000\n\twill has the permission to access /system/xbin/su. Other\n\tprocesses will never have permission to access/stat/exec\n\tsu binary.\n\n\tSay N here unless you have a vendetta against kittens.\nendmenu\n"
  },
  {
    "path": "drivers/base/superuser/Makefile",
    "content": "ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG\r\nccflags-$(CONFIG_ASSISTED_SUPERUSER) += -Isecurity/selinux/include -Isecurity/selinux/ss -Isecurity/selinux\r\n\r\nobj-$(CONFIG_ASSISTED_SUPERUSER) += superuser.o"
  },
  {
    "path": "drivers/base/superuser/superuser.c",
    "content": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2015-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.\n * Copyright (C) 2021 LoveSy <shana@zju.edu.cn>. All Rights Reserved.\n */\n\n/* Hello. If this is enabled in your kernel for some reason, whoever is\n * distributing your kernel to you is a complete moron, and you shouldn't\n * use their kernel anymore. But it's not my fault! People: don't enable\n * this driver! (Note that the existence of this file does not imply the\n * driver is actually in use. Look in your .config to see whether this is\n * enabled.) -Jason\n */\n\n#define pr_fmt(fmt) KBUILD_MODNAME \": \" fmt\n#include <linux/uaccess.h>\n#include <linux/module.h>\n#include <linux/fs.h>\n#include <linux/mman.h>\n#include <linux/ptrace.h>\n#include <linux/syscalls.h>\n#include <policycap.h>\n#include <security.h>\n#include <ebitmap.h>\n#include <services.h>\n#include <objsec.h>\n\ntypedef long (* syscall_wrapper)(struct pt_regs *);\n// https://man7.org/linux/man-pages/man2/syscall.2.html\n#if defined(__x86_64__)\n#define ARG0(regs) regs->di\n#define ARG1(regs) regs->si\n#elif defined(__i386__)\n#define ARG0(regs) regs->bx\n#define ARG1(regs) regs->cx\n#elif defined(__aarch64__)\n#define ARG0(regs) regs->regs[0]\n#define ARG1(regs) regs->regs[1]\n#elif defined(__arm__)\n#define ARG0(regs) regs->uregs[0]\n#define ARG1(regs) regs->uregs[1]\n#endif\nstatic bool is_permitive(void) {\n#ifdef CONFIG_HIDE_ASSISTED_SUPERUSER\n\tstruct cred *cred = (struct cred *)__task_cred(current);\n\treturn cred->uid.val == 0 || cred->uid.val == 2000 || cred->gid.val == 0 || cred->gid.val == 2000;\n#else\n\treturn true;\n#endif\n}\n\nstatic bool is_su(const char __user *filename)\n{\n\tstatic const char su_path[] = \"/system/xbin/su\";\n\tchar ufn[sizeof(su_path)];\n\n\treturn likely(!copy_from_user(ufn, filename, sizeof(ufn))) &&\n\t\t   unlikely(!memcmp(ufn, su_path, sizeof(ufn)));\n}\n\nstatic void __user *userspace_stack_buffer(const void *d, size_t len)\n{\n\t/* To avoid having to mmap a page in userspace, just write below the stack pointer. */\n\tchar __user *p = (void __user *)current_user_stack_pointer() - len;\n\n\treturn copy_to_user(p, d, len) ? NULL : p;\n}\n\nstatic char __user *sh_user_path(void)\n{\n\tstatic const char sh_path[] = \"/system/bin/sh\";\n\n\treturn userspace_stack_buffer(sh_path, sizeof(sh_path));\n}\n\nstatic syscall_wrapper old_newfstatat;\n\nstatic long new_newfstatat(struct pt_regs* regs)\n{\n\tif (is_permitive() && is_su((const char __user*)ARG1(regs)))\n\t\tARG1(regs) = (ulong) sh_user_path();\n\treturn old_newfstatat(regs);\n}\n\nstatic syscall_wrapper old_faccessat;\nstatic long new_faccessat(struct pt_regs* regs)\n{\n\tif (is_permitive() && is_su((const char __user*)ARG1(regs)))\n\t\tARG1(regs) = (ulong) sh_user_path();\n\treturn old_faccessat(regs);\n}\n\nstatic syscall_wrapper old_execve;\nstatic long new_execve(struct pt_regs* regs)\n{\n\tstatic const char now_root[] = \"Welcome to LSPosed KernelSU\\n\";\n\tint sid = -1;\n\tstruct cred *cred;\n\tstruct selinux_policy *policy;\n\tstruct policydb *policydb;\n\tstruct type_datum *typedatum;\n\tstruct task_security_struct *current_security;\n\n\tconst char __user * filename = (const char *) ARG0(regs);\n\tif (!is_permitive() || !is_su(filename))\n\t\treturn old_execve(regs);\n\n\tif (!old_execve(regs))\n\t\treturn 0;\n\n\t/* Rather than the usual commit_creds(prepare_kernel_cred(NULL)) idiom,\n\t * we manually zero out the fields in our existing one, so that we\n\t * don't have to futz with the task's key ring for disk access.\n\t */\n\tcred = (struct cred *)__task_cred(current);\n\n\t\n\tif (!security_context_str_to_sid(&selinux_state, \"u:r:su:s0\", &sid, GFP_KERNEL)) {\n\t\tcurrent_security = cred->security;\n\t\tpolicy = rcu_dereference(selinux_state.policy);\n\t\tpolicydb = &policy->policydb;\n\t\tif ((typedatum = symtab_search(&policydb->p_types, \"su\"))) {\n\t\t\tebitmap_set_bit(&policydb->permissive_map, typedatum->value, true);\n\t\t\tprintk(\"sucessfully set su (sid=%d) to permissive\", sid);\n\t\t} else {\n\t\t\tpr_err(\"failed to set su (sid=%d) to permissive\", sid);\n\t\t}\n\t} else {\n\t\tpr_err(\"failed to get su sid\");\n\t}\n\n\tif (sid != -1) {\n\t\tcurrent_security->sid = sid;\n\t\tcurrent_security->exec_sid = sid;\n\t} else {\n\t\t/* It might be enough to just change the security ctx of the\n\t\t* current task, but that requires slightly more thought than\n\t\t* just axing the whole thing here.\n\t\t*/\n\t\tenforcing_set(&selinux_state, false);\n\t}\n\tmemset(&cred->uid, 0, sizeof(cred->uid));\n\tmemset(&cred->gid, 0, sizeof(cred->gid));\n\tmemset(&cred->suid, 0, sizeof(cred->suid));\n\tmemset(&cred->euid, 0, sizeof(cred->euid));\n\tmemset(&cred->egid, 0, sizeof(cred->egid));\n\tmemset(&cred->fsuid, 0, sizeof(cred->fsuid));\n\tmemset(&cred->fsgid, 0, sizeof(cred->fsgid));\n\tmemset(&cred->cap_inheritable, 0xff, sizeof(cred->cap_inheritable));\n\tmemset(&cred->cap_permitted, 0xff, sizeof(cred->cap_permitted));\n\tmemset(&cred->cap_effective, 0xff, sizeof(cred->cap_effective));\n\tmemset(&cred->cap_bset, 0xff, sizeof(cred->cap_bset));\n\tmemset(&cred->cap_ambient, 0xff, sizeof(cred->cap_ambient));\n\n\tksys_write(2, userspace_stack_buffer(now_root, sizeof(now_root)),\n\t\t  sizeof(now_root) - 1);\n\n\tARG0(regs) = (ulong) sh_user_path();\n\treturn old_execve(regs);\n}\n\nstatic void read_syscall(void **ptr, unsigned int syscall)\n{\n\t*ptr = READ_ONCE(*((void **)sys_call_table + syscall));\n}\nstatic void replace_syscall(unsigned int syscall, void *ptr)\n{\n\tWRITE_ONCE(*((void **)sys_call_table + syscall), ptr);\n}\n#define read_and_replace_syscall(name) do { \\\n\tread_syscall((void **)&old_ ## name, __NR_ ## name); \\\n\treplace_syscall(__NR_ ## name, &new_ ## name); \\\n} while (0)\n\nstatic int superuser_init(void)\n{\n\tpr_err(\"WARNING WARNING WARNING WARNING WARNING\\n\");\n\tpr_err(\"This kernel has kernel-assisted superuser and contains a\\n\");\n\tpr_err(\"trivial way to get root. If you did not build this kernel\\n\");\n\tpr_err(\"yourself, stop what you're doing and find another kernel.\\n\");\n\tpr_err(\"This one is not safe to use.\\n\");\n\tpr_err(\"WARNING WARNING WARNING WARNING WARNING\\n\");\n\n\tread_and_replace_syscall(newfstatat);\n\tread_and_replace_syscall(faccessat);\n\tread_and_replace_syscall(execve);\n\n\treturn 0;\n}\n\nmodule_init(superuser_init);\nMODULE_LICENSE(\"GPL v2\");\nMODULE_DESCRIPTION(\"Kernel-assisted superuser for Android\");\nMODULE_AUTHOR(\"Jason A. Donenfeld <Jason@zx2c4.com> & LoveSy <shana@zju.edu.cn>\");\n"
  }
]