diff --git a/Kernel/Core/Kernel.c b/Kernel/Core/Kernel.c index 69edb25..0374bc0 100644 --- a/Kernel/Core/Kernel.c +++ b/Kernel/Core/Kernel.c @@ -172,17 +172,14 @@ void RemapPIC() { void KernelMain(uint32_t magic, uint32_t info) { ClearScreen(); PrintKernel("[SUCCESS] VoidFrame Kernel - Version 0.0.1-alpha loaded\n"); - GdtInit(); IdtInstall(); SyscallInit(); PicInstall(); MemoryInit(); ProcessInit(); - CheckPid0Magic("After ProcessInit in KernelMain"); // Create the security manager process (PID 1) - this is critical uint32_t security_pid = CreateSecureProcess(SecureKernelIntegritySubsystem, PROC_PRIV_SYSTEM); - CheckPid0Magic("After CreateSecureProcess (Security Manager) in KernelMain"); if (!security_pid) { Panic("\nCannot create SecureKernelIntegritySubsystem() - Critical security failure\n"); } diff --git a/Kernel/Process/Process.c b/Kernel/Process/Process.c index 31eb483..4a87ef7 100644 --- a/Kernel/Process/Process.c +++ b/Kernel/Process/Process.c @@ -1,130 +1,150 @@ +// --- START OF REWORKED FILE Process.c --- + #include "Process.h" #include "Kernel.h" #include "Memory.h" #include "Panic.h" #include "Io.h" -#include "../Memory/MemOps.h" // Use kernel memory ops instead of +#include "../Memory/MemOps.h" + #define NULL ((void*)0) +#define offsetof(type, member) ((uint64_t)&(((type*)0)->member)) +// For cleaner debugging, you can toggle this +// #define DEBUG_SECURITY + static Process processes[MAX_PROCESSES]; static uint32_t next_pid = 1; static uint32_t current_process = 0; static uint32_t process_count = 0; -static int need_schedule = 0; - +static volatile int need_schedule = 0; // Security globals -static uint32_t security_manager_pid = 0; // PID of SecureKernelIntegritySubsystem -static uint64_t security_magic = 0x5EC0DE4D41474943ULL; // "SECODEMAGIC" +static uint32_t security_manager_pid = 0; +// REWORK: Magic number is good. No changes needed. +static const uint64_t security_magic = 0x5EC0DE4D41474943ULL; // "SECODEMAGIC" extern void SwitchContext(ProcessContext * old, ProcessContext * new); -// Debug function to check PID 0's token magic -void CheckPid0Magic(const char* location) { - PrintKernel("CheckPid0Magic at "); - PrintKernel(location); - PrintKernel(": "); - PrintKernelHex(processes[0].token.magic); - PrintKernel("\n"); -} - -static inline uint16_t CalculateChecksum(const SecurityToken* token) { +/** + * @brief Calculates the checksum for a security token. + * + * @param token The token to checksum. + * @return The 16-bit checksum. + * + * REWORK: This implementation is more robust and cleaner. It checksums all + * fields *before* the checksum field itself. This is less error-prone than + * manually adding up chunks of the struct. + */ +static uint16_t CalculateChecksum(const SecurityToken* token, uint32_t pid_for_checksum) { uint16_t sum = 0; + const uint8_t* data = (const uint8_t*)token; - // Sum magic (8 bytes) - sum += (uint16_t)(token->magic & 0xFFFF); - sum += (uint16_t)((token->magic >> 16) & 0xFFFF); - sum += (uint16_t)((token->magic >> 32) & 0xFFFF); - sum += (uint16_t)((token->magic >> 48) & 0xFFFF); - - // Sum creator_pid (4 bytes) - sum += (uint16_t)(token->creator_pid & 0xFFFF); - sum += (uint16_t)((token->creator_pid >> 16) & 0xFFFF); - - // Sum privilege (1 byte) - sum += (uint16_t)token->privilege; + // Checksum all data in the token struct up to the checksum field itself. + for (uint64_t i = 0; i < offsetof(SecurityToken, checksum); i++) { + sum += data[i]; + } - // Sum flags (1 byte) - sum += (uint16_t)token->flags; + // REWORK: Add the process's OWN PID to the checksum. + sum += (uint16_t)(pid_for_checksum & 0xFFFF); + sum += (uint16_t)((pid_for_checksum >> 16) & 0xFFFF); return sum; } -static inline int ValidateToken(const SecurityToken* token) { - uint16_t calculated_checksum = CalculateChecksum(token); - int is_valid = (token->magic == security_magic) && - (token->checksum == calculated_checksum); - - PrintKernel("ValidateToken Debug for PID: "); - PrintKernelInt(token->creator_pid); // Using creator_pid as a proxy for process ID - PrintKernel("\n"); - PrintKernel(" Token Magic: "); PrintKernelHex(token->magic); PrintKernel("\n"); - PrintKernel(" Expected Magic: "); PrintKernelHex(security_magic); PrintKernel("\n"); - PrintKernel(" Token Checksum: "); PrintKernelHex(token->checksum); PrintKernel("\n"); - PrintKernel(" Calculated Checksum: "); PrintKernelHex(calculated_checksum); PrintKernel("\n"); - PrintKernel(" Magic Match: "); PrintKernelInt(token->magic == security_magic); PrintKernel("\n"); - PrintKernel(" Checksum Match: "); PrintKernelInt(token->checksum == calculated_checksum); PrintKernel("\n"); - PrintKernel(" Is Valid: "); PrintKernelInt(is_valid); PrintKernel("\n"); - - return is_valid; -} - -static void init_token(SecurityToken* token, uint32_t creator_pid, uint8_t privilege) { - token->magic = security_magic; - token->creator_pid = creator_pid; - token->privilege = privilege; - token->flags = 0; - token->checksum = 0; // Zero out checksum before calculating - token->checksum = CalculateChecksum(token); -} - int ShouldSchedule(void) { if (need_schedule) { - need_schedule = 0; + need_schedule = 0; // Atomically reset the flag return 1; } return 0; } +/** + * @brief Sets a flag indicating the scheduler should run at the next opportunity. + */ void RequestSchedule(void) { need_schedule = 1; } -void ProcessInit(void) { - // Clear all processes array - FastMemset(processes, 0, sizeof(Process) * MAX_PROCESSES); +void Yield() { + RequestSchedule(); + __asm__ __volatile__("hlt"); +} - // Debug print for SecurityToken size - PrintKernel("sizeof(SecurityToken): "); - PrintKernelInt(sizeof(SecurityToken)); - PrintKernel("\n"); +/** + * @brief Validates a security token's integrity. + * + * @param token The token to validate. + * @return 1 if valid, 0 otherwise. + * + * REWORK: Simplified the logic and made debug prints conditional. + * This function now has one clear purpose: check magic and checksum. + */ +static int ValidateToken(const SecurityToken* token, uint32_t pid_to_check) { + if (token->magic != security_magic) { + return 0; + } + + uint16_t calculated_checksum = CalculateChecksum(token, pid_to_check); // Pass the PID + if (token->checksum != calculated_checksum) { + return 0; + } + + return 1; +} + +/** + * @brief Initializes a security token and calculates its checksum. + * + * @param token Pointer to the token to initialize. + * @param creator_pid PID of the process creating this token. + * @param privilege The privilege level for the new token. + */ +static void init_token(SecurityToken* token, uint32_t creator_pid, uint8_t privilege, uint32_t new_pid) { + token->magic = security_magic; + token->creator_pid = creator_pid; + token->privilege = privilege; + token->flags = 0; + token->checksum = 0; + token->checksum = CalculateChecksum(token, new_pid); // Pass the new PID +} - // Create idle process (PID 0) - system privilege - processes[0].pid = 0; +// REWORK: Removed ShouldSchedule and RequestSchedule as they weren't used +// in the provided scheduling logic. If used elsewhere, they can be added back. +void ProcessInit(void) { + FastMemset(processes, 0, sizeof(Process) * MAX_PROCESSES); + + // Create idle process (PID 0) - this is the root of trust. + processes[0].pid = 0; processes[0].state = PROC_RUNNING; - processes[0].priority = 0; + processes[0].priority = 255; // Lowest priority processes[0].privilege_level = PROC_PRIV_SYSTEM; processes[0].is_user_mode = 0; - // Initialize security token for idle process - init_token(&processes[0].token, 0, PROC_PRIV_SYSTEM); - CheckPid0Magic("After init_token in ProcessInit"); - - // Clear context - for (int i = 0; i < sizeof(ProcessContext)/8; i++) { - ((uint64_t*)&processes[0].context)[i] = 0; - } + // Initialize security token for the idle process. Created by "itself" (PID 0). + init_token(&processes[0].token, 0, PROC_PRIV_SYSTEM, processes[0].pid); process_count = 1; + current_process = 0; } uint32_t CreateProcess(void (*entry_point)(void)) { return CreateSecureProcess(entry_point, PROC_PRIV_USER); } -void SecureProcessExitStub() { - PrintKernel("[SECURITY] Process returned! This shouldn't happen!\n"); +// A stub function for processes that return, which they should not. +void ProcessExitStub() { + // In a real kernel, this would be a syscall to terminate the process. + PrintKernel("[KERNEL] Process returned from its main function. This is an error!\n"); + PrintKernel("Terminating process PID: "); + PrintKernelInt(GetCurrentProcess()->pid); + PrintKernel("\n"); + + // For now, just halt. A proper implementation would terminate and schedule. + GetCurrentProcess()->state = PROC_TERMINATED; + // RequestSchedule(); // If you had a yield/schedule primitive. while (1) { __asm__ __volatile__("hlt"); } } @@ -132,16 +152,19 @@ uint32_t CreateSecureProcess(void (*entry_point)(void), uint8_t privilege) { if (!entry_point) { Panic("CreateSecureProcess: NULL entry point"); } - // Fast security check - only security manager can create system processes - if (privilege == PROC_PRIV_SYSTEM) { - if (current_process >= MAX_PROCESSES) { - Panic("CreateSecureProcess: Invalid current process"); - } - // Only security manager (or initial kernel) can create system processes - if (security_manager_pid != 0 && processes[current_process].pid != security_manager_pid) { - PrintKernel("[SECURITY] Unauthorized system process creation attempt\n"); - return 0; // Fail silently for security + // REWORK: This is a critical security boundary. + // Check if the *current* process has the right to create a process with the + // requested privilege level. + if (privilege == PROC_PRIV_SYSTEM) { + Process* creator = GetCurrentProcess(); + // Only allow the kernel (during init, pid=0) or another SYSTEM process + // to create a new SYSTEM process. + if (creator->pid != 0 && creator->privilege_level != PROC_PRIV_SYSTEM) { + PrintKernel("[SECURITY] Denied: PID "); + PrintKernelInt(creator->pid); + PrintKernel(" attempted to create a system-level process.\n"); + return 0; // Fail gracefully. } } @@ -149,127 +172,102 @@ uint32_t CreateSecureProcess(void (*entry_point)(void), uint8_t privilege) { Panic("CreateSecureProcess: Too many processes"); } - // Find free slot (optimized loop) + // Find a free process slot. int slot = -1; - for (int i = 1; i < MAX_PROCESSES; i++) { + for (int i = 0; i < MAX_PROCESSES; i++) { // Check all slots if (processes[i].state == PROC_TERMINATED) { slot = i; break; } } + // If no terminated slots, use the next available one. if (slot == -1) { - Panic("CreateSecureProcess: No free process slots"); + if (next_pid <= MAX_PROCESSES) { + slot = process_count; // Use the next empty slot + } else { + Panic("CreateSecureProcess: No free process slots"); + } } - // Clear the entire process slot to ensure a clean state + + // Clear the slot for the new process. FastMemset(&processes[slot], 0, sizeof(Process)); - // Allocate stack void* stack = AllocPage(); if (!stack) { Panic("CreateSecureProcess: Failed to allocate stack"); } - // Initialize process + // Initialize process fields processes[slot].pid = next_pid++; processes[slot].state = PROC_READY; processes[slot].stack = stack; - processes[slot].priority = (privilege == PROC_PRIV_SYSTEM) ? 0 : 1; - processes[slot].is_user_mode = (privilege != PROC_PRIV_SYSTEM); processes[slot].privilege_level = privilege; + processes[slot].priority = (privilege == PROC_PRIV_SYSTEM) ? 10 : 100; // Lower number is higher priority + processes[slot].is_user_mode = (privilege != PROC_PRIV_SYSTEM); - // Initialize security token - uint32_t creator_pid = (current_process < MAX_PROCESSES) ? processes[current_process].pid : 0; - init_token(&processes[slot].token, creator_pid, privilege); - - // Clear context - FastMemset(&processes[slot].context, 0, sizeof(ProcessContext)); + // Create the token. The creator is the currently running process. + init_token(&processes[slot].token, GetCurrentProcess()->pid, privilege, processes[slot].pid); + // Set up the initial context for the new process uint64_t rsp = (uint64_t)processes[slot].stack + STACK_SIZE; - rsp &= ~0xF; // 16-byte alignment + rsp &= ~0xF; // 16-byte alignment is good practice. - // Set up stack with proper return address + // Push the return address for the process's main function. uint64_t* stack_ptr = (uint64_t*)rsp; - *(--stack_ptr) = (uint64_t)&SecureProcessExitStub; + *(--stack_ptr) = (uint64_t)&ProcessExitStub; - // Initialize the context as a proper interrupt frame + FastMemset(&processes[slot].context, 0, sizeof(ProcessContext)); processes[slot].context.rsp = (uint64_t)stack_ptr; processes[slot].context.rip = (uint64_t)entry_point; - processes[slot].context.rflags = 0x202; // Interrupts enabled, bit 1 always 1 - processes[slot].context.cs = 0x08; // Kernel code segment - processes[slot].context.ss = 0x10; // Kernel data segment - processes[slot].context.ds = 0x10; // Kernel data segment - processes[slot].context.es = 0x10; // Kernel data segment - processes[slot].context.fs = 0x10; // Kernel data segment - processes[slot].context.gs = 0x10; // Kernel data segment - processes[slot].context.interrupt_number = 0; - processes[slot].context.error_code = 0; + processes[slot].context.rflags = 0x202; // Interrupts enabled + processes[slot].context.cs = 0x08; + processes[slot].context.ss = 0x10; process_count++; return processes[slot].pid; } void ScheduleFromInterrupt(struct Registers* regs) { - CheckPid0Magic("Start of ScheduleFromInterrupt"); - if (!regs) { - Panic("ScheduleFromInterrupt: NULL registers"); - } - - if (current_process >= MAX_PROCESSES) { - Panic("ScheduleFromInterrupt: Invalid current process"); - } - if (process_count <= 1) return; - // Find next ready process, prioritizing system processes - uint32_t next = (current_process + 1) % MAX_PROCESSES; - uint32_t start = next; - uint32_t best_candidate = current_process; - uint8_t best_priority = 255; - - do { - if (processes[next].state == PROC_READY || processes[next].state == PROC_RUNNING) { - if (next != current_process) { - // Validate security token - if (ValidateToken(&processes[next].token)) { - // Priority: system processes (0) > user processes (1) - if (processes[next].priority < best_priority) { - best_candidate = next; - best_priority = processes[next].priority; - } - } else { - // Invalid token - terminate process - PrintKernel("[SECURITY] Invalid token detected, terminating process\n"); - processes[next].state = PROC_TERMINATED; - if (processes[next].stack) { - FreePage(processes[next].stack); - processes[next].stack = NULL; - } - process_count--; - } + // Save the context of the current process + FastMemcpy(&processes[current_process].context, regs, sizeof(struct Registers)); + if (processes[current_process].state == PROC_RUNNING) { + processes[current_process].state = PROC_READY; + } + + // REWORK: The scheduler is now much simpler and faster. + // It does NOT validate security tokens. It trusts that any process in the + // ready queue is valid. Its job is simply to find the best next process. + uint32_t next_proc_idx = current_process; + uint8_t best_priority = 255; // Start with the worst possible priority + + // Round-robin search for the highest priority (lowest value) process + for (uint32_t i = 1; i <= process_count; i++) { + uint32_t candidate_idx = (current_process + i) % MAX_PROCESSES; + + if ((processes[candidate_idx].state == PROC_READY || processes[candidate_idx].state == PROC_RUNNING) + && processes[candidate_idx].pid != 0) // Don't schedule the idle process unless nothing else is ready + { + if (processes[candidate_idx].priority < best_priority) { + best_priority = processes[candidate_idx].priority; + next_proc_idx = candidate_idx; } } - next = (next + 1) % MAX_PROCESSES; - } while (next != start); - - // Switch to best candidate if different from current - if (best_candidate != current_process) { - // Save current process's full interrupt frame - // Now this is safe because ProcessContext == struct Registers - FastMemcpy(&processes[current_process].context, regs, sizeof(struct Registers)); - - // Update current process state - if (processes[current_process].state == PROC_RUNNING) { - processes[current_process].state = PROC_READY; - } - - // Update new process state - processes[best_candidate].state = PROC_RUNNING; + } - // Restore next process's full interrupt frame - FastMemcpy(regs, &processes[best_candidate].context, sizeof(struct Registers)); - current_process = best_candidate; + // If no other process was ready, schedule the idle process (pid 0) + if (next_proc_idx == current_process && processes[current_process].state != PROC_RUNNING) { + next_proc_idx = 0; // Fallback to idle process } + + // Switch to the chosen process + current_process = next_proc_idx; + processes[current_process].state = PROC_RUNNING; + + // Restore the context of the next process + FastMemcpy(regs, &processes[current_process].context, sizeof(struct Registers)); } Process* GetCurrentProcess(void) { @@ -285,10 +283,11 @@ Process* GetProcessByPid(uint32_t pid) { return &processes[i]; } } - return 0; + return NULL; } void RegisterSecurityManager(uint32_t pid) { + // This is still useful for identifying a specific process with a role. security_manager_pid = pid; PrintKernel("[SECURITY] Security manager registered with PID: "); PrintKernelInt(pid); @@ -296,52 +295,51 @@ void RegisterSecurityManager(uint32_t pid) { } void SystemService(void) { - PrintKernel("[SYSTEM] System service started\n"); + PrintKernel("[SYSTEM] System service started.\n"); + uint32_t pid = GetCurrentProcess()->pid; while (1) { - // Do system work - for (volatile int i = 0; i < 10000; i++); + PrintKernel("System service running (PID "); + PrintKernelInt(pid); + PrintKernel(")\n"); + Yield(); } } void SecureKernelIntegritySubsystem(void) { - PrintKernel("SecureKernelIntegritySubsystem() Initializing...\n"); - // Register this process as the security manager + PrintKernel("[SECURITY] SecureKernelIntegritySubsystem initializing...\n"); + Process* current = GetCurrentProcess(); - if (current) { - RegisterSecurityManager(current->pid); - PrintKernel("[SECURITY] SecureKernelIntegritySubsystem active\n"); - } + RegisterSecurityManager(current->pid); - // Example: Create a system service process + PrintKernel("[SECURITY] Creating a system service...\n"); uint32_t service_pid = CreateSecureProcess(SystemService, PROC_PRIV_SYSTEM); if (service_pid) { PrintKernel("[SECURITY] Created system service with PID: "); PrintKernelInt(service_pid); PrintKernel("\n"); + } else { + Panic("[SECURITY] Failed to create system service.\n"); } - // Main security loop + PrintKernel("[SECURITY] Integrity monitoring loop starting.\n"); + // REWORK: The SKIS is a background auditor. It runs with lower frequency + // and acts as a safety net. while (1) { - CheckPid0Magic("Start of SecureKernelIntegritySubsystem loop"); - static int check_counter = 0; - if (++check_counter % 1000 != 0) { - for (volatile int i = 0; i < 1000; i++); - continue; - } + Yield(); for (int i = 0; i < MAX_PROCESSES; i++) { - if (processes[i].state != PROC_TERMINATED) { - // Validate process tokens - if (!ValidateToken(&processes[i].token)) { - PrintKernel("[SECURITY] Token validation failed for PID: "); + if ((processes[i].state == PROC_READY || processes[i].state == PROC_RUNNING) && processes[i].pid != 0) { + if (!ValidateToken(&processes[i].token, processes[i].pid)) { + PrintKernel("[SECURITY] SecureKernelIntegritySubsystem found a corrupt token for PID: "); PrintKernelInt(processes[i].pid); - PrintKernel("\n"); - // Terminate compromised process + PrintKernel("! Terminating.\n"); processes[i].state = PROC_TERMINATED; + if (processes[i].stack) { + FreePage(processes[i].stack); + processes[i].stack = NULL; + } process_count--; } } } - // Small delay to prevent excessive CPU usage - for (volatile int i = 0; i < 1000; i++); } } \ No newline at end of file diff --git a/Kernel/Process/Process.h b/Kernel/Process/Process.h index 2b1257d..2b4972d 100644 --- a/Kernel/Process/Process.h +++ b/Kernel/Process/Process.h @@ -64,5 +64,4 @@ void ScheduleFromInterrupt(struct Registers* regs); void RegisterSecurityManager(uint32_t pid); void SecureKernelIntegritySubsystem(void); void SystemService(void); -void CheckPid0Magic(const char* location); #endif \ No newline at end of file