MicroSnapshots
In contrast to full snapshots as seen in the web interface, MicroSnapshots are designed for a fuzzing use-case - running very short tests starting from a specific point of execution then rolling back to that point and running another test.
This feature is available exclusively to on-site, Charm SDK, and desktop appliance customers with a Premium license.
This feature is available exclusively on iOS firmware.
Example
Suppose an IOKit driver is the target. The setup and main fuzzing loop might look something like this pseudocode:
// Setup
unsigned long long timeout = 0; // Timeout in usec, 0 for no timeout
io_connect_t conn;
IOServiceOpen(IOServiceGetMatchingService(
kIOMasterPortDefault,
IOServiceMatching("SomeVulnerableDriver")),
mach_task_self(),
0,
&conn);
// Main fuzzing loop
while (1) {
int res = hyp_fork(timeout);
if (!res) {
// Inside the fork, do the fuzz test
size_t testcase_len = 0;
char *testcase_buf = fuzzer_get_testcase(&testcase_len); // Get the next test case from some coordinator
IOConnectCallStructMethod(conn, selector, testcase_buf, testcase_len, NULL, NULL);
hyp_exit(1); // This return code goes to the "parent", needs to be >=1 to not collide with other status codes
} else if (res > 0) {
// Test case completed, res is the return code from the run
collect_and_report_coverage(); // Test case finished, gather the coverage and send up to the coordinator
} else if (res == -3) {
report_panic(); // Detected a panic! Let the coordinator know
} else {
// Handle other possible return values here (see possibilities below)
}
}
Setup
Note: This is subject to change when exposed as configuration in the web interface/via the API.
- Create a VM, let it fully boot, then power-off. Make note of the UUID from the URI of the device.
- SSH into the compute node the VM resides on.
- Edit
/etc/corellium/charmd_boot_patch
(create it if it doesn't exist) to append a line:name:<UUID> patch minisave-buf:1
, replacing<UUID>
with the UUID of the VM (without the brackets)minisave-buf:1
allocates a 1 GB buffer for saving state. Supported values are 1-16, in gigabytes.
- Start the VM.
The setup is complete. Either use the in-VM API (programmatic) or manually save/restore via charmd
(non-programmatic) listed below.
In-VM API
int hyp_fork(unsigned long long max_usec);
Begins recording changes, essentially starting the testcase. If max_usec
is non-zero, the execution will be terminated when the timeout is reached. Set to zero for no timeout.
Return values:
MFS_ACTIVE
(0
): in minisavestatus > 0
: returned from minisave withhyp_exit(status);
MFS_FAIL
(-1
): failed to minisaveMFS_STOP_OVERRUN
(-2
): save overran reserved RAM blockMFS_STOP_PANIC
(-3
): save terminated by panicMFS_STOP_EXTERNAL
(-4
): save terminated by charmd commandMFS_STOP_TIMER
(-5
): save terminated by running out of time (ifmax_usec
is nonzero)
void hyp_exit(unsigned status);
Rolls back to the state from when hyp_fork
was called. If function returns, rolling back the state failed.
The status code is returned to the caller of hyp_fork
(conceptually similar to the parent process in regular UNIX-y fork
).
int hyp_get_fork_state(void)
Return values:
0
: Not in minisave1
: In minisave
int hyp_commit(void);
Commits current minisave state (i.e. abandons rollback).
Return values:
0
: successMCS_FAIL
(-1
): commit failed (most likely disk save issue)MCS_NOT_ACTIVE
(-2
): not in minisave
int hyp_persist(void *data, size_t size);
Marks memory as persistent (i.e. not affected by rollback); must be 4k-aligned and mlock
ed.
Return values:
0
: successMPS_BAD_RANGE
(-1
): invalid memory rangeMPS_NOT_RESIDENT
(-2
): memory not resident (mlock it or allocate from resident pool)MPS_FAILED_MARK
(-3
): failed to mark persistent (hypervisor out of memory, probably)
For example:
posix_memalign((void **)&buf, 16384, 16384);
mlock(buf, 16384);
memset(buf, 0, 16384);
hyp_persist(buf, 16384);
int res = hyp_fork(0);
if (!res) {
strcpy(buf, "The buffer has been modified!");
hyp_exit(1);
}
printf("buf: %s\n", buf);
// Expected output: "buf: The buffer has been modified!"
void hyp_clear_persist(void)
Removes all memory marked with hyp_persist
.
int hyp_get_panic_size(void)
Returns the size of the captured panic, or -1
on failure.
int hyp_get_panic_content(void *buffer, uint64_t max_size)
Retrieve up to max_size
bytes of kernel panic data into buffer
, which must be mlock
ed.
Returns -1
on failure, or size of completed kernel panic data (regardless of whether the data was truncated to max_size
).
The panic data is in a binary format consisting of an array of these structures:
struct kernel_panic {
uint64_t timestamp;
uint64_t panic_size;
char panic_data[]; // Where the size matches panic_size
};
Note that there may be multiple panics (because sometimes iOS panics multiple times before coming to a complete stop).
Non-Programmatic Usage
For manual, non-programmatic operation, connect to
charmd
via SSH on the compute node:socat UNIX-CONNECT:/var/run/charmd -
Obtain the
list
of running VMs and identify the target VM by UUID, making note of theVMID
:> list
< 0 request:list vmid:0 name:6205c765-41f9-41c6-83f8-c53872cde90c vmtag: state:runTo save the current VM state, issue:
> minisave vmid:0 start:
< 0 request:minisave request-vmid:0 request-name:6205c765-41f9-41c6-83f8-c53872cde90cTo restore, issue:
> minisave vmid:0 stop:
< 0 request:minisave request-vmid:0 request-name:6205c765-41f9-41c6-83f8-c53872cde90c
Note: The <
and >
characters are added for clarity and are not part of the command/output. >
indicates a command entered by the user, and <
indicates a response from charmd
.
Limitations/Caveats
It is expected behavior that some Corellium or OS functionality will break when using MicroSnapshots. For example:
- Network connections will likely be terminated.
- Anything using USB/USBFlux, including SSH, will stop functioning.
- The Files, Apps, Network, CoreTrace, and Frida tabs will be unresponsive, but may work itself out after some time.
Since MicroSnapshots are intended for fuzzing purposes, using the VM interactively is not recommended. Rebooting the VM should resolve this issues until the next time MicroSnapshots are used.