Validating libfko Memory Usage with Test::Valgrind
26 October, 2013

# prove --exec 'perl -Iblib/lib -Iblib/arch -MTest::Valgrind' t/*.tHere is a complete example - first, run the test suite like so:
# ./test-fwknop.pl --enable-all --include perl --test-limit 3 [+] Starting the fwknop test suite... args: --enable-all --include perl --test-limit 3 [+] Total test buckets to execute: 3 [perl FKO module] [compile/install] to: ./FKO...................pass (1) [perl FKO module] [make test] run built-in tests................pass (2) [perl FKO module] [prove t/*.t] Test::Valgrind..................pass (3) [valgrind output] [flagged functions] ..........................pass (4) Run time: 1.27 minutes [+] 0/0/0 OpenSSL tests passed/failed/executed [+] 0/0/0 OpenSSL HMAC tests passed/failed/executed [+] 4/0/4 test buckets passed/failed/executedNote that all tests passed as shown above. This indicates that the test suite has not found any memory leaks through the fuzzing tests run via Test::Valgrind. But, let's validate this by artificially introducing a memory leak and see if the test suite can automatically catch it. For example, here is a patch that forces a memory leak in the validate_access_msg() libfko function. This function ensures that the shape of the access request conforms to something fwknop expects like "1.2.3.4,tcp/22". The memory leak happens because a new buffer is allocated from the heap but is never free()'d before returning from the function (obviously this patch is for illustration and testing purposes only):
$ git diff diff --git a/lib/fko_message.c b/lib/fko_message.c index fa6803b..c04e035 100644 --- a/lib/fko_message.c +++ b/lib/fko_message.c @@ -251,6 +251,13 @@ validate_access_msg(const char *msg) const char *ndx; int res = FKO_SUCCESS; int startlen = strnlen(msg, MAX_SPA_MESSAGE_SIZE); + char *leak = NULL; + + leak = malloc(100); + leak[0] = 'a'; + leak[1] = 'a'; + leak[2] = '\0'; + printf("LEAK: %s\n", leak); if(startlen == MAX_SPA_MESSAGE_SIZE) return(FKO_ERROR_INVALID_DATA_MESSAGE_ACCESS_MISSING);Now recompile fwknop and run the test suite again, after applying the patch (recompilation output is not shown):
# cd ../ # make # test # ./test-fwknop.pl --enable-all --include perl --test-limit 3 [+] Starting the fwknop test suite... args: --enable-all --include perl --test-limit 3 Saved results from previous run to: output.last/ Valgrind mode enabled, will import previous coverage from: output.last/valgrind-coverage/ [+] Total test buckets to execute: 3 [perl FKO module] [compile/install] to: ./FKO...................pass (1) [perl FKO module] [make test] run built-in tests................pass (2) [perl FKO module] [prove t/*.t] Test::Valgrind..................fail (3) [valgrind output] [flagged functions] ..........................fail (4) Run time: 1.27 minutes [+] 0/0/0 OpenSSL tests passed/failed/executed [+] 0/0/0 OpenSSL HMAC tests passed/failed/executed [+] 2/2/4 test buckets passed/failed/executedThis time two tests fail. The first is the test that runs the perl FKO module built-in tests under Test::Valgrind, and the second is the "flagged functions" test which compares test suite output looking for new functions that valgrind has flagged vs. the previous test suite execution. By looking at the output file of the "flagged functions" test it is easy to see the offending function where the new memory leak exists. This provides an easy, automated way of memory leak detection that is driven by perl FKO fuzzing tests.
# cat output/4.test [+] fwknop client functions (with call line numbers): 10 : validate_access_msg [fko_message.c:256] 6 : fko_set_spa_message [fko_message.c:184] 4 : fko_new_with_data [fko_funcs.c:263] 4 : fko_decrypt_spa_data [fko_encryption.c:264] 4 : fko_decode_spa_data [fko_decode.c:350]Currently, there are no known memory leaks in the fwknop code, and automation built around the Test::Valgrind module will help keep it that way.