/src/botan/src/fuzzer/mem_pool.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * (C) 2018 Jack Lloyd |
3 | | * |
4 | | * Botan is released under the Simplified BSD License (see license.txt) |
5 | | */ |
6 | | |
7 | | #include "fuzzers.h" |
8 | | #include <botan/internal/mem_pool.h> |
9 | | #include <botan/internal/bit_ops.h> |
10 | | #include <vector> |
11 | | #include <map> |
12 | | #include <utility> |
13 | | |
14 | | #include <cstdlib> |
15 | | |
16 | | namespace { |
17 | | |
18 | | size_t compute_expected_alignment(size_t plen) |
19 | 139k | { |
20 | 139k | if(Botan::is_power_of_2(plen)) |
21 | 84.9k | { |
22 | 84.9k | return plen; |
23 | 84.9k | } |
24 | 54.8k | else |
25 | 54.8k | { |
26 | 54.8k | return 8; |
27 | 54.8k | } |
28 | 139k | } |
29 | | |
30 | | struct RawPage |
31 | | { |
32 | | public: |
33 | 4 | RawPage(void* p) : m_p(p) {} |
34 | 8 | ~RawPage() { std::free(m_p); } |
35 | | |
36 | | RawPage(const RawPage& other) = default; |
37 | | RawPage& operator=(const RawPage& other) = default; |
38 | | |
39 | | RawPage(RawPage&& other) : m_p(nullptr) |
40 | 4 | { |
41 | 4 | std::swap(m_p, other.m_p); |
42 | 4 | } |
43 | | |
44 | | RawPage& operator=(RawPage&& other) |
45 | 0 | { |
46 | 0 | if(this != &other) |
47 | 0 | { |
48 | 0 | std::swap(m_p, other.m_p); |
49 | 0 | } |
50 | 0 | return (*this); |
51 | 0 | } |
52 | | |
53 | 4.79k | void* ptr() const { return m_p; } |
54 | | private: |
55 | | void* m_p; |
56 | | }; |
57 | | |
58 | | std::vector<RawPage> allocate_raw_pages(size_t count, size_t page_size) |
59 | 1 | { |
60 | 1 | std::vector<RawPage> pages; |
61 | 1 | pages.reserve(count); |
62 | | |
63 | 5 | for(size_t i = 0; i != count; ++i) |
64 | 4 | { |
65 | 4 | void* ptr = nullptr; |
66 | | |
67 | 4 | int rc = ::posix_memalign(&ptr, page_size, page_size); |
68 | 4 | FUZZER_ASSERT_EQUAL(rc, 0); |
69 | | |
70 | 4 | if(ptr) |
71 | 4 | { |
72 | 4 | pages.push_back(RawPage(ptr)); |
73 | 4 | } |
74 | 4 | } |
75 | | |
76 | 1 | return pages; |
77 | 1 | } |
78 | | |
79 | | } |
80 | | |
81 | | void fuzz(const uint8_t in[], size_t in_len) |
82 | 1.19k | { |
83 | 1.19k | const size_t page_count = 4; |
84 | 1.19k | const size_t page_size = 4096; |
85 | | |
86 | | // static to avoid repeated allocations |
87 | 1.19k | static std::vector<RawPage> raw_mem = allocate_raw_pages(page_count, page_size); |
88 | | |
89 | 1.19k | std::vector<void*> mem_pages; |
90 | 1.19k | mem_pages.reserve(raw_mem.size()); |
91 | 5.99k | for(size_t i = 0; i != raw_mem.size(); ++i) |
92 | 4.79k | mem_pages.push_back(raw_mem[i].ptr()); |
93 | | |
94 | 1.19k | Botan::Memory_Pool pool(mem_pages, page_size); |
95 | 1.19k | std::map<uint8_t*, size_t> ptrs; |
96 | | |
97 | 267k | while(in_len > 0) |
98 | 266k | { |
99 | 266k | const uint8_t op = in[0] % 2; |
100 | 266k | size_t idx = (in[0] >> 1); |
101 | 266k | in += 1; |
102 | 266k | in_len -= 1; |
103 | | |
104 | 266k | if(in_len > 0 && idx < 4) |
105 | 6.01k | { |
106 | 6.01k | idx = idx * 256 + in[0]; |
107 | 6.01k | in += 1; |
108 | 6.01k | in_len -= 1; |
109 | 6.01k | } |
110 | | |
111 | 266k | if(op == 0) |
112 | 154k | { |
113 | 154k | const size_t plen = idx + 1; // ensure non-zero |
114 | 154k | uint8_t* p = static_cast<uint8_t*>(pool.allocate(plen)); |
115 | | |
116 | 154k | if(p) |
117 | 139k | { |
118 | 139k | const size_t expected_alignment = compute_expected_alignment(plen); |
119 | 139k | const size_t alignment = reinterpret_cast<uintptr_t>(p) % expected_alignment; |
120 | 139k | if(alignment != 0) |
121 | 0 | { |
122 | 0 | FUZZER_WRITE_AND_CRASH("Pointer allocated non-aligned pointer " << static_cast<void*>(p) << " for len " << plen |
123 | 0 | << " expected " << expected_alignment << " got " << alignment); |
124 | 0 | } |
125 | | |
126 | | //printf("alloc %d -> %p\n", plen, p); |
127 | | |
128 | 6.80M | for(size_t i = 0; i != plen; ++i) |
129 | 6.67M | { |
130 | 6.67M | if(p[i] != 0) |
131 | 0 | { |
132 | 0 | FUZZER_WRITE_AND_CRASH("Pool gave out non-zeroed memory"); |
133 | 0 | } |
134 | 6.67M | } |
135 | | |
136 | | // verify it becomes zeroed later |
137 | 139k | std::memset(p, idx, plen); |
138 | | |
139 | 139k | auto insert = ptrs.insert(std::make_pair(p, plen)); |
140 | 139k | if(insert.second == false) |
141 | 0 | { |
142 | 0 | FUZZER_WRITE_AND_CRASH("Pointer " << static_cast<void*>(p) << " already existed\n"); |
143 | 0 | } |
144 | | |
145 | 139k | auto itr = insert.first; |
146 | | |
147 | | // Verify this pointer doesn't overlap with the one before it |
148 | 139k | if(itr != ptrs.begin()) |
149 | 84.8k | { |
150 | 84.8k | auto before = std::prev(itr); |
151 | 84.8k | auto ptr_before = *before; |
152 | | |
153 | 84.8k | if(ptr_before.first + ptr_before.second > p) |
154 | 0 | { |
155 | 0 | FUZZER_WRITE_AND_CRASH("Previous " << static_cast<void*>(ptr_before.first) << "/" << ptr_before.second << |
156 | 0 | " overlaps with new " << static_cast<void*>(p)); |
157 | 0 | } |
158 | 84.8k | } |
159 | | |
160 | 139k | auto after = std::next(itr); |
161 | | |
162 | 139k | if(after != ptrs.end()) |
163 | 58.0k | { |
164 | 58.0k | if(p + plen > after->first) |
165 | 0 | { |
166 | 0 | FUZZER_WRITE_AND_CRASH("New " << static_cast<void*>(p) << "/" << plen |
167 | 0 | << " overlaps following " << static_cast<void*>(after->first)); |
168 | 0 | } |
169 | 58.0k | } |
170 | 139k | } |
171 | 154k | } |
172 | 112k | else if(op == 1) |
173 | 112k | { |
174 | 112k | if(ptrs.empty()) |
175 | 4.86k | continue; |
176 | | |
177 | 107k | size_t which_ptr = idx % ptrs.size(); |
178 | | |
179 | 107k | auto itr = ptrs.begin(); |
180 | | |
181 | 1.03M | while(which_ptr-- > 0) |
182 | 923k | { |
183 | 923k | ++itr; |
184 | 923k | } |
185 | | |
186 | | //printf("free %p %d\n", itr->first, itr->second); |
187 | 107k | FUZZER_ASSERT_TRUE(pool.deallocate(itr->first, itr->second)); |
188 | 107k | ptrs.erase(itr); |
189 | 107k | } |
190 | 266k | } |
191 | 1.19k | } |