1 // Copyright 2019 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // This file defines the sandbox2::Result class which will in future handle both 16 // exit status of the sandboxed process, and possible results returned from it. 17 18 #ifndef SANDBOXED_API_SANDBOX2_RESULT_H_ 19 #define SANDBOXED_API_SANDBOX2_RESULT_H_ 20 21 #include <sys/resource.h> 22 23 #include <cstdint> 24 #include <memory> 25 #include <optional> 26 #include <string> 27 #include <utility> 28 #include <vector> 29 30 #include "absl/status/status.h" 31 #include "sandboxed_api/config.h" 32 #include "sandboxed_api/sandbox2/regs.h" 33 #include "sandboxed_api/sandbox2/syscall.h" 34 35 namespace sandbox2 { 36 37 class Result { 38 public: 39 // Final execution status. 40 enum StatusEnum { 41 // Not set yet 42 UNSET = 0, 43 // OK 44 OK, 45 // Sandbox initialization failure 46 SETUP_ERROR, 47 // Syscall violation 48 VIOLATION, 49 // Process terminated with a signal 50 SIGNALED, 51 // Process terminated with a timeout 52 TIMEOUT, 53 // Killed externally by user 54 EXTERNAL_KILL, 55 // Most likely ptrace() API failed 56 INTERNAL_ERROR, 57 }; 58 59 // Detailed reason codes 60 enum ReasonCodeEnum { 61 // Codes used by status=`SETUP_ERROR`: 62 UNSUPPORTED_ARCH = 0, 63 FAILED_TIMERS, 64 FAILED_SIGNALS, 65 FAILED_SUBPROCESS, 66 FAILED_NOTIFY, 67 FAILED_CONNECTION, 68 FAILED_WAIT, 69 FAILED_NAMESPACES, 70 FAILED_PTRACE, 71 FAILED_IPC, 72 FAILED_LIMITS, 73 FAILED_CWD, 74 FAILED_POLICY, 75 76 // Codes used by status=`INTERNAL_ERROR`: 77 FAILED_STORE, 78 FAILED_FETCH, 79 FAILED_GETEVENT, 80 FAILED_MONITOR, 81 FAILED_KILL, 82 FAILED_INTERRUPT, 83 FAILED_CHILD, 84 FAILED_INSPECT, 85 86 // TODO(wiktorg) not used currently (syscall number stored insted) - need to 87 // fix clients first 88 // Codes used by status=`VIOLATION`: 89 VIOLATION_SYSCALL, 90 VIOLATION_ARCH, 91 VIOLATION_NETWORK = 0x10000000, // TODO(eternalred): temporary value, needs 92 // to be big until it's fixed 93 }; 94 95 Result() = default; Result(const Result & other)96 Result(const Result& other) { *this = other; } 97 Result& operator=(const Result& other); 98 Result(Result&&) = default; 99 Result& operator=(Result&&) = default; 100 IgnoreResult()101 void IgnoreResult() const {} 102 103 // Setters/getters for the final status/code value. SetExitStatusCode(StatusEnum final_status,uintptr_t reason_code)104 void SetExitStatusCode(StatusEnum final_status, uintptr_t reason_code) { 105 // Don't overwrite exit status codes. 106 if (final_status_ != UNSET) { 107 return; 108 } 109 final_status_ = final_status; 110 reason_code_ = reason_code; 111 } 112 113 // Sets the stack trace. 114 // The stacktrace must be sometimes fetched before SetExitStatusCode is 115 // called, because after WIFEXITED() or WIFSIGNALED() the process is just a 116 // zombie. set_stack_trace(std::vector<std::string> value)117 void set_stack_trace(std::vector<std::string> value) { 118 stack_trace_ = std::move(value); 119 } 120 SetRegs(std::unique_ptr<Regs> regs)121 void SetRegs(std::unique_ptr<Regs> regs) { regs_ = std::move(regs); } 122 SetSyscall(std::unique_ptr<Syscall> syscall)123 void SetSyscall(std::unique_ptr<Syscall> syscall) { 124 syscall_ = std::move(syscall); 125 } 126 SetNetworkViolation(std::string network_violation)127 void SetNetworkViolation(std::string network_violation) { 128 network_violation_ = std::move(network_violation); 129 } 130 final_status()131 StatusEnum final_status() const { return final_status_; } reason_code()132 uintptr_t reason_code() const { return reason_code_; } 133 134 // If true, indicates that the non-OK status is transient and a retry might 135 // succeed. IsRetryable()136 bool IsRetryable() const { return false; } 137 138 // Returns the current syscall architecture. 139 // Client architecture when final_status_ == VIOLATION, might be different 140 // from the host architecture (32-bit vs 64-bit syscalls). GetSyscallArch()141 sapi::cpu::Architecture GetSyscallArch() const { 142 return syscall_ ? syscall_->arch() : sapi::cpu::kUnknown; 143 } 144 stack_trace()145 const std::vector<std::string>& stack_trace() const { return stack_trace_; } 146 147 // Returns the stack trace as a space-delimited string. 148 std::string GetStackTrace() const; 149 GetRegs()150 const Regs* GetRegs() const { return regs_.get(); } 151 GetSyscall()152 const Syscall* GetSyscall() const { return syscall_.get(); } 153 GetProgName()154 const std::string& GetProgName() const { return prog_name_; } 155 GetNetworkViolation()156 const std::string& GetNetworkViolation() const { return network_violation_; } 157 SetProgName(const std::string & name)158 void SetProgName(const std::string& name) { prog_name_ = name; } 159 GetProcMaps()160 const std::string& GetProcMaps() const { return proc_maps_; } 161 SetProcMaps(const std::string & proc_maps)162 void SetProcMaps(const std::string& proc_maps) { proc_maps_ = proc_maps; } 163 164 // Converts this result to a absl::Status object. The status will only be 165 // OK if the sandbox process exited normally with an exit code of 0. 166 absl::Status ToStatus() const; 167 168 // Returns a descriptive string for final result. 169 std::string ToString() const; 170 171 // Converts StatusEnum to a string. 172 static std::string StatusEnumToString(StatusEnum value); 173 174 // Converts ReasonCodeEnum to a string. 175 static std::string ReasonCodeEnumToString(ReasonCodeEnum value); 176 GetRUsageMonitor()177 rusage* GetRUsageMonitor() { return &rusage_monitor_; } 178 179 // Only set by the unotify monitor. GetRUsageSandboxee()180 const std::optional<rusage>& GetRUsageSandboxee() const { 181 return rusage_sandboxee_; 182 } 183 SetRUsageSandboxee(rusage usage)184 void SetRUsageSandboxee(rusage usage) { rusage_sandboxee_ = usage; } 185 186 private: 187 // Final execution status - see 'StatusEnum' for details. 188 StatusEnum final_status_ = UNSET; 189 // Termination cause: 190 // a). process exit value if final_status_ == OK, 191 // b). terminating signal if final_status_ == SIGNALED, 192 // c). violating syscall if final_status_ == VIOLATION, 193 // unspecified for the rest of status_ values. 194 uintptr_t reason_code_ = 0; 195 // Might contain stack-trace of the process, especially if it failed with 196 // syscall violation, or was terminated by a signal. 197 std::vector<std::string> stack_trace_; 198 // Might contain the register values of the process, similar to the stack. 199 // trace 200 std::unique_ptr<Regs> regs_; 201 // Might contain violating syscall information 202 std::unique_ptr<Syscall> syscall_; 203 // Name of the process (as it can not be accessed anymore after termination). 204 std::string prog_name_; 205 // /proc/pid/maps of the main process. 206 std::string proc_maps_; 207 // IP and port if network violation occurred 208 std::string network_violation_; 209 // Final resource usage as defined in <sys/resource.h> (man getrusage), for 210 // the Monitor thread. 211 rusage rusage_monitor_; 212 // Final resource usage for the sandboxee process, only for unotify monitor. 213 std::optional<rusage> rusage_sandboxee_; 214 }; 215 216 } // namespace sandbox2 217 218 #endif // SANDBOXED_API_SANDBOX2_RESULT_H_ 219