Files
Deshab-OS/CODE/UTSM/test/utsm_selftest.c
T
Linehu 7925c09677 feat: U4 ciphertext page dump tool
- utrw/debug.c: utrw_debug_dump_page(slot,page,offset) — kernel debug-privileged dump of 64B ciphertext + decrypted plaintext hex to serial (PCKC key derive, no capability path)
- selftest demo: dump at offset 128 shows plaintext 'deshab utsm sealed memory selftest' vs unrelated ciphertext; SELFTEST PASS (.build_tmp/qemu_serial_u4dump.log)
2026-10-02 14:40:26 +08:00

207 lines
7.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <utsm/utsm.h>
#include <utsm/pckc.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");
/* ==== 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;
}
}
/* ==== 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");
}
/* ==== 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;
}