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