Skip to content

Commit 31ede5b

Browse files
committed
Add overflow check to cs_kern_os_calloc
Co-authored by: orbisai0security
1 parent 0055d66 commit 31ede5b

2 files changed

Lines changed: 64 additions & 1 deletion

File tree

cs.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,11 @@ extern void *kern_os_realloc(void *addr, size_t nsize);
501501

502502
static void *cs_kern_os_calloc(size_t num, size_t size)
503503
{
504-
return kern_os_malloc(num * size); // malloc bzeroes the buffer
504+
size_t alloc = num * size;
505+
if (num && size != alloc / num) {
506+
return NULL; // overflow check
507+
}
508+
return kern_os_malloc(alloc); // malloc bzeroes the buffer
505509
}
506510

507511
cs_malloc_t cs_mem_malloc = kern_os_malloc;

tests/integration/test_poc.c

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,70 @@ static void test_overflow_set_reg_mem_n(void)
110110
return;
111111
}
112112

113+
/**
114+
* \brief Clone of cs.c::cs_kern_os_calloc()
115+
* So we can run it in the CI.
116+
*/
117+
static void *clone_cs_kern_os_calloc(size_t num, size_t size)
118+
{
119+
size_t alloc = num * size;
120+
if (num && size != alloc / num) {
121+
return NULL; // overflow check
122+
}
123+
return malloc(alloc);
124+
}
125+
126+
#define VALID_N 10
127+
128+
static void test_integer_overflow(void)
129+
{
130+
// Invariant: Multiplication of num * size must not overflow before allocation
131+
// We test this by ensuring the function handles boundary cases safely
132+
133+
// Test cases: exploit case, boundary values, valid input
134+
struct {
135+
size_t num;
136+
size_t size;
137+
const char *description;
138+
} test_cases[] = {
139+
// Valid normal input
140+
{ VALID_N, VALID_N, "valid normal input" },
141+
// Exploit case: multiplication overflows to small value
142+
{ SIZE_MAX, 2, "overflow to small allocation" },
143+
// Another overflow case
144+
{ 1ULL << (sizeof(size_t) * 4), 1ULL << (sizeof(size_t) * 4),
145+
"midpoint overflow" },
146+
// Zero allocation (edge case)
147+
{ 0, SIZE_MAX, "zero num" }
148+
};
149+
150+
int num_cases = sizeof(test_cases) / sizeof(test_cases[0]);
151+
152+
for (int i = 0; i < num_cases; i++) {
153+
printf("num = 0x%zx size = 0x%zx\n", test_cases[i].num,
154+
test_cases[i].size);
155+
// The security property: if multiplication would overflow,
156+
// the function should handle it safely (return NULL or abort)
157+
void *result = clone_cs_kern_os_calloc(test_cases[i].num,
158+
test_cases[i].size);
159+
160+
// For valid inputs, we expect non-NULL (or NULL is also acceptable
161+
// if memory allocation fails for other reasons)
162+
if (test_cases[i].num == VALID_N || test_cases[i].num == 0) {
163+
assert(result != NULL);
164+
free(result);
165+
} else {
166+
assert(result == NULL);
167+
}
168+
}
169+
}
170+
113171
int main()
114172
{
115173
test_overflow_cs_insn_bytes();
116174
test_overflow_cs_insn_bytes_iter();
117175
test_overflow_set_reg_mem_n();
176+
test_integer_overflow();
118177

119178
return 0;
120179
}

0 commit comments

Comments
 (0)