Itoyori  v0.0.1
context.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include "ityr/common/util.hpp"
4 
5 #if defined(__x86_64__)
6 
8 namespace ityr::ito {
9 using context_frame = context_frame_x86_64;
10 using context = context_x86_64;
11 }
12 
13 #elif defined(__aarch64__)
14 
16 namespace ityr::ito {
17 using context_frame = context_frame_aarch64;
18 using context = context_aarch64;
19 }
20 
21 #else
22 #error "This architecture is not supported"
23 #endif
24 
25 namespace ityr::ito {
26 
27 ITYR_TEST_CASE("[ityr::ito::context] save_context_with_call()") {
28  int x = 3;
29  int y = 7;
30  void* random_addr = (void*)0x123456;
31 
32  auto fn = [](context_frame* cf, void* xp, void* yp) {
33  ITYR_CHECK(*((int*)xp) == 3);
34  ITYR_CHECK(*((int*)yp) == 7);
35  ITYR_CHECK(cf->parent_frame == (void*)0x123456);
36  };
37 
38  context::save_context_with_call((context_frame*)random_addr, fn, &x, &y);
39 }
40 
41 ITYR_TEST_CASE("[ityr::ito::context] save_context_with_call() and resume()") {
42  bool ok = false;
43  // save context frame 1 (cf1)
44  context::save_context_with_call(nullptr, [](context_frame* cf1, void* ok_, void*) {
45 
46  // save context frame 2 (cf2)
47  context::save_context_with_call(cf1, [](context_frame* cf2, void* cf1_, void*) {
48  context_frame* cf1 = (context_frame*)cf1_;
49  ITYR_CHECK(cf2->parent_frame == cf1);
50 
51  // save context frame 3 (cf3)
52  context::save_context_with_call(cf2, [](context_frame* cf3, void* cf1_, void* cf2_) {
53  context_frame* cf1 = (context_frame*)cf1_;
54  context_frame* cf2 = (context_frame*)cf2_;
55  ITYR_CHECK(cf2->parent_frame == cf1);
56  ITYR_CHECK(cf3->parent_frame == cf2);
57 
58  // resume cf2 by discarding cf3 and the current execution context
59  context::resume(cf2);
60 
61  // should not reach here
62  ITYR_CHECK(false);
63  }, (void*)cf1, (void*)cf2);
64 
65  // should not reach here
66  ITYR_CHECK(false);
67  }, (void*)cf1, nullptr);
68 
69  // should reach here (check by setting a flag ok)
70  *((bool*)ok_) = true;
71  }, &ok, nullptr);
72 
73  ITYR_CHECK(ok);
74 }
75 
76 ITYR_TEST_CASE("[ityr::ito::context] call_on_stack()") {
77  int x = 3;
78  int y = 7;
79 
80  size_t stack_size = 128 * 1024;
81  void* stack_buf = std::malloc(stack_size);
82 
83  context::call_on_stack(stack_buf, stack_size,
84  [](void* xp, void* yp, void* stack_buf, void* stack_size_p) {
85  ITYR_CHECK(*((int*)xp) == 3);
86  ITYR_CHECK(*((int*)yp) == 7);
87  size_t stack_size = *((size_t*)stack_size_p);
88 
89  int a = 3;
90 
91  // Check if the local variable address is within the requested stack
92  ITYR_CHECK((uintptr_t)stack_buf <= (uintptr_t)&a);
93  ITYR_CHECK((uintptr_t)&a < (uintptr_t)stack_buf + stack_size);
94  }, &x, &y, stack_buf, &stack_size);
95 
96  std::free(stack_buf);
97 }
98 
99 ITYR_TEST_CASE("[ityr::ito::context] jump_to_stack()") {
100  size_t stack_size = 128 * 1024;
101  void* stack_buf = std::malloc(stack_size);
102 
103  context::save_context_with_call(nullptr, [](context_frame* cf, void* stack_buf, void* stack_size_p) {
104  size_t stack_size = *((size_t*)stack_size_p);
105 
106  // Set a canary to the stack bottom
107  uint8_t canary = 55;
108  *((uint8_t*)stack_buf + stack_size - 1) = canary;
109 
110  // jump to the stack just above the canary location
111  context::jump_to_stack((uint8_t*)stack_buf + stack_size - 2,
112  [](void* cf_, void* stack_buf, void* stack_size_p, void* canary_p) {
113  context_frame* cf = (context_frame*)cf_;
114  size_t stack_size = *((size_t*)stack_size_p);
115  uint8_t canary = *((size_t*)canary_p);
116 
117  int a = 3;
118 
119  // Check if the local variable address is within the requested stack
120  ITYR_CHECK((uintptr_t)stack_buf <= (uintptr_t)&a);
121  ITYR_CHECK((uintptr_t)&a < (uintptr_t)stack_buf + stack_size);
122 
123  // Check canary is not changed
124  ITYR_CHECK(*((uint8_t*)stack_buf + stack_size - 1) == canary);
125 
126  // Check if the local variable address is within the requested stack
127  ITYR_CHECK((uintptr_t)stack_buf <= (uintptr_t)&a);
128  ITYR_CHECK((uintptr_t)&a < (uintptr_t)stack_buf + stack_size);
129 
130  // resume the main context
131  context::resume(cf);
132  }, cf, stack_buf, &stack_size, &canary);
133 
134  // should not reach here
135  ITYR_CHECK(false);
136  }, stack_buf, &stack_size);
137 
138  std::free(stack_buf);
139 }
140 
141 }
#define ITYR_CHECK(cond)
Definition: util.hpp:48
Definition: aarch64.hpp:5
void free(global_ptr< T > ptr, std::size_t count)
Definition: ori.hpp:75
global_ptr< T > malloc(std::size_t count)
Definition: ori.hpp:65