]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
x86/usermode: add ring3 fault-injection tests for sys_write
authorTulio A M Mendes <[email protected]>
Fri, 6 Feb 2026 13:29:27 +0000 (10:29 -0300)
committerTulio A M Mendes <[email protected]>
Fri, 6 Feb 2026 13:29:27 +0000 (10:29 -0300)
.gitignore
src/arch/x86/usermode.c

index 7e73df7241d3b27b5b93c60a264313c67689f78b..aa39258eb16d3017b3aca46f28ba4b2bdb86ec60 100644 (file)
@@ -14,6 +14,8 @@ compile_commands.json
 clang-tidy.txt
 cppcheck.txt
 scanbuild-out/
+gcc-analyzer.txt
+splint.txt
 
 # Temporary folders
 iso_root/
index 4d7c8357398e008efc42841477164152e6be25f4..58a8acdfe2a373e27e34b254cdccecb868fdfe14 100644 (file)
@@ -8,6 +8,55 @@
 
 #if defined(__i386__)
 
+enum {
+    SYSCALL_WRITE_NO = 1,
+    SYSCALL_EXIT_NO  = 2,
+};
+
+struct emitter {
+    uint8_t* buf;
+    size_t pos;
+};
+
+struct patch {
+    size_t at;
+    size_t target;
+};
+
+static void emit8(struct emitter* e, uint8_t v) { e->buf[e->pos++] = v; }
+static void emit32(struct emitter* e, uint32_t v) {
+    e->buf[e->pos++] = (uint8_t)(v & 0xFF);
+    e->buf[e->pos++] = (uint8_t)((v >> 8) & 0xFF);
+    e->buf[e->pos++] = (uint8_t)((v >> 16) & 0xFF);
+    e->buf[e->pos++] = (uint8_t)((v >> 24) & 0xFF);
+}
+
+static void emit_mov_eax_imm(struct emitter* e, uint32_t imm) { emit8(e, 0xB8); emit32(e, imm); }
+static void emit_mov_ebx_imm(struct emitter* e, uint32_t imm) { emit8(e, 0xBB); emit32(e, imm); }
+static void emit_mov_ecx_imm(struct emitter* e, uint32_t imm) { emit8(e, 0xB9); emit32(e, imm); }
+static void emit_mov_edx_imm(struct emitter* e, uint32_t imm) { emit8(e, 0xBA); emit32(e, imm); }
+static void emit_int80(struct emitter* e) { emit8(e, 0xCD); emit8(e, 0x80); }
+static void emit_cmp_eax_imm(struct emitter* e, uint32_t imm) { emit8(e, 0x3D); emit32(e, imm); }
+
+static void emit_jne_rel8_patch(struct emitter* e, struct patch* p, size_t target) {
+    emit8(e, 0x75);
+    p->at = e->pos;
+    p->target = target;
+    emit8(e, 0x00);
+}
+
+static void emit_jmp_rel8_patch(struct emitter* e, struct patch* p, size_t target) {
+    emit8(e, 0xEB);
+    p->at = e->pos;
+    p->target = target;
+    emit8(e, 0x00);
+}
+
+static void patch_rel8(uint8_t* buf, size_t at, size_t target) {
+    int32_t rel = (int32_t)target - (int32_t)(at + 1);
+    buf[at] = (uint8_t)(int8_t)rel;
+}
+
 static void* pmm_alloc_page_low_16mb(void) {
     for (int tries = 0; tries < 4096; tries++) {
         void* p = pmm_alloc_page();
@@ -63,21 +112,121 @@ void x86_usermode_test_start(void) {
     vmm_map_page((uint64_t)(uintptr_t)stack_phys, (uint64_t)user_stack_vaddr,
                  VMM_FLAG_PRESENT | VMM_FLAG_RW | VMM_FLAG_USER);
 
-    static const uint8_t user_prog[] = {
-        0xB8, 0x01, 0x00, 0x00, 0x00,             /* mov eax, 1 (SYSCALL_WRITE) */
-        0xBB, 0x01, 0x00, 0x00, 0x00,             /* mov ebx, 1 (stdout) */
-        0xB9, 0x40, 0x00, 0x40, 0x00,             /* mov ecx, 0x00400040 */
-        0xBA, 0x12, 0x00, 0x00, 0x00,             /* mov edx, 0x12 */
-        0xCD, 0x80,                               /* int 0x80 */
-        0xB8, 0x02, 0x00, 0x00, 0x00,             /* mov eax, 2 (SYSCALL_EXIT) */
-        0xCD, 0x80,                               /* int 0x80 */
-        0xEB, 0xFE                                /* jmp $ (loop) */
-    };
-
-    static const char msg[] = "Hello from ring3!\n";
-
-    memcpy((void*)(uintptr_t)code_phys, user_prog, sizeof(user_prog));
-    memcpy((void*)((uintptr_t)code_phys + 0x40), msg, sizeof(msg) - 1);
+    const uintptr_t base = user_code_vaddr;
+    const uint32_t addr_t1_ok = (uint32_t)(base + 0x200);
+    const uint32_t addr_t1_fail = (uint32_t)(base + 0x210);
+    const uint32_t addr_t2_ok = (uint32_t)(base + 0x220);
+    const uint32_t addr_t2_fail = (uint32_t)(base + 0x230);
+    const uint32_t addr_t3_ok = (uint32_t)(base + 0x240);
+    const uint32_t addr_t3_fail = (uint32_t)(base + 0x250);
+    const uint32_t addr_msg = (uint32_t)(base + 0x300);
+
+    const uint32_t t1_ok_len = 6;
+    const uint32_t t1_fail_len = 8;
+    const uint32_t t2_ok_len = 6;
+    const uint32_t t2_fail_len = 8;
+    const uint32_t t3_ok_len = 6;
+    const uint32_t t3_fail_len = 8;
+    const uint32_t msg_len = 18;
+
+    struct emitter e = { .buf = (uint8_t*)(uintptr_t)code_phys, .pos = 0 };
+
+    /* T1: write(NULL) -> -1 */
+    emit_mov_eax_imm(&e, SYSCALL_WRITE_NO);
+    emit_mov_ebx_imm(&e, 1);
+    emit_mov_ecx_imm(&e, 0x00000000U);
+    emit_mov_edx_imm(&e, 10);
+    emit_int80(&e);
+    emit_cmp_eax_imm(&e, 0xFFFFFFFFU);
+    struct patch t1_fail_jne = {0};
+    emit_jne_rel8_patch(&e, &t1_fail_jne, 0);
+    /* OK print */
+    emit_mov_eax_imm(&e, SYSCALL_WRITE_NO);
+    emit_mov_ebx_imm(&e, 1);
+    emit_mov_ecx_imm(&e, addr_t1_ok);
+    emit_mov_edx_imm(&e, t1_ok_len);
+    emit_int80(&e);
+    struct patch t1_to_t2 = {0};
+    emit_jmp_rel8_patch(&e, &t1_to_t2, 0);
+    /* FAIL label */
+    size_t t1_fail_pos = e.pos;
+    emit_mov_eax_imm(&e, SYSCALL_WRITE_NO);
+    emit_mov_ebx_imm(&e, 1);
+    emit_mov_ecx_imm(&e, addr_t1_fail);
+    emit_mov_edx_imm(&e, t1_fail_len);
+    emit_int80(&e);
+    size_t t2_pos = e.pos;
+
+    /* T2: write(0xC0000000) -> -1 */
+    emit_mov_eax_imm(&e, SYSCALL_WRITE_NO);
+    emit_mov_ebx_imm(&e, 1);
+    emit_mov_ecx_imm(&e, 0xC0000000U);
+    emit_mov_edx_imm(&e, 10);
+    emit_int80(&e);
+    emit_cmp_eax_imm(&e, 0xFFFFFFFFU);
+    struct patch t2_fail_jne = {0};
+    emit_jne_rel8_patch(&e, &t2_fail_jne, 0);
+    /* OK print */
+    emit_mov_eax_imm(&e, SYSCALL_WRITE_NO);
+    emit_mov_ebx_imm(&e, 1);
+    emit_mov_ecx_imm(&e, addr_t2_ok);
+    emit_mov_edx_imm(&e, t2_ok_len);
+    emit_int80(&e);
+    struct patch t2_to_t3 = {0};
+    emit_jmp_rel8_patch(&e, &t2_to_t3, 0);
+    /* FAIL label */
+    size_t t2_fail_pos = e.pos;
+    emit_mov_eax_imm(&e, SYSCALL_WRITE_NO);
+    emit_mov_ebx_imm(&e, 1);
+    emit_mov_ecx_imm(&e, addr_t2_fail);
+    emit_mov_edx_imm(&e, t2_fail_len);
+    emit_int80(&e);
+    size_t t3_pos = e.pos;
+
+    /* T3: write(valid buf) -> msg_len */
+    emit_mov_eax_imm(&e, SYSCALL_WRITE_NO);
+    emit_mov_ebx_imm(&e, 1);
+    emit_mov_ecx_imm(&e, addr_msg);
+    emit_mov_edx_imm(&e, msg_len);
+    emit_int80(&e);
+    emit_cmp_eax_imm(&e, msg_len);
+    struct patch t3_fail_jne = {0};
+    emit_jne_rel8_patch(&e, &t3_fail_jne, 0);
+    /* OK print */
+    emit_mov_eax_imm(&e, SYSCALL_WRITE_NO);
+    emit_mov_ebx_imm(&e, 1);
+    emit_mov_ecx_imm(&e, addr_t3_ok);
+    emit_mov_edx_imm(&e, t3_ok_len);
+    emit_int80(&e);
+    struct patch t3_to_exit = {0};
+    emit_jmp_rel8_patch(&e, &t3_to_exit, 0);
+    /* FAIL label */
+    size_t t3_fail_pos = e.pos;
+    emit_mov_eax_imm(&e, SYSCALL_WRITE_NO);
+    emit_mov_ebx_imm(&e, 1);
+    emit_mov_ecx_imm(&e, addr_t3_fail);
+    emit_mov_edx_imm(&e, t3_fail_len);
+    emit_int80(&e);
+    size_t exit_pos = e.pos;
+    emit_mov_eax_imm(&e, SYSCALL_EXIT_NO);
+    emit_int80(&e);
+    emit8(&e, 0xEB);
+    emit8(&e, 0xFE);
+
+    patch_rel8(e.buf, t1_fail_jne.at, t1_fail_pos);
+    patch_rel8(e.buf, t1_to_t2.at, t2_pos);
+    patch_rel8(e.buf, t2_fail_jne.at, t2_fail_pos);
+    patch_rel8(e.buf, t2_to_t3.at, t3_pos);
+    patch_rel8(e.buf, t3_fail_jne.at, t3_fail_pos);
+    patch_rel8(e.buf, t3_to_exit.at, exit_pos);
+
+    memcpy((void*)((uintptr_t)code_phys + 0x200), "T1 OK\n", t1_ok_len);
+    memcpy((void*)((uintptr_t)code_phys + 0x210), "T1 FAIL\n", t1_fail_len);
+    memcpy((void*)((uintptr_t)code_phys + 0x220), "T2 OK\n", t2_ok_len);
+    memcpy((void*)((uintptr_t)code_phys + 0x230), "T2 FAIL\n", t2_fail_len);
+    memcpy((void*)((uintptr_t)code_phys + 0x240), "T3 OK\n", t3_ok_len);
+    memcpy((void*)((uintptr_t)code_phys + 0x250), "T3 FAIL\n", t3_fail_len);
+    memcpy((void*)((uintptr_t)code_phys + 0x300), "Hello from ring3!\n", msg_len);
 
     uintptr_t user_esp = user_stack_vaddr + 4096;
     enter_usermode(user_code_vaddr, user_esp);