Skip to content

Commit 6d863c0

Browse files
author
Requiem
committed
feat: improved timing attacks to reduce FPs
1 parent 3a63364 commit 6d863c0

1 file changed

Lines changed: 33 additions & 7 deletions

File tree

src/vmaware.hpp

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5462,6 +5462,7 @@ struct VM {
54625462
const HANDLE current_thread = reinterpret_cast<HANDLE>(-2LL);
54635463
SetThreadAffinityMask(current_thread, target_affinity);
54645464
SetThreadPriority(current_thread, THREAD_PRIORITY_HIGHEST); // decrease chance of being rescheduled
5465+
SetThreadPriorityBoost(current_thread, TRUE); // disable dynamic boosts
54655466

54665467
while (!state.start_test.load(std::memory_order_acquire)) {}
54675468

@@ -5508,14 +5509,28 @@ struct VM {
55085509

55095510
// the robust center: median M and MAD -> approximate sigma
55105511
const u64 M = median_of_sorted(s, 0, s.size());
5512+
5513+
// Faster MAD: select the median deviation in linear time instead of sorting all deviations.
55115514
std::vector<u64> absdev;
5512-
absdev.reserve(N);
5515+
absdev.resize(N);
55135516
for (size_t i = 0; i < N; ++i) {
55145517
const u64 d = (s[i] > M) ? (s[i] - M) : (M - s[i]);
5515-
absdev.push_back(d);
5518+
absdev[i] = d;
55165519
}
5517-
std::sort(absdev.begin(), absdev.end());
5518-
const u64 MAD = median_of_sorted(absdev, 0, absdev.size());
5520+
5521+
const size_t mad_mid = N / 2;
5522+
std::nth_element(absdev.begin(), absdev.begin() + mad_mid, absdev.end());
5523+
5524+
u64 MAD = 0;
5525+
if (N & 1) {
5526+
MAD = absdev[mad_mid];
5527+
}
5528+
else {
5529+
const u64 upper = absdev[mad_mid];
5530+
const u64 lower = *std::max_element(absdev.begin(), absdev.begin() + mad_mid);
5531+
MAD = (lower + upper) / 2;
5532+
}
5533+
55195534
// convert MAD to an approximate standard-deviation-like measure
55205535
constexpr long double kmad_to_sigma = 1.4826L; // consistent for normal approx
55215536
const long double sigma = (MAD == 0) ? 1.0L : (static_cast<long double>(MAD) * kmad_to_sigma);
@@ -5625,20 +5640,29 @@ struct VM {
56255640
SetThreadAffinityMask(current_thread, 1);
56265641
SetPriorityClass(current_process, ABOVE_NORMAL_PRIORITY_CLASS); // ABOVE_NORMAL_PRIORITY_CLASS + THREAD_PRIORITY_HIGHEST = 12 base priority
56275642
SetThreadPriority(current_thread, THREAD_PRIORITY_HIGHEST);
5643+
SetThreadPriorityBoost(current_thread, TRUE); // disable dynamic boosts
56285644

56295645
// so that hypervisor can't predict how many samples we will collect
56305646
std::mt19937 gen(std::random_device{}());
56315647
std::uniform_int_distribution<size_t> batch_dist(30000, 70000);
56325648
const size_t BATCH_SIZE = batch_dist(gen);
56335649
i32 dummy_res[4]{};
5634-
size_t valid = 0;
5650+
size_t valid = 0; // end of setup phase
5651+
SleepEx(0, FALSE); // try to get fresh quantum before starting warm-up phase, give time to kernel to set up priorities
5652+
56355653
std::vector<u64> vm_samples(BATCH_SIZE), ref_samples(BATCH_SIZE); // pre page-fault MMU, wwe wont warm-up cpuid samples for the P-states intentionally
5654+
VirtualLock(vm_samples.data(), BATCH_SIZE * sizeof(u64)); // lock the memory for the samples to prevent page faults if permissions are enough
5655+
VirtualLock(ref_samples.data(), BATCH_SIZE * sizeof(u64));
56365656

56375657
state.start_test.store(true, std::memory_order_release); // _mm_pause can be exited conditionally, spam hit L3
5638-
while (state.counter == 0) {}
5658+
// warm-up to settle caches, scheduler and frequency boosts
5659+
for (int i = 0; i < 1000; ++i) {
5660+
trigger_vmexit(dummy_res, 0x0, 0);
5661+
for (int j = 0; j < 8; ++j) _mm_lfence();
5662+
}
56395663

56405664
while (valid < BATCH_SIZE) {
5641-
// interpolated so that any turbo boost, thermal throttling, speculation (for the loop overhead itself, not for the serializing instructions), etc affects both samples
5665+
// interpolated so that any turbo boost, thermal throttling, speculation (for the loop overhead itself, not for the serializing instructions), etc affects samples equally
56425666
u64 v_pre, v_post, r_pre, r_post, sync;
56435667

56445668
sync = state.counter; while (state.counter == sync); // infer if counter got enough quantum momentum (so its currently scheduled)
@@ -5704,6 +5728,8 @@ struct VM {
57045728
}
57055729
}
57065730

5731+
VirtualUnlock(vm_samples.data(), BATCH_SIZE * sizeof(u64));
5732+
VirtualUnlock(ref_samples.data(), BATCH_SIZE * sizeof(u64));
57075733
SetPriorityClass(current_process, NORMAL_PRIORITY_CLASS);
57085734
};
57095735

0 commit comments

Comments
 (0)