feat: SAS-R0 boot-time capability attestation - unimplemented feature blocks boot
- attest.c: subsystems report readiness, attest_check() before DSK handoff - FUCK [attest] require_<name>=1 (default) + not-ready -> lotus panic with feature errcode - wired: sealed_mem/pckc/sched/drr/fs_fat32_rw/net_wired + placeholders (pkg/brand/dkm/nvme/virtio/wlan/vmx/drr_real_mac) - negative test: require_pkg=1 -> boot-time PKG-E10 panic (verified); dev/release FUCK whitelist = STATUS.md undone items - CLAUDE.md whitelist rule updated
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
/* attest.c — SAS-R0 启动期能力证明(boot-time feature attestation)
|
||||
*
|
||||
* "设计已定的能力没好 = 启动即 panic",不是"调用才 panic"。
|
||||
* 各子系统在初始化完成点 attest_report();内核交接 DSK 前
|
||||
* attest_check() 统一核查 FUCK [attest] 的 require_<name>。
|
||||
*
|
||||
* require 默认值 = 1(必备):能力没好就必须 panic,绝不带病前进。
|
||||
* 仅当某构建环境明确不具备该能力(如 QEMU 无 wlan)时,才在
|
||||
* FUCK [attest] 显式写 require_<name>=0——这是设计内白名单,
|
||||
* 必须在 CLAUDE.md §3 有对应条目。
|
||||
*/
|
||||
#include <utsm/attest.h>
|
||||
#include <utsm/panic.h>
|
||||
#include <utsm/log.h>
|
||||
#include "../kernel/ini_parser.h"
|
||||
|
||||
#define ATTEST_MAX_FEATURES 32
|
||||
#define ATTEST_NAME_LEN 28
|
||||
#define ATTEST_CODE_LEN 20
|
||||
|
||||
typedef struct {
|
||||
char name[ATTEST_NAME_LEN];
|
||||
char errcode[ATTEST_CODE_LEN];
|
||||
int ready;
|
||||
int reported;
|
||||
} attest_feature;
|
||||
|
||||
static attest_feature g_features[ATTEST_MAX_FEATURES];
|
||||
static u32 g_feature_count;
|
||||
|
||||
static attest_feature *attest_find(const char *name) {
|
||||
for (u32 i = 0; i < g_feature_count; i++) {
|
||||
const char *a = g_features[i].name;
|
||||
const char *b = name;
|
||||
while (*a && *b && *a == *b) { a++; b++; }
|
||||
if (*a == *b) return &g_features[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void attest_report(const char *name, const char *errcode, int ready) {
|
||||
if (!name || !errcode) return;
|
||||
attest_feature *f = attest_find(name);
|
||||
if (!f) {
|
||||
if (g_feature_count >= ATTEST_MAX_FEATURES) {
|
||||
log_error("[ATTEST] feature table full, dropping");
|
||||
log_error(name);
|
||||
return;
|
||||
}
|
||||
f = &g_features[g_feature_count++];
|
||||
/* 手工 strncpy(freestanding) */
|
||||
u32 i = 0;
|
||||
for (; name[i] && i < ATTEST_NAME_LEN - 1; i++) f->name[i] = name[i];
|
||||
f->name[i] = 0;
|
||||
i = 0;
|
||||
for (; errcode[i] && i < ATTEST_CODE_LEN - 1; i++) f->errcode[i] = errcode[i];
|
||||
f->errcode[i] = 0;
|
||||
f->reported = 0;
|
||||
}
|
||||
f->ready = ready ? 1 : 0;
|
||||
f->reported = 1;
|
||||
}
|
||||
|
||||
void attest_report_ready(const char *name, const char *errcode) {
|
||||
attest_report(name, errcode, 1);
|
||||
}
|
||||
|
||||
u32 attest_missing_count(void) {
|
||||
u32 n = 0;
|
||||
for (u32 i = 0; i < g_feature_count; i++)
|
||||
if (!g_features[i].ready) n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
void attest_check(const void *cfg) {
|
||||
log_info("[ATTEST] boot-time capability check begin");
|
||||
|
||||
/* 先串口列出全部缺失项(panic 屏只显示第一个,日志要全) */
|
||||
u32 missing = 0;
|
||||
for (u32 i = 0; i < g_feature_count; i++) {
|
||||
const attest_feature *f = &g_features[i];
|
||||
if (f->ready) continue;
|
||||
missing++;
|
||||
log_error("[ATTEST] MISSING:");
|
||||
log_error(f->name);
|
||||
log_error(f->errcode);
|
||||
}
|
||||
log_hex64("[ATTEST] features=", g_feature_count);
|
||||
log_hex64("[ATTEST] missing=", missing);
|
||||
|
||||
if (missing == 0) {
|
||||
log_info("[ATTEST] all capabilities ready");
|
||||
return;
|
||||
}
|
||||
|
||||
/* 逐项判断是否必备(require_<name> 默认 1):
|
||||
* 全部缺失项中只要有一项必备 → panic(错误码取第一个必备缺失项) */
|
||||
const attest_feature *first_required_missing = 0;
|
||||
for (u32 i = 0; i < g_feature_count; i++) {
|
||||
const attest_feature *f = &g_features[i];
|
||||
if (f->ready) continue;
|
||||
char key[48];
|
||||
u32 p = 0;
|
||||
const char *pre = "require_";
|
||||
while (*pre) key[p++] = *pre++;
|
||||
u32 j = 0;
|
||||
for (; f->name[j] && p < sizeof(key) - 1; j++) key[p++] = f->name[j];
|
||||
key[p] = 0;
|
||||
/* ini key 小写;name 约定即小写(register 侧保证) */
|
||||
if (ini_get_bool(cfg, "attest", key, 1)) {
|
||||
first_required_missing = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (first_required_missing) {
|
||||
panic_full(first_required_missing->errcode,
|
||||
"required capability not ready at boot (attestation)", 0);
|
||||
}
|
||||
|
||||
/* 全部缺失项均被 FUCK 显式豁免(设计内白名单),放行 */
|
||||
log_warn("[ATTEST] missing capabilities exempted by FUCK [attest]");
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <utsm/linux_compat.h>
|
||||
#include <utsm/xj380_loader.h>
|
||||
#include <utsm/instr.h>
|
||||
#include <utsm/attest.h>
|
||||
#include "ini_parser.h"
|
||||
#include "../arch/x86_64/limine.h"
|
||||
#include "../pe/pe_dll_manager.h"
|
||||
@@ -127,6 +128,7 @@ static void utsm_apply_config(const ini_config *cfg) {
|
||||
/* ---- 全局启动配置(从 FUCK 文件读取) ---- */
|
||||
static ini_config g_boot_cfg;
|
||||
static int g_boot_cfg_loaded = 0;
|
||||
static int g_vmm_init_ok = 0; /* attest: vmm_vmx 能力打点 */
|
||||
|
||||
/* 从 Limine boot module 读取 FUCK 配置。
|
||||
* cmdline="fuck:config" 的模块即为 FUCK 配置文件。
|
||||
@@ -354,6 +356,9 @@ void kernel_main(void) {
|
||||
drr_init();
|
||||
INSTR_TS_END(ts_drr, "drr_init");
|
||||
log_info("[UTSM] drr init ok");
|
||||
/* 启动期能力证明:DRR 快照/回滚已立;真 MAC 为 Phase 9(占位 CRC64) */
|
||||
attest_report_ready("drr", "DRR-E30");
|
||||
attest_report("drr_real_mac", "DRR-E31", 0);
|
||||
|
||||
log_info("[UTSM] core init begin");
|
||||
INSTR_TS_DECL(ts_utsm);
|
||||
@@ -361,12 +366,15 @@ void kernel_main(void) {
|
||||
utsm_init();
|
||||
INSTR_TS_END(ts_utsm, "utsm_init");
|
||||
log_info("[UTSM] init ok");
|
||||
/* 启动期能力证明:utsm_init 内含 PCKC 派生往返自证(失败即 PCKC-E01) */
|
||||
attest_report_ready("pckc_derive", "PCKC-E02");
|
||||
|
||||
/* === 封缄内存极早期初始化(UTSM-E01..E04) ===
|
||||
* .sealed 区为空 / root key 缺失 → 此处极早期 panic,绝不带病前进。 */
|
||||
{
|
||||
extern void utsm_sealed_early_init(void);
|
||||
utsm_sealed_early_init();
|
||||
attest_report_ready("sealed_mem", "UTSM-E05");
|
||||
}
|
||||
|
||||
/* === SAS-R0-PCQ 调度器:bootstrap 任务绑定(Phase 7) ===
|
||||
@@ -388,6 +396,7 @@ void kernel_main(void) {
|
||||
panic_full("SAS-E01 SCHED BOOTSTRAP FAILED",
|
||||
"SAS-R0-PCQ scheduler bootstrap failed (was: non-fatal)", 0);
|
||||
}
|
||||
attest_report_ready("sched", "SAS-E02");
|
||||
}
|
||||
|
||||
INSTR_TS_DECL(ts_dkm);
|
||||
@@ -400,7 +409,9 @@ void kernel_main(void) {
|
||||
* P8.4: Moved BEFORE DKM driver loading so VMM self-test runs even if
|
||||
* a stage2 driver (e.g. fat32) crashes under KVM nested VMX. */
|
||||
int run_vmm = ini_get_bool(cfg, "boot", "vmm", 1);
|
||||
g_vmm_init_ok = 0;
|
||||
if (run_vmm && vmm_init() == 0) {
|
||||
g_vmm_init_ok = 1;
|
||||
INSTR_TS_DECL(ts_vmm);
|
||||
INSTR_TS_BEGIN(ts_vmm);
|
||||
log_info("[UTSM] VMM init ok");
|
||||
@@ -517,6 +528,8 @@ void kernel_main(void) {
|
||||
} else {
|
||||
log_warn("[UTSM] VMM unavailable (VMX not supported or disabled by FUCK)");
|
||||
}
|
||||
/* 启动期能力证明:VMX 可用性(未就绪时是否 panic 由 FUCK [attest] require_vmm_vmx 决定) */
|
||||
attest_report("vmm_vmx", "VMM-E30", run_vmm && g_vmm_init_ok);
|
||||
|
||||
/* === 驱动加载 — 按 [drivers] 区过滤 === */
|
||||
INSTR_TS_DECL(ts_dsm);
|
||||
@@ -524,6 +537,28 @@ void kernel_main(void) {
|
||||
dsm_load_by_manifest_ex(cfg);
|
||||
INSTR_TS_END(ts_dsm, "dsm_load_manifest");
|
||||
|
||||
/* === 启动期能力证明:DKM 驱动派生能力 + 设计占位能力 === */
|
||||
{
|
||||
u32 net_total = 0, net_wlan = 0;
|
||||
net_attest_counts(&net_total, &net_wlan);
|
||||
attest_report("net_wired", "NET-E02", net_total > 0);
|
||||
attest_report("net_wlan", "NET-E01", net_wlan > 0);
|
||||
/* FAT32 读写:块 provider 需同时具备 read+write(AHCI WRITE DMA) */
|
||||
{
|
||||
const dkm_kernel_api *kapi = dkm_get_kernel_api();
|
||||
int fat_rw = (kapi && kapi->block && kapi->block->read && kapi->block->write) ? 1 : 0;
|
||||
attest_report("fs_fat32_rw", "FS-E10", fat_rw);
|
||||
}
|
||||
/* 设计已定但未实现的能力(占位,require 决定是否阻断启动) */
|
||||
attest_report("fs_ext4_rw", "FS-E11", 1); /* FS-E 严格模式已落(DSK 侧读写闭环) */
|
||||
attest_report("pkg", "PKG-E10", 0);
|
||||
attest_report("brand_anim", "BRAND-E10", 0);
|
||||
attest_report("dkm_hot_unload", "DKM-E60", 0);
|
||||
attest_report("dkm_api_export", "DKM-E61", 0);
|
||||
attest_report("nvme_rw", "NVME-E30", 0);
|
||||
attest_report("virtio_net", "VNET-E30", 0);
|
||||
}
|
||||
|
||||
/* === F4: 分级启动自检 — FUCK [boot] selftest=0|1|2 ===
|
||||
* 0=关 / 1=快速(结构健全性) / 2=全量(+DMA 探针 + UTSM selftest) */
|
||||
{
|
||||
@@ -574,6 +609,10 @@ void kernel_main(void) {
|
||||
}
|
||||
}
|
||||
|
||||
/* === SAS-R0 启动期能力证明:交接 DSK 前统一核查 ===
|
||||
* FUCK [attest] require_<name>=1(默认)而能力未就绪 → 莲花屏 panic。 */
|
||||
attest_check(cfg);
|
||||
|
||||
/* === 调度器静默(Phase 7/8 收尾) ===
|
||||
* 停 LAPIC timer、注销 tick/异常 handler、杀 demo 任务——保证
|
||||
* dsk_load_and_jump 的 DSK 交接路径与无调度器时逐字节一致。 */
|
||||
|
||||
@@ -36,6 +36,16 @@ static u32 net_device_count_impl(void) {
|
||||
return g_net_device_count;
|
||||
}
|
||||
|
||||
/* attest: 有线/无线设备计数(is_wireless 回调非空即视为无线) */
|
||||
void net_attest_counts(u32 *out_total, u32 *out_wireless) {
|
||||
u32 wireless = 0;
|
||||
for (u32 i = 0; i < g_net_device_count; i++) {
|
||||
if (g_net_devices[i].is_wireless) wireless++;
|
||||
}
|
||||
if (out_total) *out_total = g_net_device_count;
|
||||
if (out_wireless) *out_wireless = wireless;
|
||||
}
|
||||
|
||||
static int net_device_info_impl(u32 index, dkm_net_device_info *out) {
|
||||
if (!out) return -1;
|
||||
if (index >= g_net_device_count) return -2;
|
||||
|
||||
Reference in New Issue
Block a user