Exercise an inter-global-object buffer overflow
This exercise demonstrates an inter-object buffer overflow on baseline and CHERI-enabled architectures, and asks you to characterize and fix the bug detected by CHERI bounds enforcement. It also asks you to use GDB for debugging purposes.
This example uses two global objects (in .data
) to demonstrate an overflow.
It is worth pondering how the bounds for pointers to globals come to be set!
-
Compile
buffer-overflow-global.c
for the baseline architecture to the binarybuffer-overflow-global-baseline
and for the CHERI-aware architecture tobuffer-overflow-global-cheri
.For this exercise, add
-G0
to your compiler flags (this ensuresc
is not placed in the small data section away frombuffer
). -
Run both programs and observe the output.
-
Using GDB on the core dump (or run the CHERI program under
gdb
): Why has the CHERI program failed? -
Modify
buffer-overflow-global.c
to increase the buffer size from 128 bytes to 1Mbyte + 1 byte. -
Recompile and re-run
buffer-overflow-global-cheri
. Why does it no longer crash, even though the buffer overflow exists in the source code? Is the adjacent field still corrupted (i.e., has spatial safety been violated between allocations)? -
Modify
buffer-overflow-global.c
to restore the original buffer size of 128 bytes, and fix the bug by correcting accesses to the allocated array. -
Recompile and run
buffer-overflow-global-cheri
to demonstrate that the program is now able to continue.
Source Files
buffer-overflow-global.c
/*
* SPDX-License-Identifier: BSD-2-Clause-DARPA-SSITH-ECATS-HR0011-18-C-0016
* Copyright (c) 2020 SRI International
*/
#include <stdio.h>
char buffer[128];
char c;
#pragma weak fill_buf
void
fill_buf(char *buf, size_t len)
{
for (size_t i = 0; i <= len; i++)
buf[i] = 'b';
}
#include "main-asserts.inc"
int
main(void)
{
(void)buffer;
main_asserts();
c = 'c';
printf("c = %c\n", c);
fill_buf(buffer, sizeof(buffer));
printf("c = %c\n", c);
return 0;
}
Support code
main-asserts.inc
/*
* SPDX-License-Identifier: BSD-2-Clause-DARPA-SSITH-ECATS-HR0011-18-C-0016
* Copyright (c) 2020 SRI International
*/
#include <assert.h>
#include <stddef.h>
#ifdef __CHERI_PURE_CAPABILITY__
#include <cheriintrin.h>
#endif
#ifndef nitems
#define nitems(x) (sizeof((x)) / sizeof((x)[0]))
#endif
static void
main_asserts(void)
{
/*
* Ensure that overflowing `buffer` by 1 will hit `c`.
* In the pure-capabilty case, don't assert if the size of
* `buffer` requires padding.
*/
assert((ptraddr_t)&buffer[nitems(buffer)] == (ptraddr_t)&c
#ifdef __CHERI_PURE_CAPABILITY__
|| sizeof(buffer) < cheri_representable_length(sizeof(buffer))
#endif
);
}