DrumsBench

Experiments / EXP-020

Mechanism K: kernel page merging saves 7% with ASLR on and 41% only with ASLR off, costs 0.7 to 0.9 vCPU against a 0.25 bar, and opens a cross-session timing channel

Measure, against thresholds fixed before the run, whether kernel same-page merging (KSM) across Drums L0 sessions cuts per-session memory at an acceptable CPU cost, with and without address-space randomisation, and whether it introduces a cross-session side channel.

failedRan and missed a correctness, isolation, reset or pre-registered performance bar. Kept on the record.
Date
2026-10-24
Hypothesis
The author expected K1 to fail the memory bar, gave K2 about a 40% chance of passing it, expected the scan settings to break the CPU bar, and expected a clear timing gap.
Arms
l1-ksm
Hardware
4 vCPU, 16 GiB, cgroup v1, no KVM (dev-sandbox)
OS
Ubuntu 24.04, kernel 6.18 (sandbox)
Workload
Drums L0 sessions each with the real OSWorld guest server and its own Playwright Chromium 141; OFF, K1 (mergeable, ASLR on), K2 (mergeable, ASLR off); 3 trials to 20 sessions; two cooperating side-channel probes
Code
claude/linux-comparison-prep at 1218b2c
Evidence
docs/data/l1-ksm/ksm_bench.json
docs/data/l1-ksm/ksm_bench.log
docs/data/l1-ksm/ksm_bench_limits.json
docs/data/l1-ksm/ksm_semantics.json
docs/data/l1-ksm/ksm_sidechannel.json
docs/l1-shared-runtime-design.md (sections 12 and 13)
docs/mechanism-k-page-merging.md
Limitation
The only arm with a large saving turns address-space randomisation off in every process of the session, a security regression the author labels not shippable; both arms fail the CPU bar; the side-channel figure is an upper bound from cooperating probes with known page content, not an attack on task data.

In one paragraph

EXP-019 showed that about 125 MiB per session is duplicated browser state, and that sharing the browser process breaks isolation. Mechanism K keeps one browser per session and asks the kernel to merge identical 4 KiB pages underneath (KSM). Measured on one sandbox, 3 trials: host memory per added session 229.73 MiB with merging off; 212.70 MiB with merging on and ASLR on (K1, a 7.4% saving, interval of the difference [14.23, 19.84] MiB) at a merging-thread cost of 0.895 vCPU; 135.36 MiB with merging on and ASLR off in every session process (K2, 41.1%, interval [92.21, 96.87] MiB) at 0.706 vCPU. The pre-registered CPU bar was 0.25 vCPU; both arms fail it. K2's saving exists only because every process is laid out identically, which is exactly what ASLR prevents; the author's wording, which we adopt: "no K arm is shippable". KSM also adds a channel the other arms do not have: two cooperating probes in two sessions told whether a page with known content existed in the other session with 99.9% held-out accuracy at about 200 bits per second. "Drums" here means the L0 prototype (namespaces, overlayfs on the sandbox's own Ubuntu 24.04 root, Xvfb, openbox) plus a kernel feature; no shared-runtime (L1) result exists; incumbents' VMs can use KSM too, so nothing here compares against an incumbent.

Setup

Host. One development sandbox: 4 vCPU, 16 GiB, kernel 6.18, cgroup v1, no KVM, writable /sys/kernel/mm/ksm; hostname and provider not recorded.

The idea. Twenty sessions run the same desktop software, so many pages hold identical bytes. Linux can keep one physical copy for all of them; a session that later writes to a merged page gets its own private copy (copy-on-write). Nothing about processes, files or displays changes. The catch: with ASLR each process's pointers sit at different random addresses, so pages that contain pointers differ between sessions and do not merge.

Arms (identical sessions: real OSWorld guest server, per-session Chromium on its own Xvfb, overlay, namespaces):

ArmSetting
OFFno merge flag; ASLR as normal (the existing A0 arm)
K1every session process marked mergeable (prctl(PR_SET_MEMORY_MERGE) in the session's PID 1, inherited); ASLR on
K2K1 plus personality(ADDR_NO_RANDOMIZE) for every process exec'd in the session

Host KSM knobs, set for all arms and recorded in the ledger before writing, restored on close: run=1, pages_to_scan=20000, sleep_millisecs=2, use_zero_pages=1 (prior values 0 / 100 / 20 / 0). Aggressive on purpose so convergence waits are short; the CPU cost is measured, not hidden. Only processes that opt in are scanned, so OFF is not merged.

Pre-registered bars (design values, commit 8062ff0, 2026-10-24 06:07 UTC): M-K1 K2 slope at most 0.80 x OFF slope and the interval of (OFF minus K2) excludes 0 (K1 reported against the same rule); M-K2 merging-thread CPU at most 0.25 vCPU averaged over the trial; M-K3 in K2 the guest contract and real-server checks pass, one public task scores 0.0 then 1.0, sibling hygiene holds, ASLR is really off; M-K4 K2 create p95 at most 1.10 x OFF; M-K5 side channel reported, no bar.

What ran

envd_linux.l1proto.ksm_bench ran the three arms interleaved, 3 trials each, measuring host memory at 1, 4, 8, 12, 16 and 20 sessions after the merge counters settled (less than 1% change over 5 s, at most 90 s), plus 60 session creations per arm; a second run added 2 vCPU / 4 GiB cgroups per session (--limits, 2 trials). envd_linux.l1proto.ksm_semantics ran the K2 audit including the public task e0df059f through the real DesktopEnv. envd_linux.l1proto.ksm_sidechannel placed one probe in each of two sessions, each mapping two private anonymous regions of 8192 pages (one region with content both probes know, one random), waited 40 s for merging, timed the first write to every page, fitted a threshold on even-indexed pages and scored odd-indexed pages. Results committed in 1218b2c (06:45 UTC); the "no K arm is shippable" wording in d9de4ad (07:02 UTC).

Results

Mechanism K: kernel same-page merging across Drums L0 sessions, K1 (ASLR on) and K2 (ASLR off), with the cross-session timing side channel failed2026-10-24 · dev-sandbox

MetricValueUnitnNote
host memory per added session, OFF229.73 (227.57 to 232.33)MiB3
K1 (merging, ASLR on): host memory per added session212.7 (210.59 to 214.24)MiB30.926 x OFF; OFF minus K1 95% interval [14.23, 19.84] MiB; saving 7.4%; bar M-K1 (at most 0.80 x OFF, design value): FAIL
K1 (merging, ASLR on): ksmd CPU fraction0.895vCPU3bar M-K2 at most 0.25 vCPU (design value): FAIL
K1 (merging, ASLR on): create latency2.01 (p95 2.68)s60
K2 (merging, ASLR off): host memory per added session135.36 (134.67 to 136.41)MiB30.589 x OFF; OFF minus K2 95% interval [92.21, 96.87] MiB; saving 41.1%; bar M-K1: PASS, but only with ASLR off in every session process (security regression, not shippable)
K2 (merging, ASLR off): ksmd CPU fraction0.706vCPU3bar M-K2 at most 0.25 vCPU (design value): FAIL
K2 (merging, ASLR off): create latency1.92 (p95 2.28)s60bar M-K4 (K2 p95 at most 1.10 x OFF p95): PASS; the author does not claim the faster K2 creation as a benefit
OFF: create latency2.41 (p95 3.2)s60
K2 semantics (M-K3): guest-contract and real-server failures, namespaces distinct, ASLR really off, task e0df059f 0.0 then 1.01 / 1checksksm_semantics.json PASS true; stubbed_modules [librosa] recorded for this run; Xvfb first mapping identical in both sessions (555555554000)
side channel probe 1: median first-write latency, merged vs unique page345 to 3,854ns819211.17x; held-out balanced accuracy 0.99951; capacity 0.994 bit/page; about 203.3 bit/s over a 40.0 s round
side channel probe 2: median first-write latency, merged vs unique page342 to 2,973ns81928.69x; held-out balanced accuracy 0.99890; capacity 0.988 bit/page; about 202.1 bit/s
re-run with 2 vCPU / 4 GiB session cgroups: OFF / K1 / K2 memory per added session136.57 to 229.68MiB2OFF 229.68, K1 214.68, K2 136.57; ksmd 0.898 / 0.709 vCPU; a readiness check, not a separate result

Host: 4 vCPU, 16 GiB, cgroup v1, no KVM, Ubuntu 24.04, kernel 6.18 (sandbox). one development sandbox; hostname and provider not recorded; not a VM or cloud host. Workload: Drums L0 sessions (namespaces + overlayfs + Xvfb + openbox) each with the real OSWorld guest server and its own Playwright Chromium 141; OFF = no merging; K1 = every session process marked mergeable (prctl PR_SET_MEMORY_MERGE), ASLR on; K2 = K1 plus personality(ADDR_NO_RANDOMIZE) for every process exec'd in the session. Method: Host KSM knobs set for all arms: run=1, pages_to_scan=20000, sleep_millisecs=2, use_zero_pages=1 (prior 0/100/20/0, restored on close). Memory: slope of host used memory against sessions at 1, 4, 8, 12, 16, 20 after the merge counters settle, 3 trials per arm interleaved (2 trials in the re-run with 2 vCPU / 4 GiB session cgroups). M-K2: ksmd CPU time over trial wall time. M-K4: create latency from 60 creations per arm. M-K5: two cooperating probes in two sessions, 8192 shared-content and 8192 unique-content private pages each, first-write latency classified with a threshold fitted on even pages and scored on odd pages. Thresholds fixed in 8062ff0; results in 1218b2c.. Source: branch claude/linux-comparison-prep: docs/data/l1-ksm/ksm_bench.json (memory_summary, create_summary, knobs_set, knobs_prior); branch claude/linux-comparison-prep: docs/data/l1-ksm/ksm_bench.log; branch claude/linux-comparison-prep: docs/data/l1-ksm/ksm_bench_limits.json (memory_summary); branch claude/linux-comparison-prep: docs/data/l1-ksm/ksm_semantics.json; branch claude/linux-comparison-prep: docs/data/l1-ksm/ksm_sidechannel.json (probes); branch claude/linux-comparison-prep: docs/l1-shared-runtime-design.md sections 12 and 13.

  • No K arm is shippable (author's verdict, commit d9de4ad): K1 fails memory and CPU; K2 passes memory only with ASLR off for every process in the session, which is a security regression, and fails CPU.
  • The timing side channel is an upper bound from two cooperating probes with known page content: it confirms whether a guessable 4 KiB page exists in another session; it does not read memory and is not an attack on real task data.
  • The M-K3 isolation audit ran on K2 only and does not cover the timing channel; it was measured separately.
  • Scan knobs were set aggressively and not re-tuned; a slower scan's saving was not measured.
  • Drums here is the L0 prototype plus a kernel feature; no shared-runtime (L1) result exists; incumbents' VMs can use KSM too, so nothing here compares against an incumbent.
  • One host, one kernel, 3 trials; intervals are over trials.
MeasurementArmMeasuredBarVerdict
M-K1 memory per added sessionOFF229.73 MiB (227.57 / 232.33 / 229.30 per trial)
K1212.70 MiB (0.926 x OFF); OFF minus K1 [14.23, 19.84] MiBat most 0.80 x OFFFAIL (7.4%, real but small)
K2135.36 MiB (0.589 x OFF); OFF minus K2 [92.21, 96.87] MiBsamePASS, with ASLR off
M-K2 ksmd CPUK1 / K20.895 / 0.706 vCPU over trial wall time (per trial ksmd_cpu_s 112.6 s over 125.9 s wall for K1 trial 0; 71.2 s over 100.7 s for K2 trial 0)at most 0.25 vCPUFAIL for both
M-K3 semantics (K2 only)K2guest_contract_failures: [[],[]], real_server_failures: [[],[]]; namespaces distinct; one Xvfb per session; personality 00040000 in both; Xvfb first mapping 555555554000 in both sessions (aslr_off_same_base_in_both_sessions: true); task e0df059f 0.0 then 1.0 with a real accessibility tree; stubbed_modules: ["librosa"]all holdPASS
M-K4 create latencyOFF / K1 / K2p95 3.205 / 2.683 / 2.279 s (n = 60 each)K2 p95 at most 1.10 x OFFPASS; the author does not claim K2's faster creation as a benefit (host state was not isolated as a cause)
M-K5 side channeltwo probessee belowreporteda strong channel exists

Under the incumbent resource shape (readiness check, 2 trials, ksm_bench_limits.json): OFF 229.68, K1 214.68, K2 136.57 MiB per added session; OFF minus K2 [91.34, 94.87]; ksmd 0.898 / 0.709 vCPU. The 2 vCPU / 4 GiB limits changed nothing that matters: a session uses about 230 MiB and the merging thread is not inside the session cgroup.

The timing channel (measured, ksm_sidechannel.json)

probe 1probe 2
pages merged before timing81928192
median first-write latency, merged vs unique page3854 ns vs 345 ns (11.17x)2973 ns vs 342 ns (8.69x)
held-out true-positive / true-negative rate1.000 / 0.9990.999 / 0.999
held-out balanced accuracy0.999510.99890
binary-channel capacity per page0.994 bit0.988 bit
rate over a 40.0 s roundabout 203.3 bit/sabout 202.1 bit/s

Reading it: a sibling that can guess a page's exact content (a known file's page, a known library page, a known secret with a guessable surrounding structure) can confirm whether another session holds it, at about 200 yes/no answers per second with about 99.9% accuracy, in this setup. That is an upper bound for a cooperating probe with known content. It does not read memory and does not find content the prober cannot guess; whether it works against real task secrets was not tested. The known mitigation (do not merge sensitive regions, or merge only within one tenant) removes the sharing K sells.

Failures and surprises

Limitations

Reproduce

python -m envd_linux.l1proto.ksm_bench --out ksm_bench.json --trials 3 --max-n 20 [--limits]
python -m envd_linux.l1proto.ksm_semantics --out ksm_semantics.json --osw-python <venv python> --osw-src <OSWorld checkout>
python -m envd_linux.l1proto.ksm_sidechannel --out ksm_sidechannel.json

Needs root and a writable /sys/kernel/mm/ksm; the host knobs are restored afterwards. Check memory_summary.K2_ksmd_vcpu_fraction_mean against 0.25 and probes[].heldout_balanced_accuracy.

Sources