From b9881278af33767628211df735f27b9e542ab4db Mon Sep 17 00:00:00 2001 From: DanS Date: Sun, 7 Jun 2026 09:29:37 -0500 Subject: [PATCH] feat(mining): enforce xmrig signatures + fix multi-platform checksum/asset bugs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the release publishes a valid .sig per archive (verified against the pinned key for linux/win/macOS), enable enforcement and fix two bugs that the newer multi-platform release (v6.25.3, which added a macOS build) exposed: - kXmrigRequireSignature = true: refuse any install whose release doesn't publish a valid ed25519 signature over the archive. Verified live end-to-end against the signed v6.25.3 (archive SHA-256 + signature -> install). - Drop the redundant inner-binary SHA-256 check. It keyed on the inner filename, but both the linux and macOS archives contain a binary literally named "xmrig", so the two "xmrig (…)" checksum lines collided in the map and the linux install compared against the macOS hash -> spurious "could not verify" failure. The whole archive is already verified (SHA-256 + signature), so every extracted member is authentic by transitivity — the per-member check added nothing but ambiguity. - Fix the macOS platform token: the asset is named "...-macos-x86_64.zip", not "...-macos-x64", so selectXmrigAsset never matched it. currentXmrigPlatformToken() now returns "macos-x86_64" on Intel macs (arm64 has no build -> Unavailable). Added a matcher test for the macOS naming. Both variants build; suite stable (0 failures / multiple runs); live require-mode install verified. Co-Authored-By: Claude Opus 4.8 --- src/util/xmrig_updater.cpp | 18 +++++------------- src/util/xmrig_updater.h | 2 +- src/util/xmrig_updater_core.cpp | 4 ++-- tests/test_phase4.cpp | 10 ++++++++-- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/util/xmrig_updater.cpp b/src/util/xmrig_updater.cpp index 9adc503..442dbf4 100644 --- a/src/util/xmrig_updater.cpp +++ b/src/util/xmrig_updater.cpp @@ -321,8 +321,11 @@ void XmrigUpdater::runInstall(std::string targetDir) } } - // 3. Extract the wanted binaries (flatten the versioned subdir), verifying the miner binary's - // SHA-256 in memory before writing the executable to disk. + // 3. Extract the wanted binaries (flatten the versioned subdir). No per-member hash check is + // needed: the whole archive was already verified above (SHA-256, and the ed25519 signature + // when a key is pinned), so every member is authentic by transitivity. (A per-member check + // keyed on the inner filename is also ambiguous — e.g. both the linux and macOS archives + // contain a binary literally named "xmrig".) setProgress(State::Extracting, "Installing miner…"); const std::vector wanted = xmrigExtractBasenames(token); const std::string minerName = wanted.front(); // "xmrig" / "xmrig.exe" @@ -350,17 +353,6 @@ void XmrigUpdater::runInstall(std::string targetDir) void* mem = mz_zip_reader_extract_to_heap(&zip, i, &outSize, 0); if (!mem) { failed = true; break; } - // For the miner binary, verify the inner-binary SHA-256 before writing the executable. - if (base == minerName) { - const std::string actual = sha256Hex(mem, outSize); - const auto it = checksums.find(minerName); - if (it == checksums.end() || actual != it->second) { - mz_free(mem); - failed = true; - break; - } - } - // Atomic write: temp file in target dir, then rename over the destination. const std::string finalPath = (fs::path(targetDir) / base).string(); const std::string tmpPath = finalPath + ".tmp"; diff --git a/src/util/xmrig_updater.h b/src/util/xmrig_updater.h index 05a8861..2d56d79 100644 --- a/src/util/xmrig_updater.h +++ b/src/util/xmrig_updater.h @@ -54,7 +54,7 @@ struct XmrigRelease { // kXmrigRequireSignature=true to additionally refuse installs that publish no signature. inline constexpr const char* kXmrigSignaturePublicKeyBase64 = "j/9M+0E8NgcudP1q+23ar5uzwAFzQled8TtkFMaou6Q="; -inline constexpr bool kXmrigRequireSignature = false; // soft rollout: verify .sig if present +inline constexpr bool kXmrigRequireSignature = true; // enforced: refuse installs without a valid .sig // ── Pure helpers (no I/O; unit-tested) ─────────────────────────────────────── diff --git a/src/util/xmrig_updater_core.cpp b/src/util/xmrig_updater_core.cpp index c7aa480..c0387d2 100644 --- a/src/util/xmrig_updater_core.cpp +++ b/src/util/xmrig_updater_core.cpp @@ -77,9 +77,9 @@ std::string currentXmrigPlatformToken() return "win-x64"; #elif defined(__APPLE__) #if defined(__aarch64__) || defined(__arm64__) - return "macos-arm64"; + return "macos-arm64"; // no arm64 build published yet -> resolves to Unavailable #else - return "macos-x64"; + return "macos-x86_64"; // matches the release asset naming (note: not "macos-x64") #endif #elif defined(__linux__) #if defined(__aarch64__) diff --git a/tests/test_phase4.cpp b/tests/test_phase4.cpp index 9c13a98..dad0be8 100644 --- a/tests/test_phase4.cpp +++ b/tests/test_phase4.cpp @@ -3998,10 +3998,16 @@ void testXmrigAssetSelection() EXPECT_TRUE(linux != win); EXPECT_TRUE(rel.assets[linux].name.find("linux-x64.zip") != std::string::npos); EXPECT_TRUE(rel.assets[win].name.find("win-x64.zip") != std::string::npos); - // No macOS build is published -> graceful "not found". - EXPECT_EQ(selectXmrigAsset(rel, "macos-x64"), -1); + // No macOS build in this fixture -> graceful "not found". + EXPECT_EQ(selectXmrigAsset(rel, "macos-x86_64"), -1); EXPECT_EQ(selectXmrigAsset(rel, "macos-arm64"), -1); EXPECT_EQ(selectXmrigAsset(rel, ""), -1); + + // The matcher handles the macOS asset naming ("macos-x86_64", not "macos-x64"). + XmrigRelease mac; mac.ok = true; mac.tag = "v6.25.3"; + mac.assets.push_back({"drg-xmrig-6.25.3-macos-x86_64.zip", "https://x/m", 100}); + EXPECT_TRUE(selectXmrigAsset(mac, "macos-x86_64") >= 0); + EXPECT_EQ(selectXmrigAsset(mac, "macos-x64"), -1); // the wrong token must NOT match } void testXmrigChecksumParsing()