Bitdefender Hypervisor Memory Introspection
utils.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "utils.h"
6 #include "introcrt.h"
7 
8 // This assumes that S1 <= E1 AND S2 <= E2; If one range ends before the other starts, the ranges don't overlap
9 #define RANGES_OVERLAP(S1, E1, S2, E2) (!((E1) < (S2) || (S1) > (E2)))
10 
11 
12 size_t
14  _In_bytecount_(Length) void *Buffer,
15  _In_ size_t Length,
16  _In_ size_t SizeOfElements,
17  _In_bytecount_(SizeOfElements) void *Target
18  )
19 //
20 // Will do a binary search inside the sorted array Buffer, with each element SizeOfElements bytes in size.
21 //
22 // \ret The position where the element has been found, or -1, if the element is not in the array.
23 //
24 {
25  size_t left, right;
26  QWORD dst, src;
27 
28  if (NULL == Buffer)
29  {
30  return (size_t) -1;
31  }
32 
33  if (NULL == Target)
34  {
35  return (size_t) -1;
36  }
37 
38  left = 0;
39  right = (Length / SizeOfElements);
40 
41  switch (SizeOfElements)
42  {
43  case 1:
44  dst = *((BYTE *)Target);
45  break;
46  case 2:
47  dst = *((WORD *)Target);
48  break;
49  case 4:
50  dst = *((DWORD *)Target);
51  break;
52  case 8:
53  dst = *((QWORD *)Target);
54  break;
55  default:
56  return (size_t) -1;
57  }
58 
59  while (left < right)
60  {
61  size_t midd = (left + right) / 2;
62 
63  switch (SizeOfElements)
64  {
65  case 1:
66  src = *((BYTE *)Buffer + midd * SizeOfElements);
67  break;
68  case 2:
69  src = *((WORD *)((BYTE *)Buffer + midd * SizeOfElements));
70  break;
71  case 4:
72  src = *((DWORD *)((BYTE *)Buffer + midd * SizeOfElements));
73  break;
74  case 8:
75  src = *((QWORD *)((BYTE *)Buffer + midd * SizeOfElements));
76  break;
77  default:
78  return (size_t) -1;
79  }
80 
81  if (dst == src)
82  {
83  return midd;
84  }
85  else if (dst < src)
86  {
87  // We must continue the search to the left.
88  right = midd;
89  }
90  else
91  {
92  // We must continue the search to the right.
93  left = midd + 1;
94  }
95  }
96 
97  return (size_t) -1;
98 }
99 
100 
101 size_t
103  _In_bytecount_(Length) void *Buffer,
104  _In_ size_t Length,
105  _In_ size_t MaximumLength,
106  _In_ size_t SizeOfElements,
107  _In_bytecount_(SizeOfElements) void *Target
108  )
109 {
110  size_t i;
111  QWORD src, dst;
112 
113  if (NULL == Buffer)
114  {
115  return (size_t) -1;
116  }
117 
118  if (NULL == Target)
119  {
120  return (size_t) -1;
121  }
122 
123  if (MaximumLength < Length + SizeOfElements)
124  {
125  return (size_t) -1;
126  }
127 
128  switch (SizeOfElements)
129  {
130  case 1:
131  dst = *((BYTE *)Target);
132  break;
133  case 2:
134  dst = *((WORD *)Target);
135  break;
136  case 4:
137  dst = *((DWORD *)Target);
138  break;
139  case 8:
140  dst = *((QWORD *)Target);
141  break;
142  default:
143  return (size_t) -1;
144  }
145 
146  for (i = Length; i > 0; i -= SizeOfElements)
147  {
148  switch (SizeOfElements)
149  {
150  case 1:
151  src = *((BYTE *)Buffer + i - SizeOfElements);
152  break;
153  case 2:
154  src = *((WORD *)((BYTE *)Buffer + i - SizeOfElements));
155  break;
156  case 4:
157  src = *((DWORD *)((BYTE *)Buffer + i - SizeOfElements));
158  break;
159  case 8:
160  src = *((QWORD *)((BYTE *)Buffer + i - SizeOfElements));
161  break;
162  default:
163  return (size_t) -1;
164  }
165 
166  if (dst > src)
167  {
168  memcpy((BYTE *)Buffer + i, &dst, SizeOfElements);
169  return i / SizeOfElements;
170  }
171  else
172  {
173  memcpy((BYTE *)Buffer + i, &src, SizeOfElements);
174  }
175  }
176 
177  // We must put it on position 0.
178  memcpy(Buffer, Target, SizeOfElements);
179 
180  return 0;
181 }
182 
183 
184 //
185 // Using a if-else/switch by ElementSize to do indexing of Array, slows this down by 30-50%
186 // This macro is only needed for `pivot` type, and for direct indexing.
187 // Names generated: _QuickSort<TypeOfArray>, eg: _QuickSortQWORD, _QuickSortBYTE, etc.
188 //
189 #define QUICKSORT_FUNCTION(Array, TypeOfArray) \
190 static void \
191 _QuickSort##TypeOfArray( \
192  _Inout_updates_all_(NumberOfElements) TypeOfArray *Array, \
193  _In_ const DWORD NumberOfElements \
194  ) \
195 { \
196  DWORD begin[64] = {0}, end[64] = {0}; \
197  TypeOfArray pivot; \
198  int i = 0; \
199  int swap; \
200  \
201  end[0] = NumberOfElements; \
202  \
203  while (i >= 0) \
204  { \
205  int left = begin[i]; \
206  int right = end[i] - 1; \
207  \
208  if (left < right) \
209  { \
210  pivot = Array[left]; \
211  \
212  while (left < right) \
213  { \
214  while (Array[right] >= pivot && left < right) \
215  { \
216  right--; \
217  } \
218  \
219  if (left < right) \
220  { \
221  Array[left++] = Array[right]; \
222  } \
223  \
224  while (Array[left] <= pivot && left < right) \
225  { \
226  left++; \
227  } \
228  \
229  if (left < right) \
230  { \
231  Array[right--] = Array[left]; \
232  } \
233  } \
234  \
235  Array[left] = pivot; \
236  \
237  begin[i + 1] = left + 1; \
238  end[i + 1] = end[i]; \
239  end[i++] = left; \
240  \
241  if (end[i] - begin[i] > end[i - 1] - begin[i - 1]) \
242  { \
243  swap = begin[i]; \
244  begin[i] = begin[i - 1]; \
245  begin[i - 1] = swap; \
246  \
247  swap = end[i]; \
248  end[i] = end[i - 1]; \
249  end[i - 1] = swap; \
250  } \
251  } \
252  else \
253  { \
254  i--; \
255  } \
256  } \
257 }
258 
259 
260 QUICKSORT_FUNCTION(Array, QWORD);
261 QUICKSORT_FUNCTION(Array, DWORD);
262 QUICKSORT_FUNCTION(Array, WORD);
263 QUICKSORT_FUNCTION(Array, BYTE);
264 
265 
266 void
268  _Inout_updates_bytes_(NumberOfElements *ElementSize) void *Array,
269  _In_ const DWORD NumberOfElements,
270  _In_ const BYTE ElementSize
271  )
272 {
273  switch (ElementSize)
274  {
275  case 1:
276  _QuickSortBYTE(Array, NumberOfElements);
277  break;
278  case 2:
279  _QuickSortWORD(Array, NumberOfElements);
280  break;
281  case 4:
282  _QuickSortDWORD(Array, NumberOfElements);
283  break;
284  case 8:
285  _QuickSortQWORD(Array, NumberOfElements);
286  break;
287  }
288 }
289 
290 
291 size_t
293  _In_bytecount_(Count *SizeOfElements) void *Buffer,
294  _In_ size_t Count, // Number of structures
295  _In_ size_t SizeOfElements, // Elements size
296  _In_ DWORD CompareFieldOffset, // The offset of the compare field
297  _In_bytecount_(TargetSize) void *Target,
298  _In_ DWORD TargetSize
299  )
300 //
301 // Will do a binary search inside the sorted array of structures Buffer, with each element SizeOfElements bytes in size.
302 // Will compare the Element at CompareFieldOffset with the element at Target, both of size TargetSize.
303 //
304 // \ret The position where the element has been found, or -1, if the element is not in the array.
305 //
306 {
307  size_t left, right;
308  QWORD dst, src;
309 
310  if (NULL == Buffer)
311  {
312  return (size_t) -1;
313  }
314 
315  if (NULL == Target)
316  {
317  return (size_t) -1;
318  }
319 
320  left = 0;
321  right = Count;
322 
323  switch (TargetSize)
324  {
325  case 1:
326  dst = *((BYTE *)Target);
327  break;
328  case 2:
329  dst = *((WORD *)Target);
330  break;
331  case 4:
332  dst = *((DWORD *)Target);
333  break;
334  case 8:
335  dst = *((QWORD *)Target);
336  break;
337  default:
338  return (size_t) -1;
339  }
340 
341  while (left < right)
342  {
343  size_t midd = (left + right) / 2;
344 
345  switch (TargetSize)
346  {
347  case 1:
348  src = *((BYTE *)Buffer + midd * SizeOfElements + CompareFieldOffset);
349  break;
350  case 2:
351  src = *((WORD *)((BYTE *)Buffer + midd * SizeOfElements + CompareFieldOffset));
352  break;
353  case 4:
354  src = *((DWORD *)((BYTE *)Buffer + midd * SizeOfElements + CompareFieldOffset));
355  break;
356  case 8:
357  src = *((QWORD *)((BYTE *)Buffer + midd * SizeOfElements + CompareFieldOffset));
358  break;
359  default:
360  return (size_t) -1;
361  }
362 
363  if (dst == src)
364  {
365  return midd;
366  }
367  else if (dst < src)
368  {
369  // We must continue the search to the left.
370  right = midd;
371  }
372  else
373  {
374  // We must continue the search to the right.
375  left = midd + 1;
376  }
377  }
378 
379  return (size_t) -1;
380 }
381 
382 
383 void
385  _Inout_updates_(NumberOfElements) QWORD *Array,
386  _In_ const DWORD NumberOfElements
387  )
388 {
389  BOOLEAN swapped = TRUE;
390  size_t j = 0;
391 
392  while (swapped)
393  {
394  swapped = FALSE;
395  j++;
396 
397  for (size_t i = 0; i < NumberOfElements - j; i++)
398  {
399  if (Array[i] > Array[i + 1])
400  {
401  QWORD tmp = Array[i];
402  Array[i] = Array[i + 1];
403  Array[i + 1] = tmp;
404 
405  swapped = TRUE;
406  }
407  }
408  }
409 }
410 
411 
412 BOOLEAN
414  _In_bytecount_(BufferSize) void *Buffer,
415  _In_ size_t BufferSize
416  )
417 {
418  static const char zeroPage[PAGE_SIZE] = { 0 };
419 
420  if (BufferSize > PAGE_SIZE || NULL == Buffer)
421  {
422  return FALSE;
423  }
424 
425  return memcmp(Buffer, zeroPage, BufferSize) == 0;
426 }
_Bool BOOLEAN
Definition: intro_types.h:58
void UtilSortQwords(QWORD *Array, const DWORD NumberOfElements)
Definition: utils.c:384
uint8_t BYTE
Definition: intro_types.h:47
#define _In_
Definition: intro_sal.h:21
uint16_t WORD
Definition: intro_types.h:48
BOOLEAN UtilIsBufferZero(void *Buffer, size_t BufferSize)
Definition: utils.c:413
#define _In_bytecount_(expr)
Definition: intro_sal.h:42
#define _Inout_updates_bytes_(expr)
Definition: intro_sal.h:33
#define QUICKSORT_FUNCTION(Array, TypeOfArray)
Definition: utils.c:189
unsigned long long QWORD
Definition: intro_types.h:53
#define TRUE
Definition: intro_types.h:30
size_t UtilBinarySearchStructure(void *Buffer, size_t Count, size_t SizeOfElements, DWORD CompareFieldOffset, void *Target, DWORD TargetSize)
Definition: utils.c:292
#define _Inout_updates_(expr)
Definition: intro_sal.h:32
#define PAGE_SIZE
Definition: common.h:70
uint32_t DWORD
Definition: intro_types.h:49
void UtilQuickSort(void *Array, const DWORD NumberOfElements, const BYTE ElementSize)
Definition: utils.c:267
size_t UtilBinarySearch(void *Buffer, size_t Length, size_t SizeOfElements, void *Target)
Definition: utils.c:13
size_t UtilInsertOrdered(void *Buffer, size_t Length, size_t MaximumLength, size_t SizeOfElements, void *Target)
Definition: utils.c:102
#define FALSE
Definition: intro_types.h:34