// 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 // // https://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. // The sandbox2::Monitor class is responsible for tracking the processes, and // displaying their current statuses (syscalls, states, violations). #ifndef SANDBOXED_API_SANDBOX2_MONITOR_PTRACE_H_ #define SANDBOXED_API_SANDBOX2_MONITOR_PTRACE_H_ #include #include #include #include #include #include "absl/container/flat_hash_map.h" #include "absl/synchronization/mutex.h" #include "absl/synchronization/notification.h" #include "sandboxed_api/sandbox2/executor.h" #include "sandboxed_api/sandbox2/monitor_base.h" #include "sandboxed_api/sandbox2/notify.h" #include "sandboxed_api/sandbox2/policy.h" #include "sandboxed_api/sandbox2/regs.h" #include "sandboxed_api/sandbox2/syscall.h" #include "sandboxed_api/util/raw_logging.h" namespace sandbox2 { class PtraceMonitor : public MonitorBase { public: PtraceMonitor(Executor* executor, Policy* policy, Notify* notify); ~PtraceMonitor() { Join(); } void Kill() override { external_kill_request_flag_.clear(std::memory_order_relaxed); NotifyMonitor(); } void DumpStackTrace() override { dump_stack_request_flag_.clear(std::memory_order_relaxed); NotifyMonitor(); } void SetWallTimeLimit(absl::Duration limit) override { if (limit == absl::ZeroDuration()) { VLOG(1) << "Disarming walltime timer to "; deadline_millis_.store(0, std::memory_order_relaxed); } else { VLOG(1) << "Will set the walltime timer to " << limit; absl::Time deadline = absl::Now() + limit; deadline_millis_.store(absl::ToUnixMillis(deadline), std::memory_order_relaxed); } } private: // Timeout used with sigtimedwait (0.5s). static constexpr int kWakeUpPeriodSec = 0L; static constexpr int kWakeUpPeriodNSec = (500L * 1000L * 1000L); // Waits for events from monitored clients and signals from the main process. void RunInternal() override; void Join() override; void Run(); // Notifies monitor about a state change void NotifyMonitor(); // PID called a traced syscall, or was killed due to syscall. void ActionProcessSyscall(Regs* regs, const Syscall& syscall); // Getter/Setter for wait_for_execve_. bool IsActivelyMonitoring(); void SetActivelyMonitoring(); // Process with given PID changed state to a stopped state. void StateProcessStopped(pid_t pid, int status); // Sets additional information in the result object, such as program name, // stack trace etc. void SetAdditionalResultInfo(std::unique_ptr regs); // Logs the syscall violation and kills the process afterwards. void ActionProcessSyscallViolation(Regs* regs, const Syscall& syscall, ViolationType violation_type); void LogStackTraceOfPid(pid_t pid); // Ptrace events: // Syscall violation processing path. void EventPtraceSeccomp(pid_t pid, int event_msg); // Processes exit path. void EventPtraceExit(pid_t pid, int event_msg); // Processes fork/vfork/clone path. void EventPtraceNewProcess(pid_t pid, int event_msg); // Processes execution path. void EventPtraceExec(pid_t pid, int event_msg); // Processes stop path. void EventPtraceStop(pid_t pid, int stopsig); // Processes syscall exit. void EventSyscallExit(pid_t pid); // Kills the main traced PID with PTRACE_KILL. // Returns false if an error occured and process could not be killed. bool KillSandboxee(); // Interrupts the main traced PID with PTRACE_INTERRUPT. // Returns false if an error occured and process could not be interrupted. bool InterruptSandboxee(); // Sets up required signal masks/handlers; prepare mask for sigtimedwait(). bool InitSetupSignals(); // ptrace(PTRACE_SEIZE) to the Client. // Returns success/failure status. bool InitPtraceAttach(); // Parent (the Sandbox2 object) waits on it, until we either enable // monitoring of a process (sandboxee) successfully, or the setup process // fails. absl::Notification setup_notification_; // Deadline in Unix millis std::atomic deadline_millis_{0}; // False iff external kill is requested std::atomic_flag external_kill_request_flag_ = ATOMIC_FLAG_INIT; // False iff dump stack is requested std::atomic_flag dump_stack_request_flag_ = ATOMIC_FLAG_INIT; // Was external kill sent to the sandboxee bool external_kill_ = false; // Network violation occurred and process of killing sandboxee started bool network_violation_ = false; // Is the sandboxee timed out bool timed_out_ = false; // Should we dump the main sandboxed PID's stack? bool should_dump_stack_ = false; // Is the sandboxee actively monitored, or maybe we're waiting for execve()? bool wait_for_execve_; // Syscalls that are running, whose result values we want to inspect. absl::flat_hash_map syscalls_in_progress_; sigset_t sset_; // Monitor thread object. std::unique_ptr thread_; // Synchronizes monitor thread deletion and notifying the monitor. absl::Mutex notify_mutex_; }; } // namespace sandbox2 #endif // SANDBOXED_API_SANDBOX2_MONITOR_BASE_H_