Validating libfko Memory Usage with Test::Valgrind
26 October, 2013
The fwknop project consistently uses valgrind to ensure that memory leaks, double free() conditions, and other problems do not creep into the code base. A high level of automation is built around valgrind usage with the fwknop test suite, and a recent addition extends this even further by using the excellent CPAN Test::Valgrind module. Even though the test suite has had the ability to run tests through valgrind, previous to this change these tests only applied to the fwknop C binaries when executed directly by the test suite. Further, some of the most rigorous testing is done through the usage of the perl FKO extension to fuzz libfko functions, so without the Test::Valgrind module these tests also could not take advantage of valgrind support. Now that the test suite supports Test::Valgrind (and a check is done to see if it is installed), all fuzzing tests can also be validated with valgrind. Technically, the fuzzing tests have been added as FKO built-in tests in the t/ directory, and the test suite runs them through Test::Valgrind like this:# 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.