| // Copyright 2019 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. |
| |
| // This file defines the sandbox2::Result class which will in future handle both |
| // exit status of the sandboxed process, and possible results returned from it. |
| |
| #ifndef SANDBOXED_API_SANDBOX2_RESULT_H_ |
| #define SANDBOXED_API_SANDBOX2_RESULT_H_ |
| |
| #include <sys/resource.h> |
| |
| #include <cstdint> |
| #include <memory> |
| #include <optional> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "absl/status/status.h" |
| #include "sandboxed_api/config.h" |
| #include "sandboxed_api/sandbox2/regs.h" |
| #include "sandboxed_api/sandbox2/syscall.h" |
| |
| namespace sandbox2 { |
| |
| class Result { |
| public: |
| // Final execution status. |
| enum StatusEnum { |
| // Not set yet |
| UNSET = 0, |
| // OK |
| OK, |
| // Sandbox initialization failure |
| SETUP_ERROR, |
| // Syscall violation |
| VIOLATION, |
| // Process terminated with a signal |
| SIGNALED, |
| // Process terminated with a timeout |
| TIMEOUT, |
| // Killed externally by user |
| EXTERNAL_KILL, |
| // Most likely ptrace() API failed |
| INTERNAL_ERROR, |
| }; |
| |
| // Detailed reason codes |
| enum ReasonCodeEnum { |
| // Codes used by status=`SETUP_ERROR`: |
| UNSUPPORTED_ARCH = 0, |
| FAILED_TIMERS, |
| FAILED_SIGNALS, |
| FAILED_SUBPROCESS, |
| FAILED_NOTIFY, |
| FAILED_CONNECTION, |
| FAILED_WAIT, |
| FAILED_NAMESPACES, |
| FAILED_PTRACE, |
| FAILED_IPC, |
| FAILED_LIMITS, |
| FAILED_CWD, |
| FAILED_POLICY, |
| |
| // Codes used by status=`INTERNAL_ERROR`: |
| FAILED_STORE, |
| FAILED_FETCH, |
| FAILED_GETEVENT, |
| FAILED_MONITOR, |
| FAILED_KILL, |
| FAILED_INTERRUPT, |
| FAILED_CHILD, |
| FAILED_INSPECT, |
| |
| // TODO(wiktorg) not used currently (syscall number stored insted) - need to |
| // fix clients first |
| // Codes used by status=`VIOLATION`: |
| VIOLATION_SYSCALL, |
| VIOLATION_ARCH, |
| VIOLATION_NETWORK = 0x10000000, // TODO(eternalred): temporary value, needs |
| // to be big until it's fixed |
| }; |
| |
| Result() = default; |
| Result(const Result& other) { *this = other; } |
| Result& operator=(const Result& other); |
| Result(Result&&) = default; |
| Result& operator=(Result&&) = default; |
| |
| void IgnoreResult() const {} |
| |
| // Setters/getters for the final status/code value. |
| void SetExitStatusCode(StatusEnum final_status, uintptr_t reason_code) { |
| // Don't overwrite exit status codes. |
| if (final_status_ != UNSET) { |
| return; |
| } |
| final_status_ = final_status; |
| reason_code_ = reason_code; |
| } |
| |
| // Sets the stack trace. |
| // The stacktrace must be sometimes fetched before SetExitStatusCode is |
| // called, because after WIFEXITED() or WIFSIGNALED() the process is just a |
| // zombie. |
| void set_stack_trace(std::vector<std::string> value) { |
| stack_trace_ = std::move(value); |
| } |
| |
| void SetRegs(std::unique_ptr<Regs> regs) { regs_ = std::move(regs); } |
| |
| void SetSyscall(std::unique_ptr<Syscall> syscall) { |
| syscall_ = std::move(syscall); |
| } |
| |
| void SetNetworkViolation(std::string network_violation) { |
| network_violation_ = std::move(network_violation); |
| } |
| |
| StatusEnum final_status() const { return final_status_; } |
| uintptr_t reason_code() const { return reason_code_; } |
| |
| // If true, indicates that the non-OK status is transient and a retry might |
| // succeed. |
| bool IsRetryable() const { return false; } |
| |
| // Returns the current syscall architecture. |
| // Client architecture when final_status_ == VIOLATION, might be different |
| // from the host architecture (32-bit vs 64-bit syscalls). |
| sapi::cpu::Architecture GetSyscallArch() const { |
| return syscall_ ? syscall_->arch() : sapi::cpu::kUnknown; |
| } |
| |
| const std::vector<std::string>& stack_trace() const { return stack_trace_; } |
| |
| // Returns the stack trace as a space-delimited string. |
| std::string GetStackTrace() const; |
| |
| const Regs* GetRegs() const { return regs_.get(); } |
| |
| const Syscall* GetSyscall() const { return syscall_.get(); } |
| |
| const std::string& GetProgName() const { return prog_name_; } |
| |
| const std::string& GetNetworkViolation() const { return network_violation_; } |
| |
| void SetProgName(const std::string& name) { prog_name_ = name; } |
| |
| const std::string& GetProcMaps() const { return proc_maps_; } |
| |
| void SetProcMaps(const std::string& proc_maps) { proc_maps_ = proc_maps; } |
| |
| // Converts this result to a absl::Status object. The status will only be |
| // OK if the sandbox process exited normally with an exit code of 0. |
| absl::Status ToStatus() const; |
| |
| // Returns a descriptive string for final result. |
| std::string ToString() const; |
| |
| // Converts StatusEnum to a string. |
| static std::string StatusEnumToString(StatusEnum value); |
| |
| // Converts ReasonCodeEnum to a string. |
| static std::string ReasonCodeEnumToString(ReasonCodeEnum value); |
| |
| rusage* GetRUsageMonitor() { return &rusage_monitor_; } |
| |
| // Only set by the unotify monitor. |
| const std::optional<rusage>& GetRUsageSandboxee() const { |
| return rusage_sandboxee_; |
| } |
| |
| void SetRUsageSandboxee(rusage usage) { rusage_sandboxee_ = usage; } |
| |
| private: |
| // Final execution status - see 'StatusEnum' for details. |
| StatusEnum final_status_ = UNSET; |
| // Termination cause: |
| // a). process exit value if final_status_ == OK, |
| // b). terminating signal if final_status_ == SIGNALED, |
| // c). violating syscall if final_status_ == VIOLATION, |
| // unspecified for the rest of status_ values. |
| uintptr_t reason_code_ = 0; |
| // Might contain stack-trace of the process, especially if it failed with |
| // syscall violation, or was terminated by a signal. |
| std::vector<std::string> stack_trace_; |
| // Might contain the register values of the process, similar to the stack. |
| // trace |
| std::unique_ptr<Regs> regs_; |
| // Might contain violating syscall information |
| std::unique_ptr<Syscall> syscall_; |
| // Name of the process (as it can not be accessed anymore after termination). |
| std::string prog_name_; |
| // /proc/pid/maps of the main process. |
| std::string proc_maps_; |
| // IP and port if network violation occurred |
| std::string network_violation_; |
| // Final resource usage as defined in <sys/resource.h> (man getrusage), for |
| // the Monitor thread. |
| rusage rusage_monitor_; |
| // Final resource usage for the sandboxee process, only for unotify monitor. |
| std::optional<rusage> rusage_sandboxee_; |
| }; |
| |
| } // namespace sandbox2 |
| |
| #endif // SANDBOXED_API_SANDBOX2_RESULT_H_ |