Coverage Report

Created: 2020-06-30 13:58

/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 <stdlib.h>
15
16
namespace {
17
18
size_t compute_expected_alignment(size_t plen)
19
133k
   {
20
133k
   if(Botan::is_power_of_2(plen))
21
82.6k
      {
22
82.6k
      return plen;
23
82.6k
      }
24
50.9k
   else
25
50.9k
      {
26
50.9k
      return 8;
27
50.9k
      }
28
133k
   }
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.86k
      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
1
63
5
   for(size_t i = 0; i != count; ++i)
64
4
      {
65
4
      void* ptr = nullptr;
66
4
67
4
      int rc = ::posix_memalign(&ptr, page_size, page_size);
68
4
      FUZZER_ASSERT_EQUAL(rc, 0);
69
4
70
4
      if(ptr)
71
4
         {
72
4
         pages.push_back(RawPage(ptr));
73
4
         }
74
4
      }
75
1
76
1
   return pages;
77
1
   }
78
79
}
80
81
void fuzz(const uint8_t in[], size_t in_len)
82
1.21k
   {
83
1.21k
   const size_t page_count = 4;
84
1.21k
   const size_t page_size = 4096;
85
1.21k
86
1.21k
   // static to avoid repeated allocations
87
1.21k
   static std::vector<RawPage> raw_mem = allocate_raw_pages(page_count, page_size);
88
1.21k
89
1.21k
   std::vector<void*> mem_pages;
90
1.21k
   mem_pages.reserve(raw_mem.size());
91
6.07k
   for(size_t i = 0; i != raw_mem.size(); ++i)
92
4.86k
      mem_pages.push_back(raw_mem[i].ptr());
93
1.21k
94
1.21k
   Botan::Memory_Pool pool(mem_pages, page_size);
95
1.21k
   std::map<uint8_t*, size_t> ptrs;
96
1.21k
97
256k
   while(in_len > 0)
98
255k
      {
99
255k
      const uint8_t op = in[0] % 2;
100
255k
      size_t idx = (in[0] >> 1);
101
255k
      in += 1;
102
255k
      in_len -= 1;
103
255k
104
255k
      if(in_len > 0 && idx < 4)
105
10.4k
         {
106
10.4k
         idx = idx * 256 + in[0];
107
10.4k
         in += 1;
108
10.4k
         in_len -= 1;
109
10.4k
         }
110
255k
111
255k
      //printf("%d %d\n", op, idx);
112
255k
113
255k
      if(op == 0)
114
152k
         {
115
152k
         const size_t plen = idx + 1; // ensure non-zero
116
152k
         uint8_t* p = static_cast<uint8_t*>(pool.allocate(plen));
117
152k
118
152k
         if(p)
119
133k
            {
120
133k
            const size_t expected_alignment = compute_expected_alignment(plen);
121
133k
            const size_t alignment = reinterpret_cast<uintptr_t>(p) % expected_alignment;
122
133k
            if(alignment != 0)
123
0
               {
124
0
               FUZZER_WRITE_AND_CRASH("Pointer allocated non-aligned pointer " << static_cast<void*>(p) << " for len " << plen
125
0
                                      << " expected " << expected_alignment << " got " << alignment);
126
0
               }
127
133k
128
133k
            //printf("alloc %d -> %p\n", plen, p);
129
133k
130
5.94M
            for(size_t i = 0; i != plen; ++i)
131
5.81M
               {
132
5.81M
               if(p[i] != 0)
133
0
                  {
134
0
                  FUZZER_WRITE_AND_CRASH("Pool gave out non-zeroed memory");
135
0
                  }
136
5.81M
               }
137
133k
138
133k
            // verify it becomes zeroed later
139
133k
            std::memset(p, idx, plen);
140
133k
141
133k
            auto insert = ptrs.insert(std::make_pair(p, plen));
142
133k
            if(insert.second == false)
143
0
               {
144
0
               FUZZER_WRITE_AND_CRASH("Pointer " << static_cast<void*>(p) << " already existed\n");
145
0
               }
146
133k
147
133k
            auto itr = insert.first;
148
133k
149
133k
            // Verify this pointer doesn't overlap with the one before it
150
133k
            if(itr != ptrs.begin())
151
74.3k
               {
152
74.3k
               auto before = std::prev(itr);
153
74.3k
               auto ptr_before = *before;
154
74.3k
155
74.3k
               if(ptr_before.first + ptr_before.second > p)
156
0
                  {
157
0
                  FUZZER_WRITE_AND_CRASH("Previous " << static_cast<void*>(ptr_before.first) << "/" << ptr_before.second <<
158
0
                                         " overlaps with new " << static_cast<void*>(p));
159
0
                  }
160
74.3k
               }
161
133k
162
133k
            auto after = std::next(itr);
163
133k
164
133k
            if(after != ptrs.end())
165
51.4k
               {
166
51.4k
               if(p + plen > after->first)
167
0
                  {
168
0
                  FUZZER_WRITE_AND_CRASH("New " << static_cast<void*>(p) << "/" << plen
169
0
                                         << " overlaps following " << static_cast<void*>(after->first));
170
0
                  }
171
51.4k
               }
172
133k
            }
173
152k
         }
174
102k
      else if(op == 1)
175
102k
         {
176
102k
         if(ptrs.empty())
177
25
            return;
178
102k
179
102k
         size_t which_ptr = idx % ptrs.size();
180
102k
181
102k
         auto itr = ptrs.begin();
182
102k
183
874k
         while(which_ptr-- > 0)
184
772k
            {
185
772k
            ++itr;
186
772k
            }
187
102k
188
102k
         //printf("free %p %d\n", itr->first, itr->second);
189
102k
         FUZZER_ASSERT_TRUE(pool.deallocate(itr->first, itr->second));
190
102k
         ptrs.erase(itr);
191
102k
         }
192
255k
      }
193
1.21k
   }