Compare commits

...

4 Commits

Author SHA1 Message Date
Leonmmcoset
a4f2c8eb89 我tm跟个sb似的 2026-04-19 20:34:59 +08:00
Leonmmcoset
1a3510d8d9 USC安全系统 2026-04-19 20:21:12 +08:00
Leonmmcoset
c21c5b327e 代码分类 2026-04-19 16:42:27 +08:00
Leonmmcoset
739be1d7f7 更新Wine+更新menuconfig 2026-04-19 16:07:44 +08:00
49 changed files with 2280 additions and 234 deletions

1
.gitignore vendored
View File

@@ -2,7 +2,6 @@ build/
build-cmake*/ build-cmake*/
*.iso *.iso
*.tar *.tar
limine/
# CMake generated files # CMake generated files
CMakeCache.txt CMakeCache.txt

View File

@@ -125,10 +125,27 @@ if(EXISTS "${CLEONOS_MENUCONFIG_CMAKE}")
endif() endif()
function(cl_set_bool_cache VAR_NAME DEFAULT_VALUE DOC_TEXT) function(cl_set_bool_cache VAR_NAME DEFAULT_VALUE DOC_TEXT)
if(NOT DEFINED ${VAR_NAME}) set(_raw_value "")
set(_has_value OFF)
if(DEFINED ${VAR_NAME})
set(_raw_value "${${VAR_NAME}}")
set(_has_value ON)
elseif(DEFINED ${VAR_NAME}_IS_ENABLED)
set(_raw_value "${${VAR_NAME}_IS_ENABLED}")
set(_has_value ON)
endif()
if(NOT _has_value)
set(${VAR_NAME} ${DEFAULT_VALUE} CACHE BOOL "${DOC_TEXT}") set(${VAR_NAME} ${DEFAULT_VALUE} CACHE BOOL "${DOC_TEXT}")
else() else()
set(${VAR_NAME} ${${VAR_NAME}} CACHE BOOL "${DOC_TEXT}" FORCE) string(TOUPPER "${_raw_value}" _raw_upper)
if(_raw_upper STREQUAL "Y" OR _raw_upper STREQUAL "M" OR _raw_upper STREQUAL "ON" OR _raw_upper STREQUAL "TRUE" OR _raw_upper STREQUAL "1")
set(_bool_value ON)
else()
set(_bool_value OFF)
endif()
set(${VAR_NAME} ${_bool_value} CACHE BOOL "${DOC_TEXT}" FORCE)
endif() endif()
endfunction() endfunction()
@@ -164,6 +181,19 @@ cl_set_bool_cache(CLEONOS_CLKS_ENABLE_TTY_READY_LOG ON "Print TTY ready logs")
cl_set_bool_cache(CLEONOS_CLKS_ENABLE_IDLE_DEBUG_LOG ON "Print idle loop debug log") cl_set_bool_cache(CLEONOS_CLKS_ENABLE_IDLE_DEBUG_LOG ON "Print idle loop debug log")
cl_set_bool_cache(CLEONOS_CLKS_ENABLE_PROCFS ON "Enable virtual /proc procfs syscall layer") cl_set_bool_cache(CLEONOS_CLKS_ENABLE_PROCFS ON "Enable virtual /proc procfs syscall layer")
cl_set_bool_cache(CLEONOS_CLKS_ENABLE_EXEC_SERIAL_LOG ON "Enable EXEC info logs on serial output") cl_set_bool_cache(CLEONOS_CLKS_ENABLE_EXEC_SERIAL_LOG ON "Enable EXEC info logs on serial output")
cl_set_bool_cache(CLEONOS_CLKS_ENABLE_USC ON "Enable UserSafeController dangerous syscall confirmations")
cl_set_bool_cache(CLEONOS_CLKS_ENABLE_USC_SC_FS_MKDIR ON "USC intercept policy: FS_MKDIR")
cl_set_bool_cache(CLEONOS_CLKS_ENABLE_USC_SC_FS_WRITE ON "USC intercept policy: FS_WRITE")
cl_set_bool_cache(CLEONOS_CLKS_ENABLE_USC_SC_FS_APPEND ON "USC intercept policy: FS_APPEND")
cl_set_bool_cache(CLEONOS_CLKS_ENABLE_USC_SC_FS_REMOVE ON "USC intercept policy: FS_REMOVE")
cl_set_bool_cache(CLEONOS_CLKS_ENABLE_USC_SC_EXEC_PATH ON "USC intercept policy: EXEC_PATH")
cl_set_bool_cache(CLEONOS_CLKS_ENABLE_USC_SC_EXEC_PATHV ON "USC intercept policy: EXEC_PATHV")
cl_set_bool_cache(CLEONOS_CLKS_ENABLE_USC_SC_EXEC_PATHV_IO ON "USC intercept policy: EXEC_PATHV_IO")
cl_set_bool_cache(CLEONOS_CLKS_ENABLE_USC_SC_SPAWN_PATH ON "USC intercept policy: SPAWN_PATH")
cl_set_bool_cache(CLEONOS_CLKS_ENABLE_USC_SC_SPAWN_PATHV ON "USC intercept policy: SPAWN_PATHV")
cl_set_bool_cache(CLEONOS_CLKS_ENABLE_USC_SC_PROC_KILL ON "USC intercept policy: PROC_KILL")
cl_set_bool_cache(CLEONOS_CLKS_ENABLE_USC_SC_SHUTDOWN ON "USC intercept policy: SHUTDOWN")
cl_set_bool_cache(CLEONOS_CLKS_ENABLE_USC_SC_RESTART ON "USC intercept policy: RESTART")
cl_set_bool_cache(CLEONOS_CLKS_ENABLE_KBD_TTY_SWITCH_HOTKEY ON "Enable ALT+F1..F4 TTY switch hotkey") cl_set_bool_cache(CLEONOS_CLKS_ENABLE_KBD_TTY_SWITCH_HOTKEY ON "Enable ALT+F1..F4 TTY switch hotkey")
cl_set_bool_cache(CLEONOS_CLKS_ENABLE_KBD_CTRL_SHORTCUTS ON "Enable Ctrl+A/C/V keyboard shortcuts") cl_set_bool_cache(CLEONOS_CLKS_ENABLE_KBD_CTRL_SHORTCUTS ON "Enable Ctrl+A/C/V keyboard shortcuts")
cl_set_bool_cache(CLEONOS_CLKS_ENABLE_KBD_FORCE_STOP_HOTKEY ON "Enable Ctrl+Alt+C force-stop hotkey") cl_set_bool_cache(CLEONOS_CLKS_ENABLE_KBD_FORCE_STOP_HOTKEY ON "Enable Ctrl+Alt+C force-stop hotkey")
@@ -197,6 +227,19 @@ cl_bool_to_int(CLEONOS_CLKS_ENABLE_TTY_READY_LOG CLKS_CFG_TTY_READY_LOG_INT)
cl_bool_to_int(CLEONOS_CLKS_ENABLE_IDLE_DEBUG_LOG CLKS_CFG_IDLE_DEBUG_LOG_INT) cl_bool_to_int(CLEONOS_CLKS_ENABLE_IDLE_DEBUG_LOG CLKS_CFG_IDLE_DEBUG_LOG_INT)
cl_bool_to_int(CLEONOS_CLKS_ENABLE_PROCFS CLKS_CFG_PROCFS_INT) cl_bool_to_int(CLEONOS_CLKS_ENABLE_PROCFS CLKS_CFG_PROCFS_INT)
cl_bool_to_int(CLEONOS_CLKS_ENABLE_EXEC_SERIAL_LOG CLKS_CFG_EXEC_SERIAL_LOG_INT) cl_bool_to_int(CLEONOS_CLKS_ENABLE_EXEC_SERIAL_LOG CLKS_CFG_EXEC_SERIAL_LOG_INT)
cl_bool_to_int(CLEONOS_CLKS_ENABLE_USC CLKS_CFG_USC_INT)
cl_bool_to_int(CLEONOS_CLKS_ENABLE_USC_SC_FS_MKDIR CLKS_CFG_USC_SC_FS_MKDIR_INT)
cl_bool_to_int(CLEONOS_CLKS_ENABLE_USC_SC_FS_WRITE CLKS_CFG_USC_SC_FS_WRITE_INT)
cl_bool_to_int(CLEONOS_CLKS_ENABLE_USC_SC_FS_APPEND CLKS_CFG_USC_SC_FS_APPEND_INT)
cl_bool_to_int(CLEONOS_CLKS_ENABLE_USC_SC_FS_REMOVE CLKS_CFG_USC_SC_FS_REMOVE_INT)
cl_bool_to_int(CLEONOS_CLKS_ENABLE_USC_SC_EXEC_PATH CLKS_CFG_USC_SC_EXEC_PATH_INT)
cl_bool_to_int(CLEONOS_CLKS_ENABLE_USC_SC_EXEC_PATHV CLKS_CFG_USC_SC_EXEC_PATHV_INT)
cl_bool_to_int(CLEONOS_CLKS_ENABLE_USC_SC_EXEC_PATHV_IO CLKS_CFG_USC_SC_EXEC_PATHV_IO_INT)
cl_bool_to_int(CLEONOS_CLKS_ENABLE_USC_SC_SPAWN_PATH CLKS_CFG_USC_SC_SPAWN_PATH_INT)
cl_bool_to_int(CLEONOS_CLKS_ENABLE_USC_SC_SPAWN_PATHV CLKS_CFG_USC_SC_SPAWN_PATHV_INT)
cl_bool_to_int(CLEONOS_CLKS_ENABLE_USC_SC_PROC_KILL CLKS_CFG_USC_SC_PROC_KILL_INT)
cl_bool_to_int(CLEONOS_CLKS_ENABLE_USC_SC_SHUTDOWN CLKS_CFG_USC_SC_SHUTDOWN_INT)
cl_bool_to_int(CLEONOS_CLKS_ENABLE_USC_SC_RESTART CLKS_CFG_USC_SC_RESTART_INT)
cl_bool_to_int(CLEONOS_CLKS_ENABLE_KBD_TTY_SWITCH_HOTKEY CLKS_CFG_KBD_TTY_SWITCH_HOTKEY_INT) cl_bool_to_int(CLEONOS_CLKS_ENABLE_KBD_TTY_SWITCH_HOTKEY CLKS_CFG_KBD_TTY_SWITCH_HOTKEY_INT)
cl_bool_to_int(CLEONOS_CLKS_ENABLE_KBD_CTRL_SHORTCUTS CLKS_CFG_KBD_CTRL_SHORTCUTS_INT) cl_bool_to_int(CLEONOS_CLKS_ENABLE_KBD_CTRL_SHORTCUTS CLKS_CFG_KBD_CTRL_SHORTCUTS_INT)
cl_bool_to_int(CLEONOS_CLKS_ENABLE_KBD_FORCE_STOP_HOTKEY CLKS_CFG_KBD_FORCE_STOP_HOTKEY_INT) cl_bool_to_int(CLEONOS_CLKS_ENABLE_KBD_FORCE_STOP_HOTKEY CLKS_CFG_KBD_FORCE_STOP_HOTKEY_INT)
@@ -244,6 +287,19 @@ set(ARCH_CFLAGS
"-DCLKS_CFG_IDLE_DEBUG_LOG=${CLKS_CFG_IDLE_DEBUG_LOG_INT}" "-DCLKS_CFG_IDLE_DEBUG_LOG=${CLKS_CFG_IDLE_DEBUG_LOG_INT}"
"-DCLKS_CFG_PROCFS=${CLKS_CFG_PROCFS_INT}" "-DCLKS_CFG_PROCFS=${CLKS_CFG_PROCFS_INT}"
"-DCLKS_CFG_EXEC_SERIAL_LOG=${CLKS_CFG_EXEC_SERIAL_LOG_INT}" "-DCLKS_CFG_EXEC_SERIAL_LOG=${CLKS_CFG_EXEC_SERIAL_LOG_INT}"
"-DCLKS_CFG_USC=${CLKS_CFG_USC_INT}"
"-DCLKS_CFG_USC_SC_FS_MKDIR=${CLKS_CFG_USC_SC_FS_MKDIR_INT}"
"-DCLKS_CFG_USC_SC_FS_WRITE=${CLKS_CFG_USC_SC_FS_WRITE_INT}"
"-DCLKS_CFG_USC_SC_FS_APPEND=${CLKS_CFG_USC_SC_FS_APPEND_INT}"
"-DCLKS_CFG_USC_SC_FS_REMOVE=${CLKS_CFG_USC_SC_FS_REMOVE_INT}"
"-DCLKS_CFG_USC_SC_EXEC_PATH=${CLKS_CFG_USC_SC_EXEC_PATH_INT}"
"-DCLKS_CFG_USC_SC_EXEC_PATHV=${CLKS_CFG_USC_SC_EXEC_PATHV_INT}"
"-DCLKS_CFG_USC_SC_EXEC_PATHV_IO=${CLKS_CFG_USC_SC_EXEC_PATHV_IO_INT}"
"-DCLKS_CFG_USC_SC_SPAWN_PATH=${CLKS_CFG_USC_SC_SPAWN_PATH_INT}"
"-DCLKS_CFG_USC_SC_SPAWN_PATHV=${CLKS_CFG_USC_SC_SPAWN_PATHV_INT}"
"-DCLKS_CFG_USC_SC_PROC_KILL=${CLKS_CFG_USC_SC_PROC_KILL_INT}"
"-DCLKS_CFG_USC_SC_SHUTDOWN=${CLKS_CFG_USC_SC_SHUTDOWN_INT}"
"-DCLKS_CFG_USC_SC_RESTART=${CLKS_CFG_USC_SC_RESTART_INT}"
"-DCLKS_CFG_KBD_TTY_SWITCH_HOTKEY=${CLKS_CFG_KBD_TTY_SWITCH_HOTKEY_INT}" "-DCLKS_CFG_KBD_TTY_SWITCH_HOTKEY=${CLKS_CFG_KBD_TTY_SWITCH_HOTKEY_INT}"
"-DCLKS_CFG_KBD_CTRL_SHORTCUTS=${CLKS_CFG_KBD_CTRL_SHORTCUTS_INT}" "-DCLKS_CFG_KBD_CTRL_SHORTCUTS=${CLKS_CFG_KBD_CTRL_SHORTCUTS_INT}"
"-DCLKS_CFG_KBD_FORCE_STOP_HOTKEY=${CLKS_CFG_KBD_FORCE_STOP_HOTKEY_INT}" "-DCLKS_CFG_KBD_FORCE_STOP_HOTKEY=${CLKS_CFG_KBD_FORCE_STOP_HOTKEY_INT}"
@@ -303,8 +359,6 @@ endif()
set(KERNEL_SOURCE_DIRS set(KERNEL_SOURCE_DIRS
"${CMAKE_SOURCE_DIR}/clks/kernel" "${CMAKE_SOURCE_DIR}/clks/kernel"
"${CMAKE_SOURCE_DIR}/clks/lib"
"${CMAKE_SOURCE_DIR}/clks/drivers"
"${CMAKE_SOURCE_DIR}/clks/arch/${CLKS_ARCH}" "${CMAKE_SOURCE_DIR}/clks/arch/${CLKS_ARCH}"
) )
@@ -329,6 +383,15 @@ list(REMOVE_DUPLICATES ASM_SOURCES)
list(SORT C_SOURCES) list(SORT C_SOURCES)
list(SORT ASM_SOURCES) list(SORT ASM_SOURCES)
set(CLKS_BOOT_LIMINE_SOURCE "clks/kernel/boot/limine/limine_requests.c")
if(EXISTS "${CMAKE_SOURCE_DIR}/${CLKS_BOOT_LIMINE_SOURCE}")
list(APPEND C_SOURCES "${CLKS_BOOT_LIMINE_SOURCE}")
list(REMOVE_DUPLICATES C_SOURCES)
list(SORT C_SOURCES)
else()
cl_log_error("missing required boot source: ${CLKS_BOOT_LIMINE_SOURCE}")
endif()
file(GLOB_RECURSE KERNEL_INC_SOURCES_ABS CONFIGURE_DEPENDS file(GLOB_RECURSE KERNEL_INC_SOURCES_ABS CONFIGURE_DEPENDS
"${CMAKE_SOURCE_DIR}/clks/**/*.inc" "${CMAKE_SOURCE_DIR}/clks/**/*.inc"
) )

View File

@@ -34,11 +34,64 @@
#define CLKS_SYSCALL_KERNEL_ADDR_BASE 0xFFFF800000000000ULL #define CLKS_SYSCALL_KERNEL_ADDR_BASE 0xFFFF800000000000ULL
#define CLKS_SYSCALL_STATS_MAX_ID CLKS_SYSCALL_EXEC_PATHV_IO #define CLKS_SYSCALL_STATS_MAX_ID CLKS_SYSCALL_EXEC_PATHV_IO
#define CLKS_SYSCALL_STATS_RING_SIZE 256U #define CLKS_SYSCALL_STATS_RING_SIZE 256U
#define CLKS_SYSCALL_USC_MAX_ALLOWED_APPS 64U
#ifndef CLKS_CFG_PROCFS #ifndef CLKS_CFG_PROCFS
#define CLKS_CFG_PROCFS 1 #define CLKS_CFG_PROCFS 1
#endif #endif
#ifndef CLKS_CFG_USC
#define CLKS_CFG_USC 1
#endif
#ifndef CLKS_CFG_USC_SC_FS_MKDIR
#define CLKS_CFG_USC_SC_FS_MKDIR 1
#endif
#ifndef CLKS_CFG_USC_SC_FS_WRITE
#define CLKS_CFG_USC_SC_FS_WRITE 1
#endif
#ifndef CLKS_CFG_USC_SC_FS_APPEND
#define CLKS_CFG_USC_SC_FS_APPEND 1
#endif
#ifndef CLKS_CFG_USC_SC_FS_REMOVE
#define CLKS_CFG_USC_SC_FS_REMOVE 1
#endif
#ifndef CLKS_CFG_USC_SC_EXEC_PATH
#define CLKS_CFG_USC_SC_EXEC_PATH 1
#endif
#ifndef CLKS_CFG_USC_SC_EXEC_PATHV
#define CLKS_CFG_USC_SC_EXEC_PATHV 1
#endif
#ifndef CLKS_CFG_USC_SC_EXEC_PATHV_IO
#define CLKS_CFG_USC_SC_EXEC_PATHV_IO 1
#endif
#ifndef CLKS_CFG_USC_SC_SPAWN_PATH
#define CLKS_CFG_USC_SC_SPAWN_PATH 1
#endif
#ifndef CLKS_CFG_USC_SC_SPAWN_PATHV
#define CLKS_CFG_USC_SC_SPAWN_PATHV 1
#endif
#ifndef CLKS_CFG_USC_SC_PROC_KILL
#define CLKS_CFG_USC_SC_PROC_KILL 1
#endif
#ifndef CLKS_CFG_USC_SC_SHUTDOWN
#define CLKS_CFG_USC_SC_SHUTDOWN 1
#endif
#ifndef CLKS_CFG_USC_SC_RESTART
#define CLKS_CFG_USC_SC_RESTART 1
#endif
struct clks_syscall_frame { struct clks_syscall_frame {
u64 rax; u64 rax;
u64 rbx; u64 rbx;
@@ -92,6 +145,10 @@ static u64 clks_syscall_stats_recent_id_count[CLKS_SYSCALL_STATS_MAX_ID + 1ULL];
static u16 clks_syscall_stats_recent_ring[CLKS_SYSCALL_STATS_RING_SIZE]; static u16 clks_syscall_stats_recent_ring[CLKS_SYSCALL_STATS_RING_SIZE];
static u32 clks_syscall_stats_recent_head = 0U; static u32 clks_syscall_stats_recent_head = 0U;
static u32 clks_syscall_stats_recent_size = 0U; static u32 clks_syscall_stats_recent_size = 0U;
#if CLKS_CFG_USC != 0
static clks_bool clks_syscall_usc_allowed_used[CLKS_SYSCALL_USC_MAX_ALLOWED_APPS];
static char clks_syscall_usc_allowed_path[CLKS_SYSCALL_USC_MAX_ALLOWED_APPS][CLKS_EXEC_PROC_PATH_MAX];
#endif
#if defined(CLKS_ARCH_X86_64) #if defined(CLKS_ARCH_X86_64)
static inline void clks_syscall_outb(u16 port, u8 value) { static inline void clks_syscall_outb(u16 port, u8 value) {
@@ -1641,6 +1698,264 @@ static void clks_syscall_serial_write_hex64(u64 value) {
} }
} }
#if CLKS_CFG_USC != 0
static void clks_syscall_usc_sleep_until_input(void) {
#if defined(CLKS_ARCH_X86_64)
u64 flags = 0ULL;
__asm__ volatile("pushfq; popq %0" : "=r"(flags) : : "memory");
if ((flags & (1ULL << 9)) != 0ULL) {
__asm__ volatile("hlt" : : : "memory");
} else {
__asm__ volatile("sti; hlt; cli" : : : "memory");
}
#elif defined(CLKS_ARCH_AARCH64)
clks_cpu_pause();
#endif
}
static const char *clks_syscall_usc_syscall_name(u64 id) {
switch (id) {
case CLKS_SYSCALL_FS_MKDIR:
return "FS_MKDIR";
case CLKS_SYSCALL_FS_WRITE:
return "FS_WRITE";
case CLKS_SYSCALL_FS_APPEND:
return "FS_APPEND";
case CLKS_SYSCALL_FS_REMOVE:
return "FS_REMOVE";
case CLKS_SYSCALL_EXEC_PATH:
return "EXEC_PATH";
case CLKS_SYSCALL_EXEC_PATHV:
return "EXEC_PATHV";
case CLKS_SYSCALL_EXEC_PATHV_IO:
return "EXEC_PATHV_IO";
case CLKS_SYSCALL_SPAWN_PATH:
return "SPAWN_PATH";
case CLKS_SYSCALL_SPAWN_PATHV:
return "SPAWN_PATHV";
case CLKS_SYSCALL_PROC_KILL:
return "PROC_KILL";
case CLKS_SYSCALL_SHUTDOWN:
return "SHUTDOWN";
case CLKS_SYSCALL_RESTART:
return "RESTART";
default:
return "UNKNOWN";
}
}
static clks_bool clks_syscall_usc_is_dangerous(u64 id) {
switch (id) {
case CLKS_SYSCALL_FS_MKDIR:
return (CLKS_CFG_USC_SC_FS_MKDIR != 0) ? CLKS_TRUE : CLKS_FALSE;
case CLKS_SYSCALL_FS_WRITE:
return (CLKS_CFG_USC_SC_FS_WRITE != 0) ? CLKS_TRUE : CLKS_FALSE;
case CLKS_SYSCALL_FS_APPEND:
return (CLKS_CFG_USC_SC_FS_APPEND != 0) ? CLKS_TRUE : CLKS_FALSE;
case CLKS_SYSCALL_FS_REMOVE:
return (CLKS_CFG_USC_SC_FS_REMOVE != 0) ? CLKS_TRUE : CLKS_FALSE;
case CLKS_SYSCALL_EXEC_PATH:
return (CLKS_CFG_USC_SC_EXEC_PATH != 0) ? CLKS_TRUE : CLKS_FALSE;
case CLKS_SYSCALL_EXEC_PATHV:
return (CLKS_CFG_USC_SC_EXEC_PATHV != 0) ? CLKS_TRUE : CLKS_FALSE;
case CLKS_SYSCALL_EXEC_PATHV_IO:
return (CLKS_CFG_USC_SC_EXEC_PATHV_IO != 0) ? CLKS_TRUE : CLKS_FALSE;
case CLKS_SYSCALL_SPAWN_PATH:
return (CLKS_CFG_USC_SC_SPAWN_PATH != 0) ? CLKS_TRUE : CLKS_FALSE;
case CLKS_SYSCALL_SPAWN_PATHV:
return (CLKS_CFG_USC_SC_SPAWN_PATHV != 0) ? CLKS_TRUE : CLKS_FALSE;
case CLKS_SYSCALL_PROC_KILL:
return (CLKS_CFG_USC_SC_PROC_KILL != 0) ? CLKS_TRUE : CLKS_FALSE;
case CLKS_SYSCALL_SHUTDOWN:
return (CLKS_CFG_USC_SC_SHUTDOWN != 0) ? CLKS_TRUE : CLKS_FALSE;
case CLKS_SYSCALL_RESTART:
return (CLKS_CFG_USC_SC_RESTART != 0) ? CLKS_TRUE : CLKS_FALSE;
default:
return CLKS_FALSE;
}
}
static void clks_syscall_usc_copy_path(char *dst, usize dst_size, const char *src) {
usize i = 0U;
if (dst == CLKS_NULL || dst_size == 0U) {
return;
}
if (src == CLKS_NULL) {
dst[0] = '\0';
return;
}
while (src[i] != '\0' && i + 1U < dst_size) {
dst[i] = src[i];
i++;
}
dst[i] = '\0';
}
static clks_bool clks_syscall_usc_current_app_path(char *out_path, usize out_size) {
u64 pid;
struct clks_exec_proc_snapshot snap;
if (out_path == CLKS_NULL || out_size == 0U) {
return CLKS_FALSE;
}
out_path[0] = '\0';
pid = clks_exec_current_pid();
if (pid == 0ULL) {
return CLKS_FALSE;
}
if (clks_exec_proc_snapshot(pid, &snap) == CLKS_FALSE || snap.path[0] == '\0') {
return CLKS_FALSE;
}
clks_syscall_usc_copy_path(out_path, out_size, snap.path);
return CLKS_TRUE;
}
static i32 clks_syscall_usc_find_allowed_path(const char *path) {
u32 i;
if (path == CLKS_NULL || path[0] == '\0') {
return -1;
}
for (i = 0U; i < CLKS_SYSCALL_USC_MAX_ALLOWED_APPS; i++) {
if (clks_syscall_usc_allowed_used[i] == CLKS_TRUE &&
clks_strcmp(clks_syscall_usc_allowed_path[i], path) == 0) {
return (i32)i;
}
}
return -1;
}
static void clks_syscall_usc_remember_path(const char *path) {
u32 i;
if (path == CLKS_NULL || path[0] == '\0') {
return;
}
if (clks_syscall_usc_find_allowed_path(path) >= 0) {
return;
}
for (i = 0U; i < CLKS_SYSCALL_USC_MAX_ALLOWED_APPS; i++) {
if (clks_syscall_usc_allowed_used[i] == CLKS_FALSE) {
clks_syscall_usc_allowed_used[i] = CLKS_TRUE;
clks_syscall_usc_copy_path(clks_syscall_usc_allowed_path[i], sizeof(clks_syscall_usc_allowed_path[i]), path);
return;
}
}
}
static void clks_syscall_usc_emit_text_line(const char *label, const char *value) {
char message[320];
usize pos = 0U;
message[0] = '\0';
pos = clks_syscall_procfs_append_text(message, sizeof(message), pos, label);
pos = clks_syscall_procfs_append_text(message, sizeof(message), pos, ": ");
pos = clks_syscall_procfs_append_text(message, sizeof(message), pos, value);
(void)pos;
clks_log(CLKS_LOG_WARN, "USC", message);
}
static void clks_syscall_usc_emit_hex_line(const char *label, u64 value) {
clks_log_hex(CLKS_LOG_WARN, "USC", label, value);
}
static clks_bool clks_syscall_usc_prompt_allow(const char *app_path, u64 id, u64 arg0, u64 arg1, u64 arg2) {
const char *name = clks_syscall_usc_syscall_name(id);
u32 tty_index = clks_exec_current_tty();
#if !defined(CLKS_CFG_KEYBOARD) || (CLKS_CFG_KEYBOARD == 0)
(void)tty_index;
clks_syscall_usc_emit_text_line("BLOCK", "keyboard disabled, cannot prompt");
return CLKS_FALSE;
#else
clks_syscall_usc_emit_text_line("DANGEROUS_SYSCALL", "REQUEST DETECTED");
clks_syscall_usc_emit_text_line("APP", app_path);
clks_syscall_usc_emit_hex_line("SYSCALL_ID", id);
clks_syscall_usc_emit_text_line("SYSCALL_NAME", name);
clks_syscall_usc_emit_hex_line("ARG0", arg0);
clks_syscall_usc_emit_hex_line("ARG1", arg1);
clks_syscall_usc_emit_hex_line("ARG2", arg2);
clks_log(CLKS_LOG_WARN, "USC", "CONFIRM: Allow this app permanently? [y/N]");
clks_tty_write("[WARN][USC] Allow this app permanently? [y/N]: ");
clks_serial_write("[WARN][USC] Allow this app permanently? [y/N]: ");
while (1) {
char ch = '\0';
if (clks_keyboard_pop_char_for_tty(tty_index, &ch) == CLKS_TRUE) {
if (ch == 'y' || ch == 'Y') {
clks_tty_write("y\n");
clks_serial_write("y\n");
return CLKS_TRUE;
}
if (ch == 'n' || ch == 'N' || ch == '\n' || ch == '\r' || ch == 27) {
clks_tty_write("n\n");
clks_serial_write("n\n");
return CLKS_FALSE;
}
continue;
}
clks_syscall_usc_sleep_until_input();
}
#endif
}
#endif
static clks_bool clks_syscall_usc_check(u64 id, u64 arg0, u64 arg1, u64 arg2) {
#if CLKS_CFG_USC == 0
(void)id;
(void)arg0;
(void)arg1;
(void)arg2;
return CLKS_TRUE;
#else
char app_path[CLKS_EXEC_PROC_PATH_MAX];
if (clks_syscall_usc_is_dangerous(id) == CLKS_FALSE) {
return CLKS_TRUE;
}
if (clks_exec_is_running() == CLKS_FALSE || clks_exec_current_path_is_user() == CLKS_FALSE) {
return CLKS_TRUE;
}
if (clks_syscall_usc_current_app_path(app_path, sizeof(app_path)) == CLKS_FALSE) {
clks_syscall_usc_emit_text_line("BLOCK", "cannot resolve current app path");
return CLKS_FALSE;
}
if (clks_syscall_usc_find_allowed_path(app_path) >= 0) {
return CLKS_TRUE;
}
if (clks_syscall_usc_prompt_allow(app_path, id, arg0, arg1, arg2) == CLKS_TRUE) {
clks_syscall_usc_remember_path(app_path);
clks_syscall_usc_emit_text_line("ALLOW", app_path);
return CLKS_TRUE;
}
clks_syscall_usc_emit_text_line("DENY", app_path);
return CLKS_FALSE;
#endif
}
static void clks_syscall_stats_reset(void) { static void clks_syscall_stats_reset(void) {
clks_syscall_stats_total = 0ULL; clks_syscall_stats_total = 0ULL;
clks_memset(clks_syscall_stats_id_count, 0, sizeof(clks_syscall_stats_id_count)); clks_memset(clks_syscall_stats_id_count, 0, sizeof(clks_syscall_stats_id_count));
@@ -1754,6 +2069,10 @@ void clks_syscall_init(void) {
clks_syscall_symbols_checked = CLKS_FALSE; clks_syscall_symbols_checked = CLKS_FALSE;
clks_syscall_symbols_data = CLKS_NULL; clks_syscall_symbols_data = CLKS_NULL;
clks_syscall_symbols_size = 0ULL; clks_syscall_symbols_size = 0ULL;
#if CLKS_CFG_USC != 0
clks_memset(clks_syscall_usc_allowed_used, 0, sizeof(clks_syscall_usc_allowed_used));
clks_memset(clks_syscall_usc_allowed_path, 0, sizeof(clks_syscall_usc_allowed_path));
#endif
clks_syscall_stats_reset(); clks_syscall_stats_reset();
clks_log(CLKS_LOG_INFO, "SYSCALL", "INT80 FRAMEWORK ONLINE"); clks_log(CLKS_LOG_INFO, "SYSCALL", "INT80 FRAMEWORK ONLINE");
} }
@@ -1773,6 +2092,10 @@ u64 clks_syscall_dispatch(void *frame_ptr) {
clks_syscall_stats_record(id); clks_syscall_stats_record(id);
clks_syscall_trace_user_program(id); clks_syscall_trace_user_program(id);
if (clks_syscall_usc_check(id, frame->rbx, frame->rcx, frame->rdx) == CLKS_FALSE) {
return (u64)-1;
}
switch (id) { switch (id) {
case CLKS_SYSCALL_LOG_WRITE: case CLKS_SYSCALL_LOG_WRITE:
return clks_syscall_log_write(frame->rbx, frame->rcx); return clks_syscall_log_write(frame->rbx, frame->rcx);

View File

@@ -53,6 +53,7 @@ static clks_bool clks_userland_probe_elf(const char *path, const char *tag) {
return CLKS_TRUE; return CLKS_TRUE;
} }
#if CLKS_CFG_USER_INIT_SCRIPT_PROBE
static void clks_userland_probe_init_script(void) { static void clks_userland_probe_init_script(void) {
const void *data; const void *data;
u64 size = 0ULL; u64 size = 0ULL;
@@ -67,6 +68,7 @@ static void clks_userland_probe_init_script(void) {
clks_log(CLKS_LOG_INFO, "USER", "INIT SCRIPT READY /SHELL/INIT.CMD"); clks_log(CLKS_LOG_INFO, "USER", "INIT SCRIPT READY /SHELL/INIT.CMD");
clks_log_hex(CLKS_LOG_INFO, "USER", "INIT_SCRIPT_SIZE", size); clks_log_hex(CLKS_LOG_INFO, "USER", "INIT_SCRIPT_SIZE", size);
} }
#endif
static clks_bool clks_userland_request_shell_exec(void) { static clks_bool clks_userland_request_shell_exec(void) {
u64 status = (u64)-1; u64 status = (u64)-1;

View File

@@ -4,193 +4,373 @@
"key": "CLEONOS_CLKS_ENABLE_AUDIO", "key": "CLEONOS_CLKS_ENABLE_AUDIO",
"title": "Audio Driver Init", "title": "Audio Driver Init",
"description": "Initialize kernel audio subsystem during boot.", "description": "Initialize kernel audio subsystem during boot.",
"type": "bool",
"default": true "default": true
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_MOUSE", "key": "CLEONOS_CLKS_ENABLE_MOUSE",
"title": "PS/2 Mouse Input", "title": "PS/2 Mouse Input",
"description": "Initialize kernel PS/2 mouse input subsystem.", "description": "Initialize kernel PS/2 mouse input subsystem.",
"type": "bool",
"default": true "default": true
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_DESKTOP", "key": "CLEONOS_CLKS_ENABLE_DESKTOP",
"title": "TTY2 Desktop", "title": "TTY2 Desktop",
"description": "Enable desktop compositor tick/update path on TTY2.", "description": "Enable desktop compositor tick/update path on TTY2.",
"default": true "type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_MOUSE"
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_DRIVER_MANAGER", "key": "CLEONOS_CLKS_ENABLE_DRIVER_MANAGER",
"title": "Driver Manager", "title": "Driver Manager",
"description": "Initialize kernel ELF driver manager.", "description": "Initialize kernel ELF driver manager.",
"type": "bool",
"default": true "default": true
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_KELF", "key": "CLEONOS_CLKS_ENABLE_KELF",
"title": "KELF Executor", "title": "KELF Executor",
"description": "Enable kernel ELF app dispatcher and kelfd task.", "description": "Enable kernel ELF app dispatcher and kelfd task.",
"default": true "type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_DRIVER_MANAGER && CLEONOS_CLKS_ENABLE_ELFRUNNER_INIT",
"imply": [
"CLEONOS_CLKS_ENABLE_ELFRUNNER_PROBE",
"CLEONOS_CLKS_ENABLE_USER_SYSTEM_APP_PROBE"
]
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_USERLAND_AUTO_EXEC", "key": "CLEONOS_CLKS_ENABLE_USERLAND_AUTO_EXEC",
"title": "Auto Enter User Shell", "title": "Auto Enter User Shell",
"description": "Auto-exec /shell/shell.elf after kernel boot.", "description": "Auto-exec /shell/shell.elf after kernel boot.",
"default": true "type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_USRD_TASK && CLEONOS_CLKS_ENABLE_KEYBOARD",
"select": [
"CLEONOS_CLKS_ENABLE_USRD_TASK",
"CLEONOS_CLKS_ENABLE_KEYBOARD"
],
"imply": [
"CLEONOS_CLKS_ENABLE_USER_INIT_SCRIPT_PROBE",
"CLEONOS_CLKS_ENABLE_SHELL_MODE_LOG"
]
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_HEAP_SELFTEST", "key": "CLEONOS_CLKS_ENABLE_HEAP_SELFTEST",
"title": "Heap Selftest", "title": "Heap Selftest",
"description": "Run kmalloc/kfree selftest during kernel boot.", "description": "Run kmalloc/kfree selftest during kernel boot.",
"type": "bool",
"default": true "default": true
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_EXTERNAL_PSF", "key": "CLEONOS_CLKS_ENABLE_EXTERNAL_PSF",
"title": "Load External PSF Font", "title": "Load External PSF Font",
"description": "Load /system/tty.psf and apply it to framebuffer TTY.", "description": "Load /system/tty.psf and apply it to framebuffer TTY.",
"type": "bool",
"default": true "default": true
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_KEYBOARD", "key": "CLEONOS_CLKS_ENABLE_KEYBOARD",
"title": "PS/2 Keyboard Input", "title": "PS/2 Keyboard Input",
"description": "Initialize PS/2 keyboard input subsystem.", "description": "Initialize PS/2 keyboard input subsystem.",
"default": true "type": "bool",
"default": true,
"imply": [
"CLEONOS_CLKS_ENABLE_KBD_TTY_SWITCH_HOTKEY",
"CLEONOS_CLKS_ENABLE_KBD_CTRL_SHORTCUTS"
]
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_ELFRUNNER_PROBE", "key": "CLEONOS_CLKS_ENABLE_ELFRUNNER_PROBE",
"title": "ELFRUNNER Probe", "title": "ELFRUNNER Probe",
"description": "Probe kernel ELF runtime metadata after ELFRUNNER init.", "description": "Probe kernel ELF runtime metadata after ELFRUNNER init.",
"default": true "type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_ELFRUNNER_INIT && CLEONOS_CLKS_ENABLE_KELF"
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_KLOGD_TASK", "key": "CLEONOS_CLKS_ENABLE_KLOGD_TASK",
"title": "Scheduler Task: klogd", "title": "Scheduler Task: klogd",
"description": "Enable periodic klogd maintenance task.", "description": "Enable periodic klogd maintenance task.",
"type": "bool",
"default": true "default": true
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_KWORKER_TASK", "key": "CLEONOS_CLKS_ENABLE_KWORKER_TASK",
"title": "Scheduler Task: kworker", "title": "Scheduler Task: kworker",
"description": "Enable periodic kernel worker service-heartbeat task.", "description": "Enable periodic kernel worker service-heartbeat task.",
"type": "bool",
"default": true "default": true
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_USRD_TASK", "key": "CLEONOS_CLKS_ENABLE_USRD_TASK",
"title": "Scheduler Task: usrd", "title": "Scheduler Task: usrd",
"description": "Enable user/runtime dispatch task (shell tick, tty tick, exec tick).", "description": "Enable user/runtime dispatch task (shell tick, tty tick, exec tick).",
"type": "bool",
"default": true "default": true
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_BOOT_VIDEO_LOG", "key": "CLEONOS_CLKS_ENABLE_BOOT_VIDEO_LOG",
"title": "Boot Video Geometry Logs", "title": "Boot Video Geometry Logs",
"description": "Print framebuffer width/height/pitch/bpp logs at boot.", "description": "Print framebuffer width/height/pitch/bpp logs at boot.",
"default": true "type": "tristate",
"default": "y"
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_PMM_STATS_LOG", "key": "CLEONOS_CLKS_ENABLE_PMM_STATS_LOG",
"title": "PMM Stats Logs", "title": "PMM Stats Logs",
"description": "Print PMM managed/free/used/dropped pages at boot.", "description": "Print PMM managed/free/used/dropped pages at boot.",
"default": true "type": "tristate",
"default": "y"
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_HEAP_STATS_LOG", "key": "CLEONOS_CLKS_ENABLE_HEAP_STATS_LOG",
"title": "Heap Stats Logs", "title": "Heap Stats Logs",
"description": "Print heap total/free bytes at boot.", "description": "Print heap total/free bytes at boot.",
"default": true "type": "tristate",
"default": "y"
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_FS_ROOT_LOG", "key": "CLEONOS_CLKS_ENABLE_FS_ROOT_LOG",
"title": "FS Root Children Log", "title": "FS Root Children Log",
"description": "Print root directory children count during FS init.", "description": "Print root directory children count during FS init.",
"default": true "type": "tristate",
"default": "y",
"depends_on": "CLEONOS_CLKS_ENABLE_SYSTEM_DIR_CHECK"
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_SYSTEM_DIR_CHECK", "key": "CLEONOS_CLKS_ENABLE_SYSTEM_DIR_CHECK",
"title": "FS /SYSTEM Sanity Check", "title": "FS /SYSTEM Sanity Check",
"description": "Require /system directory check during boot.", "description": "Require /system directory check during boot.",
"type": "bool",
"default": true "default": true
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_ELFRUNNER_INIT", "key": "CLEONOS_CLKS_ENABLE_ELFRUNNER_INIT",
"title": "ELFRUNNER Init", "title": "ELFRUNNER Init",
"description": "Initialize ELFRUNNER framework in kernel boot path.", "description": "Initialize ELFRUNNER framework in kernel boot path.",
"type": "bool",
"default": true "default": true
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_SYSCALL_TICK_QUERY", "key": "CLEONOS_CLKS_ENABLE_SYSCALL_TICK_QUERY",
"title": "SYSCALL Tick Query", "title": "SYSCALL Tick Query",
"description": "Query timer ticks via syscall and log result during boot.", "description": "Query timer ticks via syscall and log result during boot.",
"default": true "type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_PROCFS"
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_TTY_READY_LOG", "key": "CLEONOS_CLKS_ENABLE_TTY_READY_LOG",
"title": "TTY Ready Logs", "title": "TTY Ready Logs",
"description": "Print TTY count/active/cursor ready logs.", "description": "Print TTY count/active/cursor ready logs.",
"default": true "type": "tristate",
"default": "y"
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_IDLE_DEBUG_LOG", "key": "CLEONOS_CLKS_ENABLE_IDLE_DEBUG_LOG",
"title": "Idle Loop Debug Log", "title": "Idle Loop Debug Log",
"description": "Print debug log before entering kernel idle loop.", "description": "Print debug log before entering kernel idle loop.",
"default": true "type": "tristate",
"default": "y"
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_PROCFS", "key": "CLEONOS_CLKS_ENABLE_PROCFS",
"title": "Virtual /proc", "title": "Virtual /proc",
"description": "Enable virtual procfs paths (/proc, /proc/list, /proc/self, /proc/<pid>) in syscall FS layer.", "description": "Enable virtual procfs paths (/proc, /proc/list, /proc/self, /proc/<pid>) in syscall FS layer.",
"type": "bool",
"default": true "default": true
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_EXEC_SERIAL_LOG", "key": "CLEONOS_CLKS_ENABLE_EXEC_SERIAL_LOG",
"title": "EXEC Serial Logs", "title": "EXEC Serial Logs",
"description": "Print EXEC run/return/path logs to serial output.", "description": "Print EXEC run/return/path logs to serial output.",
"default": true "type": "tristate",
"default": "y"
},
{
"key": "CLEONOS_CLKS_ENABLE_USC",
"title": "UserSafeController (USC)",
"description": "Prompt before dangerous user syscalls and remember per-app approval for current boot.",
"type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_KEYBOARD",
"group": "USC Syscall Policy"
},
{
"key": "CLEONOS_CLKS_ENABLE_USC_SC_FS_MKDIR",
"title": "Intercept FS_MKDIR",
"description": "USC prompt for syscall FS_MKDIR.",
"type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_USC",
"group": "USC Syscall Policy"
},
{
"key": "CLEONOS_CLKS_ENABLE_USC_SC_FS_WRITE",
"title": "Intercept FS_WRITE",
"description": "USC prompt for syscall FS_WRITE.",
"type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_USC",
"group": "USC Syscall Policy"
},
{
"key": "CLEONOS_CLKS_ENABLE_USC_SC_FS_APPEND",
"title": "Intercept FS_APPEND",
"description": "USC prompt for syscall FS_APPEND.",
"type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_USC",
"group": "USC Syscall Policy"
},
{
"key": "CLEONOS_CLKS_ENABLE_USC_SC_FS_REMOVE",
"title": "Intercept FS_REMOVE",
"description": "USC prompt for syscall FS_REMOVE.",
"type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_USC",
"group": "USC Syscall Policy"
},
{
"key": "CLEONOS_CLKS_ENABLE_USC_SC_EXEC_PATH",
"title": "Intercept EXEC_PATH",
"description": "USC prompt for syscall EXEC_PATH.",
"type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_USC",
"group": "USC Syscall Policy"
},
{
"key": "CLEONOS_CLKS_ENABLE_USC_SC_EXEC_PATHV",
"title": "Intercept EXEC_PATHV",
"description": "USC prompt for syscall EXEC_PATHV.",
"type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_USC",
"group": "USC Syscall Policy"
},
{
"key": "CLEONOS_CLKS_ENABLE_USC_SC_EXEC_PATHV_IO",
"title": "Intercept EXEC_PATHV_IO",
"description": "USC prompt for syscall EXEC_PATHV_IO.",
"type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_USC",
"group": "USC Syscall Policy"
},
{
"key": "CLEONOS_CLKS_ENABLE_USC_SC_SPAWN_PATH",
"title": "Intercept SPAWN_PATH",
"description": "USC prompt for syscall SPAWN_PATH.",
"type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_USC",
"group": "USC Syscall Policy"
},
{
"key": "CLEONOS_CLKS_ENABLE_USC_SC_SPAWN_PATHV",
"title": "Intercept SPAWN_PATHV",
"description": "USC prompt for syscall SPAWN_PATHV.",
"type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_USC",
"group": "USC Syscall Policy"
},
{
"key": "CLEONOS_CLKS_ENABLE_USC_SC_PROC_KILL",
"title": "Intercept PROC_KILL",
"description": "USC prompt for syscall PROC_KILL.",
"type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_USC",
"group": "USC Syscall Policy"
},
{
"key": "CLEONOS_CLKS_ENABLE_USC_SC_SHUTDOWN",
"title": "Intercept SHUTDOWN",
"description": "USC prompt for syscall SHUTDOWN.",
"type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_USC",
"group": "USC Syscall Policy"
},
{
"key": "CLEONOS_CLKS_ENABLE_USC_SC_RESTART",
"title": "Intercept RESTART",
"description": "USC prompt for syscall RESTART.",
"type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_USC",
"group": "USC Syscall Policy"
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_KBD_TTY_SWITCH_HOTKEY", "key": "CLEONOS_CLKS_ENABLE_KBD_TTY_SWITCH_HOTKEY",
"title": "Keyboard TTY Switch Hotkey", "title": "Keyboard TTY Switch Hotkey",
"description": "Enable ALT+F1..F4 keyboard hotkey for active TTY switching.", "description": "Enable ALT+F1..F4 keyboard hotkey for active TTY switching.",
"default": true "type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_KEYBOARD"
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_KBD_CTRL_SHORTCUTS", "key": "CLEONOS_CLKS_ENABLE_KBD_CTRL_SHORTCUTS",
"title": "Keyboard Ctrl Shortcuts", "title": "Keyboard Ctrl Shortcuts",
"description": "Enable Ctrl+A/C/V shortcuts for input selection/copy/paste.", "description": "Enable Ctrl+A/C/V shortcuts for input selection/copy/paste.",
"default": true "type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_KEYBOARD",
"imply": [
"CLEONOS_CLKS_ENABLE_KBD_TTY_SWITCH_HOTKEY"
]
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_KBD_FORCE_STOP_HOTKEY", "key": "CLEONOS_CLKS_ENABLE_KBD_FORCE_STOP_HOTKEY",
"title": "Keyboard Force-Stop Hotkey", "title": "Keyboard Force-Stop Hotkey",
"description": "Enable Ctrl+Alt+C force-stop for current running user process.", "description": "Enable Ctrl+Alt+C force-stop for current running user process.",
"default": true "type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_KEYBOARD && CLEONOS_CLKS_ENABLE_PROCFS"
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_USER_INIT_SCRIPT_PROBE", "key": "CLEONOS_CLKS_ENABLE_USER_INIT_SCRIPT_PROBE",
"title": "User Init Script Probe", "title": "User Init Script Probe",
"description": "Probe and log /shell/init.cmd presence during userland init.", "description": "Probe and log /shell/init.cmd presence during userland init.",
"default": true "type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_USERLAND_AUTO_EXEC"
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_USER_SYSTEM_APP_PROBE", "key": "CLEONOS_CLKS_ENABLE_USER_SYSTEM_APP_PROBE",
"title": "User System App Probe", "title": "User System App Probe",
"description": "Probe /system/elfrunner.elf and /system/memc.elf during userland init.", "description": "Probe /system/elfrunner.elf and /system/memc.elf during userland init.",
"default": true "type": "bool",
"default": true,
"depends_on": "CLEONOS_CLKS_ENABLE_KELF"
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_SCHED_TASK_COUNT_LOG", "key": "CLEONOS_CLKS_ENABLE_SCHED_TASK_COUNT_LOG",
"title": "Scheduler Task Count Log", "title": "Scheduler Task Count Log",
"description": "Print scheduler task count after scheduler initialization.", "description": "Print scheduler task count after scheduler initialization.",
"default": true "type": "tristate",
"default": "y",
"depends_on": "CLEONOS_CLKS_ENABLE_KLOGD_TASK || CLEONOS_CLKS_ENABLE_KWORKER_TASK || CLEONOS_CLKS_ENABLE_USRD_TASK"
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_INTERRUPT_READY_LOG", "key": "CLEONOS_CLKS_ENABLE_INTERRUPT_READY_LOG",
"title": "Interrupt Ready Log", "title": "Interrupt Ready Log",
"description": "Print IDT/PIC initialized log after interrupt setup.", "description": "Print IDT/PIC initialized log after interrupt setup.",
"default": true "type": "tristate",
"default": "y"
}, },
{ {
"key": "CLEONOS_CLKS_ENABLE_SHELL_MODE_LOG", "key": "CLEONOS_CLKS_ENABLE_SHELL_MODE_LOG",
"title": "Shell Mode Log", "title": "Shell Mode Log",
"description": "Print whether boot default mode is user shell or kernel shell.", "description": "Print whether boot default mode is user shell or kernel shell.",
"default": true "type": "tristate",
"default": "y"
} }
] ]
} }

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -37,13 +37,17 @@ python wine/cleonos_wine.py build/x86_64/ramdisk_root/shell/shell.elf --rootfs b
## 支持 ## 支持
- ELF64 (x86_64) PT_LOAD 段装载 - ELF64 (x86_64) PT_LOAD 段装载
- CLeonOS `int 0x80` syscall 0..60 - CLeonOS `int 0x80` syscall 0..80`FD_*``PROC_*``STATS_*``EXEC_PATHV_IO`
- TTY 输出与键盘输入队列 - TTY 输出与键盘输入队列
- rootfs 文件/目录访问(`FS_*` - rootfs 文件/目录访问(`FS_*`
- `/temp` 写入限制(`FS_MKDIR/WRITE/APPEND/REMOVE` - `/temp` 写入限制(`FS_MKDIR/WRITE/APPEND/REMOVE`
- `EXEC_PATH/EXEC_PATHV` 执行 ELF带深度限制 - `EXEC_PATH/EXEC_PATHV` 执行 ELF带深度限制
- `EXEC_PATHV_IO`(支持 stdio fd 继承/重定向)
- `SPAWN_PATH/SPAWN_PATHV/WAITPID/EXIT/SLEEP_TICKS/YIELD` - `SPAWN_PATH/SPAWN_PATHV/WAITPID/EXIT/SLEEP_TICKS/YIELD`
- 进程 `argv/env` 查询(`PROC_ARGC/PROC_ARGV/PROC_ENVC/PROC_ENV` - 进程 `argv/env` 查询(`PROC_ARGC/PROC_ARGV/PROC_ENVC/PROC_ENV`
- 进程枚举与快照(`PROC_COUNT/PROC_PID_AT/PROC_SNAPSHOT/PROC_KILL`
- syscall 统计(`STATS_TOTAL/STATS_ID_COUNT/STATS_RECENT_*`
- 文件描述符(`FD_OPEN/FD_READ/FD_WRITE/FD_CLOSE/FD_DUP`
- 异常退出状态编码与故障元信息(`PROC_LAST_SIGNAL/PROC_FAULT_*` - 异常退出状态编码与故障元信息(`PROC_LAST_SIGNAL/PROC_FAULT_*`
## 参数 ## 参数

View File

@@ -69,6 +69,48 @@ SYS_PROC_LAST_SIGNAL = 57
SYS_PROC_FAULT_VECTOR = 58 SYS_PROC_FAULT_VECTOR = 58
SYS_PROC_FAULT_ERROR = 59 SYS_PROC_FAULT_ERROR = 59
SYS_PROC_FAULT_RIP = 60 SYS_PROC_FAULT_RIP = 60
SYS_PROC_COUNT = 61
SYS_PROC_PID_AT = 62
SYS_PROC_SNAPSHOT = 63
SYS_PROC_KILL = 64
SYS_KDBG_SYM = 65
SYS_KDBG_BT = 66
SYS_KDBG_REGS = 67
SYS_STATS_TOTAL = 68
SYS_STATS_ID_COUNT = 69
SYS_STATS_RECENT_WINDOW = 70
SYS_STATS_RECENT_ID = 71
SYS_FD_OPEN = 72
SYS_FD_READ = 73
SYS_FD_WRITE = 74
SYS_FD_CLOSE = 75
SYS_FD_DUP = 76
SYS_DL_OPEN = 77
SYS_DL_CLOSE = 78
SYS_DL_SYM = 79
SYS_EXEC_PATHV_IO = 80
# proc states (from cleonos/c/include/cleonos_syscall.h)
PROC_STATE_UNUSED = 0
PROC_STATE_PENDING = 1
PROC_STATE_RUNNING = 2
PROC_STATE_EXITED = 3
PROC_STATE_STOPPED = 4
# signals (from cleonos/c/include/cleonos_syscall.h)
SIGKILL = 9
SIGTERM = 15
SIGCONT = 18
SIGSTOP = 19
# open flags (from cleonos/c/include/cleonos_syscall.h)
O_RDONLY = 0x0000
O_WRONLY = 0x0001
O_RDWR = 0x0002
O_CREAT = 0x0040
O_TRUNC = 0x0200
O_APPEND = 0x0400
FD_INHERIT = U64_MASK
def u64(value: int) -> int: def u64(value: int) -> int:

View File

@@ -6,40 +6,48 @@ import sys
import time import time
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from typing import List, Optional, Tuple from typing import Dict, List, Optional, Tuple
from .constants import ( from .constants import (
DEFAULT_MAX_EXEC_DEPTH, DEFAULT_MAX_EXEC_DEPTH,
FD_INHERIT,
FS_NAME_MAX, FS_NAME_MAX,
MAX_CSTR, MAX_CSTR,
MAX_IO_READ, MAX_IO_READ,
O_APPEND,
O_CREAT,
O_RDONLY,
O_RDWR,
O_TRUNC,
O_WRONLY,
PAGE_SIZE, PAGE_SIZE,
PROC_STATE_EXITED,
PROC_STATE_PENDING,
PROC_STATE_RUNNING,
PROC_STATE_STOPPED,
SIGCONT,
SIGKILL,
SIGSTOP,
SIGTERM,
SYS_AUDIO_AVAILABLE, SYS_AUDIO_AVAILABLE,
SYS_AUDIO_PLAY_TONE, SYS_AUDIO_PLAY_TONE,
SYS_AUDIO_STOP, SYS_AUDIO_STOP,
SYS_CONTEXT_SWITCHES, SYS_CONTEXT_SWITCHES,
SYS_CUR_TASK, SYS_CUR_TASK,
SYS_DL_CLOSE,
SYS_DL_OPEN,
SYS_DL_SYM,
SYS_EXEC_PATH, SYS_EXEC_PATH,
SYS_EXEC_PATHV, SYS_EXEC_PATHV,
SYS_EXEC_PATHV_IO,
SYS_EXEC_REQUESTS, SYS_EXEC_REQUESTS,
SYS_EXEC_SUCCESS, SYS_EXEC_SUCCESS,
SYS_EXIT, SYS_EXIT,
SYS_GETPID, SYS_FD_CLOSE,
SYS_PROC_ARGC, SYS_FD_DUP,
SYS_PROC_ARGV, SYS_FD_OPEN,
SYS_PROC_ENVC, SYS_FD_READ,
SYS_PROC_ENV, SYS_FD_WRITE,
SYS_PROC_FAULT_ERROR,
SYS_PROC_FAULT_RIP,
SYS_PROC_FAULT_VECTOR,
SYS_PROC_LAST_SIGNAL,
SYS_SLEEP_TICKS,
SYS_SPAWN_PATH,
SYS_SPAWN_PATHV,
SYS_WAITPID,
SYS_YIELD,
SYS_SHUTDOWN,
SYS_RESTART,
SYS_FS_APPEND, SYS_FS_APPEND,
SYS_FS_CHILD_COUNT, SYS_FS_CHILD_COUNT,
SYS_FS_GET_CHILD_NAME, SYS_FS_GET_CHILD_NAME,
@@ -50,6 +58,7 @@ from .constants import (
SYS_FS_STAT_SIZE, SYS_FS_STAT_SIZE,
SYS_FS_STAT_TYPE, SYS_FS_STAT_TYPE,
SYS_FS_WRITE, SYS_FS_WRITE,
SYS_GETPID,
SYS_KBD_BUFFERED, SYS_KBD_BUFFERED,
SYS_KBD_DROPPED, SYS_KBD_DROPPED,
SYS_KBD_GET_CHAR, SYS_KBD_GET_CHAR,
@@ -61,8 +70,29 @@ from .constants import (
SYS_LOG_JOURNAL_COUNT, SYS_LOG_JOURNAL_COUNT,
SYS_LOG_JOURNAL_READ, SYS_LOG_JOURNAL_READ,
SYS_LOG_WRITE, SYS_LOG_WRITE,
SYS_PROC_ARGC,
SYS_PROC_ARGV,
SYS_PROC_COUNT,
SYS_PROC_ENVC,
SYS_PROC_ENV,
SYS_PROC_FAULT_ERROR,
SYS_PROC_FAULT_RIP,
SYS_PROC_FAULT_VECTOR,
SYS_PROC_KILL,
SYS_PROC_LAST_SIGNAL,
SYS_PROC_PID_AT,
SYS_PROC_SNAPSHOT,
SYS_RESTART,
SYS_SERVICE_COUNT, SYS_SERVICE_COUNT,
SYS_SERVICE_READY_COUNT, SYS_SERVICE_READY_COUNT,
SYS_SHUTDOWN,
SYS_SLEEP_TICKS,
SYS_SPAWN_PATH,
SYS_SPAWN_PATHV,
SYS_STATS_ID_COUNT,
SYS_STATS_RECENT_ID,
SYS_STATS_RECENT_WINDOW,
SYS_STATS_TOTAL,
SYS_TASK_COUNT, SYS_TASK_COUNT,
SYS_TIMER_TICKS, SYS_TIMER_TICKS,
SYS_TTY_ACTIVE, SYS_TTY_ACTIVE,
@@ -75,6 +105,8 @@ from .constants import (
SYS_USER_LAUNCH_OK, SYS_USER_LAUNCH_OK,
SYS_USER_LAUNCH_TRIES, SYS_USER_LAUNCH_TRIES,
SYS_USER_SHELL_READY, SYS_USER_SHELL_READY,
SYS_WAITPID,
SYS_YIELD,
page_ceil, page_ceil,
page_floor, page_floor,
u64, u64,
@@ -124,6 +156,15 @@ class ELFImage:
segments: List[ELFSegment] segments: List[ELFSegment]
@dataclass
class FDEntry:
kind: str
flags: int
offset: int = 0
path: str = ""
tty_index: int = 0
EXEC_PATH_MAX = 192 EXEC_PATH_MAX = 192
EXEC_ARG_LINE_MAX = 256 EXEC_ARG_LINE_MAX = 256
EXEC_ENV_LINE_MAX = 512 EXEC_ENV_LINE_MAX = 512
@@ -131,6 +172,8 @@ EXEC_MAX_ARGS = 24
EXEC_MAX_ENVS = 24 EXEC_MAX_ENVS = 24
EXEC_ITEM_MAX = 128 EXEC_ITEM_MAX = 128
EXEC_STATUS_SIGNAL_FLAG = 1 << 63 EXEC_STATUS_SIGNAL_FLAG = 1 << 63
PROC_PATH_MAX = 192
FD_MAX = 64
class CLeonOSWineNative: class CLeonOSWineNative:
@@ -150,6 +193,7 @@ class CLeonOSWineNative:
ppid: int = 0, ppid: int = 0,
argv_items: Optional[List[str]] = None, argv_items: Optional[List[str]] = None,
env_items: Optional[List[str]] = None, env_items: Optional[List[str]] = None,
inherited_fds: Optional[Dict[int, FDEntry]] = None,
) -> None: ) -> None:
self.elf_path = elf_path self.elf_path = elf_path
self.rootfs = rootfs self.rootfs = rootfs
@@ -175,9 +219,97 @@ class CLeonOSWineNative:
self._stack_size = 0x0000000000020000 self._stack_size = 0x0000000000020000
self._ret_sentinel = 0x00007FFF10000000 self._ret_sentinel = 0x00007FFF10000000
self._mapped_ranges: List[Tuple[int, int]] = [] self._mapped_ranges: List[Tuple[int, int]] = []
self._tty_index = int(self.state.tty_active)
self._fds: Dict[int, FDEntry] = {}
self._fd_inherited = inherited_fds if inherited_fds is not None else {}
default_path = self._normalize_guest_path(self.guest_path_hint or f"/{self.elf_path.name}") default_path = self._normalize_guest_path(self.guest_path_hint or f"/{self.elf_path.name}")
self.argv_items, self.env_items = self._prepare_exec_items(default_path, self.argv_items, self.env_items) self.argv_items, self.env_items = self._prepare_exec_items(default_path, self.argv_items, self.env_items)
self._init_default_fds()
@staticmethod
def _clone_fd_entry(entry: FDEntry) -> FDEntry:
return FDEntry(kind=entry.kind, flags=int(entry.flags), offset=int(entry.offset), path=str(entry.path), tty_index=int(entry.tty_index))
@staticmethod
def _fd_access_mode(flags: int) -> int:
return int(flags) & 0x3
@classmethod
def _fd_access_mode_valid(cls, flags: int) -> bool:
mode = cls._fd_access_mode(flags)
return mode in (O_RDONLY, O_WRONLY, O_RDWR)
@classmethod
def _fd_can_read(cls, flags: int) -> bool:
mode = cls._fd_access_mode(flags)
return mode in (O_RDONLY, O_RDWR)
@classmethod
def _fd_can_write(cls, flags: int) -> bool:
mode = cls._fd_access_mode(flags)
return mode in (O_WRONLY, O_RDWR)
def _init_default_fds(self) -> None:
self._fds = {
0: FDEntry(kind="tty", flags=O_RDONLY, offset=0, tty_index=self._tty_index),
1: FDEntry(kind="tty", flags=O_WRONLY, offset=0, tty_index=self._tty_index),
2: FDEntry(kind="tty", flags=O_WRONLY, offset=0, tty_index=self._tty_index),
}
for target in (0, 1, 2):
inherited = self._fd_inherited.get(target)
if inherited is not None:
self._fds[target] = self._clone_fd_entry(inherited)
for target in (0, 1, 2):
entry = self._fds.get(target)
if entry is not None and entry.kind == "tty":
self._tty_index = int(entry.tty_index)
break
def _fd_lookup(self, fd: int) -> Optional[FDEntry]:
if fd < 0 or fd >= FD_MAX:
return None
return self._fds.get(int(fd))
def _fd_find_free(self) -> int:
for fd in range(FD_MAX):
if fd not in self._fds:
return fd
return -1
def _stdio_entry_for_child(self, target_fd: int, override_fd: int, require_read: bool, require_write: bool) -> Optional[FDEntry]:
if override_fd == FD_INHERIT:
src = self._fd_lookup(target_fd)
else:
src = self._fd_lookup(override_fd)
if src is None:
return None
if require_read and not self._fd_can_read(src.flags):
return None
if require_write and not self._fd_can_write(src.flags):
return None
return self._clone_fd_entry(src)
def _build_child_stdio_map(self, stdin_fd: int, stdout_fd: int, stderr_fd: int) -> Optional[Dict[int, FDEntry]]:
child_map: Dict[int, FDEntry] = {}
in_entry = self._stdio_entry_for_child(0, stdin_fd, require_read=True, require_write=False)
out_entry = self._stdio_entry_for_child(1, stdout_fd, require_read=False, require_write=True)
err_entry = self._stdio_entry_for_child(2, stderr_fd, require_read=False, require_write=True)
if in_entry is None or out_entry is None or err_entry is None:
return None
child_map[0] = in_entry
child_map[1] = out_entry
child_map[2] = err_entry
return child_map
def run(self) -> Optional[int]: def run(self) -> Optional[int]:
if self.pid == 0: if self.pid == 0:
@@ -187,6 +319,7 @@ class CLeonOSWineNative:
self.state.set_current_pid(self.pid) self.state.set_current_pid(self.pid)
self.state.set_proc_cmdline(self.pid, self.argv_items, self.env_items) self.state.set_proc_cmdline(self.pid, self.argv_items, self.env_items)
self.state.set_proc_fault(self.pid, 0, 0, 0, 0) self.state.set_proc_fault(self.pid, 0, 0, 0, 0)
self.state.set_proc_running(self.pid, self.argv_items[0] if self.argv_items else self.guest_path_hint, self._tty_index)
uc = Uc(UC_ARCH_X86, UC_MODE_64) uc = Uc(UC_ARCH_X86, UC_MODE_64)
self._install_hooks(uc) self._install_hooks(uc)
@@ -252,6 +385,7 @@ class CLeonOSWineNative:
arg1 = self._reg_read(uc, UC_X86_REG_RCX) arg1 = self._reg_read(uc, UC_X86_REG_RCX)
arg2 = self._reg_read(uc, UC_X86_REG_RDX) arg2 = self._reg_read(uc, UC_X86_REG_RDX)
self.state.record_syscall(syscall_id)
self.state.context_switches = u64(self.state.context_switches + 1) self.state.context_switches = u64(self.state.context_switches + 1)
ret = self._dispatch_syscall(uc, syscall_id, arg0, arg1, arg2) ret = self._dispatch_syscall(uc, syscall_id, arg0, arg1, arg2)
self._reg_write(uc, UC_X86_REG_RAX, u64(ret)) self._reg_write(uc, UC_X86_REG_RAX, u64(ret))
@@ -291,6 +425,8 @@ class CLeonOSWineNative:
return self._exec_path(uc, arg0) return self._exec_path(uc, arg0)
if sid == SYS_EXEC_PATHV: if sid == SYS_EXEC_PATHV:
return self._exec_pathv(uc, arg0, arg1, arg2) return self._exec_pathv(uc, arg0, arg1, arg2)
if sid == SYS_EXEC_PATHV_IO:
return self._exec_pathv_io(uc, arg0, arg1, arg2)
if sid == SYS_SPAWN_PATH: if sid == SYS_SPAWN_PATH:
return self._spawn_path(uc, arg0) return self._spawn_path(uc, arg0)
if sid == SYS_SPAWN_PATHV: if sid == SYS_SPAWN_PATHV:
@@ -315,6 +451,14 @@ class CLeonOSWineNative:
return self._proc_fault_error() return self._proc_fault_error()
if sid == SYS_PROC_FAULT_RIP: if sid == SYS_PROC_FAULT_RIP:
return self._proc_fault_rip() return self._proc_fault_rip()
if sid == SYS_PROC_COUNT:
return self._proc_count()
if sid == SYS_PROC_PID_AT:
return self._proc_pid_at(uc, arg0, arg1)
if sid == SYS_PROC_SNAPSHOT:
return self._proc_snapshot(uc, arg0, arg1, arg2)
if sid == SYS_PROC_KILL:
return self._proc_kill(uc, arg0, arg1)
if sid == SYS_EXIT: if sid == SYS_EXIT:
return self._request_exit(uc, arg0) return self._request_exit(uc, arg0)
if sid == SYS_SLEEP_TICKS: if sid == SYS_SLEEP_TICKS:
@@ -400,6 +544,30 @@ class CLeonOSWineNative:
return self.state.kbd_drop_count return self.state.kbd_drop_count
if sid == SYS_KBD_HOTKEY_SWITCHES: if sid == SYS_KBD_HOTKEY_SWITCHES:
return self.state.kbd_hotkey_switches return self.state.kbd_hotkey_switches
if sid == SYS_STATS_TOTAL:
return self.state.stats_total()
if sid == SYS_STATS_ID_COUNT:
return self.state.stats_id_count(arg0)
if sid == SYS_STATS_RECENT_WINDOW:
return self.state.stats_recent_window()
if sid == SYS_STATS_RECENT_ID:
return self.state.stats_recent_id_count(arg0)
if sid == SYS_FD_OPEN:
return self._fd_open(uc, arg0, arg1, arg2)
if sid == SYS_FD_READ:
return self._fd_read(uc, arg0, arg1, arg2)
if sid == SYS_FD_WRITE:
return self._fd_write(uc, arg0, arg1, arg2)
if sid == SYS_FD_CLOSE:
return self._fd_close(arg0)
if sid == SYS_FD_DUP:
return self._fd_dup(arg0)
if sid == SYS_DL_OPEN:
return u64_neg1()
if sid == SYS_DL_CLOSE:
return 0
if sid == SYS_DL_SYM:
return 0
return u64_neg1() return u64_neg1()
@@ -409,6 +577,15 @@ class CLeonOSWineNative:
sys.stdout.write(text) sys.stdout.write(text)
sys.stdout.flush() sys.stdout.flush()
def _host_write_bytes(self, data: bytes) -> None:
if not data:
return
if hasattr(sys.stdout, "buffer"):
sys.stdout.buffer.write(data)
sys.stdout.flush()
return
self._host_write(data.decode("utf-8", errors="replace"))
def _load_segments(self, uc: Uc) -> None: def _load_segments(self, uc: Uc) -> None:
for seg in self.image.segments: for seg in self.image.segments:
start = page_floor(seg.vaddr) start = page_floor(seg.vaddr)
@@ -504,6 +681,30 @@ class CLeonOSWineNative:
except UcError: except UcError:
return b"" return b""
def _read_guest_bytes_exact(self, uc: Uc, addr: int, size: int) -> Optional[bytes]:
if size < 0 or addr == 0:
return None
if size == 0:
return b""
out = bytearray()
cursor = int(addr)
left = int(size)
while left > 0:
chunk = min(left, MAX_IO_READ)
try:
data = uc.mem_read(cursor, chunk)
except UcError:
return None
if len(data) != chunk:
return None
out.extend(data)
cursor += chunk
left -= chunk
return bytes(out)
def _write_guest_bytes(self, uc: Uc, addr: int, data: bytes) -> bool: def _write_guest_bytes(self, uc: Uc, addr: int, data: bytes) -> bool:
if addr == 0: if addr == 0:
return False return False
@@ -743,16 +944,86 @@ class CLeonOSWineNative:
return 1 if self._write_guest_bytes(uc, out_ptr, encoded + b"\x00") else 0 return 1 if self._write_guest_bytes(uc, out_ptr, encoded + b"\x00") else 0
def _exec_path(self, uc: Uc, path_ptr: int) -> int: def _exec_path(self, uc: Uc, path_ptr: int) -> int:
return self._spawn_path_common(uc, path_ptr, 0, 0, return_pid=False) return self._spawn_path_common(
uc,
path_ptr,
0,
0,
return_pid=False,
env_line_override=None,
stdin_fd=FD_INHERIT,
stdout_fd=FD_INHERIT,
stderr_fd=FD_INHERIT,
)
def _exec_pathv(self, uc: Uc, path_ptr: int, argv_ptr: int, env_ptr: int) -> int: def _exec_pathv(self, uc: Uc, path_ptr: int, argv_ptr: int, env_ptr: int) -> int:
return self._spawn_path_common(uc, path_ptr, argv_ptr, env_ptr, return_pid=False) return self._spawn_path_common(
uc,
path_ptr,
argv_ptr,
env_ptr,
return_pid=False,
env_line_override=None,
stdin_fd=FD_INHERIT,
stdout_fd=FD_INHERIT,
stderr_fd=FD_INHERIT,
)
def _exec_pathv_io(self, uc: Uc, path_ptr: int, argv_ptr: int, req_ptr: int) -> int:
req_data: Optional[bytes]
env_ptr: int
stdin_fd: int
stdout_fd: int
stderr_fd: int
env_line: str
if req_ptr == 0:
return u64_neg1()
req_data = self._read_guest_bytes_exact(uc, req_ptr, 32)
if req_data is None or len(req_data) != 32:
return u64_neg1()
env_ptr, stdin_fd, stdout_fd, stderr_fd = struct.unpack("<QQQQ", req_data)
env_line = self._read_guest_cstring(uc, env_ptr, EXEC_ENV_LINE_MAX) if env_ptr != 0 else ""
return self._spawn_path_common(
uc,
path_ptr,
argv_ptr,
0,
return_pid=False,
env_line_override=env_line,
stdin_fd=stdin_fd,
stdout_fd=stdout_fd,
stderr_fd=stderr_fd,
)
def _spawn_path(self, uc: Uc, path_ptr: int) -> int: def _spawn_path(self, uc: Uc, path_ptr: int) -> int:
return self._spawn_path_common(uc, path_ptr, 0, 0, return_pid=True) return self._spawn_path_common(
uc,
path_ptr,
0,
0,
return_pid=True,
env_line_override=None,
stdin_fd=FD_INHERIT,
stdout_fd=FD_INHERIT,
stderr_fd=FD_INHERIT,
)
def _spawn_pathv(self, uc: Uc, path_ptr: int, argv_ptr: int, env_ptr: int) -> int: def _spawn_pathv(self, uc: Uc, path_ptr: int, argv_ptr: int, env_ptr: int) -> int:
return self._spawn_path_common(uc, path_ptr, argv_ptr, env_ptr, return_pid=True) return self._spawn_path_common(
uc,
path_ptr,
argv_ptr,
env_ptr,
return_pid=True,
env_line_override=None,
stdin_fd=FD_INHERIT,
stdout_fd=FD_INHERIT,
stderr_fd=FD_INHERIT,
)
def _spawn_path_common( def _spawn_path_common(
self, self,
@@ -762,17 +1033,30 @@ class CLeonOSWineNative:
env_ptr: int, env_ptr: int,
*, *,
return_pid: bool, return_pid: bool,
env_line_override: Optional[str],
stdin_fd: int,
stdout_fd: int,
stderr_fd: int,
) -> int: ) -> int:
path = self._read_guest_cstring(uc, path_ptr, EXEC_PATH_MAX) path = self._read_guest_cstring(uc, path_ptr, EXEC_PATH_MAX)
guest_path = self._normalize_guest_path(path) guest_path = self._normalize_guest_path(path)
argv_line = self._read_guest_cstring(uc, argv_ptr, EXEC_ARG_LINE_MAX) if argv_ptr != 0 else "" argv_line = self._read_guest_cstring(uc, argv_ptr, EXEC_ARG_LINE_MAX) if argv_ptr != 0 else ""
env_line = self._read_guest_cstring(uc, env_ptr, EXEC_ENV_LINE_MAX) if env_ptr != 0 else "" env_line = (
env_line_override
if env_line_override is not None
else (self._read_guest_cstring(uc, env_ptr, EXEC_ENV_LINE_MAX) if env_ptr != 0 else "")
)
host_path = self._guest_to_host(guest_path, must_exist=True) host_path = self._guest_to_host(guest_path, must_exist=True)
child_stdio = self._build_child_stdio_map(int(stdin_fd), int(stdout_fd), int(stderr_fd))
self.state.exec_requests = u64(self.state.exec_requests + 1) self.state.exec_requests = u64(self.state.exec_requests + 1)
self.state.user_exec_requested = 1 self.state.user_exec_requested = 1
self.state.user_launch_tries = u64(self.state.user_launch_tries + 1) self.state.user_launch_tries = u64(self.state.user_launch_tries + 1)
if child_stdio is None:
self.state.user_launch_fail = u64(self.state.user_launch_fail + 1)
return u64_neg1()
if host_path is None or not host_path.is_file(): if host_path is None or not host_path.is_file():
self.state.user_launch_fail = u64(self.state.user_launch_fail + 1) self.state.user_launch_fail = u64(self.state.user_launch_fail + 1)
return u64_neg1() return u64_neg1()
@@ -802,6 +1086,7 @@ class CLeonOSWineNative:
ppid=parent_pid, ppid=parent_pid,
argv_items=argv_items, argv_items=argv_items,
env_items=env_items, env_items=env_items,
inherited_fds=child_stdio,
) )
child_ret = child.run() child_ret = child.run()
@@ -854,6 +1139,97 @@ class CLeonOSWineNative:
def _proc_fault_rip(self) -> int: def _proc_fault_rip(self) -> int:
return self.state.proc_fault_rip_value(self.state.get_current_pid()) return self.state.proc_fault_rip_value(self.state.get_current_pid())
def _proc_count(self) -> int:
return self.state.proc_count()
def _proc_pid_at(self, uc: Uc, index: int, out_ptr: int) -> int:
if out_ptr == 0:
return 0
pid = self.state.proc_pid_at(int(index))
if pid is None:
return 0
return 1 if self._write_guest_bytes(uc, out_ptr, struct.pack("<Q", u64(pid))) else 0
def _proc_snapshot(self, uc: Uc, pid: int, out_ptr: int, out_size: int) -> int:
if out_ptr == 0 or out_size < (13 * 8 + PROC_PATH_MAX):
return 0
target = int(pid)
state_value = self.state.proc_state_value(target)
if state_value == 0:
return 0
path = self.state.proc_path_value(target)
encoded_path = path.encode("utf-8", errors="replace")
if len(encoded_path) >= PROC_PATH_MAX:
encoded_path = encoded_path[: PROC_PATH_MAX - 1]
path_buf = encoded_path + b"\x00" + (b"\x00" * (PROC_PATH_MAX - len(encoded_path) - 1))
blob = struct.pack(
"<13Q",
u64(target),
u64(self.state.proc_ppid(target)),
u64(state_value),
u64(self.state.proc_started_tick_value(target)),
u64(self.state.proc_exited_tick_value(target)),
u64(self.state.proc_exit_status_value(target)),
u64(self.state.proc_runtime_ticks(target)),
u64(self.state.proc_mem_bytes_value(target)),
u64(self.state.proc_tty_index_value(target)),
u64(self.state.proc_signal(target)),
u64(self.state.proc_fault_vector_value(target)),
u64(self.state.proc_fault_error_value(target)),
u64(self.state.proc_fault_rip_value(target)),
) + path_buf
return 1 if self._write_guest_bytes(uc, out_ptr, blob) else 0
def _proc_kill(self, uc: Uc, pid: int, signal: int) -> int:
target = int(pid)
if target <= 0:
return u64_neg1()
current_state = self.state.proc_state_value(target)
if current_state == 0:
return u64_neg1()
effective_signal = int(signal) & 0xFF
if effective_signal == 0:
effective_signal = SIGTERM
self.state.set_proc_fault(target, effective_signal, 0, 0, 0)
if current_state == PROC_STATE_EXITED:
return 1
if effective_signal == SIGCONT:
if current_state == PROC_STATE_STOPPED:
self.state.set_proc_pending(target)
return 1
if effective_signal == SIGSTOP and current_state in (PROC_STATE_PENDING, PROC_STATE_STOPPED):
self.state.set_proc_stopped(target)
return 1
status = self._encode_signal_status(effective_signal, 0, 0)
if target == self.state.get_current_pid():
self._exit_requested = True
self._exit_status = u64(status)
if effective_signal == SIGSTOP:
self.state.set_proc_stopped(target)
uc.emu_stop()
return 1
if effective_signal == SIGSTOP:
self.state.set_proc_stopped(target)
return 1
self.state.mark_exited(target, status)
return 1
def _wait_pid(self, uc: Uc, pid: int, out_ptr: int) -> int: def _wait_pid(self, uc: Uc, pid: int, out_ptr: int) -> int:
wait_ret, status = self.state.wait_pid(int(pid)) wait_ret, status = self.state.wait_pid(int(pid))
@@ -885,6 +1261,190 @@ class CLeonOSWineNative:
time.sleep(0) time.sleep(0)
return self.state.timer_ticks() return self.state.timer_ticks()
def _fd_open(self, uc: Uc, path_ptr: int, flags: int, mode: int) -> int:
_ = mode
guest_path = self._normalize_guest_path(self._read_guest_cstring(uc, path_ptr, EXEC_PATH_MAX))
open_flags = int(u64(flags))
lower_path = guest_path.lower()
fd_slot: int
entry: FDEntry
if not guest_path.startswith("/"):
return u64_neg1()
if not self._fd_access_mode_valid(open_flags):
return u64_neg1()
if ((open_flags & O_TRUNC) != 0 or (open_flags & O_APPEND) != 0) and not self._fd_can_write(open_flags):
return u64_neg1()
fd_slot = self._fd_find_free()
if fd_slot < 0:
return u64_neg1()
if lower_path == "/dev/tty":
entry = FDEntry(kind="tty", flags=open_flags, offset=0, tty_index=self._tty_index)
self._fds[fd_slot] = entry
return fd_slot
if lower_path == "/dev/null":
entry = FDEntry(kind="dev_null", flags=open_flags, offset=0, tty_index=self._tty_index)
self._fds[fd_slot] = entry
return fd_slot
if lower_path == "/dev/zero":
entry = FDEntry(kind="dev_zero", flags=open_flags, offset=0, tty_index=self._tty_index)
self._fds[fd_slot] = entry
return fd_slot
if lower_path == "/dev/random":
entry = FDEntry(kind="dev_random", flags=open_flags, offset=0, tty_index=self._tty_index)
self._fds[fd_slot] = entry
return fd_slot
host_path = self._guest_to_host(guest_path, must_exist=False)
if host_path is None:
return u64_neg1()
try:
if not host_path.exists():
if (open_flags & O_CREAT) == 0 or not self._fd_can_write(open_flags):
return u64_neg1()
host_path.parent.mkdir(parents=True, exist_ok=True)
host_path.write_bytes(b"")
if host_path.is_dir():
return u64_neg1()
if (open_flags & O_TRUNC) != 0:
host_path.write_bytes(b"")
offset = int(host_path.stat().st_size) if (open_flags & O_APPEND) != 0 else 0
except Exception:
return u64_neg1()
entry = FDEntry(kind="file", flags=open_flags, offset=offset, path=str(host_path), tty_index=self._tty_index)
self._fds[fd_slot] = entry
return fd_slot
def _fd_read(self, uc: Uc, fd: int, out_ptr: int, size: int) -> int:
req = int(u64(size))
entry = self._fd_lookup(int(fd))
data: bytes
if req == 0:
return 0
if out_ptr == 0:
return u64_neg1()
if entry is None or not self._fd_can_read(entry.flags):
return u64_neg1()
req = min(req, MAX_IO_READ)
if entry.kind == "tty":
out = bytearray()
while len(out) < req:
key = self.state.pop_key()
if key is None:
break
out.append(key & 0xFF)
data = bytes(out)
elif entry.kind == "dev_null":
return 0
elif entry.kind == "dev_zero":
data = b"\x00" * req
elif entry.kind == "dev_random":
data = os.urandom(req)
elif entry.kind == "file":
try:
with open(entry.path, "rb") as fh:
fh.seek(entry.offset)
data = fh.read(req)
except Exception:
return u64_neg1()
else:
return u64_neg1()
if len(data) == 0:
return 0
if not self._write_guest_bytes(uc, int(out_ptr), data):
return u64_neg1()
entry.offset += len(data)
return len(data)
def _fd_write(self, uc: Uc, fd: int, buf_ptr: int, size: int) -> int:
req = int(u64(size))
entry = self._fd_lookup(int(fd))
data: Optional[bytes]
write_pos: int
if req == 0:
return 0
if buf_ptr == 0:
return u64_neg1()
if entry is None or not self._fd_can_write(entry.flags):
return u64_neg1()
req = min(req, MAX_IO_READ)
data = self._read_guest_bytes_exact(uc, int(buf_ptr), req)
if data is None:
return u64_neg1()
if entry.kind == "tty":
self._host_write_bytes(data)
entry.offset += len(data)
return len(data)
if entry.kind in ("dev_null", "dev_zero", "dev_random"):
entry.offset += len(data)
return len(data)
if entry.kind != "file":
return u64_neg1()
try:
host_path = Path(entry.path)
if not host_path.exists():
if (entry.flags & O_CREAT) == 0 or not self._fd_can_write(entry.flags):
return u64_neg1()
host_path.parent.mkdir(parents=True, exist_ok=True)
host_path.write_bytes(b"")
with open(host_path, "r+b") as fh:
write_pos = int(entry.offset)
fh.seek(write_pos)
fh.write(data)
except Exception:
return u64_neg1()
entry.offset += len(data)
return len(data)
def _fd_close(self, fd: int) -> int:
key = int(fd)
if key not in self._fds:
return u64_neg1()
del self._fds[key]
return 0
def _fd_dup(self, fd: int) -> int:
src = self._fd_lookup(int(fd))
if src is None:
return u64_neg1()
slot = self._fd_find_free()
if slot < 0:
return u64_neg1()
self._fds[slot] = self._clone_fd_entry(src)
return slot
@staticmethod @staticmethod
def _truncate_item_text(text: str, max_bytes: int = EXEC_ITEM_MAX) -> str: def _truncate_item_text(text: str, max_bytes: int = EXEC_ITEM_MAX) -> str:
if max_bytes <= 1: if max_bytes <= 1:

View File

@@ -6,7 +6,7 @@ import time
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Deque, Dict, List, Optional, Tuple from typing import Deque, Dict, List, Optional, Tuple
from .constants import u64 from .constants import PROC_STATE_EXITED, PROC_STATE_PENDING, PROC_STATE_RUNNING, PROC_STATE_STOPPED, u64
@dataclass @dataclass
@@ -37,13 +37,27 @@ class SharedKernelState:
kbd_hotkey_switches: int = 0 kbd_hotkey_switches: int = 0
log_journal_cap: int = 256 log_journal_cap: int = 256
log_journal: Deque[str] = field(default_factory=lambda: collections.deque(maxlen=256)) log_journal: Deque[str] = field(default_factory=lambda: collections.deque(maxlen=256))
fs_write_max: int = 65536 fs_write_max: int = 16 * 1024 * 1024
# syscall stats
stats_lock: threading.Lock = field(default_factory=threading.Lock)
stats_total_calls: int = 0
stats_id_total: Dict[int, int] = field(default_factory=dict)
stats_recent_window_cap: int = 256
stats_recent_ring: Deque[int] = field(default_factory=lambda: collections.deque(maxlen=256))
# process table
proc_lock: threading.Lock = field(default_factory=threading.Lock) proc_lock: threading.Lock = field(default_factory=threading.Lock)
proc_next_pid: int = 1 proc_next_pid: int = 1
proc_current_pid: int = 0 proc_current_pid: int = 0
proc_parents: Dict[int, int] = field(default_factory=dict) proc_parents: Dict[int, int] = field(default_factory=dict)
proc_status: Dict[int, Optional[int]] = field(default_factory=dict) proc_status: Dict[int, Optional[int]] = field(default_factory=dict)
proc_state: Dict[int, int] = field(default_factory=dict)
proc_started_tick: Dict[int, int] = field(default_factory=dict)
proc_exited_tick: Dict[int, int] = field(default_factory=dict)
proc_mem_bytes: Dict[int, int] = field(default_factory=dict)
proc_tty_index: Dict[int, int] = field(default_factory=dict)
proc_path: Dict[int, str] = field(default_factory=dict)
proc_argv: Dict[int, List[str]] = field(default_factory=dict) proc_argv: Dict[int, List[str]] = field(default_factory=dict)
proc_env: Dict[int, List[str]] = field(default_factory=dict) proc_env: Dict[int, List[str]] = field(default_factory=dict)
proc_last_signal: Dict[int, int] = field(default_factory=dict) proc_last_signal: Dict[int, int] = field(default_factory=dict)
@@ -54,6 +68,32 @@ class SharedKernelState:
def timer_ticks(self) -> int: def timer_ticks(self) -> int:
return (time.monotonic_ns() - self.start_ns) // 1_000_000 return (time.monotonic_ns() - self.start_ns) // 1_000_000
def record_syscall(self, sid: int) -> None:
key = int(u64(sid))
with self.stats_lock:
self.stats_total_calls = int(u64(self.stats_total_calls + 1))
self.stats_id_total[key] = int(u64(self.stats_id_total.get(key, 0) + 1))
self.stats_recent_ring.append(key)
def stats_total(self) -> int:
with self.stats_lock:
return int(self.stats_total_calls)
def stats_id_count(self, sid: int) -> int:
key = int(u64(sid))
with self.stats_lock:
return int(self.stats_id_total.get(key, 0))
def stats_recent_window(self) -> int:
with self.stats_lock:
return len(self.stats_recent_ring)
def stats_recent_id_count(self, sid: int) -> int:
key = int(u64(sid))
with self.stats_lock:
return sum(1 for item in self.stats_recent_ring if item == key)
def push_key(self, key: int) -> None: def push_key(self, key: int) -> None:
with self.kbd_lock: with self.kbd_lock:
if len(self.kbd_queue) >= self.kbd_queue_cap: if len(self.kbd_queue) >= self.kbd_queue_cap:
@@ -94,6 +134,8 @@ class SharedKernelState:
return list(self.log_journal)[index_from_oldest] return list(self.log_journal)[index_from_oldest]
def alloc_pid(self, ppid: int) -> int: def alloc_pid(self, ppid: int) -> int:
now = self.timer_ticks()
with self.proc_lock: with self.proc_lock:
pid = int(self.proc_next_pid) pid = int(self.proc_next_pid)
@@ -107,6 +149,12 @@ class SharedKernelState:
self.proc_parents[pid] = int(ppid) self.proc_parents[pid] = int(ppid)
self.proc_status[pid] = None self.proc_status[pid] = None
self.proc_state[pid] = PROC_STATE_PENDING
self.proc_started_tick[pid] = now
self.proc_exited_tick[pid] = 0
self.proc_mem_bytes[pid] = 0
self.proc_tty_index[pid] = int(self.tty_active)
self.proc_path[pid] = ""
self.proc_argv[pid] = [] self.proc_argv[pid] = []
self.proc_env[pid] = [] self.proc_env[pid] = []
self.proc_last_signal[pid] = 0 self.proc_last_signal[pid] = 0
@@ -123,12 +171,51 @@ class SharedKernelState:
with self.proc_lock: with self.proc_lock:
return int(self.proc_current_pid) return int(self.proc_current_pid)
def set_proc_running(self, pid: int, path: Optional[str], tty_index: int) -> None:
if pid <= 0:
return
now = self.timer_ticks()
with self.proc_lock:
if pid not in self.proc_status:
return
self.proc_state[pid] = PROC_STATE_RUNNING
if self.proc_started_tick.get(pid, 0) == 0:
self.proc_started_tick[pid] = now
self.proc_tty_index[pid] = int(tty_index)
if path:
self.proc_path[pid] = str(path)
def mark_exited(self, pid: int, status: int) -> None: def mark_exited(self, pid: int, status: int) -> None:
if pid <= 0: if pid <= 0:
return return
with self.proc_lock: with self.proc_lock:
self.proc_status[int(pid)] = int(u64(status)) self.proc_status[int(pid)] = int(u64(status))
self.proc_state[int(pid)] = PROC_STATE_EXITED
self.proc_exited_tick[int(pid)] = self.timer_ticks()
def set_proc_stopped(self, pid: int) -> None:
if pid <= 0:
return
with self.proc_lock:
if pid not in self.proc_status:
return
if self.proc_state.get(pid, PROC_STATE_PENDING) != PROC_STATE_EXITED:
self.proc_state[pid] = PROC_STATE_STOPPED
def set_proc_pending(self, pid: int) -> None:
if pid <= 0:
return
with self.proc_lock:
if pid not in self.proc_status:
return
if self.proc_state.get(pid, PROC_STATE_PENDING) != PROC_STATE_EXITED:
self.proc_state[pid] = PROC_STATE_PENDING
def wait_pid(self, pid: int) -> Tuple[int, int]: def wait_pid(self, pid: int) -> Tuple[int, int]:
with self.proc_lock: with self.proc_lock:
@@ -151,6 +238,8 @@ class SharedKernelState:
return return
self.proc_argv[pid] = [str(item) for item in argv] self.proc_argv[pid] = [str(item) for item in argv]
self.proc_env[pid] = [str(item) for item in env] self.proc_env[pid] = [str(item) for item in env]
if argv:
self.proc_path[pid] = str(argv[0])
def set_proc_fault(self, pid: int, signal: int, vector: int, error_code: int, rip: int) -> None: def set_proc_fault(self, pid: int, signal: int, vector: int, error_code: int, rip: int) -> None:
if pid <= 0: if pid <= 0:
@@ -164,6 +253,68 @@ class SharedKernelState:
self.proc_fault_error[pid] = int(u64(error_code)) self.proc_fault_error[pid] = int(u64(error_code))
self.proc_fault_rip[pid] = int(u64(rip)) self.proc_fault_rip[pid] = int(u64(rip))
def proc_count(self) -> int:
with self.proc_lock:
return len(self.proc_status)
def proc_pid_at(self, index: int) -> Optional[int]:
if index < 0:
return None
with self.proc_lock:
ordered = sorted(self.proc_status.keys())
if index >= len(ordered):
return None
return int(ordered[index])
def proc_state_value(self, pid: int) -> int:
with self.proc_lock:
return int(self.proc_state.get(int(pid), 0))
def proc_ppid(self, pid: int) -> int:
with self.proc_lock:
return int(self.proc_parents.get(int(pid), 0))
def proc_started_tick_value(self, pid: int) -> int:
with self.proc_lock:
return int(self.proc_started_tick.get(int(pid), 0))
def proc_exited_tick_value(self, pid: int) -> int:
with self.proc_lock:
return int(self.proc_exited_tick.get(int(pid), 0))
def proc_exit_status_value(self, pid: int) -> int:
with self.proc_lock:
value = self.proc_status.get(int(pid))
return int(value) if value is not None else 0
def proc_runtime_ticks(self, pid: int) -> int:
with self.proc_lock:
start = int(self.proc_started_tick.get(int(pid), 0))
state = int(self.proc_state.get(int(pid), 0))
end = int(self.proc_exited_tick.get(int(pid), 0))
if start == 0:
return 0
if state == PROC_STATE_EXITED and end >= start:
return end - start
now = self.timer_ticks()
return 0 if now < start else now - start
def proc_mem_bytes_value(self, pid: int) -> int:
with self.proc_lock:
return int(self.proc_mem_bytes.get(int(pid), 0))
def proc_tty_index_value(self, pid: int) -> int:
with self.proc_lock:
return int(self.proc_tty_index.get(int(pid), 0))
def proc_path_value(self, pid: int) -> str:
with self.proc_lock:
return str(self.proc_path.get(int(pid), ""))
def proc_argc(self, pid: int) -> int: def proc_argc(self, pid: int) -> int:
with self.proc_lock: with self.proc_lock:
return len(self.proc_argv.get(int(pid), [])) return len(self.proc_argv.get(int(pid), []))