many vulnerabilities we looked at due to poor bounds checking
char buffer[42];
memcpy(buffer, attacker_controlled, len);
len42 passed to __memcpy_chk_FORTIFY_SOURCELinux C standard library + GCC features
adds automatic checking to a bunch of string/array functions
also printf (disable %n unless format string is a constant)
often enabled by default
GCC options:
-D_FORTIFY_SOURCE=1 — enable (backwards-compatible only)-D_FORTIFY_SOURCE=2 — enable (constant sizes only)-D_FORTIFY_SOURCE=3 — enable (computed sizes, sometimes)-U_FORTIFY_SOURCE — disablewill add checks (gcc 9.3 -O2, FORTIFY_SOURCE=1/2)
will add checks (gcc 14.2 or clang 20 -Os, FORTIFY_SOURCE=3)
will add check (gcc 14.2 or clang 20 -Os, FORTIFY_SOURCE=3)
‘‘Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.’’
exercise: what should the call have been?
‘‘If src contains n or more bytes, strncat() writes n+1 bytes to dest (n from src plus the terminating null byte). Therefore, the size of dest must be at least strlen(dest)+n+1.’’
exercise: what should the call have been?
strcpy_s, strcat_s (same idea, differentname)MyPtr strcpy(MyPtr dest, const MyPtr src) {
int i;
do {
CHECK(src.pointer + i <= src.maximum);
CHECK(src.pointer + i >= src.minimum);
CHECK(dest.pointer + i <= dest.maximum);
CHECK(dest.pointer + i >= dest.minimum);
dest.pointer[i] = src.pointer[i];
i += 1;
CHECK(src.pointer + i <= src.maximum);
CHECK(src.pointer + i >= src.minimum);
} while (src.pointer[i] != '\0');
return dest;
}from FreeBSD’s bootpd (server for machines that boot from the network):
from perl’s source code:
Necula et al, ‘‘CCured: Type-Safe Retrofitting of Legacy Code’’ (2002)
extension to C to add fat pointers
actually three different types of pointers:
needs source changes to annotate some pointer usage
1-2.5x time overhead
malloc()/new/* bounds lookup */
mov buf, %rax
shr %rax, 4
mov LOOKUP_TABLE(%rax), %al
/* array element address computation */
... // char * p = buf[i];
/* bound check */
mov buf, %rbx
xor p, %rbx
shr %al, %rbx
jz ok
... // handle possible violation
ok:
adapted from paper figure
suppose program allocates:
using baggy bounds, estimate:
space required for padding
space required for table
suppose program allocates:
using baggy bounds, estimate:
estimate:
thought question:
with bounds checking, what’s fastest possible code?
in code generated by f2c (Fortran to C translator and cleaned up slightly)
like baggy bounds:
unlike baggy bounds:
array[offset] isn’t part of any object
struct foo {
char buffer[1024];
int *pointer;
};
struct foo array_of_foos[1024];
...
char *p = &array_of_foos[4].buffer[4]
pros vs baggy bounds:
cons vs baggy bounds:
similar to AddressSanitizer — but no compiler modificaitons
instead: is an emulator (plus alternate malloc/new implementation)
convert whole basic blocks
end with call to translate_and_run
cache converted code
translate_and_run checks cache firstpatch calls to translate_and_run to refer directly to cached code
do something more clever than movq rax_location, ...
ends up being ‘‘just-in-time’’ compiler
early VMWare: for instructions without hardware virtualization support
used by Apple to handle changing CPU designs
Rosetta 2: run Intel on ARM (current)
Rosetta: run Power PC on Intel (2005–2011)
Mac 68k emulator: Run Motorola 680x0 on Power PC (1994–2005)
which schemes detect or prevent from being harmful…?
of:
which schemes detect or prevent from being harmful…?
only Valgrind Memcheck handles assembly code
other techniques require C compiler to produce different assembly
which schemes detect or prevent from being harmful…?
schemes:
which schemes detect or prevent from being harmful…?
schemes:
which schemes detect or prevent from being harmful…?
schemes: