Example: fuzzer.c: ``` #include <stdio.h> #include <string.h> #include<stdlib.h> int main() { char src[] = "lorem ipsum dolor sit amet"; char *dst; dst = malloc(10); strcpy(dst, src); printf("%s\n", dst); } ``` Makefile: ``` CC=gcc CFLAGS=-I. -Wall -Wextra -Werror -g -O2 LDFLAGS=-lopenosc OBJ = fuzzer.o %.o: %.c $(CC) -c -o $@ $< $(CFLAGS) $(LDFLAGS) fuzzer: $(OBJ) $(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) .PHONY:clean clean: rm fuzzer *.o ``` Result: ``` $ make gcc -c -o fuzzer.o fuzzer.c -I. -Wall -Wextra -Werror -g -O2 -lopenosc fuzzer.c: In function ‘main’: fuzzer.c:10:9: error: ‘strcpy’ writing 27 bytes into a region of size 10 [-Werror=stringop-overflow=] 10 | strcpy(dst, src); | ^~~~~~~~~~~~~~~~ fuzzer.c:8:15: note: destination object of size 10 allocated by ‘malloc’ 8 | dst = malloc(10); | ^~~~~~~~~~ fuzzer.c:10:9: error: ‘strcpy’ forming offset [10, 26] is out of the bounds [0, 10] [-Werror=array-bounds=] 10 | strcpy(dst, src); | ^~~~~~~~~~~~~~~~ cc1: all warnings being treated as errors make: *** [Makefile:7: fuzzer.o] Error 1 ``` Now add `-include openosc.h` to `CFLAGS`, Makefile: ``` CC=gcc CFLAGS=-I. -Wall -Wextra -Werror -g -O2 -include openosc.h LDFLAGS=-lopenosc OBJ = fuzzer.o %.o: %.c $(CC) -c -o $@ $< $(CFLAGS) $(LDFLAGS) fuzzer: $(OBJ) $(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) .PHONY:clean clean: rm fuzzer *.o ``` And run `make` again: ``` $ make gcc -c -o fuzzer.o fuzzer.c -I. -Wall -Wextra -Werror -g -O2 -include openosc.h -lopenosc gcc -o fuzzer fuzzer.o -I. -Wall -Wextra -Werror -g -O2 -include openosc.h -lopenosc ``` The compile time errors have disappeared and have been moved to runtime: ``` $ ./fuzzer lorem ips $ journalctl --since "2 min ago" Nov 20 22:24:09 archlinux-cisco fuzzer[319384]: DATACORRUPTION-DATAINCONSISTENCY: openosc 1.0.6 Copy error -Traceback= ./fuzzer +0x10bb libc.so.6+0x27cd0 libc.so.6+0x27d8a +0x1115 ``` Using OpenOSC, we've transitioned from a program which didn't compile to an invalid program which truncates the result and reports the buffer overflow at runtime. This is opposite from what is usually desired, i.e. fail as early as possible, catch errors at compile-time rather than at runtime.