Skip to content

Forks from never ran machines crash #63

@chc4

Description

@chc4

tinykvm has a forkserver feature, where you can prepare a VM for copy-on-write, and then initialize a forked machine off of that parent.

This works fine in cases where the parent machine has ran and the forks do vmcalls to other functions (such as the Fork and run main() testcase), but trying to use it for a forkserver which repeatedly runs the main entry point instead crashes with a kernel fault.

For example:

TEST_CASE("Fork before main()", "[Fork]")
{
	const auto binary = build_and_load(R"M(
#include <stdio.h>
int main() {
	printf("Hello World!\n");
	return 666;
}
static unsigned value = 12345;
void set_value(int v) {
	value = v;
}
int func1() {
	return value;
}
int func2() {
	return 54321;
}
)M");

	tinykvm::Machine machine { binary, {
		.max_mem = MAX_MEMORY,
		.master_direct_memory_writes = true
	} };

	// We need to create a Linux environment for runtimes to work well
	machine.setup_linux({"fork"}, env);
	auto main_regs = machine.registers();
	machine.prepare_copy_on_write();
	REQUIRE(machine.is_forkable());
	REQUIRE(!machine.is_forked());

	auto fork1 = tinykvm::Machine { machine, {
		.max_mem = MAX_MEMORY, .max_cow_mem = MAX_COWMEM
	} };

	fork1.run(4.0f);
	REQUIRE(fork1.return_value() == 666); // Main() return value
	fork1.reset_to(machine, tinykvm::MachineOptions { });
	fork1.run(4.0f);
	REQUIRE(fork1.return_value() == 666); // Main() return value

}

crashes with

3: *** Page Fault on address 0x0
3: Error code: 0x4 (memory read)
3: * Page not present
3: * CPL=3 Page fault
3: CR0: 0x80040033  CR3: 0x7000000000
3: CR2: 0x0  CR4: 0x350E20
3: RAX: 0x4  RBX: 0x1  RCX: 0xA
3: RDX: 0x4A5F50  RSI: 0x0  RDI: 0x0
3: RIP: 0x21E6  RBP: 0x641AE0  RSP: 0x3FC0
3: SS: 0x0  CS: 0x8  DS: 0x23  FS: 0x0  GS: 0x0
3: FS BASE: 0x0  GS BASE: 0x5050
3: Failing RIP: 0x404224
3: Fail RFLAGS: 0x13046
3: Failing CS:  0x2B
3: Failing RSP: 0x641A80
3: Failing SS:  0x23
3: RIP  0x404224   __libc_setup_tls + 0x64

I suspect what's going on here is something to do with the usercode.asm entrypoint stub? But honestly I have been trying to figure out what's the issue for a while and it's kind of impossible.

I'd like to use tinykvm for a fuzzer, which needs to be able to run a guest program from its ELF entrypoint repeatedly. I can probably work around this by always using a shim fuzzing harness which has a "setup" function which loads the program under test and then a vmcall-able "run_one" instead, but this seems like something that probably should be working.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions