shell bypass 403
/** @file lsm_common.c @brief LSM based hooks @details Copyright (c) 2024 Acronis International GmbH @author Bruce Wang ([email protected]) @since $Id: $ */ #include "debug.h" #include "ftrace_hooks/ftrace_events.h" #include "lsm_common.h" #include "syscall_common.h" #include "transport_protocol.h" #include <linux/version.h> #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 8, 0) #include <asm/ia32_unistd.h> // for ia32_sys_call_table '__NR_ia32_*' system call function indices #endif #include <linux/fsnotify.h> #ifdef KERNEL_MOCK #include <stdlib.h> #endif static bool lsm_available(void) { #ifndef CONFIG_SECURITY return false; #endif #ifdef KERNEL_MOCK if (getenv("KERNEL_MOCK_BLOCK_LSM")) return false; #endif return true; } static bool security_path_available(void) { #ifdef KERNEL_MOCK if (getenv("KERNEL_MOCK_BLOCK_LSM_PATH")) return false; #endif #ifdef CONFIG_SECURITY_PATH return true; #else return false; #endif } static bool g_lsm_hooks_registered = false; int lsm_hooks_init(void) { if (lsm_available()) { if (register_lsm_pre_events()) { return -1; } else { g_lsm_hooks_registered = true; } } else { WPRINTF("lsm is not available"); } IPRINTF(""); return 0; } void lsm_hooks_exit(void) { if (lsm_available() && g_lsm_hooks_registered) { unregister_lsm_pre_events(); g_lsm_hooks_registered = false; IPRINTF(""); } } bool lsm_registered(void) { return g_lsm_hooks_registered; } bool lsm_has_open(void) { return lsm_registered() && ftrace_post_event_have(FTRACE_POST_EVENT_FSNOTIFY); } bool lsm_has_security_path(void) { return lsm_registered() && security_path_available(); } bool lsm_has_complex_post(void) { return lsm_registered() && security_path_available() && ftrace_post_event_have(FTRACE_POST_EVENT_FSNOTIFY); } uint64_t wanted_fsnotify_events(void) { uint64_t common_flags = FS_DELETE_SELF | FS_DELETE | FS_OPEN | FS_MODIFY; if (!g_lsm_hooks_registered) { return common_flags; } if (lsm_has_complex_post()) { return FS_CREATE | FS_MOVE_SELF | common_flags; } else { return FS_CREATE | common_flags; } } #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 8, 0) #define SYS_CALL_NR(syscall) __NR_##syscall #define IA32_SYS_CALL_NR(syscall) __NR_ia32_##syscall static const int k_syscalls_fs_replaced[] = { SYS_CALL_NR(open), SYS_CALL_NR(openat), SYS_CALL_NR(creat), SYS_CALL_NR(close), }; static const int k_syscalls_fs_ia32_replaced[] = { IA32_SYS_CALL_NR(open), IA32_SYS_CALL_NR(openat), IA32_SYS_CALL_NR(creat), IA32_SYS_CALL_NR(close), }; #ifdef CONFIG_SECURITY_PATH static const int k_syscalls_fs_path_replaced[] = { SYS_CALL_NR(rename), SYS_CALL_NR(renameat), SYS_CALL_NR(renameat2), SYS_CALL_NR(unlink), SYS_CALL_NR(unlinkat), }; static const int k_syscalls_fs_path_ia32_replaced[] = { IA32_SYS_CALL_NR(rename), IA32_SYS_CALL_NR(renameat), IA32_SYS_CALL_NR(renameat2), IA32_SYS_CALL_NR(unlink), IA32_SYS_CALL_NR(unlinkat), }; #endif static const int k_syscalls_rw_replaced[] = { SYS_CALL_NR(read), SYS_CALL_NR(pread64), SYS_CALL_NR(readv), SYS_CALL_NR(preadv), SYS_CALL_NR(preadv2), SYS_CALL_NR(write), SYS_CALL_NR(pwrite64), SYS_CALL_NR(writev), SYS_CALL_NR(pwritev), SYS_CALL_NR(pwritev2), }; static const int k_syscalls_ia32_rw_replaced[] = { IA32_SYS_CALL_NR(read), IA32_SYS_CALL_NR(pread64), IA32_SYS_CALL_NR(readv), IA32_SYS_CALL_NR(preadv), IA32_SYS_CALL_NR(preadv2), IA32_SYS_CALL_NR(write), IA32_SYS_CALL_NR(pwrite64), IA32_SYS_CALL_NR(writev), IA32_SYS_CALL_NR(pwritev), IA32_SYS_CALL_NR(pwritev2), }; static bool syscall_listed_in(const int *syscalls, size_t size, int syscall_nr) { size_t i; for (i = 0; i < size; i++) { if (syscalls[i] == syscall_nr) { return true; } } return false; } bool syscall_replaced_by_lsm(int syscall_nr, bool ia32) { { bool fs_syscall; if (ia32) { fs_syscall = syscall_listed_in(k_syscalls_fs_ia32_replaced, ARRAY_SIZE(k_syscalls_fs_ia32_replaced), syscall_nr); } else { fs_syscall = syscall_listed_in(k_syscalls_fs_replaced, ARRAY_SIZE(k_syscalls_fs_replaced), syscall_nr); } if (fs_syscall) { // fs syscalls are replaced by LSM hooks + fsnotify if (!g_lsm_hooks_registered) { return false; } if (!ftrace_post_event_have(FTRACE_POST_EVENT_FSNOTIFY)) { return false; } return true; } } #ifdef CONFIG_SECURITY_PATH if (lsm_has_security_path()) { bool fs_path_syscall; if (ia32) { fs_path_syscall = syscall_listed_in(k_syscalls_fs_path_ia32_replaced, ARRAY_SIZE(k_syscalls_fs_path_ia32_replaced), syscall_nr); } else { fs_path_syscall = syscall_listed_in(k_syscalls_fs_path_replaced, ARRAY_SIZE(k_syscalls_fs_path_replaced), syscall_nr); } if (fs_path_syscall) { // fs syscalls are replaced by LSM hooks + fsnotify if (!g_lsm_hooks_registered) { return false; } if (!ftrace_post_event_have(FTRACE_POST_EVENT_FSNOTIFY)) { return false; } return true; } } #endif { bool rw_syscall; if (ia32) { rw_syscall = syscall_listed_in(k_syscalls_ia32_rw_replaced, ARRAY_SIZE(k_syscalls_ia32_rw_replaced), syscall_nr); } else { rw_syscall = syscall_listed_in(k_syscalls_rw_replaced, ARRAY_SIZE(k_syscalls_rw_replaced), syscall_nr); } if (rw_syscall) { // rw syscall hooks are replaced by rw_verify_area (and maybe clone hooks in the future) if (!ftrace_post_event_have(FTRACE_PRE_EVENT_RW_VERIFY_AREA)) { return false; } return true; } } // Unknown syscall, assuming not replaced return false; } #endif