mr-fox ~ # tor --verify-configMay 27 16:27:29.867 [notice] Tor 0.3.1.2-alpha (git-61625b8f26384a4a) running on Linux with Libevent 2.1.8-stable, OpenSSL LibreSSL 2.5.4, Zlib 1.2.11, Liblzma 5.2.3, and Libzstd N/A.May 27 16:27:29.867 [notice] Tor can't help you if you use it wrong! Learn how to be safe at https://www.torproject.org/download/download#warningMay 27 16:27:29.867 [notice] This version is not a stable Tor release. Expect more bugs than usual.May 27 16:27:29.867 [notice] Read configuration file "/etc/tor/torrc".============================================================ T= 1495895249Tor 0.3.1.2-alpha (git-61625b8f26384a4a) died: Caught signal 11tor(+0x172296)[0x5594c9e62296]tor(+0x178a1e)[0x5594c9e68a1e]tor(+0x178a1e)[0x5594c9e68a1e]tor(config_get_lines_include+0x38)[0x5594c9e68ec8]tor(options_init_from_string+0x1df)[0x5594c9dedabf]tor(options_init_from_torrc+0x1f1)[0x5594c9dedfd1]tor(tor_init+0x313)[0x5594c9d3e1d3]tor(tor_main+0x6e)[0x5594c9d3f67e]tor(main+0x28)[0x5594c9d38c98]/lib64/libc.so.6(__libc_start_main+0xfc)[0x7fc3f452e72c]tor(_start+0x29)[0x5594c9d38ce9]Aborted
toralf, can you either give your explicit torrc files (are you running Tor as root like the # prompt implies) or better, run it under valgrind and give us a more useful trace?
The bug was triggered by including a folder with a non-empty file without any values followed by another file.
The problem is in the config_process_include() function. When this function is called to process an included folder, it will call config_get_included_list() for each file in the folder. config_get_included_list() will write the list of values on the file to included_list and the pointer to the last entry of the list to *list_last. When a file contains no values, both included_list and *list_last will be null. The bug is that, after calling config_get_included_list(), we update the the *next pointer with the following code:
When *list_last is null, we're are updating *next with the offset of next on the config_line_t struct (0x10 on a 64bit system). The next file on the folder will go through the same code and crash when writing to !**next.
But (not knowing the code here at all, though I admit I am stunned to find a ***next :) it is a confusing fix. If !*list_last, then assign *next to *next? If that's actually what you meant to do, wouldn't it be simpler to do it with something like
if (*list_last) *next = &(*list_last)->next;
?
(I am in a twisty maze of pointers to pointers to pointers, all alike.)
Assigning *next to *next is a no-op, so the code I wrote does the same as the version with the if.
However, the version with the if is indeed easier to read. I've changed it on my branch.
I'm unable to reproduce the double free. Maybe someone else can try?
Just for completeness:
The attached t.tgz does contain the non-empty no-vars-containing 60_* file. Shouldn't that help to reproduce the bug ?
I extracted the tarball into a separate directory (not wanting to overwrite global configurations) without changing the %include. This caused Tor to abort prematurely because it couldn't find the /etc/tor/torrc.d/ directory and didn't reproduce the issue. The description in comment:3 lead me down the wrong path so in the end i wasn't able to reproduce it.
Changing the %include to the torrc.d directory in my extraction directory and the STR from comment:12 both reproduce the issue on my side now.