Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 17 additions & 11 deletions infra/experimental/SystemSan/SystemSan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <unistd.h>

/* Linux */
#include <linux/elf.h>
#include <sys/ptrace.h>
#include <syscall.h>
#include <fcntl.h>
Expand All @@ -40,6 +41,7 @@
#include <string>
#include <vector>

#include "arch.h"
#include "inspect_utils.h"
#include "inspect_dns.h"

Expand Down Expand Up @@ -169,7 +171,7 @@ std::string read_string(pid_t pid, unsigned long reg, unsigned long length) {

void inspect_for_injection(pid_t pid, const user_regs_struct &regs) {
// Inspect a PID's registers for the sign of shell injection.
std::string path = read_string(pid, regs.rdi, kTripWire.length());
std::string path = read_string(pid, REGS_ARG1, kTripWire.length());
if (!path.length()) {
return;
}
Expand All @@ -181,7 +183,7 @@ void inspect_for_injection(pid_t pid, const user_regs_struct &regs) {

std::string get_pathname(pid_t pid, const user_regs_struct &regs) {
// Parse the pathname from the memory specified in the RDI register.
std::string pathname = read_string(pid, regs.rdi, kShellPathnameLength);
std::string pathname = read_string(pid, REGS_ARG1, kShellPathnameLength);
debug_log("Pathname is %s (len %lu)\n", pathname.c_str(), pathname.length());
return pathname;
}
Expand Down Expand Up @@ -262,7 +264,7 @@ void match_error_pattern(std::string buffer, std::string shell, pid_t pid) {

void inspect_for_corruption(pid_t pid, const user_regs_struct &regs) {
// Inspect a PID's registers for shell corruption.
std::string buffer = read_string(pid, regs.rsi, regs.rdx);
std::string buffer = read_string(pid, REGS_ARG2, REGS_ARG3);
debug_log("Write buffer: %s\n", buffer.c_str());
match_error_pattern(buffer, g_shell_pids[pid], pid);
}
Expand Down Expand Up @@ -297,12 +299,12 @@ bool has_unprintable(const std::string &value) {

void inspect_for_arbitrary_file_open(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);
std::string path = read_string(pid, REGS_ARG2, kRootDirMaxLength);
if (!path.length()) {
return;
}
if (path.substr(0, kFzAbsoluteDirectory.length()) == kFzAbsoluteDirectory) {
log_file_open(path, regs.rdx, pid);
log_file_open(path, REGS_ARG3, pid);
return;
}
if (path[0] == '/' && path.length() > 1) {
Expand All @@ -314,7 +316,7 @@ void inspect_for_arbitrary_file_open(pid_t pid, const user_regs_struct &regs) {
if (has_unprintable(path_absolute_topdir)) {
struct stat dirstat;
if (stat(path_absolute_topdir.c_str(), &dirstat) != 0) {
log_file_open(path, regs.rdx, pid);
log_file_open(path, REGS_ARG3, pid);
}
}
}
Expand Down Expand Up @@ -399,13 +401,17 @@ int trace(std::map<pid_t, Tracee> pids) {

if (is_syscall) {
user_regs_struct regs;
if (ptrace(PTRACE_GETREGS, pid, 0, &regs) == -1) {
debug_log("ptrace(PTRACE_GETREGS, %d): %s", pid, strerror(errno));
struct iovec iov {
.iov_base = &regs,
.iov_len = sizeof(struct user_regs_struct),
};
if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov) == -1) {
debug_log("ptrace(PTRACE_GETREGSET, %d): %s", pid, strerror(errno));
continue;
}

if (tracee.syscall_enter) {
if (regs.orig_rax == __NR_execve) {
if (REGS_SYSCALL == __NR_execve) {
// This is a new process.
auto parent = root_pids[pid];
parent.ran_exec = true;
Expand All @@ -420,12 +426,12 @@ int trace(std::map<pid_t, Tracee> pids) {

inspect_dns_syscalls(pid, regs);

if (regs.orig_rax == __NR_openat) {
if (REGS_SYSCALL == __NR_openat) {
// TODO(metzman): Re-enable this once we have config/flag support.
// inspect_for_arbitrary_file_open(pid, regs);
}

if (regs.orig_rax == __NR_write &&
if (REGS_SYSCALL == __NR_write &&
g_shell_pids.find(pid) != g_shell_pids.end()) {
debug_log("Inspecting the `write` buffer of shell process %d.",
pid);
Expand Down
27 changes: 27 additions & 0 deletions infra/experimental/SystemSan/arch.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2023 Google LLC

* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at

* http://www.apache.org/licenses/LICENSE-2.0

* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#if defined(__aarch64__)
#define REGS_SYSCALL regs.regs[8]
#define REGS_ARG1 regs.regs[0]
#define REGS_ARG2 regs.regs[1]
#define REGS_ARG3 regs.regs[2]
#elif defined(__x86_64__)
#define REGS_SYSCALL regs.orig_rax
#define REGS_ARG1 regs.rdi
#define REGS_ARG2 regs.rsi
#define REGS_ARG3 regs.rdx
#endif
21 changes: 11 additions & 10 deletions infra/experimental/SystemSan/inspect_dns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include <iostream>

#include "arch.h"
#include "inspect_utils.h"


Expand All @@ -38,12 +39,12 @@ const size_t kDnsHeaderLen = 12;


void inspect_for_arbitrary_dns_connect(pid_t pid, const user_regs_struct &regs) {
auto memory = read_memory(pid, regs.rsi, sizeof(struct sockaddr_in));
auto memory = read_memory(pid, REGS_ARG2, sizeof(struct sockaddr_in));
if (memory.size()) {
struct sockaddr_in * sa = reinterpret_cast<struct sockaddr_in *>(memory.data());
if (sa->sin_family == AF_INET && htons(sa->sin_port) == 53) {
// save file descriptor for later sendmmsg
kFdDns = regs.rdi;
kFdDns = REGS_ARG1;
}
}
}
Expand Down Expand Up @@ -168,8 +169,8 @@ void inspect_for_arbitrary_dns_pkt(std::vector<std::byte> data, pid_t pid) {
}

void inspect_for_arbitrary_dns_fdbuffer(pid_t pid, const user_regs_struct &regs) {
if (kFdDns > 0 && kFdDns == (int) regs.rdi) {
auto memory = read_memory(pid, regs.rsi, regs.rdx);
if (kFdDns > 0 && kFdDns == (int) REGS_ARG1) {
auto memory = read_memory(pid, REGS_ARG2, REGS_ARG3);
if (memory.size()) {
inspect_for_arbitrary_dns_pkt(memory, pid);
}
Expand All @@ -188,8 +189,8 @@ void inspect_for_arbitrary_dns_iov(pid_t pid, unsigned long iov) {
}

void inspect_for_arbitrary_dns_sendmsg(pid_t pid, const user_regs_struct &regs) {
if (kFdDns > 0 && kFdDns == (int) regs.rdi) {
auto memory = read_memory(pid, regs.rsi, sizeof(struct msghdr));
if (kFdDns > 0 && kFdDns == (int) REGS_ARG1) {
auto memory = read_memory(pid, REGS_ARG2, sizeof(struct msghdr));
if (memory.size()) {
struct msghdr * msg = reinterpret_cast<struct msghdr *>(memory.data());
if (msg->msg_iovlen == 1) {
Expand All @@ -200,8 +201,8 @@ void inspect_for_arbitrary_dns_sendmsg(pid_t pid, const user_regs_struct &regs)
}

void inspect_for_arbitrary_dns_sendmmsg(pid_t pid, const user_regs_struct &regs) {
if (kFdDns > 0 && kFdDns == (int) regs.rdi) {
auto memory = read_memory(pid, regs.rsi, sizeof(struct mmsghdr));
if (kFdDns > 0 && kFdDns == (int) REGS_ARG1) {
auto memory = read_memory(pid, REGS_ARG2, sizeof(struct mmsghdr));
if (memory.size()) {
struct mmsghdr * msg = reinterpret_cast<struct mmsghdr *>(memory.data());
if (msg->msg_hdr.msg_iovlen == 1) {
Expand All @@ -212,12 +213,12 @@ void inspect_for_arbitrary_dns_sendmmsg(pid_t pid, const user_regs_struct &regs)
}

void inspect_dns_syscalls(pid_t pid, const user_regs_struct &regs) {
switch (regs.orig_rax) {
switch (REGS_SYSCALL) {
case __NR_connect:
inspect_for_arbitrary_dns_connect(pid, regs);
break;
case __NR_close:
if (kFdDns > 0 && kFdDns == (int) regs.rdi) {
if (kFdDns > 0 && kFdDns == (int) REGS_ARG1) {
// reset DNS file descriptor on close
kFdDns = 0;
}
Expand Down
1 change: 1 addition & 0 deletions infra/experimental/SystemSan/inspect_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <vector>
#include <map>

#include "arch.h"
#include "inspect_utils.h"

extern pid_t g_root_pid;
Expand Down