xref: /aosp_15_r20/external/capstone/windows/winkernel_mm.c (revision 9a0e4156d50a75a99ec4f1653a0e9602a5d45c18)
1*9a0e4156SSadaf Ebrahimi /* Capstone Disassembly Engine */
2*9a0e4156SSadaf Ebrahimi /* By Satoshi Tanda <[email protected]>, 2016 */
3*9a0e4156SSadaf Ebrahimi 
4*9a0e4156SSadaf Ebrahimi #include "winkernel_mm.h"
5*9a0e4156SSadaf Ebrahimi #include <ntddk.h>
6*9a0e4156SSadaf Ebrahimi #include <Ntintsafe.h>
7*9a0e4156SSadaf Ebrahimi 
8*9a0e4156SSadaf Ebrahimi // A pool tag for memory allocation
9*9a0e4156SSadaf Ebrahimi static const ULONG CS_WINKERNEL_POOL_TAG = 'kwsC';
10*9a0e4156SSadaf Ebrahimi 
11*9a0e4156SSadaf Ebrahimi 
12*9a0e4156SSadaf Ebrahimi // A structure to implement realloc()
13*9a0e4156SSadaf Ebrahimi typedef struct _CS_WINKERNEL_MEMBLOCK {
14*9a0e4156SSadaf Ebrahimi 	size_t size;   // A number of bytes allocated
15*9a0e4156SSadaf Ebrahimi 	__declspec(align(MEMORY_ALLOCATION_ALIGNMENT))
16*9a0e4156SSadaf Ebrahimi 	char data[ANYSIZE_ARRAY];  // An address returned to a caller
17*9a0e4156SSadaf Ebrahimi } CS_WINKERNEL_MEMBLOCK;
18*9a0e4156SSadaf Ebrahimi 
19*9a0e4156SSadaf Ebrahimi 
20*9a0e4156SSadaf Ebrahimi // free()
cs_winkernel_free(void * ptr)21*9a0e4156SSadaf Ebrahimi void CAPSTONE_API cs_winkernel_free(void *ptr)
22*9a0e4156SSadaf Ebrahimi {
23*9a0e4156SSadaf Ebrahimi 	if (ptr) {
24*9a0e4156SSadaf Ebrahimi 		ExFreePoolWithTag(CONTAINING_RECORD(ptr, CS_WINKERNEL_MEMBLOCK, data), CS_WINKERNEL_POOL_TAG);
25*9a0e4156SSadaf Ebrahimi 	}
26*9a0e4156SSadaf Ebrahimi }
27*9a0e4156SSadaf Ebrahimi 
28*9a0e4156SSadaf Ebrahimi // malloc()
cs_winkernel_malloc(size_t size)29*9a0e4156SSadaf Ebrahimi void * CAPSTONE_API cs_winkernel_malloc(size_t size)
30*9a0e4156SSadaf Ebrahimi {
31*9a0e4156SSadaf Ebrahimi 	// Disallow zero length allocation because they waste pool header space and,
32*9a0e4156SSadaf Ebrahimi 	// in many cases, indicate a potential validation issue in the calling code.
33*9a0e4156SSadaf Ebrahimi 	NT_ASSERT(size);
34*9a0e4156SSadaf Ebrahimi 
35*9a0e4156SSadaf Ebrahimi 	// FP; a use of NonPagedPool is required for Windows 7 support
36*9a0e4156SSadaf Ebrahimi #pragma prefast(suppress : 30030)		// Allocating executable POOL_TYPE memory
37*9a0e4156SSadaf Ebrahimi 	size_t number_of_bytes = 0;
38*9a0e4156SSadaf Ebrahimi 	CS_WINKERNEL_MEMBLOCK *block = NULL;
39*9a0e4156SSadaf Ebrahimi 	// A specially crafted size value can trigger the overflow.
40*9a0e4156SSadaf Ebrahimi 	// If the sum in a value that overflows or underflows the capacity of the type,
41*9a0e4156SSadaf Ebrahimi 	// the function returns NULL.
42*9a0e4156SSadaf Ebrahimi 	if (!NT_SUCCESS(RtlSizeTAdd(size, FIELD_OFFSET(CS_WINKERNEL_MEMBLOCK, data), &number_of_bytes))) {
43*9a0e4156SSadaf Ebrahimi 		return NULL;
44*9a0e4156SSadaf Ebrahimi 	}
45*9a0e4156SSadaf Ebrahimi 	block = (CS_WINKERNEL_MEMBLOCK *)ExAllocatePoolWithTag(
46*9a0e4156SSadaf Ebrahimi 			NonPagedPool, number_of_bytes, CS_WINKERNEL_POOL_TAG);
47*9a0e4156SSadaf Ebrahimi 	if (!block) {
48*9a0e4156SSadaf Ebrahimi 		return NULL;
49*9a0e4156SSadaf Ebrahimi 	}
50*9a0e4156SSadaf Ebrahimi 	block->size = size;
51*9a0e4156SSadaf Ebrahimi 
52*9a0e4156SSadaf Ebrahimi 	return block->data;
53*9a0e4156SSadaf Ebrahimi }
54*9a0e4156SSadaf Ebrahimi 
55*9a0e4156SSadaf Ebrahimi // calloc()
cs_winkernel_calloc(size_t n,size_t size)56*9a0e4156SSadaf Ebrahimi void * CAPSTONE_API cs_winkernel_calloc(size_t n, size_t size)
57*9a0e4156SSadaf Ebrahimi {
58*9a0e4156SSadaf Ebrahimi 	size_t total = n * size;
59*9a0e4156SSadaf Ebrahimi 
60*9a0e4156SSadaf Ebrahimi 	void *new_ptr = cs_winkernel_malloc(total);
61*9a0e4156SSadaf Ebrahimi 	if (!new_ptr) {
62*9a0e4156SSadaf Ebrahimi 		return NULL;
63*9a0e4156SSadaf Ebrahimi 	}
64*9a0e4156SSadaf Ebrahimi 
65*9a0e4156SSadaf Ebrahimi 	return RtlFillMemory(new_ptr, total, 0);
66*9a0e4156SSadaf Ebrahimi }
67*9a0e4156SSadaf Ebrahimi 
68*9a0e4156SSadaf Ebrahimi // realloc()
cs_winkernel_realloc(void * ptr,size_t size)69*9a0e4156SSadaf Ebrahimi void * CAPSTONE_API cs_winkernel_realloc(void *ptr, size_t size)
70*9a0e4156SSadaf Ebrahimi {
71*9a0e4156SSadaf Ebrahimi 	void *new_ptr = NULL;
72*9a0e4156SSadaf Ebrahimi 	size_t current_size = 0;
73*9a0e4156SSadaf Ebrahimi 	size_t smaller_size = 0;
74*9a0e4156SSadaf Ebrahimi 
75*9a0e4156SSadaf Ebrahimi 	if (!ptr) {
76*9a0e4156SSadaf Ebrahimi 		return cs_winkernel_malloc(size);
77*9a0e4156SSadaf Ebrahimi 	}
78*9a0e4156SSadaf Ebrahimi 
79*9a0e4156SSadaf Ebrahimi 	new_ptr = cs_winkernel_malloc(size);
80*9a0e4156SSadaf Ebrahimi 	if (!new_ptr) {
81*9a0e4156SSadaf Ebrahimi 		return NULL;
82*9a0e4156SSadaf Ebrahimi 	}
83*9a0e4156SSadaf Ebrahimi 
84*9a0e4156SSadaf Ebrahimi 	current_size = CONTAINING_RECORD(ptr, CS_WINKERNEL_MEMBLOCK, data)->size;
85*9a0e4156SSadaf Ebrahimi 	smaller_size = (current_size < size) ? current_size : size;
86*9a0e4156SSadaf Ebrahimi 	RtlCopyMemory(new_ptr, ptr, smaller_size);
87*9a0e4156SSadaf Ebrahimi 	cs_winkernel_free(ptr);
88*9a0e4156SSadaf Ebrahimi 
89*9a0e4156SSadaf Ebrahimi 	return new_ptr;
90*9a0e4156SSadaf Ebrahimi }
91*9a0e4156SSadaf Ebrahimi 
92*9a0e4156SSadaf Ebrahimi // vsnprintf(). _vsnprintf() is available for drivers, but it differs from
93*9a0e4156SSadaf Ebrahimi // vsnprintf() in a return value and when a null-terminator is set.
94*9a0e4156SSadaf Ebrahimi // cs_winkernel_vsnprintf() takes care of those differences.
95*9a0e4156SSadaf Ebrahimi #pragma warning(push)
96*9a0e4156SSadaf Ebrahimi // Banned API Usage : _vsnprintf is a Banned API as listed in dontuse.h for
97*9a0e4156SSadaf Ebrahimi // security purposes.
98*9a0e4156SSadaf Ebrahimi #pragma warning(disable : 28719)
cs_winkernel_vsnprintf(char * buffer,size_t count,const char * format,va_list argptr)99*9a0e4156SSadaf Ebrahimi int CAPSTONE_API cs_winkernel_vsnprintf(char *buffer, size_t count, const char *format, va_list argptr)
100*9a0e4156SSadaf Ebrahimi {
101*9a0e4156SSadaf Ebrahimi 	int result = _vsnprintf(buffer, count, format, argptr);
102*9a0e4156SSadaf Ebrahimi 
103*9a0e4156SSadaf Ebrahimi 	// _vsnprintf() returns -1 when a string is truncated, and returns "count"
104*9a0e4156SSadaf Ebrahimi 	// when an entire string is stored but without '\0' at the end of "buffer".
105*9a0e4156SSadaf Ebrahimi 	// In both cases, null-terminator needs to be added manually.
106*9a0e4156SSadaf Ebrahimi 	if (result == -1 || (size_t)result == count) {
107*9a0e4156SSadaf Ebrahimi 		buffer[count - 1] = '\0';
108*9a0e4156SSadaf Ebrahimi 	}
109*9a0e4156SSadaf Ebrahimi 
110*9a0e4156SSadaf Ebrahimi 	if (result == -1) {
111*9a0e4156SSadaf Ebrahimi 		// In case when -1 is returned, the function has to get and return a number
112*9a0e4156SSadaf Ebrahimi 		// of characters that would have been written. This attempts so by retrying
113*9a0e4156SSadaf Ebrahimi 		// the same conversion with temp buffer that is most likely big enough to
114*9a0e4156SSadaf Ebrahimi 		// complete formatting and get a number of characters that would have been
115*9a0e4156SSadaf Ebrahimi 		// written.
116*9a0e4156SSadaf Ebrahimi 		char* tmp = cs_winkernel_malloc(0x1000);
117*9a0e4156SSadaf Ebrahimi 		if (!tmp) {
118*9a0e4156SSadaf Ebrahimi 			return result;
119*9a0e4156SSadaf Ebrahimi 		}
120*9a0e4156SSadaf Ebrahimi 
121*9a0e4156SSadaf Ebrahimi 		result = _vsnprintf(tmp, 0x1000, format, argptr);
122*9a0e4156SSadaf Ebrahimi 		NT_ASSERT(result != -1);
123*9a0e4156SSadaf Ebrahimi 		cs_winkernel_free(tmp);
124*9a0e4156SSadaf Ebrahimi 	}
125*9a0e4156SSadaf Ebrahimi 
126*9a0e4156SSadaf Ebrahimi 	return result;
127*9a0e4156SSadaf Ebrahimi }
128*9a0e4156SSadaf Ebrahimi #pragma warning(pop)
129