Update:
Prelude
DWARF debug info is used on Windows/GNU, as opposed to PDB debug info on Windows/MSVC.
WinAPI has tools for reading PDB, but can't read DWARF. libbacktrace can read DWARF, that's why libbacktrace is used on Windows/GNU but not on Windows/MSVC.
Debug info enriches backtraces with file names, line numbers, inlined functions etc in addition to the minimal backtrace - non-inlined function names and addresses, that can be obtained with WinAPI alone without using libbacktrace.
The problem
libbacktrace needs to the read the executable file to extract DWARF debug info from it.
If filename is not provided to libbacktrace in backtrace_create_state
(this is what https://github.com/rust-lang/rust/pull/33554 did), then libbacktrace will try to retrieve it itself using getexecname
, /proc/self/exe
or /proc/curproc/file
, whatever works first. Neither works on Windows/GNU, therefore backtraces are broken.
In any case, the executable file is read and interpreted by libbacktrace whether we provide the filename to backtrace_create_state
or not, unless some error happens. There's still a window between the file name is retrieved and the file is read, so the hypothetical vulnerability discussed above is inherent to libbacktrace, but the attack window is much smaller because libbactrace falls back to getexecname
etc almost immediately before reading the file and don't cache the obtained filename for later use.
So, why don't we patch libbacktrace like this commit does and use GetModuleFileName
(instead of /proc/self/exe
etc) to get the fallback name on Windows? This fixes backtraces for sure.
The answer is that GetModuleFileName
returns the original executable name with which it was launched. If executable is renamed and replaced with a malicious file, then GetModuleFileName
will refer to the malicious file even if it's called after renaming.
Possible solutions
- Try to use
QueryFullProcessImageName
instead of GetModuleFileName
, it should support renaming (this is what https://github.com/rust-lang/rust/pull/37359 does).
- Use minimal backtraces on Windows/GNU without additional goodies like line numbers, they doesn't require libbacktrace at all.
- Use
GetModuleFileName
and enjoy the hypothetical vulnerability (i.e. revert #33554 for Windows).
- Rewrite libbacktrace
in Rust and harden it against ill-formed malicious DWARVes.
Most helpful comment
Regarding @alexcrichton 's alternatives from https://github.com/rust-lang/rust/pull/37359#issuecomment-256182219
Unless there's a way to somehow automatically read DWARF into a process' memory with OS' help, I don't see a way to avoid reading it from a file.
This means either even more invasive changes in libbacktraces to make it secure enough (how to determine if it's secure enough?), or find a readily available more secure version of libbacktrace (any concrete variants? how to determine if the alternative is secure enough?), or rewrite libbacktrace by ourselves (how to determine if our rewrite is secure enough?). Why do we think libbacktrace is not secure enough? I haven't seen any proofs that unintentional code-execution is possible yet.
Meanwhile, a tier1 platform doesn't have backtraces for almost half a year.