Files
Deshab-OS/CODE/UTSM/test/utsm_selftest.c
T

310 lines
12 KiB
C
Raw Normal View History

#include <utsm/utsm.h>
2026-10-02 14:29:28 +08:00
#include <utsm/pckc.h>
#include <utsm/crypto.h>
#include <utsm/dma.h>
#include <utsm/dkm.h>
#include <utsm/log.h>
#include <utsm/segment.h>
#include <utsm/arena.h>
#include <utsm/drr.h>
#include <utsm/sched_ext.h>
int memcmp(const void *a, const void *b, usize len);
usize strlen(const char *s);
/* selftest 与 LAPIC/PIT tick 竞态:tick 在别的任务上唤醒 sleeper 时
* 会向同一 runqueue 入队,破坏 pick_next 的确定性断言(偶发
* block/wake FAIL → arch_halt_forever)。临界区内关中断。 */
static u64 selftest_irq_save(void) {
u64 flags;
__asm__ volatile("pushfq; popq %0; cli" : "=r"(flags) :: "memory");
return flags;
}
static void selftest_irq_restore(u64 flags) {
__asm__ volatile("pushq %0; popfq" :: "r"(flags) : "memory");
}
int utsm_selftest_run(void) {
log_info("[UTSM] selftest enter");
/* utsm_process_context is ~8KB (256 capabilities × 32 bytes).
* Allocate from arena instead of stack to avoid kernel stack overflow. */
utsm_process_context *process = (utsm_process_context *)kmem_alloc(sizeof(utsm_process_context));
if (!process) {
log_error("[UTSM] selftest: failed to allocate process context");
return UTSM_ERR_NO_MEMORY;
}
utsm_process_create_test(process, 1);
utsm_capability cap;
int status = utsm_create_segment(process, UTSM_PAGE_SIZE, UTSM_SEG_F_READ | UTSM_SEG_F_WRITE | UTSM_SEG_F_STRONG_RECOVERY, &cap);
if (status != UTSM_OK) {
log_error("[UTSM] selftest create segment failed");
return status;
}
const char *message = "deshab utsm sealed memory selftest";
u64 len = strlen(message) + 1;
status = utsm_write(cap, 128, message, len);
if (status != UTSM_OK) {
log_error("[UTSM] selftest write failed");
return status;
}
log_info("[UTSM] selftest write ok");
utsm_segment_desc *desc = utsm_get_segment(cap.segment_slot);
if (!desc) {
return UTSM_ERR_INVALID;
}
if (memcmp(desc->cipher_base + 128, message, len) == 0) {
log_error("[UTSM] raw cipher equals plaintext");
return UTSM_ERR_INVALID;
}
log_info("[UTSM] raw cipher check ok");
char readback[64];
status = utsm_read(cap, 128, readback, len);
if (status != UTSM_OK) {
log_error("[UTSM] selftest read failed");
return status;
}
if (memcmp(readback, message, len) != 0) {
log_error("[UTSM] selftest read mismatch");
return UTSM_ERR_INVALID;
}
log_info("[UTSM] selftest read ok");
/* ==== U5: chacha20 KAT(RFC 8439 §2.4.2 官方向量)====
* 历史注:FUCK 注释曾提"并行会话 chacha20 KAT 间歇 FAIL"——该测试
* 从未合并进本树(幽灵缺陷)。本 KAT 为确定性官方向量,不依赖
* 硬件/时钟/随机数,PASS/FAIL 完全可复现。期望值由
* test/gen_chacha_kat.py 生成,并经 pycryptodome 独立对拍。 */
{
#include "chacha_kat.inc"
u8 ks[64];
utsm_chacha20_block(kat_key, kat_nonce, kat_counter, ks);
if (memcmp(ks, kat_expect, 64) != 0) {
log_error("[UTSM] selftest chacha20 KAT FAIL (RFC 8439 §2.4.2)");
return UTSM_ERR_INVALID;
}
log_info("[UTSM] selftest chacha20 KAT ok (RFC 8439 §2.4.2)");
/* page MAC 确定性:同输入同 MAC、跨页不同 MAC */
const u64 *rk = drr_get_root_key();
u64 m1 = utsm_page_mac(rk, 0, 0, 0, desc->cipher_base);
u64 m2 = utsm_page_mac(rk, 0, 0, 0, desc->cipher_base);
u64 m3 = utsm_page_mac(rk, 0, 1, 0, desc->cipher_base);
if (m1 != m2 || m1 == m3) {
log_error("[UTSM] selftest page MAC determinism FAIL");
return UTSM_ERR_INVALID;
}
log_info("[UTSM] selftest page MAC determinism ok");
/* ==== U3+: 封缄内存 .sealed 区 MAC 校验(UTSM-E03 路径自证) ==== */
{
extern void utsm_sealed_verify(void);
utsm_sealed_verify(); /* 不符即 panic,返回即通过 */
log_info("[UTSM] selftest sealed MAC verify ok");
}
}
2026-10-02 14:40:26 +08:00
/* ==== U4: 密文页 dump —— 串口输出密文/明文 hex 对照 ==== */
{
int dst = utrw_debug_dump_page(cap.segment_slot, 0, 128);
if (dst != UTSM_OK) {
log_error("[UTSM] selftest cipher dump failed");
return dst;
}
}
2026-10-02 14:29:28 +08:00
/* ==== U2: Slow Path 真分支(EPOCH 刷新 / KEY_MISS 重派生 / POISONED 拒绝) ==== */
{
/* 1) EPOCH 过期:伪造 stale cap(epoch=desc->key_epoch+1),slow path 应
* 返回 OK 并回传刷新后的 cap,重试 read 应成功且内容一致 */
utsm_capability stale = cap;
stale.epoch = (u32)desc->key_epoch + 1;
utsm_capability refreshed = stale;
status = utsm_slow_path(stale, UTSM_RIGHT_READ, 128, len,
UTSM_ERR_EPOCH, &refreshed);
if (status != UTSM_OK) {
log_error("[UTSM] selftest slow EPOCH recover failed");
return status;
}
char slow_rb[64];
status = utsm_read(refreshed, 128, slow_rb, len);
if (status != UTSM_OK || memcmp(slow_rb, message, len) != 0) {
log_error("[UTSM] selftest slow EPOCH retry read failed");
return (status == UTSM_OK) ? UTSM_ERR_INVALID : status;
}
log_info("[UTSM] selftest slow EPOCH ok");
/* 2) KEY_MISS:清掉该段 PCKC 缓存,slow path 重派生应返回 OK */
utsm_pckc_invalidate_slot(cap.segment_slot);
status = utsm_slow_path(refreshed, UTSM_RIGHT_READ, 128, len,
UTSM_ERR_KEY_MISS, 0);
if (status != UTSM_OK) {
log_error("[UTSM] selftest slow KEY_MISS recover failed");
return status;
}
status = utsm_read(refreshed, 128, slow_rb, len);
if (status != UTSM_OK || memcmp(slow_rb, message, len) != 0) {
log_error("[UTSM] selftest slow KEY_MISS retry read failed");
return (status == UTSM_OK) ? UTSM_ERR_INVALID : status;
}
log_info("[UTSM] selftest slow KEY_MISS ok");
/* 3) POISONED:不可恢复,原样返回;DRR fault 留痕不重启
* (selftest 场景 drr_report_fault 只计数,无 reboot 语义) */
status = utsm_slow_path(refreshed, UTSM_RIGHT_READ, 128, len,
UTSM_ERR_POISONED, 0);
if (status != UTSM_ERR_POISONED) {
log_error("[UTSM] selftest slow POISONED passthrough failed");
return UTSM_ERR_INVALID;
}
log_info("[UTSM] selftest slow POISONED ok");
}
/* ==== U3: @sealed 可选标记 —— unsealed 段明文直存(0 加解密开销) ==== */
{
utsm_capability ucap;
status = utsm_create_segment(process, UTSM_PAGE_SIZE,
UTSM_SEG_F_READ | UTSM_SEG_F_WRITE |
UTSM_SEG_F_UNSEALED,
&ucap);
if (status != UTSM_OK) {
log_error("[UTSM] selftest unsealed segment create failed");
return status;
}
const char *upl = "unsealed plain text 00";
u64 ulen = strlen(upl) + 1;
status = utsm_write(ucap, 128, upl, ulen);
if (status != UTSM_OK) {
log_error("[UTSM] selftest unsealed write failed");
return status;
}
utsm_segment_desc *udesc = utsm_get_segment(ucap.segment_slot);
if (!udesc) return UTSM_ERR_INVALID;
/* 明文直存:存储区内容必须与明文完全一致(0 开销的可观察证据) */
if (memcmp(udesc->cipher_base + 128, upl, ulen) != 0) {
log_error("[UTSM] selftest unsealed store not plaintext");
return UTSM_ERR_INVALID;
}
char urb[64];
status = utsm_read(ucap, 128, urb, ulen);
if (status != UTSM_OK || memcmp(urb, upl, ulen) != 0) {
log_error("[UTSM] selftest unsealed read failed");
return (status == UTSM_OK) ? UTSM_ERR_INVALID : status;
}
log_info("[UTSM] selftest unsealed segment ok (plain storage)");
}
/* ==== D3: 按名导出表(kapi)——按名取服务并调用 ==== */
{
const dkm_kernel_api *api = dkm_get_kernel_api();
if (!api->kapi || api->kapi->magic != DKM_KAPI_MAGIC) {
log_error("[UTSM] selftest kapi table missing");
return UTSM_ERR_INVALID;
}
void *fn = 0;
if (api->kapi->lookup("log.info", &fn) != 0) {
log_error("[UTSM] selftest kapi lookup log.info failed");
return UTSM_ERR_INVALID;
}
void (*klog)(const char *) = (void (*)(const char *))fn;
klog("[UTSM] selftest kapi: log.info via export table");
if (api->kapi->lookup("dma.alloc_pages", &fn) != 0) {
log_error("[UTSM] selftest kapi lookup dma failed");
return UTSM_ERR_INVALID;
}
int (*kalloc)(u64, u64, u64, dkm_dma_buffer *) = (int (*)(u64, u64, u64, dkm_dma_buffer *))fn;
dkm_dma_buffer kbuf;
if (kalloc(1, 4096, 0xFFFFFFFFULL, &kbuf) != 0 || !kbuf.virt) {
log_error("[UTSM] selftest kapi dma alloc failed");
return UTSM_ERR_INVALID;
}
if (api->kapi->lookup("no.such.service", &fn) == 0) {
log_error("[UTSM] selftest kapi negative lookup failed");
return UTSM_ERR_INVALID;
}
log_hex64("[UTSM] selftest kapi entries=", api->kapi->count);
log_info("[UTSM] selftest kapi ok");
}
/* ==== SCHED-1: O(1) runqueue 语义(合成 TCB,协作式,无 tick) ==== */
/* ==== SCHED-1 + SCHED-2: runqueue / block-wake(tick 竞态保护) ==== */
{
u64 st_flags = selftest_irq_save();
int rq_rc = utsm_sched_selftest_runqueue();
int bw_rc = (rq_rc == 0) ? utsm_sched_selftest_blockwake() : 0;
selftest_irq_restore(st_flags);
if (rq_rc != 0) {
log_error("[SCHED] selftest: runqueue O(1) FAIL");
return UTSM_ERR_INVALID;
}
log_info("[SCHED] selftest: runqueue O(1) PASS");
if (bw_rc != 0) {
log_error("[SCHED] selftest: block/wake FAIL");
return UTSM_ERR_INVALID;
}
log_info("[SCHED] selftest: block/wake PASS");
}
/* ==== DRR-1: 真实脏页快照 + 页级回滚 ====
* 写 P1 → 快照(捕获 P1 密文页)→ 写 P2 覆盖 → 回滚 → 读回 P1 */
{
const char *p1 = "P1-ROLLBACK-STATE-01";
const char *p2 = "P2-OVERWRITE-STATE-0";
u64 plen = strlen(p1) + 1;
status = utsm_write(cap, 512, p1, plen);
if (status != UTSM_OK) {
log_error("[DRR] selftest P1 write failed");
return status;
}
int snap = drr_ckpt_snapshot_dirty();
log_hex64("[DRR] ckpt snapshot pages=", (u64)(i64)snap);
if (snap < 1) {
log_error("[DRR] selftest snapshot failed");
return UTSM_ERR_INVALID;
}
drr_checkpoint_meta meta;
if (drr_checkpoint_recover(&meta) != 0 || meta.type != DRR_CKPT_DIRTY_PAGE ||
meta.dirty_page_count < 1) {
log_error("[DRR] selftest meta verify failed");
return UTSM_ERR_INVALID;
}
status = utsm_write(cap, 512, p2, plen);
if (status != UTSM_OK) {
log_error("[DRR] selftest P2 write failed");
return status;
}
int rb = drr_rollback_pages();
log_hex64("[DRR] rollback pages=", (u64)(i64)rb);
if (rb < 1) {
log_error("[DRR] selftest rollback failed");
return UTSM_ERR_INVALID;
}
status = utsm_read(cap, 512, readback, plen);
if (status != UTSM_OK || memcmp(readback, p1, plen) != 0) {
log_error("[DRR] rollback verify FAIL");
return UTSM_ERR_INVALID;
}
log_info("[DRR] rollback verify ok");
}
/* ==== DRR-2: 看门狗判定(dry-run:reboot 关闭,仅验证日志路径) ==== */
{
drr_set_reboot_enabled(0);
drr_watchdog_register(0xFFFFFEu, 2);
drr_heartbeat_tick();
drr_heartbeat_tick();
drr_heartbeat_tick(); /* 3 ticks > timeout 2 → 触发 */
drr_watchdog_check(); /* 期望 [DRR] FAULT: watchdog timeout */
drr_watchdog_unregister(0xFFFFFEu);
drr_set_reboot_enabled(1);
log_info("[DRR] watchdog selftest done");
}
return UTSM_OK;
}