/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 | 136k | { |
20 | 136k | if(Botan::is_power_of_2(plen)) |
21 | 84.0k | { |
22 | 84.0k | return plen; |
23 | 84.0k | } |
24 | 52.5k | else |
25 | 52.5k | { |
26 | 52.5k | return 8; |
27 | 52.5k | } |
28 | 136k | } |
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.71k | 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.17k | { |
83 | 1.17k | const size_t page_count = 4; |
84 | 1.17k | const size_t page_size = 4096; |
85 | | |
86 | | // static to avoid repeated allocations |
87 | 1.17k | static std::vector<RawPage> raw_mem = allocate_raw_pages(page_count, page_size); |
88 | | |
89 | 1.17k | std::vector<void*> mem_pages; |
90 | 1.17k | mem_pages.reserve(raw_mem.size()); |
91 | 5.89k | for(size_t i = 0; i != raw_mem.size(); ++i) |
92 | 4.71k | mem_pages.push_back(raw_mem[i].ptr()); |
93 | | |
94 | 1.17k | Botan::Memory_Pool pool(mem_pages, page_size); |
95 | 1.17k | std::map<uint8_t*, size_t> ptrs; |
96 | | |
97 | 262k | while(in_len > 0) |
98 | 261k | { |
99 | 261k | const uint8_t op = in[0] % 2; |
100 | 261k | size_t idx = (in[0] >> 1); |
101 | 261k | in += 1; |
102 | 261k | in_len -= 1; |
103 | | |
104 | 261k | if(in_len > 0 && idx < 4) |
105 | 8.23k | { |
106 | 8.23k | idx = idx * 256 + in[0]; |
107 | 8.23k | in += 1; |
108 | 8.23k | in_len -= 1; |
109 | 8.23k | } |
110 | | |
111 | 261k | if(op == 0) |
112 | 150k | { |
113 | 150k | const size_t plen = idx + 1; // ensure non-zero |
114 | 150k | uint8_t* p = static_cast<uint8_t*>(pool.allocate(plen)); |
115 | | |
116 | 150k | if(p) |
117 | 136k | { |
118 | 136k | const size_t expected_alignment = compute_expected_alignment(plen); |
119 | 136k | const size_t alignment = reinterpret_cast<uintptr_t>(p) % expected_alignment; |
120 | 136k | 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.82M | for(size_t i = 0; i != plen; ++i) |
129 | 6.68M | { |
130 | 6.68M | if(p[i] != 0) |
131 | 0 | { |
132 | 0 | FUZZER_WRITE_AND_CRASH("Pool gave out non-zeroed memory"); |
133 | 0 | } |
134 | 6.68M | } |
135 | | |
136 | | // verify it becomes zeroed later |
137 | 136k | std::memset(p, static_cast<int>(idx), plen); |
138 | | |
139 | 136k | auto insert = ptrs.insert(std::make_pair(p, plen)); |
140 | 136k | if(insert.second == false) |
141 | 0 | { |
142 | 0 | FUZZER_WRITE_AND_CRASH("Pointer " << static_cast<void*>(p) << " already existed\n"); |
143 | 0 | } |
144 | | |
145 | 136k | auto itr = insert.first; |
146 | | |
147 | | // Verify this pointer doesn't overlap with the one before it |
148 | 136k | if(itr != ptrs.begin()) |
149 | 81.7k | { |
150 | 81.7k | auto before = std::prev(itr); |
151 | 81.7k | auto ptr_before = *before; |
152 | | |
153 | 81.7k | 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 | 81.7k | } |
159 | | |
160 | 136k | auto after = std::next(itr); |
161 | | |
162 | 136k | 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 | 136k | } |
171 | 150k | } |
172 | 110k | else if(op == 1) |
173 | 110k | { |
174 | 110k | if(ptrs.empty()) |
175 | 4.02k | continue; |
176 | | |
177 | 106k | size_t which_ptr = idx % ptrs.size(); |
178 | | |
179 | 106k | auto itr = ptrs.begin(); |
180 | | |
181 | 1.06M | while(which_ptr-- > 0) |
182 | 961k | { |
183 | 961k | ++itr; |
184 | 961k | } |
185 | | |
186 | | //printf("free %p %d\n", itr->first, itr->second); |
187 | 106k | FUZZER_ASSERT_TRUE(pool.deallocate(itr->first, itr->second)); |
188 | 106k | ptrs.erase(itr); |
189 | 106k | } |
190 | 261k | } |
191 | 1.17k | } |