From 477aebd9f1f4e71fbd82efc8ad7d37091e6bb785 Mon Sep 17 00:00:00 2001 From: CinderSocket Date: Wed, 17 Jun 2026 16:09:15 -0700 Subject: [PATCH] alloc: guard calloc size overflow --- Makefile | 1 + allocation_policy.c | 16 ++++++++++++++++ allocation_policy.h | 6 ++++++ lib/host_tests/test_runtime_policy.c | 20 ++++++++++++++++++++ sam_api.c | 10 ++++++++-- 5 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 allocation_policy.c create mode 100644 allocation_policy.h diff --git a/Makefile b/Makefile index 1a5eada..7ebf7ed 100644 --- a/Makefile +++ b/Makefile @@ -40,6 +40,7 @@ test-host: board_power_lifecycle.c \ sam_startup_ui.c \ ccid_logic.c \ + allocation_policy.c \ credential_sio_label.c \ t_1_logic.c \ t_1.c \ diff --git a/allocation_policy.c b/allocation_policy.c new file mode 100644 index 0000000..518a29b --- /dev/null +++ b/allocation_policy.c @@ -0,0 +1,16 @@ +#include "allocation_policy.h" + +#include + +bool seader_size_multiply_checked(size_t count, size_t size, size_t* out) { + if(!out) { + return false; + } + + if(count != 0U && size > SIZE_MAX / count) { + return false; + } + + *out = count * size; + return true; +} diff --git a/allocation_policy.h b/allocation_policy.h new file mode 100644 index 0000000..634a098 --- /dev/null +++ b/allocation_policy.h @@ -0,0 +1,6 @@ +#pragma once + +#include +#include + +bool seader_size_multiply_checked(size_t count, size_t size, size_t* out); diff --git a/lib/host_tests/test_runtime_policy.c b/lib/host_tests/test_runtime_policy.c index f873df6..980d025 100644 --- a/lib/host_tests/test_runtime_policy.c +++ b/lib/host_tests/test_runtime_policy.c @@ -1,6 +1,8 @@ #include +#include #include "munit.h" +#include "allocation_policy.h" #include "runtime_policy.h" #include "seader_hf_read_plan.h" @@ -296,6 +298,23 @@ static MunitResult test_virtual_credential_loop_terminal_policy( return MUNIT_OK; } +static MunitResult test_checked_size_multiply_rejects_overflow( + const MunitParameter params[], + void* fixture) { + (void)params; + (void)fixture; + + size_t total_size = 0U; + munit_assert_true(seader_size_multiply_checked(4U, 8U, &total_size)); + munit_assert_size(total_size, ==, 32U); + + total_size = 123U; + munit_assert_false(seader_size_multiply_checked(SIZE_MAX, 2U, &total_size)); + munit_assert_size(total_size, ==, 123U); + munit_assert_false(seader_size_multiply_checked(1U, 1U, NULL)); + return MUNIT_OK; +} + static MunitTest test_runtime_policy_cases[] = { {(char*)"/reset-sam-metadata", test_reset_cached_sam_metadata_clears_all_fields, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, {(char*)"/begin-uhf-probe", test_begin_uhf_probe_sets_runtime_and_initializes_probe, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, @@ -309,6 +328,7 @@ static MunitTest test_runtime_policy_cases[] = { {(char*)"/reset-hf-mode", test_reset_hf_mode_clears_selection_and_detected_types, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, {(char*)"/cancel-hf-type-prompt", test_cancel_hf_type_prompt_resets_future_read_to_full_polling, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, {(char*)"/virtual-credential-terminal-policy", test_virtual_credential_loop_terminal_policy, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, + {(char*)"/checked-size-multiply", test_checked_size_multiply_rejects_overflow, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, {NULL, NULL, NULL, NULL, 0, NULL}, }; diff --git a/sam_api.c b/sam_api.c index 991c1f4..65b257e 100644 --- a/sam_api.c +++ b/sam_api.c @@ -7,6 +7,7 @@ #include "uhf_snmp_probe.h" #include "card_details_builder.h" #include "uhf_status_label.h" +#include "allocation_policy.h" #include #include #include @@ -341,9 +342,14 @@ uint8_t select_desfire_app_no_le[] = uint8_t FILE_NOT_FOUND[] = {0x6a, 0x82}; void* calloc(size_t count, size_t size) { - void* ptr = malloc(count * size); + size_t total_size = 0U; + if(!seader_size_multiply_checked(count, size, &total_size)) { + return NULL; + } + + void* ptr = malloc(total_size); if(ptr) { - memset(ptr, 0, count * size); + memset(ptr, 0, total_size); } return ptr; }