• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef SANDBOXED_API_SANDBOX2_SYSCALL_DEFS_H_
2 #define SANDBOXED_API_SANDBOX2_SYSCALL_DEFS_H_
3 
4 #include <sys/types.h>
5 
6 #include <array>
7 #include <cstddef>
8 #include <cstdint>
9 #include <optional>
10 #include <string>
11 #include <type_traits>
12 #include <vector>
13 
14 #include "absl/status/status.h"
15 #include "absl/status/statusor.h"
16 #include "absl/strings/str_format.h"
17 #include "absl/strings/string_view.h"
18 #include "absl/types/span.h"
19 #include "sandboxed_api/config.h"
20 #include "sandboxed_api/sandbox2/util.h"
21 #include "sandboxed_api/util/status_macros.h"
22 
23 namespace sandbox2 {
24 namespace syscalls {
25 
26 constexpr int kMaxArgs = 6;
27 
28 enum ArgType {
29   kPath,
30   kString,
31   kGen,
32   kStruct,
33   kPtr,
34   kArray,
35   kInt,
36   kFlags,
37   kResource,
38   kPid,
39   kSignal,
40   kIpcResource,
41   kSharedAddress,
42   kGid,
43   kUid,
44   // These kLenN types indicate that the argument is a length, and which
45   // other argument it applies to. I.e., if parameter 3 is type kPollFdArray,
46   // and parameter 4 has the length, then parameter 4 is of type kLen3.
47   kLen0,
48   kLen1,
49   kLen2,
50   kLen3,
51   kLen4,
52   kLen5,
53   kAddressFamily,
54   kGidArray,
55   kPollFdArray,
56   kSockaddr,
57 };
58 
ArgTypeToString(ArgType type)59 constexpr absl::string_view ArgTypeToString(ArgType type) {
60   switch (type) {
61     case kPath:
62       return "path";
63     case kString:
64       return "string";
65     case kGen:
66       return "generic type";
67     case kStruct:
68       return "struct";
69     case kPtr:
70       return "pointer";
71     case kArray:
72       return "array";
73     case kInt:
74       return "int";
75     case kFlags:
76       return "flags";
77     case kResource:
78       return "resource";
79     case kPid:
80       return "pid";
81     case kSignal:
82       return "signal";
83     case kIpcResource:
84       return "ipc resource";
85     case kSharedAddress:
86       return "shared address";
87     case kGid:
88       return "gid";
89     case kUid:
90       return "uid";
91     case kLen0:
92       return "length of parameter 0";
93     case kLen1:
94       return "length of parameter 1";
95     case kLen2:
96       return "length of parameter 2";
97     case kLen3:
98       return "length of parameter 3";
99     case kLen4:
100       return "length of parameter 4";
101     case kLen5:
102       return "length of parameter 5";
103     case kAddressFamily:
104       return "address family";
105     case kGidArray:
106       return "gid array";
107     case kPollFdArray:
108       return "poll fd array";
109     case kSockaddr:
110       return "sockaddr struct";
111     default:
112       return "invalid type";
113   }
114 }
115 
116 class ArgData {
117  public:
118   template <typename T>
119   struct StructArray {
120     std::vector<T> array;
121     bool truncated;
122   };
123 
124   ArgData(syscalls::ArgType type, pid_t pid, uint64_t value,
125           std::optional<uint64_t> length = std::nullopt)
type_(type)126       : type_(type), pid_(pid), value_(value), length_(length) {}
127 
type()128   ArgType type() const { return type_; }
pid()129   pid_t pid() const { return pid_; }
value()130   uint64_t value() const { return value_; }
length()131   std::optional<uint64_t> length() const { return length_; }
132 
133   std::string GetDescription() const;
134 
ReadAsString()135   absl::StatusOr<std::string> ReadAsString() const {
136     return util::ReadCPathFromPid(pid_, value_);
137   }
138 
139   template <typename T>
ReadAsStruct()140   absl::StatusOr<T> ReadAsStruct() const {
141     if (length_.has_value() && *length_ < sizeof(T)) {
142       return absl::InternalError(absl::StrFormat(
143           "specified length [%llu] is not enough for to sizeof(%s) == %llu",
144           *length_, "(struct)", sizeof(T))); // ANDROID: typeid removed, no rtti
145     }
146     SAPI_ASSIGN_OR_RETURN(std::vector<uint8_t> b,
147                           util::ReadBytesFromPid(pid_, value_, sizeof(T)));
148     return BytesToStruct<T>(b);
149   }
150 
151   template <typename T>
ReadAsStructArray()152   absl::StatusOr<StructArray<T>> ReadAsStructArray() const {
153     static uint64_t kMaxAllowedBytes = 1 << 20;  // 1MB
154 
155     if (!length_.has_value()) {
156       return absl::InternalError("length is not set");
157     }
158 
159     bool truncated = false;
160     uint64_t length = *length_ * sizeof(T);
161     if (length > kMaxAllowedBytes) {
162       truncated = true;
163       length = (kMaxAllowedBytes / sizeof(T)) * sizeof(T);
164     }
165 
166     SAPI_ASSIGN_OR_RETURN(std::vector<uint8_t> b,
167                           util::ReadBytesFromPid(pid_, value_, length));
168     absl::Span<const uint8_t> bytes = absl::MakeSpan(b);
169     if (bytes.size() < length) {
170       return absl::InternalError("could not read full struct array");
171     }
172     std::vector<T> ret;
173     for (size_t i = 0; i < bytes.size(); i += sizeof(T)) {
174       SAPI_ASSIGN_OR_RETURN(T t, BytesToStruct<T>(bytes.subspan(i, sizeof(T))));
175       ret.push_back(t);
176     }
177 
178     return StructArray<T>{std::move(ret), truncated};
179   }
180 
181  private:
182   template <typename T>
BytesToStruct(absl::Span<const uint8_t> bytes)183   static absl::StatusOr<T> BytesToStruct(absl::Span<const uint8_t> bytes) {
184     static_assert(std::is_pod<T>(), "Can only cast bytes to POD structs");
185     if (bytes.size() < sizeof(T)) {
186       return absl::InternalError(absl::StrFormat(
187           "bytes size [%llu] is not equal to sizeof(%s) == %llu", bytes.size(),
188           "struct", sizeof(T))); // ANDROID: typeid removed, no rtti
189     }
190     T t;
191     memcpy(&t, bytes.data(), sizeof(T));
192     return t;
193   }
194 
195   absl::StatusOr<std::string> GetDescriptionImpl() const;
196 
197   syscalls::ArgType type_;
198   pid_t pid_;
199   uint64_t value_;
200   std::optional<uint64_t> length_;
201 };
202 
203 }  // namespace syscalls
204 
205 class SyscallTable {
206  public:
207   // Single syscall definition
208   struct Entry {
209     // Returns the number of arguments which given syscall takes.
GetNumArgsEntry210     int GetNumArgs() const {
211       if (num_args < 0 || num_args > syscalls::kMaxArgs) {
212         return syscalls::kMaxArgs;
213       }
214       return num_args;
215     }
216 
BySyscallNrEntry217     static constexpr bool BySyscallNr(const SyscallTable::Entry& a,
218                                       const SyscallTable::Entry& b) {
219       return a.nr < b.nr;
220     }
221 
222     int nr;
223     absl::string_view name;
224     int num_args;
225     std::array<syscalls::ArgType, syscalls::kMaxArgs> arg_types;
226   };
227 
228   // Returns the syscall table for the architecture.
229   static SyscallTable get(sapi::cpu::Architecture arch);
230 
size()231   int size() { return data_.size(); }
232 
233   absl::string_view GetName(int syscall) const;
234 
235   std::vector<syscalls::ArgData> GetArgumentsData(int syscall,
236                                                   const uint64_t values[],
237                                                   pid_t pid) const;
238 
239   std::vector<std::string> GetArgumentsDescription(int syscall,
240                                                    const uint64_t values[],
241                                                    pid_t pid) const;
242 
243   absl::StatusOr<Entry> GetEntry(int syscall) const;
244   // Returns the first entry matching the provided name.
245   absl::StatusOr<Entry> GetEntry(absl::string_view name) const;
246 
GetEntries()247   absl::Span<const Entry> GetEntries() const { return data_; }
248 
249  private:
250   constexpr SyscallTable() = default;
SyscallTable(absl::Span<const Entry> data)251   explicit constexpr SyscallTable(absl::Span<const Entry> data) : data_(data) {}
252 
253   const absl::Span<const Entry> data_;
254 };
255 
256 }  // namespace sandbox2
257 
258 #endif  // SANDBOXED_API_SANDBOX2_SYSCALL_DEFS_H_
259