跳到主要内容

Lua-LSM Risc-V

编译 Busybox

先安装 toolchains 参考 xv6 实验手册

sudo pacman -S riscv64-linux-gnu-binutils riscv64-linux-gnu-gcc riscv64-linux-gnu-gdb qemu-emulators-full bc git base-devel

clone 下来 busybox 代码库,开始编译

git clone --depth=1 https://github.com/mirror/busybox.git
cd busybox
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- defconfig
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- menuconfig

Settings -> Build Options -> Build static binary (no shared libs),按空格键选中。还有取消编译 tc(我的系统上编译 tc 会报错,mailing list 里也有类似的报告)。

# Compile using all available CPU cores
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- -j"$(nproc)"

# Install into a target directory named 'rootfs'
rm -rf ../rootfs
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- CONFIG_PREFIX=../rootfs install

cd ../rootfs

# Create a directory tree
mkdir -p dev proc sys etc root

# Write a simple init script
cat > init << "EOF"
#!/bin/sh

# Mount essential pseudo-filesystems
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs none /dev

echo "=== Minimal RISC-V Kernel Dev Environment Ready ==="

# Launch an interactive shell (manages job control)
exec setsid cttyhack /bin/sh
EOF
# Make the init script executable
chmod +x init

# Pack into a CPIO archive
find . | cpio -o -H newc | gzip > /tmp/lua-lsm-initramfs.cpio.gz

编译

你当前环境已经装好了交叉编译器和 QEMU。建议使用独立输出目录,避免在源码树中产生大量构建文件。

1. 生成配置

在仓库根目录执行:

mkdir -p /tmp/lua-lsm-riscv-build

make O=/tmp/lua-lsm-riscv-build \
ARCH=riscv \
CROSS_COMPILE=riscv64-linux-gnu- \
defconfig

启用 Lua-LSM:

scripts/config \
--file /tmp/lua-lsm-riscv-build/.config \
--enable SECURITY \
--enable SECURITYFS \
--enable LUA \
--enable SECURITY_LUA_LSM

确保 Lua LSM 在启动顺序中。先检查当前配置:

grep '^CONFIG_LSM=' /tmp/lua-lsm-riscv-build/.config

如果结果里没有 lua,可以设置为:

scripts/config \
--file /tmp/lua-lsm-riscv-build/.config \
--set-str LSM "landlock,lockdown,yama,integrity,apparmor,lua,bpf"

最后解析配置依赖:

make O=/tmp/lua-lsm-riscv-build \
ARCH=riscv \
CROSS_COMPILE=riscv64-linux-gnu- \
olddefconfig

确认关键配置:

grep -E '^CONFIG_(ARCH_HAS_SETJMP|ARCH_SETJMP|HAS_LUA|LUA|SECURITY_LUA_LSM|LSM)=' \
/tmp/lua-lsm-riscv-build/.config

2. 编译内核

仓库的构建脚本硬编码调用了 gsed。如果系统没有 gsed,先建立一个临时兼容命令:

mkdir -p /tmp/lua-lsm-tools
ln -sf /usr/bin/sed /tmp/lua-lsm-tools/gsed

另外如果编译的是 x86 架构,需要改一下:

diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index e5a2b9a91..d93107697 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -287,16 +287,16 @@ static const char *sym_name(const char *sym_strtab, Elf_Sym *sym)
return name;
}

-#if BYTE_ORDER == LITTLE_ENDIAN
+#if __BYTE_ORDER == __LITTLE_ENDIAN
# define le16_to_cpu(val) (val)
# define le32_to_cpu(val) (val)
# define le64_to_cpu(val) (val)
-#endif
-
-#if BYTE_ORDER == BIG_ENDIAN
+#elif __BYTE_ORDER == __BIG_ENDIAN
# define le16_to_cpu(val) bswap_16(val)
# define le32_to_cpu(val) bswap_32(val)
# define le64_to_cpu(val) bswap_64(val)
+#else
+# error "Unknown byte order"
#endif

static uint16_t elf16_to_cpu(uint16_t val)

编译:

PATH=/tmp/lua-lsm-tools:$PATH \
make O=/tmp/lua-lsm-riscv-build \
ARCH=riscv \
CROSS_COMPILE=riscv64-linux-gnu- \
-j"$(nproc)" \
Image

生成文件:

/tmp/lua-lsm-riscv-build/arch/riscv/boot/Image
/tmp/lua-lsm-riscv-build/vmlinux

确认架构:

file /tmp/lua-lsm-riscv-build/vmlinux

3. 只运行 setjmp KUnit 测试

启用测试:

scripts/config \
--file /tmp/lua-lsm-riscv-build/.config \
--enable KUNIT \
--enable RISCV_SETJMP_KUNIT

make O=/tmp/lua-lsm-riscv-build \
ARCH=riscv \
CROSS_COMPILE=riscv64-linux-gnu- \
olddefconfig

PATH=/tmp/lua-lsm-tools:$PATH \
make O=/tmp/lua-lsm-riscv-build \
ARCH=riscv \
CROSS_COMPILE=riscv64-linux-gnu- \
-j"$(nproc)" \
Image

用 QEMU 启动:

qemu-system-riscv64 \
-machine virt \
-m 1G \
-smp 2 \
-nographic \
-kernel /tmp/lua-lsm-riscv-build/arch/riscv/boot/Image \
-append "console=ttyS0 earlycon=sbi kunit.filter_glob=riscv_setjmp*"

预期看到:

# Subtest: riscv_setjmp
ok 1 setjmp_initial_return_test
ok 2 setjmp_zero_value_test
ok 3 setjmp_cross_stack_test
# riscv_setjmp: pass:3 fail:0 skip:0 total:3

测试之后会出现:

VFS: Unable to mount root fs

这是因为没有提供 rootfs。KUnit 已经在挂载 rootfs 前运行完毕,所以不影响测试结果。

Ctrl-A,松开后再按 X,可退出 QEMU。

4. 启动到可交互 Shell

启动:

qemu-system-riscv64 \
-machine virt \
-m 1G \
-smp 2 \
-nographic \
-kernel /tmp/lua-lsm-riscv-build/arch/riscv/boot/Image \
-initrd /tmp/lua-lsm-initramfs.cpio.gz \
-append "console=ttyS0 earlycon=sbi rdinit=/init lsm=landlock,lockdown,yama,integrity,apparmor,lua,bpf"

进入 shell 后创建挂载点并挂载:

mkdir -p /sys/kernel/security
mount -t securityfs securityfs /sys/kernel/security

/sys/kernel/security 不是普通 sysfs 目录,它是 securityfs 的挂载点

检查:

mount
ls -la /sys/kernel/security
cat /sys/kernel/security/lsm

/sys/kernel/security/lsm 应该列出当前实际启用的 LSM,例如:

capability,landlock,lockdown,yama,...

检查:

cat /sys/kernel/security/lua/version
cat /sys/kernel/security/lua/modules

加载策略:

cat /policy.lua > /sys/kernel/security/lua/register
cat /sys/kernel/security/lua/modules

如果只是验证 RISC-V setjmp/longjmp,做到第 3 部分即可;如果要验证 Lua 策略动态加载、执行与错误回退,则必须准备第 4 部分的 RISC-V initramfs。