PACMAN is Open-Source
We are delighted to share all of our code with the community, including a suite of in-house tools we built for performing microarchitectural security research on Apple Silicon devices, as well as two full reference implementations of the PACMAN attack.
PacmanKit is a battle-tested suite of utilities designed to make cross-privilege microarchitectural security research on macOS simple and easy. PacmanKit is loaded as an IOKit kernel extension and can be used from both Rust and C (or from your favorite systems language).
|PacmanKit Feature Overview|
||Reveal the kernelcache base address|
||Read arbitrary kernel memory|
||Write arbitrary kernel memory|
||Read/ execute memory and report the latency in cycles|
||Spectre-vulnerable method to read/ execute an address|
||Translate a virtual address to physical address|
||Leak the address of an
||Free memory allocated by
||Read and leak the contents of MSRs from kernel mode|
||Reveal the addresses of some helper methods in
||Leak the current BSD process structure|
||Compute a PAC from the kernel for a pointer|
When performing high precision microarchitectural reverse engineering work (whether it be for security research, performance engineering, or something else), you need precise timing. On legacy
x86_64 machines, this could be accomplished with the
rdtsc instruction. However, on M1, no such high precision timer is available to users.
PacmanPatcher solves this problem by universally enabling all high performance timers in userspace. It works by applying a set of binary patches to a macOS kernel binary. You can then install the patched kernel to your Mac and have full access to all timers. Detailed instructions for its use can be found in the PacmanPatcher repository.
PacmanFinder is a Ghidra script for locating PACMAN Gadgets.
Recall a PACMAN Gadget is a code snippet of the form:
if (condition): check_pac(ptr) load(checked_ptr)
PacmanFinder uses static analysis to locate code snippets that follow this pattern and reports them to you. Human-readable reports from
PacmanFinder look like the following:
I found 2 gadgets in _getattrlistbulk at [('d', fffffe00076080c0), ('d', fffffe00076080c4)] I found 1 gadgets in _proc_rlimit_control at [('d', fffffe0007951ac4)] I found 1 gadgets in _memorystatus_available_memory at [('d', fffffe000796dad8)] I found 1 gadgets in _getdirentriesattr at [('d', fffffe000764925c)] I found 2 gadgets in _fs_snapshot at [('d', fffffe000764e194), ('d', fffffe000764e198)] I found 3 gadgets in _lseek at [('d', fffffe0007640fc8), ('d', fffffe0007641134), ('d', fffffe0007641138)] I found 1 gadgets in _quotactl at [('d', fffffe000763a8c8)] I found 1 gadgets in _sendfile at [('d', fffffe00079ce8a4)] I found 1 gadgets in _process_policy at [('d', fffffe00079f25cc)]
Gadgets are broken down by function and are reported as a list of tuples. The first part of the tuple is either an
i for instruction, or a
d for data. The second part is the address within the binary the gadget lives at.
memorystatus_available_memory has one gadget
('d', fffffe000796dad8), which is a data gadget located at
For those really tough reverse engineering tasks (understanding privileged instruction behavior, boot process, etc.), PacmanOS is the tool you need. PacmanOS is a Rust-based bare metal environment that runs with hypervisor (EL2) privileges on M1. PacmanOS handles the heavy lifting of communicating with iBoot, linking the kernel mach-o, and basic drivers (eg. framebuffer support) so you can focus on writing zero noise experiments.
PacmanOS has two goals:
- Provide a zero-compromises, zero-noise microarchitectural reverse engineering environment in Rust.
- Run with hypervisor privileges (EL2) so that any and all MSRs can be set, reset, probed, etc. as desired.
Non-goals are things such as a command line interface, filesystem, USB drivers, context switching, etc. as these all increase noise and violate goal #1. For a full-featured alternative OS to run on your Mac, consider Asahi Linux or FreeBSD.
PACMAN Proof-of-Concept Implementations
PACMAN I is the first generation attack as seen in our ISCA 2022 paper. PACMAN I is written in C.
PACMAN II is a complete reimplementation of the PACMAN attack in Rust as seen at our DEF CON 30 talk. It is faster and relies on fewer assumptions than PACMAN I. You’ll need PacmanKit installed for this attack to run (as the victim IOUserClient is located in PacmanKit). The attack also uses PacmanKit for kernel read/ write (which we assume the attacker can do via a bug they have found).
All our code is released under the MIT License:
MIT License Copyright (c) 2022 Joseph Ravichandran, Weon Taek Na, Jay Lang, Mengjia Yan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.