From: Tulio A M Mendes Date: Mon, 27 Apr 2026 16:58:38 +0000 (-0300) Subject: tests: expand host unit tests from 47 to 101 checks X-Git-Url: https://projects.tadryanom.me/?a=commitdiff_plain;h=5f693680c64b1731fe0e71407f463a3e285d1838;p=AdrOS.git tests: expand host unit tests from 47 to 101 checks test_utils.c (28→63): - tar_parse_octal: zero, simple, large, empty, null-term, non-octal skip - path_is_mountpoint_prefix: root, exact, child, no-match, partial, empty - normalize_mountpoint: root, simple, trailing-slash, empty, null, normalized - vfs_check_permission: root, owner/group/other read/write, mode-0, 0644 - elf32_validate: valid ET_EXEC/ET_DYN, bad magic/class/type/machine, no phnum, truncated, null test_security.c (19→38): - Signal mask: valid excludes KILL/STOP, includes USR1, pending&blocked, deliverable/blocked, KILL/STOP always deliverable - chmod symbolic: u+x, go-w, a+x, a=rw, u+s, g+s, +t, o-x, u=rw,go=r, no-change gdb_checks.py (6→10): - Process table PID 1 state check - Scheduler active runqueue bitmap - Mount table count - Frame 0 refcount Test results: 63/63 + 38/38 + 111/111 = 212 host PASS --- diff --git a/tests/gdb_checks.py b/tests/gdb_checks.py index 5a94de58..336330c8 100644 --- a/tests/gdb_checks.py +++ b/tests/gdb_checks.py @@ -121,6 +121,52 @@ def run_checks(): except gdb.error as e: c.check("VGA mapping accessible", False, str(e)) + # ---- Process Table ---- + try: + # PID 1 (init/fulltest) should exist and be in RUNNING state + proc_ptr = gdb.parse_and_eval("(struct process*)process_table") + if proc_ptr: + p1_state = c.read_u32(int(proc_ptr) + 0) # state is first field + # State values: RUNNING=1, READY=2, BLOCKED=3, SLEEPING=4, ZOMBIE=5 + c.check("PID 1 state is RUNNING or READY", + p1_state is not None and (p1_state == 1 or p1_state == 2), + f"state={p1_state}") + except gdb.error as e: + c.check("Process table accessible", False, str(e)) + + # ---- Scheduler State ---- + try: + # active_runqueue bitmap should be non-zero (at least one process ready) + rq_bitmap = gdb.parse_and_eval("active_rq.bitmap") + bitmap_val = int(rq_bitmap) & 0xFFFFFFFF + c.check("Active runqueue bitmap non-zero (processes ready)", + bitmap_val != 0, + f"bitmap={bitmap_val:#x}") + except gdb.error as e: + c.check("Scheduler runqueue accessible", False, str(e)) + + # ---- Mount Table ---- + try: + # g_mount_count should be > 0 (at least root mounted) + mc = gdb.parse_and_eval("g_mount_count") + mount_count = int(mc) + c.check("Mount count > 0", + mount_count > 0, + f"mount_count={mount_count}") + except gdb.error as e: + c.check("Mount table accessible", False, str(e)) + + # ---- Frame Reference Counts ---- + try: + # frame_refcount[0] should be > 0 (frame 0 is never freed) + ref0 = gdb.parse_and_eval("frame_refcount[0]") + ref0_val = int(ref0) & 0xFFFFFFFF + c.check("Frame 0 refcount > 0", + ref0_val > 0, + f"refcount[0]={ref0_val}") + except gdb.error as e: + c.check("Frame refcounts accessible", False, str(e)) + # ---- Summary ---- total = c.passed + c.failed print(f"\n {c.passed}/{total} passed, {c.failed} failed") diff --git a/tests/test_security.c b/tests/test_security.c index 3a4a2221..308ad748 100644 --- a/tests/test_security.c +++ b/tests/test_security.c @@ -82,6 +82,104 @@ static uint32_t sanitize_eflags(uint32_t eflags) { return (eflags & ~0x3000U) | 0x200U; } +/* Signal mask logic from kernel/scheduler.c and kernel/syscall.c */ +#define SIGKILL 9 +#define SIGSTOP 19 +#define PROCESS_MAX_SIG 32 + +static uint32_t sig_valid_mask(void) { + /* SIGKILL and SIGSTOP cannot be blocked */ + uint32_t all = 0; + for (int i = 1; i < PROCESS_MAX_SIG; i++) { + if (i != SIGKILL && i != SIGSTOP) + all |= (1U << (uint32_t)i); + } + return all; +} + +static uint32_t sig_pending_and_blocked(uint32_t pending, uint32_t blocked) { + /* sigpending returns: pending & blocked */ + return pending & blocked; +} + +static int sig_is_deliverable(uint32_t sig, uint32_t blocked) { + /* Signal is deliverable if not blocked (except KILL/STOP always deliverable) */ + if (sig == (uint32_t)SIGKILL || sig == (uint32_t)SIGSTOP) return 1; + return (blocked & (1U << sig)) == 0; +} + +/* chmod symbolic mode parsing from user/cmds/chmod/chmod.c */ +static unsigned int parse_symbolic(const char* mode, unsigned int old) { + unsigned int result = old; + const char* p = mode; + while (*p) { + unsigned int who_bits = 0; + int has_u = 0, has_g = 0, has_o = 0; + while (*p == 'u' || *p == 'g' || *p == 'o' || *p == 'a') { + switch (*p) { + case 'u': has_u = 1; break; + case 'g': has_g = 1; break; + case 'o': has_o = 1; break; + case 'a': has_u = has_g = has_o = 1; break; + } + p++; + } + if (!has_u && !has_g && !has_o) has_u = has_g = has_o = 1; + + if (has_u) who_bits |= 04700; + if (has_g) who_bits |= 02070; + if (has_o) who_bits |= 00007; + + while (*p) { + char op = *p; + if (op != '+' && op != '-' && op != '=') break; + p++; + + unsigned int perm = 0; + while (*p == 'r' || *p == 'w' || *p == 'x' || + *p == 's' || *p == 't') { + switch (*p) { + case 'r': + if (has_u) perm |= 0400; + if (has_g) perm |= 0040; + if (has_o) perm |= 0004; + break; + case 'w': + if (has_u) perm |= 0200; + if (has_g) perm |= 0020; + if (has_o) perm |= 0002; + break; + case 'x': + if (has_u) perm |= 0100; + if (has_g) perm |= 0010; + if (has_o) perm |= 0001; + break; + case 's': + if (has_u) perm |= 04000; + if (has_g) perm |= 02000; + break; + case 't': + perm |= 01000; + break; + } + p++; + } + + if (op == '+') { + result |= perm; + } else if (op == '-') { + result &= ~perm; + } else { + result &= ~who_bits; + result |= perm; + } + + if (*p == ',') { p++; break; } + } + } + return result & 07777; +} + /* ======== user_range_ok TESTS ======== */ TEST(urange_null_ptr) { @@ -216,6 +314,114 @@ TEST(eflags_iopl1) { ASSERT_EQ(clean & 0x3000, 0); } +/* ======== Signal mask TESTS ======== */ + +TEST(sigmask_valid_excludes_kill) { + /* SIGKILL (bit 9) must not be in valid mask */ + uint32_t mask = sig_valid_mask(); + ASSERT_EQ(mask & (1U << SIGKILL), 0); +} + +TEST(sigmask_valid_excludes_stop) { + /* SIGSTOP (bit 19) must not be in valid mask */ + uint32_t mask = sig_valid_mask(); + ASSERT_EQ(mask & (1U << SIGSTOP), 0); +} + +TEST(sigmask_valid_includes_usr1) { + /* SIGUSR1 (bit 10) must be in valid mask */ + uint32_t mask = sig_valid_mask(); + ASSERT_TRUE(mask & (1U << 10)); +} + +TEST(sigmask_pending_and_blocked) { + /* sigpending = pending & blocked */ + uint32_t pending = (1U << 10) | (1U << 12); /* SIGUSR1, SIGUSR2 */ + uint32_t blocked = (1U << 10); /* only SIGUSR1 blocked */ + uint32_t result = sig_pending_and_blocked(pending, blocked); + ASSERT_EQ(result, (1U << 10)); /* only SIGUSR1 pending+blocked */ +} + +TEST(sigmask_pending_not_blocked) { + /* Signal pending but not blocked → not in sigpending result */ + uint32_t pending = (1U << 10); + uint32_t blocked = 0; + uint32_t result = sig_pending_and_blocked(pending, blocked); + ASSERT_EQ(result, 0); +} + +TEST(sigmask_deliverable_normal) { + /* Normal signal not blocked → deliverable */ + ASSERT_TRUE(sig_is_deliverable(10, 0)); +} + +TEST(sigmask_deliverable_blocked) { + /* Normal signal blocked → not deliverable */ + ASSERT_FALSE(sig_is_deliverable(10, (1U << 10))); +} + +TEST(sigmask_kill_always_deliverable) { + /* SIGKILL always deliverable even if blocked */ + ASSERT_TRUE(sig_is_deliverable(SIGKILL, (1U << SIGKILL))); +} + +TEST(sigmask_stop_always_deliverable) { + /* SIGSTOP always deliverable even if blocked */ + ASSERT_TRUE(sig_is_deliverable(SIGSTOP, (1U << SIGSTOP))); +} + +/* ======== chmod symbolic mode TESTS ======== */ + +TEST(chmod_u_plus_x) { + /* u+x on 0644 → 0744 (only user gets execute) */ + ASSERT_EQ(parse_symbolic("u+x", 0644), 0744); +} + +TEST(chmod_go_minus_w) { + /* go-w on 0666 → 0644 */ + ASSERT_EQ(parse_symbolic("go-w", 0666), 0644); +} + +TEST(chmod_a_plus_x) { + /* a+x on 0644 → 0755 */ + ASSERT_EQ(parse_symbolic("a+x", 0644), 0755); +} + +TEST(chmod_a_eq_rw) { + /* a=rw on 0755 → 0666 */ + ASSERT_EQ(parse_symbolic("a=rw", 0755), 0666); +} + +TEST(chmod_u_plus_s) { + /* u+s on 0755 → 4755 (setuid) */ + ASSERT_EQ(parse_symbolic("u+s", 0755), 04755); +} + +TEST(chmod_g_plus_s) { + /* g+s on 0755 → 2755 (setgid) */ + ASSERT_EQ(parse_symbolic("g+s", 0755), 02755); +} + +TEST(chmod_plus_t) { + /* +t on 0777 → 1777 (sticky) */ + ASSERT_EQ(parse_symbolic("+t", 0777), 01777); +} + +TEST(chmod_o_minus_x) { + /* o-x on 0755 → 0754 */ + ASSERT_EQ(parse_symbolic("o-x", 0755), 0754); +} + +TEST(chmod_u_eq_rw_go_eq_r) { + /* u=rw,go=r on 0755 → 0644 */ + ASSERT_EQ(parse_symbolic("u=rw,go=r", 0755), 0644); +} + +TEST(chmod_no_change) { + /* u+r on already 0755 → 0755 */ + ASSERT_EQ(parse_symbolic("u+r", 0755), 0755); +} + /* ======== MAIN ======== */ int main(void) { printf("\n=========================================\n"); @@ -247,6 +453,29 @@ int main(void) { RUN(eflags_preserves_other); RUN(eflags_iopl1); + /* signal mask */ + RUN(sigmask_valid_excludes_kill); + RUN(sigmask_valid_excludes_stop); + RUN(sigmask_valid_includes_usr1); + RUN(sigmask_pending_and_blocked); + RUN(sigmask_pending_not_blocked); + RUN(sigmask_deliverable_normal); + RUN(sigmask_deliverable_blocked); + RUN(sigmask_kill_always_deliverable); + RUN(sigmask_stop_always_deliverable); + + /* chmod symbolic mode */ + RUN(chmod_u_plus_x); + RUN(chmod_go_minus_w); + RUN(chmod_a_plus_x); + RUN(chmod_a_eq_rw); + RUN(chmod_u_plus_s); + RUN(chmod_g_plus_s); + RUN(chmod_plus_t); + RUN(chmod_o_minus_x); + RUN(chmod_u_eq_rw_go_eq_r); + RUN(chmod_no_change); + printf("\n %d/%d passed, %d failed\n", g_tests_passed, g_tests_run, g_tests_failed); if (g_tests_failed > 0) { diff --git a/tests/test_utils.c b/tests/test_utils.c index 78d98ce0..aae92f8d 100644 --- a/tests/test_utils.c +++ b/tests/test_utils.c @@ -196,6 +196,127 @@ static uint64_t align_up(uint64_t value, uint64_t align) { return (value + align - 1) & ~(align - 1); } +/* From src/drivers/initrd.c — tar octal parsing */ +static uint32_t tar_parse_octal(const char* s, size_t n) { + uint32_t v = 0; + for (size_t i = 0; i < n; i++) { + if (s[i] == 0) break; + if (s[i] < '0' || s[i] > '7') continue; + v = (v << 3) + (uint32_t)(s[i] - '0'); + } + return v; +} + +/* From src/kernel/fs.c — mount point prefix check */ +static int path_is_mountpoint_prefix(const char* mp, const char* path) { + size_t mpl = strlen(mp); + if (mpl == 0) return 0; + if (strcmp(mp, "/") == 0) return 1; + if (strncmp(path, mp, mpl) != 0) return 0; + if (path[mpl] == 0) return 1; + if (path[mpl] == '/') return 1; + return 0; +} + +/* From src/kernel/fs.c — mountpoint normalization */ +static void normalize_mountpoint(const char* in, char* out, size_t out_sz) { + if (!out || out_sz == 0) return; + out[0] = 0; + if (!in || in[0] == 0) { + strcpy(out, "/"); + return; + } + size_t i = 0; + if (in[0] != '/') { + out[i++] = '/'; + } + for (size_t j = 0; in[j] != 0 && i + 1 < out_sz; j++) { + out[i++] = in[j]; + } + out[i] = 0; + size_t l = strlen(out); + while (l > 1 && out[l - 1] == '/') { + out[l - 1] = 0; + l--; + } +} + +/* From src/kernel/syscall.c — permission check (simplified for host test) */ +#define EACCES 13 +static int vfs_check_permission(uint32_t mode, uint32_t euid, uint32_t egid, + uint32_t file_uid, uint32_t file_gid, int want) { + if (euid == 0) return 0; /* root — allow all */ + if (mode == 0) return 0; /* mode not set — permissive */ + uint32_t perm; + if (euid == file_uid) { + perm = (mode >> 6) & 7; + } else if (egid == file_gid) { + perm = (mode >> 3) & 7; + } else { + perm = mode & 7; + } + if (((uint32_t)want & perm) != (uint32_t)want) return -EACCES; + return 0; +} + +/* From src/arch/x86/elf.c — ELF header validation (simplified for host) */ +#define ELF_MAGIC0 0x7F +#define ELF_MAGIC1 'E' +#define ELF_MAGIC2 'L' +#define ELF_MAGIC3 'F' +#define ELFCLASS32 1 +#define ELFDATA2LSB 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define EM_386 3 +#define EINVAL 22 +#define EFAULT 14 + +typedef struct { + uint8_t e_ident[16]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint32_t e_entry; + uint32_t e_phoff; + uint32_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; +} test_elf32_ehdr_t; + +typedef struct { + uint32_t p_type; + uint32_t p_offset; + uint32_t p_vaddr; + uint32_t p_paddr; + uint32_t p_filesz; + uint32_t p_memsz; + uint32_t p_flags; + uint32_t p_align; +} test_elf32_phdr_t; + +static int elf32_validate(const test_elf32_ehdr_t* eh, size_t file_len) { + if (!eh) return -EFAULT; + if (file_len < sizeof(*eh)) return -EINVAL; + if (eh->e_ident[0] != ELF_MAGIC0 || + eh->e_ident[1] != ELF_MAGIC1 || + eh->e_ident[2] != ELF_MAGIC2 || + eh->e_ident[3] != ELF_MAGIC3) + return -EINVAL; + if (eh->e_ident[4] != ELFCLASS32) return -EINVAL; + if (eh->e_ident[5] != ELFDATA2LSB) return -EINVAL; + if (eh->e_type != ET_EXEC && eh->e_type != ET_DYN) return -EINVAL; + if (eh->e_machine != EM_386) return -EINVAL; + if (eh->e_phentsize != sizeof(test_elf32_phdr_t)) return -EINVAL; + if (eh->e_phnum == 0) return -EINVAL; + return 0; +} + /* ======== TESTS ======== */ /* --- itoa tests --- */ @@ -354,6 +475,255 @@ TEST(align_up_zero) { ASSERT_EQ(align_up(0, 4096), 0); } +/* --- tar_parse_octal tests --- */ +TEST(tar_octal_zero) { + ASSERT_EQ(tar_parse_octal("0", 2), 0); +} + +TEST(tar_octal_simple) { + ASSERT_EQ(tar_parse_octal("644", 4), 0644); +} + +TEST(tar_octal_large) { + ASSERT_EQ(tar_parse_octal("100644", 7), 0100644); +} + +TEST(tar_octal_empty) { + ASSERT_EQ(tar_parse_octal("", 1), 0); +} + +TEST(tar_octal_null_term) { + /* Stops at NUL even if n is larger */ + ASSERT_EQ(tar_parse_octal("755\0ignored", 10), 0755); +} + +TEST(tar_octal_skips_non_octal) { + /* Space padding is common in tar headers */ + ASSERT_EQ(tar_parse_octal(" 644 ", 6), 0644); +} + +/* --- path_is_mountpoint_prefix tests --- */ +TEST(mountprefix_root) { + ASSERT_EQ(path_is_mountpoint_prefix("/", "/anything"), 1); +} + +TEST(mountprefix_exact) { + ASSERT_EQ(path_is_mountpoint_prefix("/disk", "/disk"), 1); +} + +TEST(mountprefix_child) { + ASSERT_EQ(path_is_mountpoint_prefix("/disk", "/disk/file"), 1); +} + +TEST(mountprefix_no_match) { + ASSERT_EQ(path_is_mountpoint_prefix("/disk", "/other"), 0); +} + +TEST(mountprefix_partial) { + /* /dis should not match /disk */ + ASSERT_EQ(path_is_mountpoint_prefix("/dis", "/disk"), 0); +} + +TEST(mountprefix_empty) { + ASSERT_EQ(path_is_mountpoint_prefix("", "/anything"), 0); +} + +/* --- normalize_mountpoint tests --- */ +TEST(normmount_root) { + char out[128]; + normalize_mountpoint("/", out, sizeof(out)); + ASSERT_STR_EQ(out, "/"); +} + +TEST(normmount_simple) { + char out[128]; + normalize_mountpoint("disk", out, sizeof(out)); + ASSERT_STR_EQ(out, "/disk"); +} + +TEST(normmount_trailing_slash) { + char out[128]; + normalize_mountpoint("/disk/", out, sizeof(out)); + ASSERT_STR_EQ(out, "/disk"); +} + +TEST(normmount_empty) { + char out[128]; + normalize_mountpoint("", out, sizeof(out)); + ASSERT_STR_EQ(out, "/"); +} + +TEST(normmount_null) { + char out[128]; + normalize_mountpoint(NULL, out, sizeof(out)); + ASSERT_STR_EQ(out, "/"); +} + +TEST(normmount_already_normalized) { + char out[128]; + normalize_mountpoint("/disk", out, sizeof(out)); + ASSERT_STR_EQ(out, "/disk"); +} + +/* --- vfs_check_permission tests --- */ +TEST(perm_root_allows) { + /* Root can do anything */ + ASSERT_EQ(vfs_check_permission(0100, 0, 0, 1000, 1000, 4), 0); +} + +TEST(perm_owner_read) { + /* mode=0400, owner wants read → allowed */ + ASSERT_EQ(vfs_check_permission(0400, 1000, 100, 1000, 100, 4), 0); +} + +TEST(perm_owner_no_write) { + /* mode=0400, owner wants write → denied */ + ASSERT_EQ(vfs_check_permission(0400, 1000, 100, 1000, 100, 2), -EACCES); +} + +TEST(perm_group_read) { + /* mode=0040, group member wants read → allowed */ + ASSERT_EQ(vfs_check_permission(0040, 2000, 100, 1000, 100, 4), 0); +} + +TEST(perm_other_read) { + /* mode=0004, other wants read → allowed */ + ASSERT_EQ(vfs_check_permission(0004, 3000, 200, 1000, 100, 4), 0); +} + +TEST(perm_other_no_write) { + /* mode=0004, other wants write → denied */ + ASSERT_EQ(vfs_check_permission(0004, 3000, 200, 1000, 100, 2), -EACCES); +} + +TEST(perm_mode_zero_permissive) { + /* mode=0 → permissive (allow all) */ + ASSERT_EQ(vfs_check_permission(0, 1000, 100, 1000, 100, 7), 0); +} + +TEST(perm_rw_file) { + /* mode=0644: owner rw, group/other read */ + ASSERT_EQ(vfs_check_permission(0644, 1000, 100, 1000, 100, 6), 0); /* owner rw */ + ASSERT_EQ(vfs_check_permission(0644, 2000, 100, 1000, 100, 4), 0); /* group read */ + ASSERT_EQ(vfs_check_permission(0644, 2000, 100, 1000, 100, 2), -EACCES); /* group no write */ + ASSERT_EQ(vfs_check_permission(0644, 3000, 200, 1000, 100, 4), 0); /* other read */ + ASSERT_EQ(vfs_check_permission(0644, 3000, 200, 1000, 100, 2), -EACCES); /* other no write */ +} + +/* --- elf32_validate tests --- */ +TEST(elf_valid_exec) { + test_elf32_ehdr_t eh; + memset(&eh, 0, sizeof(eh)); + eh.e_ident[0] = 0x7F; + eh.e_ident[1] = 'E'; + eh.e_ident[2] = 'L'; + eh.e_ident[3] = 'F'; + eh.e_ident[4] = ELFCLASS32; + eh.e_ident[5] = ELFDATA2LSB; + eh.e_type = ET_EXEC; + eh.e_machine = EM_386; + eh.e_phentsize = sizeof(test_elf32_phdr_t); + eh.e_phnum = 1; + ASSERT_EQ(elf32_validate(&eh, sizeof(eh)), 0); +} + +TEST(elf_valid_dyn) { + test_elf32_ehdr_t eh; + memset(&eh, 0, sizeof(eh)); + eh.e_ident[0] = 0x7F; + eh.e_ident[1] = 'E'; + eh.e_ident[2] = 'L'; + eh.e_ident[3] = 'F'; + eh.e_ident[4] = ELFCLASS32; + eh.e_ident[5] = ELFDATA2LSB; + eh.e_type = ET_DYN; + eh.e_machine = EM_386; + eh.e_phentsize = sizeof(test_elf32_phdr_t); + eh.e_phnum = 1; + ASSERT_EQ(elf32_validate(&eh, sizeof(eh)), 0); +} + +TEST(elf_bad_magic) { + test_elf32_ehdr_t eh; + memset(&eh, 0, sizeof(eh)); + eh.e_ident[0] = 'X'; + ASSERT_EQ(elf32_validate(&eh, sizeof(eh)), -EINVAL); +} + +TEST(elf_bad_class) { + test_elf32_ehdr_t eh; + memset(&eh, 0, sizeof(eh)); + eh.e_ident[0] = 0x7F; + eh.e_ident[1] = 'E'; + eh.e_ident[2] = 'L'; + eh.e_ident[3] = 'F'; + eh.e_ident[4] = 2; /* ELFCLASS64 */ + eh.e_ident[5] = ELFDATA2LSB; + eh.e_type = ET_EXEC; + eh.e_machine = EM_386; + eh.e_phentsize = sizeof(test_elf32_phdr_t); + eh.e_phnum = 1; + ASSERT_EQ(elf32_validate(&eh, sizeof(eh)), -EINVAL); +} + +TEST(elf_bad_type) { + test_elf32_ehdr_t eh; + memset(&eh, 0, sizeof(eh)); + eh.e_ident[0] = 0x7F; + eh.e_ident[1] = 'E'; + eh.e_ident[2] = 'L'; + eh.e_ident[3] = 'F'; + eh.e_ident[4] = ELFCLASS32; + eh.e_ident[5] = ELFDATA2LSB; + eh.e_type = 0; /* ET_NONE */ + eh.e_machine = EM_386; + eh.e_phentsize = sizeof(test_elf32_phdr_t); + eh.e_phnum = 1; + ASSERT_EQ(elf32_validate(&eh, sizeof(eh)), -EINVAL); +} + +TEST(elf_bad_machine) { + test_elf32_ehdr_t eh; + memset(&eh, 0, sizeof(eh)); + eh.e_ident[0] = 0x7F; + eh.e_ident[1] = 'E'; + eh.e_ident[2] = 'L'; + eh.e_ident[3] = 'F'; + eh.e_ident[4] = ELFCLASS32; + eh.e_ident[5] = ELFDATA2LSB; + eh.e_type = ET_EXEC; + eh.e_machine = 0x3E; /* EM_X86_64 */ + eh.e_phentsize = sizeof(test_elf32_phdr_t); + eh.e_phnum = 1; + ASSERT_EQ(elf32_validate(&eh, sizeof(eh)), -EINVAL); +} + +TEST(elf_no_phnum) { + test_elf32_ehdr_t eh; + memset(&eh, 0, sizeof(eh)); + eh.e_ident[0] = 0x7F; + eh.e_ident[1] = 'E'; + eh.e_ident[2] = 'L'; + eh.e_ident[3] = 'F'; + eh.e_ident[4] = ELFCLASS32; + eh.e_ident[5] = ELFDATA2LSB; + eh.e_type = ET_EXEC; + eh.e_machine = EM_386; + eh.e_phentsize = sizeof(test_elf32_phdr_t); + eh.e_phnum = 0; + ASSERT_EQ(elf32_validate(&eh, sizeof(eh)), -EINVAL); +} + +TEST(elf_truncated) { + test_elf32_ehdr_t eh; + memset(&eh, 0, sizeof(eh)); + ASSERT_EQ(elf32_validate(&eh, 10), -EINVAL); +} + +TEST(elf_null) { + ASSERT_EQ(elf32_validate(NULL, 100), -EFAULT); +} + /* ======== MAIN ======== */ int main(void) { printf("\n=========================================\n"); @@ -398,6 +768,51 @@ int main(void) { RUN(align_up_exact); RUN(align_up_zero); + /* tar_parse_octal */ + RUN(tar_octal_zero); + RUN(tar_octal_simple); + RUN(tar_octal_large); + RUN(tar_octal_empty); + RUN(tar_octal_null_term); + RUN(tar_octal_skips_non_octal); + + /* path_is_mountpoint_prefix */ + RUN(mountprefix_root); + RUN(mountprefix_exact); + RUN(mountprefix_child); + RUN(mountprefix_no_match); + RUN(mountprefix_partial); + RUN(mountprefix_empty); + + /* normalize_mountpoint */ + RUN(normmount_root); + RUN(normmount_simple); + RUN(normmount_trailing_slash); + RUN(normmount_empty); + RUN(normmount_null); + RUN(normmount_already_normalized); + + /* vfs_check_permission */ + RUN(perm_root_allows); + RUN(perm_owner_read); + RUN(perm_owner_no_write); + RUN(perm_group_read); + RUN(perm_other_read); + RUN(perm_other_no_write); + RUN(perm_mode_zero_permissive); + RUN(perm_rw_file); + + /* elf32_validate */ + RUN(elf_valid_exec); + RUN(elf_valid_dyn); + RUN(elf_bad_magic); + RUN(elf_bad_class); + RUN(elf_bad_type); + RUN(elf_bad_machine); + RUN(elf_no_phnum); + RUN(elf_truncated); + RUN(elf_null); + printf("\n %d/%d passed, %d failed\n", g_tests_passed, g_tests_run, g_tests_failed); if (g_tests_failed > 0) {