This is the repository for Crucible, a library that transparently retrofits Meltdown-type transient execution vulnerabilities on any x86_64 Linux machine. Crucible works on completely unmodified code, including existing PoCs. For a detailed description of Crucible's working principles, see our paper Crucible: Retrofitting Commodity CPUs with Vulnerabilities via Transparent Software Emulation (PDF).
For the IEEE S&P 2026 Artifact, which also contains the benchmarks and experiments of the paper, see https://doi.org/10.5281/zenodo.19498819.
- Accurate simulation of the Meltdown vulnerability. Crucible comes with a kernel module that gives it access to your system's kernel memory, creating a realistic leakage profile. It also supports the Meltdown 3a variant, which leaks privileged system registers.
- If given a victim program to attack, Crucible can also simulate the effects of various MDS vulnerabilities, including RIDL, ZombieLoad, and Downfall. Crucible achieves this by using Intel PIN to track the victim's memory accesses, feeding them into a simulation model of, e.g., the LBF, or the SIMD buffer. This model can be easily adjusted and replaced.
- Transparent simulation of fault suppression with Intel TSX, even on CPUs that do not support it.
- Crucible can be injected into any dynamically linked x86_64 ELF binary. The attacker code is completely oblivious to Crucible and requires no modifications to make Crucible work.
- If given a model of your CPU's PMCs, Crucible can feed it information about the simulated transient instruction stream.
- CPU: Most x86_64 processors from the last ~8 years, Intel or AMD, should work. Newer CPUs with larger caches tend to produce cleaner leakage. However, depending on which CPU you use specifically, restrictions may apply:
- TSX simulation only works on CPUs that do not already support Intel TSX themselves.
- PMC simulation is currently only implemented for Intel CPUs.
- OS: We recommend using Ubuntu 24.04. or Debian 13. Please run Crucible on native hardware, i.e., not in a VM.
Note: We recommend disabling hardware prefetchers before running the experiments. We provide a script that disables the prefetchers on most Intel and AMD CPUs (run sudo ./disable_prefetchers.sh).
Warning: Crucible’s modkmap kernel module allows unprivileged user-mode programs to read and edit arbitrary physical memory. This breaches various security boundaries, and unchecked access can lead to system instability and data loss.
sudo apt-get install cmake make ninja-build gcc g++ gperf pkg-config autoconf automake libtool libcapstone-dev msr-tools linux-headers-$(uname -r) python3 python3-pip python3-numpy python3-matplotlib python3-psutilCrucible requires Intel PIN for buffer simulation.
- Download PIN v4.1 from https://www.intel.com/content/www/us/en/developer/articles/tool/pin-a-binary-instrumentation-tool-downloads.html
- Extract it and set the
PIN_ROOTenvironment variable:Add toexport PIN_ROOT=/path/to/pin-4.1~/.bashrcto persist across sessions. Your configuration is correct when running$PIN_ROOT/pinin a terminal successfully invokes the PIN binary.
To build Crucible, run the following:
mkdir build && cd build
cmake -S ..
make -j$(nproc)This produces:
build/libcrucible.so- The main preloadable librarybuild/obj-intel64/victim-tracer.so- PIN tool for buffer simulationbuild/libcpu-buffers-basic.so- Default buffer modelbuild/libskylake-arith-div.so- An example PMC modelbuild/modkmap.ko- A kernel module that grants Crucible direct access to kernel memory
Before starting the experiments, insert modkmap by running the following:
sudo insmod modkmap.ko
Additionally, ensure that user-mode programs can access the MSRs by running:
sudo modprobe msr
If you prefer not to install the build dependencies manually, a Docker-based build is available.
It uses a Debian 13 image with all dependencies pre-installed, including Intel PIN.
The kernel module (modkmap.ko) is not built this way, since building kernel modules requires the running host kernel's headers.
To start the build, run
./docker-build.shTo use the result, you still need to build and insert modkmap.ko. To do this, navigate to modkmap/ in a terminal, run make, and insert the module as described above.
Crucible can be configured with a configuration file called crucible.yaml.
When using Crucible, such a file must always be in the working directory.
The demos we provide already include configurations known to work.
See crucible/crucible.yaml for a description of the configuration options.
To run a program with Crucible, either link the library explicitly or use the LD_PRELOAD environment variable to a path to libcrucible.so.
Setting LD_PRELOAD will load Crucible when the program starts up, even if it does not link to Crucible on its own.
In the following examples, the commands always use a relative path to libcrucible.so in its build directory.
However, feel free to move libcrucible.so to the working directory to shorten the commands.
In the following demos, you can always leave the LD_PRELOAD part out to see how a program behaves without Crucible.
Note: The current version of Crucible may print warnings related to MSR and PMC files when starting without root privileges. For programs that do not target the 3a variant, this can be safely ignored. These warnings should disappear when running as root.
MDS and Downfall attacks require a victim program whose memory accesses Crucible can observe.
To enable this, set use_buffer_simulation: 1 and specify a model library (e.g., libcpu-buffers-basic.so) in crucible.yaml, then start the attacker with LD_PRELOAD as usual.
Crucible will load the model and print a message saying it is waiting for the victim to connect.
Once the attacker is waiting, launch the victim under Intel PIN with Crucible's victim-tracer tool:
$PIN_ROOT/pin -t /path/to/build/obj-intel64/victim-tracer.so -- <victim> [args...]The PIN tool intercepts every memory access in the victim process and forwards it to the attacker over a local TCP connection on port 2851.
Crucible feeds these notifications into the buffer model, which the attacker reads during simulated transient execution to reconstruct the victim's in-flight data.
For information on writing a custom buffer model, see src/buffer_simulation_models/README.md.
The demos/ directory contains simple examples demonstrating Crucible’s features.
demos/meltdown contains demos that leak secrets from kernel memory and system registers, and demos/mds contains demos that demonstrate Crucible's buffer simulation for MDS and Downfall.
To build the demos, navigate to any of these directories in a terminal and run make.
To start a demo, run: LD_PRELOAD=../../build/libcrucible.so ./<demo>
If root is needed, use: sudo env LD_PRELOAD=../../build/libcrucible.so ./<demo>
demos/meltdown/meltdownis a demo for the original Meltdown vulnerability, implemented with signal handlers for fault suppression. It interacts with the modkmap kernel module to get the address of a test buffer in the kernel, and leaks its contents. If successful, it should leak the0xbabyte for all offsets.demos/meltdown/meltdown_tsxis a version of the previous demo that uses Intel TSX for fault suppression. This only works if the target CPU does not support Intel TSX itself.demos/meltdown/meltdown_3ais a demo for the 3a variant. It leaks the APIC base address from MSR0x1b. You can verify that the address is correct by runningsudo rdmsr -a 0x1b.
Note: This demo requires root privileges to work correctly, as Crucible needs access to the target MSR.
In contrast to the Meltdown demos, the MDS demos use Crucible’s buffer simulation.
This means that after starting them with Crucible, they wait for an instrumented victim program to connect.
A sample victim is provided in demos/mds/victim.c.
To connect to a waiting demo, start the victim with PIN and Crucible’s buffer simulation tool:
$PIN_ROOT/pin -t ../../build/obj-intel64/victim-tracer.so -- ./victimOnly start the victim when an attacker program is already waiting.
demos/mds/mdsexploits MDS leakage from the LFB. With the provided sample victim, it should leak the 0xba byte periodically.demos/mds/downfallexploits Downfall, i.e., leakage from the SIMD buffer. With the provided sample victim, it should leak the 0xca byte periodically.
The window_length demo in demos/mds/pmc_simulation demonstrates Crucible's PMC simulation capabilities. See the paper for a description of what this experiment does. This requires an Intel CPU, preferably Alder Lake (12th Gen Intel Core) or newer. To start it, run
sudo env LD_PRELOAD=../../crucible/build/libcrucible.so ./window_length out.binTo view the results, run ./plot.py out.bin.
The result should resemble the “nop only” plot in the bottom half of Figure 5 in the paper.
To add a CPUID instruction after 120 instructions, as is the case in the “Added CPUID” plot, start the demo with
sudo env LD_PRELOAD=../../crucible/build/libcrucible.so ./window_length out.bin cpuidFinally, the “No simulation” line can be reproduced by starting the demo without Crucible, i.e., with ./window_length out.bin.
- No leakage / wrong values: Check that
modkmap.kois loaded (/dev/modkmapexists) and the correctcrucible.yamlis in the working directory. Also, note that you are still using a real cache side channel, so make sure that your cache primitives are calibrated correctly. - PIN tool fails to attach: Verify
PIN_ROOTpoints to PIN v4.1, and the victim-tracer was built successfully (build/obj-intel64/victim-tracer.soexists). - Leakage rate is low: This is expected - Crucible forks a new process per fault, which is slower than regular fault suppression.