Fix multiple bugs with shell detection:
1. We weren't correctly extracting the argument to be passed to
readlink. We needed to take the null terminator into account, as we
extract this string from memory.
2. readlink does **not** null terminate the output. Fix this.
3. `binary_name.compare(0, 2, "sh")` for detecting if the binary is "sh"
was too liberal, and included "shell_injection_poc_fuzzer" because the
prefix matched.
Also reduce some very noisy debug logging.
cc @oliverchang @Alan32Liu after #9100 and #8448
After compiling locally, I can see that
`./SystemSan ./target_dns -dict=vuln.dict`
crashes in a few seconds with
```
===BUG DETECTED: Arbitrary domain name resolution===
===Domain resolved: .f.z===
===DNS request type: 0, class: 256===
==315== ERROR: libFuzzer: deadly signal
#0 0x539131 in __sanitizer_print_stack_trace /src/llvm-project/compiler-rt/lib/asan/asan_stack.cpp:87:3
#1 0x457c48 in fuzzer::PrintStackTrace() /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerUtil.cpp:210:5
#2 0x43c923 in fuzzer::Fuzzer::CrashCallback() /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:233:3
#3 0x7fa57940041f (/lib/x86_64-linux-gnu/libpthread.so.0+0x1441f) (BuildId: 7b4536f41cdaa5888408e82d0836e33dcf436466)
#4 0x7fa5793ff7db in send (/lib/x86_64-linux-gnu/libpthread.so.0+0x137db) (BuildId: 7b4536f41cdaa5888408e82d0836e33dcf436466)
#5 0x503ba4 in __interceptor_send /src/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:6802:17
#6 0x7fa578abf462 (/lib/x86_64-linux-gnu/libresolv.so.2+0xb462) (BuildId: 4519041bde5b859c55798ac0745b0b6199cb7d94)
#7 0x7fa578abbc43 in __res_context_query (/lib/x86_64-linux-gnu/libresolv.so.2+0x7c43) (BuildId: 4519041bde5b859c55798ac0745b0b6199cb7d94)
#8 0x7fa578abc8ed in __res_context_search (/lib/x86_64-linux-gnu/libresolv.so.2+0x88ed) (BuildId: 4519041bde5b859c55798ac0745b0b6199cb7d94)
#9 0x7fa578ad2cc1 (/lib/x86_64-linux-gnu/libnss_dns.so.2+0x2cc1) (BuildId: 3fac4ec397ba8e8938fe298f103113f315465130)
#10 0x7fa578ad2e8b in _nss_dns_gethostbyname3_r (/lib/x86_64-linux-gnu/libnss_dns.so.2+0x2e8b) (BuildId: 3fac4ec397ba8e8938fe298f103113f315465130)
#11 0x7fa578ad2f41 in _nss_dns_gethostbyname2_r (/lib/x86_64-linux-gnu/libnss_dns.so.2+0x2f41) (BuildId: 3fac4ec397ba8e8938fe298f103113f315465130)
#12 0x7fa5792fdc9d in gethostbyname2_r (/lib/x86_64-linux-gnu/libc.so.6+0x130c9d) (BuildId: 1878e6b475720c7c51969e69ab2d276fae6d1dee)
#13 0x7fa5792d179e (/lib/x86_64-linux-gnu/libc.so.6+0x10479e) (BuildId: 1878e6b475720c7c51969e69ab2d276fae6d1dee)
#14 0x7fa5792d2f58 in getaddrinfo (/lib/x86_64-linux-gnu/libc.so.6+0x105f58) (BuildId: 1878e6b475720c7c51969e69ab2d276fae6d1dee)
#15 0x4d93ac in getaddrinfo /src/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:2667:13
#16 0x56c8d9 in LLVMFuzzerTestOneInput /out/SystemSan/target_dns.cpp:35:11
#17 0x43dec3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:611:15
#18 0x43d6aa in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:514:3
#19 0x43ed79 in fuzzer::Fuzzer::MutateAndTestOne() /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:757:19
#20 0x43fa45 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, std::__Fuzzer::allocator<fuzzer::SizedFile> >&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:895:5
#21 0x42edaf in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:912:6
#22 0x458402 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
#23 0x7fa5791f1082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082) (BuildId: 1878e6b475720c7c51969e69ab2d276fae6d1dee)
#24 0x41f7ed in _start (/out/SystemSan/target_dns+0x41f7ed)
NOTE: libFuzzer has rudimentary signal handlers.
Combine libFuzzer with AddressSanitizer or similar for better crash reports.
SUMMARY: libFuzzer: deadly signal
MS: 2 CrossOver-ManualDict- DE: "f.z"-; base unit: ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4
0x66,0x2e,0x7a,
f.z
artifact_prefix='./'; Test unit written to ./crash-926813b2d6adde373f96a10594a5314951588384
Base64: Zi56
```
You can also try
```
echo -n f.z > toto
./SystemSan ./target_dns toto
```
Co-authored-by: Oliver Chang <oliverchang@users.noreply.github.com>
Co-authored-by: jonathanmetzman <31354670+jonathanmetzman@users.noreply.github.com>
cc @oliverchang
Log the file trying to be opened and the flags (read or write) for
opening the file
Co-authored-by: Oliver Chang <oliverchang@users.noreply.github.com>
* Rename execSan to SystemSan.
All of the bug detectors we've built (or plan to build) relate to system
state.
* fix documentation
* fix more documentation
This causes race conditions with stacktrace printing and does not return
the same exit code as the child process.
Just send the SIGABRT and let our tracing handle the exit.
* A PoC with `node-shell-quote` v1.7.3.
* A description of the shell injection bug in the prev version of shell-quote and how to reproduce it with `execSan`.
* Amend the instructions to run `execSan` on `node-shell-quote` and `pytorch-lightning`.
* Removes the `: ` prefix in our previous pattern to capture case ii and reduce false negatives:
1. Our previous pattern (i.e. `: Syntax error`) is designed to reduce false positives, but it relies on `dash` to print out an error message within one `write` syscall. E.g. `sh: 1: Syntax error: "invalid_command" unexpected`.
2. In some cases, `dash` breaks the message into multiple `write` syscalls. E.g. it invokes 2 `writes` whose buffers respectively contain `sh: 1:`, ` Syntax error: "invalid_command" unexpected`.
* Fix outdated wording
* A TODO about using more specific patterns of error messages
* Remove redundant tripwire from Makefile
* Detect shell corruption based on syntax errors
* Type, name, format, typo, etc.
* Error pattern matching logic
* clang-format
* Code structure fix
* Extend the pathname length of shell to be safe
* Remove redundant operations on memory read from regs
* More specific patterns
* Identify sh
* Remove redudant substr
* Document shell corruption in README.md
* Clang-format
* Organise printf/debug_log/cerr
* Remove a completed TODO
* Use readlink instead of `file`
* Clang-format
* execSan: Follow forks.
- ptrace all child processes.
- Look for execve() calls with /tmp/tripwire as the first argument.
There's no need for it to actually run.
- Convert to C++.
* remove ununused tripwire code
* comments
* An attempt to detect shell injection with ptrace
* Relocate sanitizer files
* Add headers and file descriptions
* Better cleanup
* Name and analogy
* TODOs
* safer cleanup
* More descriptive name
* More descriptive README.md
* More descriptive file names
* One more TODOs