Coverage Report

Created: 2022-11-24 06:56

/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
   }