Coverage Report

Created: 2024-05-20 06:13

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