Fix symlink bug detection (#9215)

This commit is contained in:
jonathanmetzman 2022-12-15 08:38:18 -05:00 committed by GitHub
parent b8a9236e5e
commit 0303aab0b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 33 additions and 14 deletions

View File

@ -32,6 +32,8 @@
#include <syscall.h>
#include <fcntl.h>
#include <algorithm>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <map>
@ -87,7 +89,9 @@ std::map<pid_t, ThreadParent> root_pids;
constexpr int kShellPathnameLength = 20;
std::string kEvilLinkBombfile = "/tmp/evil-link-bombfile";
std::string kEvilLinkBombfileContents = "initial";
const std:: string kEvilLinkError = "Symbolic link followed";
const size_t kPathMax = 4096;
// Syntax error messages of each shell.
const std::map<std::string, std::set<std::string>> kShellSyntaxErrors = {
@ -165,8 +169,10 @@ std::string read_string(pid_t pid, unsigned long reg, unsigned long length) {
return "";
}
auto location = std::find(memory.begin(), memory.end(), static_cast<std::byte>(NULL));
size_t str_length = location - memory.begin();
std::string content(reinterpret_cast<char *>(memory.data()),
std::min(memory.size(), length));
std::min(str_length, length));
return content;
}
@ -324,7 +330,8 @@ void inspect_for_arbitrary_file_open(pid_t pid, const user_regs_struct &regs) {
}
std::string read_evil_link_bombfile() {
const std::ifstream bombfile(kEvilLinkBombfile, std::ios_base::binary);
const std::ifstream bombfile(kEvilLinkBombfile,
std::ios_base::binary);
if (bombfile.fail())
return "";
std::stringstream stream;
@ -332,36 +339,47 @@ std::string read_evil_link_bombfile() {
return stream.str();
}
// https://oss-fuzz.com/testcase-detail/4882113260552192
void report_bug_in_process(std::string bug_type, pid_t pid) {
std::cerr << "===BUG DETECTED: " << bug_type << "===" << std::endl;
tgkill(root_pids[pid].parent_tid, pid, SIGABRT);
}
void inspect_for_evil_link(pid_t pid, const user_regs_struct &regs) {
(void) regs;
std::string contents = read_evil_link_bombfile();
if ((contents.compare("original")) != 0) {
report_bug(kEvilLinkError, pid);
exit(1);
if ((contents.compare(kEvilLinkBombfileContents)) != 0) {
report_bug_in_process(kEvilLinkError, pid);
}
}
void evil_open_hook(pid_t pid, const user_regs_struct &regs) {
// Inspect a PID's register for the sign of arbitrary file open.
std::string path = read_string(pid, regs.rsi, kRootDirMaxLength);
void evil_openat_hook(pid_t pid, const user_regs_struct &regs) {
std::string path = read_string(pid, regs.rsi, kPathMax);
if (!path.length()) {
return;
}
if (std::filesystem::exists(path))
return;
size_t slash_idx = path.rfind('/');
if (slash_idx == std::string::npos)
return;
std::string dir = path.substr(0, slash_idx);
std::cout << "DIR" << slash_idx << " " << dir << std::endl;
if ((dir.compare("/tmp")) != 0)
return;
std::string command = "ln -s " + kEvilLinkBombfile + " " + path;
std::cout << "COMMAND" << command << std::endl;
std::string command = "rm -f " + path + " && ln -s " + kEvilLinkBombfile + " " + path;
std::cout << "COMMAND " << command << std::endl;
system(command.c_str());
}
void initialize_evil_link_bombfile() {
system(("printf 'original' > " + kEvilLinkBombfile).c_str());
std::string command = ("printf " + kEvilLinkBombfileContents + " > " +
kEvilLinkBombfile);
std::cout << "COMMAND " << command << std::endl;
system(command.c_str());
system(("cat " + kEvilLinkBombfile).c_str());
}
int trace(std::map<pid_t, Tracee> pids) {
@ -467,7 +485,7 @@ int trace(std::map<pid_t, Tracee> pids) {
if (regs.orig_rax == __NR_openat) {
// TODO(metzman): Re-enable this once we have config/flag support.
// inspect_for_arbitrary_file_open(pid, regs);
evil_open_hook(pid, regs);
evil_openat_hook(pid, regs);
}
if (regs.orig_rax == __NR_close) {
@ -512,6 +530,7 @@ int main(int argc, char **argv) {
fatal_log("Expecting at least one arguments, received %d", argc - 1);
}
initialize_evil_link_bombfile();
// Create an executable tripwire file, as programs may check for existence

View File

@ -53,7 +53,7 @@ std::vector<std::byte> read_memory(pid_t pid, unsigned long long address,
void report_bug(std::string bug_type, pid_t tid) {
// Report the bug found based on the bug code.
std::cerr << "===BUG DETECTED: " << bug_type.c_str() << "===\n";
std::cerr << "===BUG DETECTED: " << bug_type << "===" << std::endl;
// Rely on sanitizers/libFuzzer to produce a stacktrace by sending SIGABRT
// to the root process.
// Note: this may not be reliable or consistent if shell injection happens