mirror of
https://github.com/capstone-engine/capstone
synced 2026-08-11 16:26:07 -04:00
Add overflow check to cs_kern_os_calloc (#2980)
Co-authored by: orbisai0security
This commit is contained in:
parent
6f41db9228
commit
857e556ced
2 changed files with 64 additions and 1 deletions
6
cs.c
6
cs.c
|
|
@ -501,7 +501,11 @@ extern void *kern_os_realloc(void *addr, size_t nsize);
|
|||
|
||||
static void *cs_kern_os_calloc(size_t num, size_t size)
|
||||
{
|
||||
return kern_os_malloc(num * size); // malloc bzeroes the buffer
|
||||
size_t alloc = num * size;
|
||||
if (num && size != alloc / num) {
|
||||
return NULL; // overflow check
|
||||
}
|
||||
return kern_os_malloc(alloc); // malloc bzeroes the buffer
|
||||
}
|
||||
|
||||
cs_malloc_t cs_mem_malloc = kern_os_malloc;
|
||||
|
|
|
|||
|
|
@ -110,6 +110,64 @@ static void test_overflow_set_reg_mem_n(void)
|
|||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Clone of cs.c::cs_kern_os_calloc()
|
||||
* So we can run it in the CI.
|
||||
*/
|
||||
static void *clone_cs_kern_os_calloc(size_t num, size_t size)
|
||||
{
|
||||
size_t alloc = num * size;
|
||||
if (num && size != alloc / num) {
|
||||
return NULL; // overflow check
|
||||
}
|
||||
return malloc(alloc);
|
||||
}
|
||||
|
||||
#define VALID_N 10
|
||||
|
||||
static void test_integer_overflow(void)
|
||||
{
|
||||
// Invariant: Multiplication of num * size must not overflow before allocation
|
||||
// We test this by ensuring the function handles boundary cases safely
|
||||
|
||||
// Test cases: exploit case, boundary values, valid input
|
||||
struct {
|
||||
size_t num;
|
||||
size_t size;
|
||||
const char *description;
|
||||
} test_cases[] = {
|
||||
// Valid normal input
|
||||
{ VALID_N, VALID_N, "valid normal input" },
|
||||
// Exploit case: multiplication overflows to small value
|
||||
{ SIZE_MAX, 2, "overflow to small allocation" },
|
||||
// Another overflow case
|
||||
{ 1ULL << (sizeof(size_t) * 4), 1ULL << (sizeof(size_t) * 4),
|
||||
"midpoint overflow" },
|
||||
// Zero allocation (edge case)
|
||||
{ 0, SIZE_MAX, "zero num" }
|
||||
};
|
||||
|
||||
int num_cases = sizeof(test_cases) / sizeof(test_cases[0]);
|
||||
|
||||
for (int i = 0; i < num_cases; i++) {
|
||||
printf("num = 0x%zx size = 0x%zx\n", test_cases[i].num,
|
||||
test_cases[i].size);
|
||||
// The security property: if multiplication would overflow,
|
||||
// the function should handle it safely (return NULL or abort)
|
||||
void *result = clone_cs_kern_os_calloc(test_cases[i].num,
|
||||
test_cases[i].size);
|
||||
|
||||
// For valid inputs, we expect non-NULL (or NULL is also acceptable
|
||||
// if memory allocation fails for other reasons)
|
||||
if (test_cases[i].num == VALID_N || test_cases[i].num == 0) {
|
||||
assert(result != NULL);
|
||||
free(result);
|
||||
} else {
|
||||
assert(result == NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Signed left shift overflow when assembling a little-endian SH-DSP
|
||||
/// parallel instruction word. code[3] is promoted to int and shifted
|
||||
/// left by 24, which is UB whenever its top bit is set (code[3] >= 0x80).
|
||||
|
|
@ -155,6 +213,7 @@ int main()
|
|||
test_overflow_cs_insn_bytes();
|
||||
test_overflow_cs_insn_bytes_iter();
|
||||
test_overflow_set_reg_mem_n();
|
||||
test_integer_overflow();
|
||||
test_ub_shift_sh_dsp_p();
|
||||
test_ub_isintn_xtensa_offset();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue