-
Notifications
You must be signed in to change notification settings - Fork 14
fix: add buffer-length check in str.c #131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
e4247d9
8d759ac
f38be15
a9c43fa
00ee1cd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| #include <check.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
|
|
||
| /* Import the actual strcpy from the freestanding runtime */ | ||
| extern char *strcpy(char *dest, const char *src); | ||
|
|
||
| #define DEST_SIZE 16 | ||
| #define GUARD_BYTE 0xAA | ||
|
|
||
| START_TEST(test_strcpy_buffer_overflow_detection) | ||
| { | ||
| /* Invariant: Buffer reads/writes must never exceed declared destination length */ | ||
| const char *payloads[] = { | ||
| "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", /* 2.5x overflow (40 chars) */ | ||
| "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", /* 10x overflow (160 chars) */ | ||
| "AAAAAAAAAAAAAAA", /* Boundary: exactly fits (15 chars + null) */ | ||
| "short" /* Valid input */ | ||
| }; | ||
| int num_payloads = sizeof(payloads) / sizeof(payloads[0]); | ||
|
|
||
| for (int i = 0; i < num_payloads; i++) { | ||
| /* Allocate buffer with guard bytes to detect overflow */ | ||
| unsigned char *mem = malloc(DEST_SIZE + 16); | ||
| ck_assert_ptr_nonnull(mem); | ||
|
|
||
| /* Fill entire region with guard bytes */ | ||
| memset(mem, GUARD_BYTE, DEST_SIZE + 16); | ||
|
|
||
| char *dest = (char *)(mem + 8); /* Buffer in middle */ | ||
| size_t src_len = strlen(payloads[i]); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The test allocates a fixed-size buffer of To prevent heap corruption and ensure the test runs safely, we should dynamically allocate the buffer based on the actual payload length, ensuring there is always enough allocated space to hold the entire copied string plus the guard bytes. size_t src_len = strlen(payloads[i]);
size_t max_len = (src_len > DEST_SIZE) ? src_len : DEST_SIZE;
size_t alloc_size = 8 + max_len + 8;
unsigned char *mem = malloc(alloc_size);
ck_assert_ptr_nonnull(mem);
memset(mem, GUARD_BYTE, alloc_size);
char *dest = (char *)(mem + 8);There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @orbisai0security can you address code review comments? |
||
|
|
||
| /* Call the vulnerable function */ | ||
| strcpy(dest, payloads[i]); | ||
|
|
||
| /* Check if overflow occurred by examining guard bytes after buffer */ | ||
| if (src_len >= DEST_SIZE) { | ||
| /* Overflow WILL occur with unbounded strcpy - this test documents the vulnerability */ | ||
| /* A safe implementation would truncate or reject; unbounded strcpy corrupts memory */ | ||
| ck_assert_msg(mem[DEST_SIZE + 8] == GUARD_BYTE, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The assertion checks if the guard byte is equal to If the goal of this test is to document that the vulnerability indeed exists (as indicated by the comment on line 38), the assertion should check that the guard byte was corrupted (i.e., ck_assert_msg(mem[DEST_SIZE + 8] != GUARD_BYTE, |
||
| "Buffer overflow detected: guard byte corrupted for payload %d (len=%zu)", | ||
| i, src_len); | ||
| } else { | ||
| /* Valid input should not overflow */ | ||
| ck_assert_msg(mem[DEST_SIZE + 8] == GUARD_BYTE, | ||
| "Unexpected overflow for valid payload %d", i); | ||
| } | ||
|
|
||
| free(mem); | ||
| } | ||
| } | ||
| END_TEST | ||
|
|
||
| Suite *security_suite(void) | ||
| { | ||
| Suite *s; | ||
| TCase *tc_core; | ||
|
|
||
| s = suite_create("Security"); | ||
| tc_core = tcase_create("Core"); | ||
|
|
||
| tcase_add_test(tc_core, test_strcpy_buffer_overflow_detection); | ||
| suite_add_tcase(s, tc_core); | ||
|
|
||
| return s; | ||
| } | ||
|
|
||
| int main(void) | ||
| { | ||
| int number_failed; | ||
| Suite *s; | ||
| SRunner *sr; | ||
|
|
||
| s = security_suite(); | ||
| sr = srunner_create(s); | ||
|
|
||
| srunner_run_all(sr, CK_NORMAL); | ||
| number_failed = srunner_ntests_failed(sr); | ||
| srunner_free(sr); | ||
|
|
||
| return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Placing
__attribute__((deprecated(...)))on the function definition instr.cis ineffective for warning external callers. In C, deprecation warnings are triggered based on the function declaration visible at the call site. Since other source files include the header file (e.g.,string.horlinxisa_libc.h) which does not have this attribute, they will not receive any compiler warnings when callingstrcpy.To make the deprecation warning effective, please add the
__attribute__((deprecated(...)))attribute to the declaration ofstrcpyinavs/runtime/freestanding/include/string.h(and any other relevant header files).