-
Notifications
You must be signed in to change notification settings - Fork 53
/
native.cpp
144 lines (119 loc) · 3.82 KB
/
native.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_string.hpp>
#include <libriscv/machine.hpp>
#include <libriscv/native_heap.hpp>
extern std::vector<uint8_t> build_and_load(const std::string& code,
const std::string& args = "-O2 -static", bool cpp = false);
static const uint64_t MAX_INSTRUCTIONS = 10'000'000ul;
static const std::string cwd {SRCDIR};
using namespace riscv;
static const int HEAP_SYSCALLS_BASE = 470;
static const int MEMORY_SYSCALLS_BASE = 475;
static const int THREADS_SYSCALL_BASE = 490;
template <int W>
static void setup_native_system_calls(riscv::Machine<W>& machine)
{
// Syscall-backed heap
constexpr size_t heap_size = 65536;
auto heap = machine.memory.mmap_allocate(heap_size);
machine.setup_native_heap(HEAP_SYSCALLS_BASE, heap, heap_size);
machine.setup_native_memory(MEMORY_SYSCALLS_BASE);
machine.setup_native_threads(THREADS_SYSCALL_BASE);
}
TEST_CASE("Activate native helper syscalls", "[Native]")
{
const auto binary = build_and_load(R"M(
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char** argv)
{
const char *hello = (const char*)atol(argv[1]);
printf("%s\n", hello);
return 666;
})M");
riscv::Machine<RISCV64> machine { binary };
machine.setup_linux_syscalls();
setup_native_system_calls(machine);
// Allocate string on heap
static const std::string hello = "Hello World!";
auto addr = machine.arena().malloc(64);
machine.copy_to_guest(addr, hello.data(), hello.size()+1);
// Pass string address to guest as main argument
machine.setup_linux(
{"native", std::to_string(addr)},
{"LC_TYPE=C", "LC_ALL=C", "USER=root"});
// Catch output from machine
struct State {
bool output_is_hello_world = false;
} state;
machine.set_userdata(&state);
machine.set_printer([] (const auto& m, const char* data, size_t size) {
auto* state = m.template get_userdata<State> ();
std::string text{data, data + size};
state->output_is_hello_world = (text == "Hello World!\n");
});
// Run simulation
machine.simulate(MAX_INSTRUCTIONS);
REQUIRE(machine.return_value() == 666);
REQUIRE(state.output_is_hello_world);
}
TEST_CASE("Use native helper syscalls", "[Native]")
{
const auto binary = build_and_load(R"M(
#include <include/native_libc.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
char* hello = malloc(13);
memcpy(hello, "Hello World!", 13);
printf("%s\n", hello);
return 666;
})M", "-O2 -static -I" + cwd);
riscv::Machine<RISCV64> machine { binary };
setup_native_system_calls(machine);
machine.setup_linux_syscalls();
machine.setup_linux(
{"native"},
{"LC_TYPE=C", "LC_ALL=C", "USER=root"});
// Catch output from machine
struct State {
bool output_is_hello_world = false;
} state;
machine.set_userdata(&state);
machine.set_printer([] (const auto& m, const char* data, size_t size) {
auto* state = m.template get_userdata<State> ();
std::string text{data, data + size};
state->output_is_hello_world = (text == "Hello World!\n");
});
// Run simulation
machine.simulate(MAX_INSTRUCTIONS);
REQUIRE(machine.return_value() == 666);
REQUIRE(state.output_is_hello_world);
}
TEST_CASE("Free unknown causes exception", "[Native]")
{
const auto binary = build_and_load(R"M(
#include <include/native_libc.h>
int main()
{
free((void *)0x1234);
return 666;
})M", "-O2 -static -I" + cwd);
riscv::Machine<RISCV64> machine { binary };
setup_native_system_calls(machine);
machine.setup_linux_syscalls();
machine.setup_linux(
{"native"},
{"LC_TYPE=C", "LC_ALL=C", "USER=root"});
bool error = false;
try {
machine.simulate(MAX_INSTRUCTIONS);
} catch (const std::exception& e) {
// Libtcc does not forward the real exception (instead throws a generic SYSTEM_CALL_FAILED)
if constexpr (!libtcc_enabled)
REQUIRE(std::string(e.what()) == "Possible double-free for freed pointer");
error = true;
}
REQUIRE(error);
}