using ASAN and UBSAN to find bugs - victronenergy/venus GitHub Wiki

Note: available since Venus OS v3.70

Compiling with ASAN / UBSAN on a target

These are just small example how to enable ASAN / UBSAN on Venus OS. Search the internet for more details about these sanitizers.

install required packages

First make sure opkg is setup correctly. There after install the compiler and ASAN.

opkg install packagegroup-core-buildessential libasan-dev libubsan-dev

simple test

create a test program

Create a problematic program, e.g. bug.c

int main() {
	char a[10];
	a[20] = 'a';
	return 0;
}

and compile it with gcc -fsanitize=address bug.c -o bug.

run it

When executed it will produce:

root@ekrano:~# ./bug
=================================================================
==6563==ERROR: AddressSanitizer: stack-buffer-overflow on address 0xb4f00034 at pc 0x000106f4 bp 0xbea7aae4 sp 0xbea7aadc
WRITE of size 1 at 0xb4f00034 thread T0
    #0 0x106f0 in main (/data/home/root/test+0x106f0) (BuildId: 73c93f7c973944059f1bab9e071fe39f94cb9e5a)
    #1 0xb67cc4f0  (/lib/libc.so.6+0x1f4f0) (BuildId: cc306752adb5a209c295f52718558bdfe5e92412)
    #2 0xb67cc5dc in __libc_start_main (/lib/libc.so.6+0x1f5dc) (BuildId: cc306752adb5a209c295f52718558bdfe5e92412)

Address 0xb4f00034 is located in stack of thread T0 at offset 52 in frame
    #0 0x10618 in main (/data/home/root/test+0x10618) (BuildId: 73c93f7c973944059f1bab9e071fe39f94cb9e5a)

  This frame has 1 object(s):
    [32, 42) 'a' (line 2) <== Memory access at offset 52 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/data/home/root/test+0x106f0) (BuildId: 73c93f7c973944059f1bab9e071fe39f94cb9e5a) in main
Shadow bytes around the buggy address:
  0xb4effd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xb4effe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xb4effe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xb4efff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xb4efff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0xb4f00000: f1 f1 f1 f1 00 02[f3]f3 00 00 00 00 00 00 00 00
  0xb4f00080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xb4f00100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xb4f00180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xb4f00200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xb4f00280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==6563==ABORTING

ubsan test

Besides asan also ubsan is available, checking for undefined behavior. asan and ubsan can also be combined.

overflow.c

int main(int argc, char **argv) {
  int k = 0x7fffffff;
  k += argc;
  return 0;
}
root@ekrano:~# gcc -fsanitize=undefined overflow.c -o overflow
.root@ekrano:~# ./overflow 
overflow.c:3:5: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'

shared test

Just for testing, nobody in his right mind does this normally like this.

create files

test.c

void test(void) {
	char a[10];
	a[20] = 'a';
}

main.c

extern void test(void);

int main() {
	test();
	return 0;
}

Mind the -fsanitize=address in the link step.

gcc -fPIC -fsanitize=address -c test.c -o test.o
gcc --shared test.o -o libtest.so
gcc -fsanitize=address main.c -L. -ltest -o test

When running export LD_LIBRARY_PATH=. && ./test the output should be like above.

cmake

add_compile_options(-fsanitize=address)
add_link_options(-fsanitize=address)

Running remotely / compiling with the SDK

The SDK contains support for libasan / libubsan by default. Compilation is like above, the only thing which needs to be installed done on the target is opkg install libasan libubsan.