一加8系氢/氧11-内核KernelSU编译教程

KernelSU 是 Android GKI 设备的 root 解决方案,它工作在内核模式,并直接在内核空间中为用户空间应用程序授予 root 权限。KernelSU内核Root隐藏性更高。黑鹰本人一直用氢11养老,所以旧版本的集成KernelSU很少,所以才有了今天这个教程,乐享网也是第一次接触内核,所以教程不是很完美,也是自己的一个笔记。有想尝试的可以自己编译一下。

安装Ubuntu

Horizon Clang 是在 Ubuntu 22.04 + glibc 2.35 的环境下编译的,所以需要第一步安装22.04.3 LTS系统。

Ubuntu 22.04:https://ubuntu.com/download/desktop

安装Ubuntu教程省略,可以在网上找教程。

安装基础软件包

sudo apt-get install libncurses5-dev libncurses-dev libssl-dev device-tree-compiler bc cpio lib32ncurses5-dev lib32z1 build-essential binutils bc bison build-essential ccache curl flex g++-multilib gcc-multilib git gnupg gperf imagemagick lib32ncurses5-dev lib32readline-dev lib32z1-dev liblz4-tool libncurses5 libncurses5-dev libsdl1.2-dev libssl-dev libxml2 libxml2-utils lzop pngcrush rsync schedtool squashfs-tools xsltproc zip zlib1g-dev git

Horizon需要安装python2

sudo apt install python2

安装基础包我这也会出现编译错误,如果出现错误下方再安装一遍

#更新安装列表:
apt-get update

#安装gcc:
apt install gcc

#安装make:
apt-get install make

安装库:
sudo apt install bison
sudo apt install flex
sudo apt install libssl-dev

编译方法

内核源自大佬:https://blog.xzr.moe/archives/313
首先,创建工作空间,获取内核本体代码:

mkdir workspace
cd workspace
git clone https://github.com/libxzr/android_kernel_oneplus_sm8250 -b oos11/final

然后,获取内核压缩包的代码:

git clone https://github.com/libxzr/AnyKernel3 -b op8/11

获取编译工具链,此处推荐 Horizon Clang ,R18 版本是基于其 16.x 版本编译测试的。
工具链在解压后放在 workspace 的 clang 目录处,不可有额外的目录嵌套,即需要确保 workspace/clang/bin/clang 是编译器的可执行文件。

Horizon Clang下载地址

百度网盘:https://pan.baidu.com/s/1fueWlqRpNDjY9LyCPqQR2w 提取码:x698

天翼云盘:https://cloud.189.cn/t/yABBreVZfUFf 提取码:9bp9

下载之后复制到workspace/目录下

确保命令行在workspace,开始解压

mkdir clang
tar -xJvf Horizon-Clang-<版本>.tar.xz -C clang

然后,获取内核本体中的 submodules:

cd android_kernel_oneplus_sm8250
git submodule init
git submodule update

开启kernel su支持

安卓开启kernel su支持
拉取内核源码,进入你的内核源码文件夹,执行以下命令

curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -

修改文件内核配置文件。
修改内核源码:/workspace/android_kernel_oneplus_sm8250/arch/Arm64/configs/op8-perf_defconfig

//将这部分注释掉
#CONFIG_MODULE_SIG_FORCE=y //这个参数是验证内核驱动,需要关掉,不然会出现无法触摸、屏幕不工作、黑屏等问题
//开启kernel su的开关
CONFIG_KPROBES=y
CONFIG_HAVE_KPROBES=y
CONFIG_KPROBE_EVENTS=y

//强制加载内核驱动模块,不加载内核模块会直接G掉
CONFIG_MODULES=y
CONFIG_MODULE_FORCE_LOAD=y

//SELinux默认是Permissive状态
CONFIG_SECURITY_SELINUX_DEVELOP=y

//关闭AVB验证
CONFIG_DM_VERITY=y  
CONFIG_DM_VERITY_AVB=y

主要是要改四个地方:

  1. do_faccessat,通常位于 fs/open.c
  2. do_execveat_common,通常位于 fs/exec.c
  3. vfs_read,通常位于 fs/read_write.c
  4. vfs_statx,通常位于 fs/stat.c

修改内核源码/workspace/android_kernel_oneplus_sm8250/fs/exec.c文件

//addcode start
extern int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv,
            void *envp, int *flags);
//addcode end
static int do_execveat_common(int fd, struct filename *filename,
			      struct user_arg_ptr argv,
			      struct user_arg_ptr envp,
			      int flags)
{
    //addcode
    ksu_handle_execveat(&fd, &filename, &argv, &envp, &flags);
    //addcode end
	return __do_execve_file(fd, filename, argv, envp, flags, NULL);
}

修改内核源码/workspace/android_kernel_oneplus_sm8250/fs/read_write.c文件

//addcode start
extern int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
            size_t *count_ptr, loff_t **pos);
//addcode end
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
	ssize_t ret;
    //addcode start
    ksu_handle_vfs_read(&file, &buf, &count, &pos);
    //addcode end
	if (!(file->f_mode & FMODE_READ))
		return -EBADF;
	if (!(file->f_mode & FMODE_CAN_READ))
		return -EINVAL;
	if (unlikely(!access_ok(VERIFY_WRITE, buf, count)))
		return -EFAULT;

修改内核/workspace/android_kernel_oneplus_sm8250/fs/stat.c文件

 //addcode start
extern int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags);
//addcode end
/**
 * vfs_statx - Get basic and extra attributes by filename
 * @dfd: A file descriptor representing the base dir for a relative filename
 * @filename: The name of the file of interest
 * @flags: Flags to control the query
 * @stat: The result structure to fill in.
 * @request_mask: STATX_xxx flags indicating what the caller wants
 *
 * This function is a wrapper around vfs_getattr().  The main difference is
 * that it uses a filename and base directory to determine the file location.
 * Additionally, the use of AT_SYMLINK_NOFOLLOW in flags will prevent a symlink
 * at the given name from being referenced.
 *
 * 0 will be returned on success, and a -ve error code if unsuccessful.
 */
int vfs_statx(int dfd, const char __user *filename, int flags,
	      struct kstat *stat, u32 request_mask)
{
	struct path path;
	int error = -EINVAL;
	unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT;
	//addcode start
        ksu_handle_stat(&dfd, &filename, &flags);
        //addcode end
	if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
		       AT_EMPTY_PATH | KSTAT_QUERY_FLAGS)) != 0)
		return -EINVAL;

修改内核/workspace/android_kernel_oneplus_sm8250/fs/open.c

//addcode start
extern int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
             int *flags);
//addcode end
long do_faccessat(int dfd, const char __user *filename, int mode)
{
	const struct cred *old_cred;
	struct cred *override_cred;
	struct path path;
	struct inode *inode;
	struct vfsmount *mnt;
	int res;
	unsigned int lookup_flags = LOOKUP_FOLLOW;
    //addcode start
    ksu_handle_faccessat(&dfd, &filename, &mode, NULL);
    //addcode end
	if (mode & ~S_IRWXO)	/* where's F_OK, X_OK, W_OK, R_OK? */
		return -EINVAL;

	override_cred = prepare_creds();
	if (!override_cred)
		return -ENOMEM;

KernelSU 内置安全模式 drivers/input/input.c和kernel/module.c文件

修改内核/workspace/android_kernel_oneplus_sm8250/drivers/input/input.c 中的 input_handle_event 方法:

//addcode start
extern int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, int *value);
//addcode end
static void input_handle_event(struct input_dev *dev,
			       unsigned int type, unsigned int code, int value)
{
	int disposition = input_get_disposition(dev, type, code, &value);
    //addcode start
    ksu_handle_input_handle_event(&type, &code, &value);
    //addcode end
	if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
		add_input_randomness(type, code, value);

修改内核/workspace/android_kernel_oneplus_sm8250/kernel/module.c文件

第一处:

static int try_to_force_load(struct module *mod, const char *reason)
{
#ifdef CONFIG_MODULE_FORCE_LOAD
	if (!test_taint(TAINT_FORCED_MODULE))
		pr_warn("%s: %s: kernel tainted.\n", mod->name, reason);
	add_taint_module(mod, TAINT_FORCED_MODULE, LOCKDEP_NOW_UNRELIABLE);
	return 0;
#else
	return -ENOEXEC;
#endif
}

#ifdef CONFIG_MODVERSIONS
//这里改成0,始终为true
#if 0

static u32 resolve_rel_crc(const s32 *crc)
{

第二处:

static int load_module(struct load_info *info, const char __user *uargs,
		       int flags)
{
	struct module *mod;
	long err = 0;
	char *after_dashes;
	//addcode加入这两个flags,跳过内核模块验证,强制加载
        flags |= MODULE_INIT_IGNORE_MODVERSIONS;
        flags |= MODULE_INIT_IGNORE_VERMAGIC;
        //addcode end
	err = elf_header_check(info);
	if (err)
		goto free_copy;

编译内核

参考的编译脚本:

horizon_build.sh

#!/bin/bash
set -e

DIR="$( cd "$( dirname "$0"  )" &&cd ..&& pwd  )"
source="$( cd "$( dirname "$0"  )" && pwd  )"

CLANG_PATH="${DIR}/clang"

args="-j$(nproc --all) \
O=out \
ARCH=arm64 \
CLANG_TRIPLE=aarch64-linux-gnu- \
CROSS_COMPILE=${CLANG_PATH}/bin/aarch64-linux-gnu- \
CC=${CLANG_PATH}/bin/clang \
CROSS_COMPILE_COMPAT=${CLANG_PATH}/bin/arm-linux-gnueabi- \
AR=${CLANG_PATH}/bin/llvm-ar \
NM=${CLANG_PATH}/bin/llvm-nm \
LLVM_AR=${CLANG_PATH}/bin/llvm-ar \
LLVM_NM=${CLANG_PATH}/bin/llvm-nm \
OBJCOPY=${CLANG_PATH}/bin/llvm-objcopy \
OBJDUMP=${CLANG_PATH}/bin/llvm-objdump \
STRIP=${CLANG_PATH}/bin/llvm-strip \
LD=${CLANG_PATH}/bin/ld.lld "

device="all"
clean="false"
action="build"
version="`date +"%m%d%H%M"`"
release="false"

print (){
case ${2} in
    "red")
    echo -e "\033[31m $1 \033[0m";;

    "blue")
    echo -e "\033[34m $1 \033[0m";;

    "yellow")
    echo -e "\033[33m $1 \033[0m";;

    "purple")
    echo -e "\033[35m $1 \033[0m";;

    "sky")
    echo -e "\033[36m $1 \033[0m";;

    "green")
    echo -e "\033[32m $1 \033[0m";;

    *)
    echo $1
    ;;
    esac
}

input=${*}

for i in ${input}
    do
        case ${i} in
            "op8")
            device="op8";;

            "op8p")
            device="op8p";;

            "op8t")
            device="op8t";;

            "all")
            device="all";;

            "--clean"|"-c"|"clean")
            clean="true";;
        *)
        did="false"

        if [[ $i =~ "-r=" ]];then
        release="true"&&version="${i#*r=}"&&did="true"
        fi

        if [[ $i =~ "-v=" ]];then
        version="${i#*v=}"&&did="true"
        fi
        
        if [ $did == "false" ]
        then
        print "Error input" red&&exit
        fi

        ;;
        esac
    done
    
mkzip (){
    if [ "${release}" == "true" ];then
    zipname="(${1})Horizon-Kernel-R${version}.zip"
    else
    zipname="(${1})Horizon-Kernel-${version}.zip"
    fi
    cp -f out/arch/arm64/boot/Image.gz ${DIR}/AnyKernel3
    #find ${source}/out/arch/arm64/boot/dts/vendor/qcom -name '*.dtb' -exec cat {} + > ${DIR}/AnyKernel3/dtb
    cp ${source}/out/arch/arm64/boot/dts/vendor/qcom/kona-v2.1.dtb ${DIR}/AnyKernel3/dtb
    #cp ${source}/out/arch/arm64/boot/dts/vendor/qcom/instantnoodle-t0.dtb ${DIR}/AnyKernel3/dtb
    cp ${source}/out/arch/arm64/boot/dtbo.img ${DIR}/AnyKernel3
    cd ${DIR}/AnyKernel3
    zip -r "${zipname}" *
    cp -f "${zipname}" ${DIR}
    rm -f "${zipname}"
    cd ${source}
    print "All done.Find it at ${DIR}/$zipname" green
}
    
build_op8(){
    print "Building Kernel for op8..." blue
    make $args instantnoodle_defconfig&&make $args
    mkzip "op8${1}"
}

build_op8p(){
    print "Building Kernel for op8p..." blue
    make $args instantnoodlep_defconfig&&make $args
    mkzip "op8p${1}"
}

build_op8t(){
    print "Building Kernel for op8t..." blue
    make $args kebab_defconfig&&make $args
    mkzip "op8t${1}"
}

bclean(){
    rm -rf ${source}/out/arch/arm64/boot
}

clean(){
    if [ "${clean}" == "true" ]
    then
        print "Doing cleanups" red
        make ${args} mrproper
    else
        bclean
    fi
}

if [ "${action}" == "build" ]
then
    if [ $release == "true" ]
    then
        print "You are building a release version:R${version}" green
        args+="LOCALVERSION=-R${version} "
    else
        print "You are building a snapshot version:${version}" yellow
        args+="LOCALVERSION=-${version} "
    fi
    
    if [ ${device} == "all" ]
    then
        git reset --hard
        
        clean
        build_op8t "-OOS"
        
        bclean
        git apply lineage.diff
        build_op8t "-Lineage"
        git reset --hard
        
        bclean
        build_op8p "-OOS"
        
        bclean
        git apply lineage.diff
        build_op8p "-Lineage"
        git reset --hard
        
        bclean
        git apply lineage.diff
        build_op8 "-Lineage"
        git reset --hard
        
        bclean
        build_op8 "-OOS"
        
    elif [ ${device} == "op8" ]
    then
        clean
        build_op8
    elif [ ${device} == "op8p" ]
    then
        clean
        build_op8p
    elif [ ${device} == "op8t" ]
    then
        clean
        build_op8t
    fi
fi

脚本要求的目录结构如下:

workspace
├── AnyKernel3
├── android_kernel_oneplus_sm8250
│   ├── horizon_build.sh
│   ├── KernelSU
├── clang
│   ├── bin
│   │   ├── clang

workspace 的目录名称是无所谓的,只需要确保 AnyKernel3 和 clang 在内核源码文件夹的同级目录下即可,编译脚本则放在内核源码文件夹中。

cd workspace/android_kernel_oneplus_sm8250

然后在内核源码文件夹中执行命令即可:

# 编译所有机型/系统的版本
./horizon_build.sh
# 编译所有机型/系统的版本(干净编译)
./horizon_build.sh -c

# 编译一加 8 的版本(仅氢氧)
./horizon_build.sh op8
# 编译一加 8 的版本(仅氢氧)(干净编译)
./horizon_build.sh op8 -c

# 编译一加 8P 的版本(仅氢氧)
./horizon_build.sh op8p
# 编译一加 8P 的版本(仅氢氧)(干净编译)
./horizon_build.sh op8p -c

# 编译一加 8T 的版本(仅氢氧)
./horizon_build.sh op8t
# 编译一加 8T 的版本(仅氢氧)(干净编译)
./horizon_build.sh op8t -c

最后文件输出到目录/workspace/(op8t)Horizon-Kernel-{version}.zip

刷入前先用TWRP刷入官方Boot,之后无需重启直接刷入内核刷机包即可

如果感觉麻烦也可以使用乐享网编译的直接刷入即可

© 版权声明
THE END
喜欢就支持以下吧
点赞3 分享
共2条

请登录后发表评论