Adding KernelSU Support to Android 4.9 Kernel

Adding KernelSU Support to Android 4.9 Kernel

KaguraiYoRoy
27-12-2024 / 0 Comments / 1,090 Views / Checking if indexed by search engines...

Introduction

KernelSU has been available for a while. Officially, it only supports GKI kernels, but the project provides integration guidelines for non-GKI kernels. The Xiaomi Mi 8 Pro, which I use, is based on the Android 4.9 kernel. Testing showed that directly using KernelSU's integration script caused issues, so I'm documenting the process here.
Special thanks to: Developer Tomsec for providing the 4.9 kernel fix.

Prerequisites

Let's Start

Configuring the build environment won't be detailed here. You can integrate it directly into the boot.img when building the ROM, or compile it separately as an AnyKernel3 flashable zip. This guide uses the AnyKernel3 approach.

Download Kernel Source Code and Cross-Compiler

git clone https://github.com/KaguraiYoRoy/android_kernel_xiaomi_sdm845 -b lineage-20 sdm845 #Kernel source
git clone https://android.googlesource.com/platform/prebuilts/clang/host/linux-x86 --depth=1 -b android-13.0.0_r43 clang #Clang
git clone https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9 -b android-10.0.0_r32 --depth=1 #aarch64 GCC
git clone https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9 -b android-10.0.0_r32 --depth=1 #arm GCC

Different kernels might require different cross-compilers. Please adjust according to your specific case.

Modify Kernel Source

Refer to the following two commits:

commit b5853fb7cefdc8a2e160cb73512dc6b51569fa66
Author: OnlyTomInSecond <q2781273965@gmail.com>
Date:   Wed Apr 5 11:05:12 2023 +0800

    kernelsu: allow init exec ksud under nosuid

    Change-Id: I8aa6e6d3cbee1addd5da9bb48b4c08ce91f9db81

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 4abba0e1674d..693f2ac03352 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2320,7 +2320,10 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm,
 {
        int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS);
        int nosuid = !mnt_may_suid(bprm->file->f_path.mnt);
-       int rc;
+       int rc, error;
+    static u32 ksu_sid;
+       char *secdata;
+    u32 seclen;

        if (!nnp && !nosuid)
      return 0; /* neither NNP nor nosuid */
@@ -2328,6 +2331,18 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm,
        if (new_tsec->sid == old_tsec->sid)
      return 0; /* No change in credentials */

+    if(!ksu_sid){
+     security_secctx_to_secid("u:r:su:s0", strlen("u:r:su:s0"), &ksu_sid);
+       }
+       error = security_secid_to_secctx(old_tsec->sid, &secdata, &seclen);
+       if (!error) {
+     rc = strcmp("u:r:init:s0",secdata);
+     security_release_secctx(secdata, seclen);
+     if(rc == 0 && new_tsec->sid == ksu_sid){
+   return 0;
+     }
+       }
+
        /*
         * The only transitions we permit under NNP or nosuid
         * are transitions to bounded SIDs, i.e. SIDs that are
commit 8bfe4d4de25650505798cba0a5a20db4b2ab7dd6
Author: OnlyTomInSecond <q2781273965@gmail.com>
Date:   Thu Oct 19 17:55:23 2023 +0800

    Kernelsu: add path_umount implementation.

    Change-Id: I3b0273e9857c51cc3215afab0d2cebe0dff38cfb

diff --git a/fs/namespace.c b/fs/namespace.c
index 21fd423b19cf..219a501337b0 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1711,6 +1711,38 @@ static inline bool may_mandlock(void)
 }
 #endif

+static int can_umount(const struct path *path, int flags)
+{
+       struct mount *mnt = real_mount(path->mnt);
+
+       if (!may_mount())
+     return -EPERM;
+       if (path->dentry != path->mnt->mnt_root)
+     return -EINVAL;
+       if (!check_mnt(mnt))
+     return -EINVAL;
+       if (mnt->mnt.mnt_flags & MNT_LOCKED) /* Check optimistically */
+     return -EINVAL;
+       if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN))
+     return -EPERM;
+       return 0;
+}
+
+// caller is responsible for flags being sane
+int path_umount(struct path *path, int flags)
+{
+       struct mount *mnt = real_mount(path->mnt);
+       int ret;
+
+       ret = can_umount(path, flags);
+       if (!ret)
+     ret = do_umount(mnt, flags);
+
+       /* we mustn't call path_put() as that would clear mnt_expiry_mark */
+       dput(path->dentry);
+       mntput_no_expire(mnt);
+       return ret;
+}
 /*
  * Now umount can handle mount points as well as block devices.
  * This is important for filesystems which use unnamed block devices.

Solution Source: Tomsec

Enable KPROBE Support

Open your kernel's defconfig file and add the following three lines:

CONFIG_KPROBES=y
CONFIG_HAVE_KPROBES=y
CONFIG_KPROBE_EVENTS=y

Integrate KernelSU

This step is the same as the official ksu guide. Execute the following command in the kernel root directory:

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

Write the AnyKernel3 Script

Download AnyKernel3 and modify anykernel.sh according to the README. You can refer to my repository for modifications:

Compile the Kernel

It's recommended to refer to online tutorials for this step, as compilation parameter settings can vary for different kernels.
I've packaged the compilation process into a shell script for reference:

#!/bin/bash
ARCH="arm64"
CLANG_DIR="$WORKSPACE/clang/clang-r450784d" #Clang directory
CC="$CLANG_DIR/bin/clang"
export PATH="$CLANG_DIR/bin:$PATH"
OUT_DIR="./out"
CLANG_TRIPLE="aarch64-linux-gnu-"
CROSS_COMPILE="$WORKSPACE/aarch64-linux-android-4.9/bin/aarch64-linux-androidkernel-" #aarch64 GCC
CROSS_COMPILE_ARM32="$WORKSPACE/arm-linux-androideabi-4.9/bin/arm-linux-androidkernel-" #arm GCC
CC_ADDITION_FLAGS="AR=llvm-ar NM=llvm-nm OBJCOPY=llvm-objcopy OBJDUMP=llvm-objdump STRIP=llvm-strip LLVM_IAS=1 LLVM=1 LD=ld.lld"
ANYKERNEL_DIR="$WORKSPACE/AnyKernel3" #Location of your prepared AnyKernel3 directory

THREAD=$(nproc --all)

args="-j$THREAD O=$OUT_DIR ARCH=$ARCH CROSS_COMPILE=$CROSS_COMPILE CROSS_COMPILE_ARM32=$CROSS_COMPILE_ARM32 CC=$CC CLANG_TRIPLE=$CLANG_TRIPLE $CC_ADDITION_FLAGS"

### Compile Kernel ###
echo "[+]Args: $args"
echo "[+}Generate .config"
make equuleus_user_defconfig $args #Here 'equuleus_user_defconfig' is the defconfig file for the equuleus kernel. Replace it with your kernel's config file name.
echo "[+]Begin Build"
make $args
### Compilation Complete ###

### Create AnyKernel3 Zip ###
cd $WORKSPACE/sdm845/KernelSU
KSU_VERSION='v0.9.5'
TARGET_KERNEL="Mi8Pro-LineageKernel-KernelSU$KSU_VERSION" #Kernel filename
echo "[+]KernelSU Version: $KSU_VERSION"
echo "[+]Target file: $TARGET_KERNEL"
cd $WORKSPACE/AnyKernel3
cp $WORKSPACE/sdm845/out/arch/arm64/boot/Image .
cp $WORKSPACE/sdm845/out/arch/arm64/boot/Image.gz .
cp $WORKSPACE/sdm845/out/arch/arm64/boot/Image.gz-dtb .
OUTPUT_FILE=${TARGET_KERNEL}-$(date +"%y.%m.%d").zip
echo "[+]Output: $OUTPUT_FILE"
zip -r $OUTPUT_FILE *
mv $OUTPUT_FILE $WORKSPACE

Flashing

Use a recovery like TWRP to flash the zip.

Automatically Compile the Kernel using GitHub Actions

Refer to this YAML file for workflow setup: https://github.com/iYoRoy-AOSP-Institute/AnyKernel3-equuleus/blob/13/.github/workflows/build.yml

3

Comments (0)

Cancel