diff --git a/tests/src/vm_test.cpp b/tests/src/vm_test.cpp index 8a9f77e..d5df419 100644 --- a/tests/src/vm_test.cpp +++ b/tests/src/vm_test.cpp @@ -13,6 +13,7 @@ #include "compiler/Codegen.h" #include "compiler/Linker.h" #include "compiler/Project.h" +#include "compiler/Stb.h" #include "compiler/Typecheck.h" #include "isa/Encode.h" #include "isa/Instr.h" @@ -155,6 +156,16 @@ static std::vector hand_image(const std::vector& consts for (size_t i = 0; i < data.size(); ++i) { b[off_data + i] = data[i]; } + // 型号标识(STATOR1)+ 真实 SHA-256 尾(用 compiler 实现填) + const char* mid = "STATOR1"; + for (size_t i = 0; i < 32; ++i) { + b[72 + i] = i < 7 ? static_cast(mid[i]) : 0; + } + uint8_t digest[32]; + compiler::sha256(b.data(), b.size() - 32, digest); + for (int i = 0; i < 32; ++i) { + b[b.size() - 32 + i] = digest[i]; + } return b; } @@ -428,6 +439,64 @@ static bool test_bad_const() { return true; } +// ---- 10. 12.13 校验:SHA 篡改拒绝 + 型号不匹配拒绝 ---- + +static bool test_verify() { + std::string err; + vm::Machine m; + + // 正常映像可跑 + CHECK(make_machine("tests/cases/01_empty_main", &m, &err)); + CHECK(m.run_cycle() == vm::Fault::None); + + // SHA 篡改:改一字节 → create 拒绝 + { + const std::string toml = std::string(REPO_ROOT) + "/tests/cases/01_empty_main/project.toml"; + compiler::Project p; + CHECK(compiler::parse_project(toml, &p, &err)); + std::vector units; + for (const std::string& f : compiler::compile_files(p)) { + compiler::SourceUnit u; + CHECK(compiler::load_unit(p.base_dir + "/" + f, &u, &err)); + units.push_back(std::move(u)); + } + compiler::LinkResult link; + CHECK(compiler::link_project(p, units, &link, &err)); + compiler::MachineConfig cfg; + CHECK(cfg.load(std::string(REPO_ROOT) + "/compiler/machine.toml", &err)); + std::vector img; + CHECK(compiler::codegen_project(p, units, link, cfg, &img, &err)); + img[100] ^= 0x01; // 篡改代码段一字节 + vm::Machine bad; + CHECK(!vm::Machine::create(img, &bad, &err)); + CHECK(err.find("sha256 mismatch") != std::string::npos); + } + + // 型号不匹配:手拼映像改型号(重算 SHA,仅型号不一致)→ create 拒绝 + { + const std::vector consts; + const std::vector funcs = {{ + { + isa::enc_ret(), + }, + 8, + }}; + std::vector img = hand_image(consts, funcs); + for (int i = 0; i < 5; ++i) { + img[72 + i] = "OTHER"[i]; + } + uint8_t digest[32]; + compiler::sha256(img.data(), img.size() - 32, digest); + for (int i = 0; i < 32; ++i) { + img[img.size() - 32 + i] = digest[i]; + } + vm::Machine bad; + CHECK(!vm::Machine::create(img, &bad, &err)); + CHECK(err.find("model mismatch") != std::string::npos); + } + return true; +} + int main() { if (!test_hand_scalar()) return 1; if (!test_hand_call()) return 1; @@ -438,6 +507,7 @@ int main() { if (!test_determinism()) return 1; if (!test_step()) return 1; if (!test_bad_const()) return 1; + if (!test_verify()) return 1; std::printf("vm_test: %d checks passed\n", g_checks); return 0; } diff --git a/vm/include/vm/Image.h b/vm/include/vm/Image.h index d899354..e3dac36 100644 --- a/vm/include/vm/Image.h +++ b/vm/include/vm/Image.h @@ -17,6 +17,10 @@ namespace vm { + // 执行器内建支持型号(与 machine.toml [meta] 对齐;.stb 型号不匹配直接拒绝) + static const char* const kModelName = "STATOR"; + static const uint32_t kModelVersion = 1; + // 映像头(字段与 Doc/isa/指令与映像.md 一致) struct ImageHeader { uint32_t cycle_limit = 0; @@ -62,7 +66,12 @@ namespace vm { const uint8_t* code_bytes() const; // 字节码段起点 const uint8_t* data_bytes() const; // 数据段起点 - size_t data_len() const; // 字节数 + size_t data_len() const; // 字节数(不含 SHA 尾) + + // 12.13:型号标识与 SHA-256 校验 + std::string model_id() const; + bool model_matches(const std::string& name, uint32_t version) const; + bool sha_ok() const; // 文件尾 32 字节 SHA-256 校验 public: // 默认构造为无效态(ok() == false) diff --git a/vm/src/Image.cpp b/vm/src/Image.cpp index 54bcd4c..d826c00 100644 --- a/vm/src/Image.cpp +++ b/vm/src/Image.cpp @@ -7,6 +7,9 @@ #include "vm/Image.h" +#include +#include + namespace vm { namespace { @@ -16,7 +19,8 @@ namespace { const size_t kHeaderSize = 104; const size_t kConstEntrySize = 12; const size_t kFuncRowSize = 12; - const size_t kSha256Size = 32; // 文件尾(步骤 8 校验) + const size_t kSha256Size = 32; + const size_t kModelIdSize = 32; uint32_t get_le32(const uint8_t* p) { return static_cast(p[0]) @@ -33,6 +37,124 @@ namespace { return v; } + // ---- SHA-256(执行器侧实现,与 compiler 各一份)---- + + const uint32_t kShaK[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, + 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, + }; + + inline uint32_t rotr(uint32_t x, uint32_t n) { return (x >> n) | (x << (32 - n)); } + + struct Sha256 { + uint32_t h[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; + uint64_t total = 0; + uint8_t block[64]; + size_t block_len = 0; + + void update(const uint8_t* data, size_t len) { + total += len; + while (len > 0) { + const size_t n = (block_len < 64) ? (64 - block_len) : 0; + const size_t take = len < n ? len : n; + if (take == 0) { + break; + } + for (size_t i = 0; i < take; ++i) { + block[block_len + i] = data[i]; + } + block_len += take; + data += take; + len -= take; + if (block_len == 64) { + process(); + block_len = 0; + } + } + } + + void process() { + uint32_t w[64]; + for (int i = 0; i < 16; ++i) { + w[i] = get_be32(block + i * 4); + } + for (int i = 16; i < 64; ++i) { + const uint32_t s0 = rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ (w[i - 15] >> 3); + const uint32_t s1 = rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ (w[i - 2] >> 10); + w[i] = w[i - 16] + s0 + w[i - 7] + s1; + } + uint32_t a = h[0], b = h[1], c = h[2], d = h[3]; + uint32_t e = h[4], f = h[5], g = h[6], hh = h[7]; + for (int i = 0; i < 64; ++i) { + const uint32_t s1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25); + const uint32_t ch = (e & f) ^ (~e & g); + const uint32_t t1 = hh + s1 + ch + kShaK[i] + w[i]; + const uint32_t s0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22); + const uint32_t maj = (a & b) ^ (a & c) ^ (b & c); + const uint32_t t2 = s0 + maj; + hh = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + h[0] += a; h[1] += b; h[2] += c; h[3] += d; + h[4] += e; h[5] += f; h[6] += g; h[7] += hh; + } + + void final(uint8_t out[32]) { + const uint64_t bitlen = total * 8; + const uint8_t pad = 0x80; + update(&pad, 1); + const uint8_t zeros[64] = {0}; + while (block_len != 56) { + const size_t n = (block_len < 56) ? (56 - block_len) : (64 - block_len); + update(zeros, n); + } + for (int i = 0; i < 8; ++i) { + const uint8_t b2[1] = {static_cast((bitlen >> (56 - 8 * i)) & 0xFF)}; + update(b2, 1); + } + for (int i = 0; i < 8; ++i) { + out[i * 4 + 0] = static_cast((h[i] >> 24) & 0xFF); + out[i * 4 + 1] = static_cast((h[i] >> 16) & 0xFF); + out[i * 4 + 2] = static_cast((h[i] >> 8) & 0xFF); + out[i * 4 + 3] = static_cast(h[i] & 0xFF); + } + } + + static uint32_t get_be32(const uint8_t* p) { + return (static_cast(p[0]) << 24) | (static_cast(p[1]) << 16) | + (static_cast(p[2]) << 8) | static_cast(p[3]); + } + }; + + void sha256(const uint8_t* data, size_t len, uint8_t out[32]) { + Sha256 s; + s.update(data, len); + s.final(out); + } + + void fill_model_id(const std::string& name, uint32_t version, char out[32]) { + const std::string id = name + std::to_string(version); + for (size_t i = 0; i < 32; ++i) { + out[i] = i < id.size() ? id[i] : '\0'; + } + } + } // namespace Image Image::from(const uint8_t* buf, size_t len) { @@ -144,8 +266,35 @@ const uint8_t* Image::data_bytes() const { } size_t Image::data_len() const { - // 步骤 7:含 SHA 尾(步骤 8 收紧并校验) - return ok_ ? len_ - hdr_.offset_data : 0; + return ok_ ? (len_ - kSha256Size) - hdr_.offset_data : 0; +} + +std::string Image::model_id() const { + if (!ok_) { + return ""; + } + std::string s(reinterpret_cast(buf_ + 72), kModelIdSize); + const size_t z = s.find('\0'); + if (z != std::string::npos) { + s.resize(z); + } + return s; +} + +bool Image::model_matches(const std::string& name, uint32_t version) const { + char want[kModelIdSize]; + fill_model_id(name, version, want); + return std::memcmp(buf_ + 72, want, kModelIdSize) == 0; +} + +bool Image::sha_ok() const { + if (!ok_) { + return false; + } + const size_t content_len = len_ - kSha256Size; + uint8_t digest[32]; + sha256(buf_, content_len, digest); + return std::memcmp(buf_ + content_len, digest, 32) == 0; } } // namespace vm diff --git a/vm/src/Machine.cpp b/vm/src/Machine.cpp index 2753b58..ab869cf 100644 --- a/vm/src/Machine.cpp +++ b/vm/src/Machine.cpp @@ -32,6 +32,20 @@ bool Machine::create(const std::vector& image, Machine* out, } return false; } + // 12.13:型号匹配与 SHA-256 校验(不匹配/篡改直接拒绝) + if (!out->image_.sha_ok()) { + if (err) { + *err = "image sha256 mismatch"; + } + return false; + } + if (!out->image_.model_matches(kModelName, kModelVersion)) { + if (err) { + *err = "image model mismatch: '" + out->image_.model_id() + + "' (expect " + kModelName + std::to_string(kModelVersion) + ")"; + } + return false; + } // 数据区工作副本(8 字节定宽槽) out->data_.assign(out->image_.data_bytes(), out->image_.data_bytes() + out->image_.data_len());