1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "sandbox/win/src/crosscall_server.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <atomic>
11 #include <string>
12 #include <vector>
13
14 #include "base/logging.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "sandbox/win/src/crosscall_client.h"
17 #include "sandbox/win/src/crosscall_params.h"
18
19 // See comment in atomicops.h. This is needed any time windows.h is included
20 // after atomicops.h.
21 #undef MemoryBarrier
22
23 // This code performs the ipc message validation. Potential security flaws
24 // on the ipc are likelier to be found in this code than in the rest of
25 // the ipc code.
26
27 namespace {
28
29 // The buffer for a message must match the max channel size.
30 const size_t kMaxBufferSize = sandbox::kIPCChannelSize;
31
32 } // namespace
33
34 namespace sandbox {
35
36 // The template types are used to calculate the maximum expected size.
37 typedef ActualCallParams<0, kMaxBufferSize> ActualCP0;
38 typedef ActualCallParams<1, kMaxBufferSize> ActualCP1;
39 typedef ActualCallParams<2, kMaxBufferSize> ActualCP2;
40 typedef ActualCallParams<3, kMaxBufferSize> ActualCP3;
41 typedef ActualCallParams<4, kMaxBufferSize> ActualCP4;
42 typedef ActualCallParams<5, kMaxBufferSize> ActualCP5;
43 typedef ActualCallParams<6, kMaxBufferSize> ActualCP6;
44 typedef ActualCallParams<7, kMaxBufferSize> ActualCP7;
45 typedef ActualCallParams<8, kMaxBufferSize> ActualCP8;
46 typedef ActualCallParams<9, kMaxBufferSize> ActualCP9;
47
48 // Returns the actual size for the parameters in an IPC buffer. Returns
49 // zero if the |param_count| is zero or too big.
GetActualBufferSize(uint32_t param_count,void * buffer_base)50 uint32_t GetActualBufferSize(uint32_t param_count, void* buffer_base) {
51 // Retrieve the actual size and the maximum size of the params buffer.
52 switch (param_count) {
53 case 0:
54 return 0;
55 case 1:
56 return reinterpret_cast<ActualCP1*>(buffer_base)->GetSize();
57 case 2:
58 return reinterpret_cast<ActualCP2*>(buffer_base)->GetSize();
59 case 3:
60 return reinterpret_cast<ActualCP3*>(buffer_base)->GetSize();
61 case 4:
62 return reinterpret_cast<ActualCP4*>(buffer_base)->GetSize();
63 case 5:
64 return reinterpret_cast<ActualCP5*>(buffer_base)->GetSize();
65 case 6:
66 return reinterpret_cast<ActualCP6*>(buffer_base)->GetSize();
67 case 7:
68 return reinterpret_cast<ActualCP7*>(buffer_base)->GetSize();
69 case 8:
70 return reinterpret_cast<ActualCP8*>(buffer_base)->GetSize();
71 case 9:
72 return reinterpret_cast<ActualCP9*>(buffer_base)->GetSize();
73 default:
74 return 0;
75 }
76 }
77
78 // Returns the minimum size for the parameters in an IPC buffer. Returns
79 // zero if the |param_count| is less than zero or too big.
GetMinDeclaredActualCallParamsSize(uint32_t param_count)80 uint32_t GetMinDeclaredActualCallParamsSize(uint32_t param_count) {
81 switch (param_count) {
82 case 0:
83 return offsetof(ActualCP0, parameters_);
84 case 1:
85 return offsetof(ActualCP1, parameters_);
86 case 2:
87 return offsetof(ActualCP2, parameters_);
88 case 3:
89 return offsetof(ActualCP3, parameters_);
90 case 4:
91 return offsetof(ActualCP4, parameters_);
92 case 5:
93 return offsetof(ActualCP5, parameters_);
94 case 6:
95 return offsetof(ActualCP6, parameters_);
96 case 7:
97 return offsetof(ActualCP7, parameters_);
98 case 8:
99 return offsetof(ActualCP8, parameters_);
100 case 9:
101 return offsetof(ActualCP9, parameters_);
102 default:
103 return 0;
104 }
105 }
106
107 // Verifies that the declared sizes of an IPC buffer are within range.
IsSizeWithinRange(uint32_t buffer_size,uint32_t min_declared_size,uint32_t declared_size)108 bool IsSizeWithinRange(uint32_t buffer_size,
109 uint32_t min_declared_size,
110 uint32_t declared_size) {
111 if ((buffer_size < min_declared_size) ||
112 (sizeof(CrossCallParamsEx) > min_declared_size)) {
113 // Minimal computed size bigger than existing buffer or param_count
114 // integer overflow.
115 return false;
116 }
117
118 if ((declared_size > buffer_size) || (declared_size < min_declared_size)) {
119 // Declared size is bigger than buffer or smaller than computed size
120 // or param_count is equal to 0 or bigger than 9.
121 return false;
122 }
123
124 return true;
125 }
126
CrossCallParamsEx()127 CrossCallParamsEx::CrossCallParamsEx() : CrossCallParams(IpcTag::UNUSED, 0) {}
128
129 // We override the delete operator because the object's backing memory
130 // is hand allocated in CreateFromBuffer. We don't override the new operator
131 // because the constructors are private so there is no way to mismatch
132 // new & delete.
operator delete(void * raw_memory)133 void CrossCallParamsEx::operator delete(void* raw_memory) throw() {
134 if (!raw_memory) {
135 // C++ standard allows 'delete 0' behavior.
136 return;
137 }
138 delete[] reinterpret_cast<char*>(raw_memory);
139 }
140
141 // This function uses a SEH try block so cannot use C++ objects that
142 // have destructors or else you get Compiler Error C2712. So no DCHECKs
143 // inside this function.
CreateFromBuffer(void * buffer_base,uint32_t buffer_size,uint32_t * output_size)144 CrossCallParamsEx* CrossCallParamsEx::CreateFromBuffer(void* buffer_base,
145 uint32_t buffer_size,
146 uint32_t* output_size) {
147 // IMPORTANT: Everything inside buffer_base and derived from it such
148 // as param_count and declared_size is untrusted.
149 if (!buffer_base)
150 return nullptr;
151 if (buffer_size < sizeof(CrossCallParams))
152 return nullptr;
153 if (buffer_size > kMaxBufferSize)
154 return nullptr;
155
156 char* backing_mem = nullptr;
157 uint32_t param_count = 0;
158 uint32_t declared_size;
159 uint32_t min_declared_size;
160 CrossCallParamsEx* copied_params = nullptr;
161
162 // Touching the untrusted buffer is done under a SEH try block. This
163 // will catch memory access violations so we don't crash.
164 __try {
165 CrossCallParams* call_params =
166 reinterpret_cast<CrossCallParams*>(buffer_base);
167
168 // Check against the minimum size given the number of stated params
169 // if too small we bail out.
170 param_count = call_params->GetParamsCount();
171 min_declared_size = GetMinDeclaredActualCallParamsSize(param_count);
172
173 // Initial check for the buffer being big enough to determine the actual
174 // buffer size.
175 if (buffer_size < min_declared_size)
176 return nullptr;
177
178 // Retrieve the declared size which if it fails returns 0.
179 declared_size = GetActualBufferSize(param_count, buffer_base);
180
181 if (!IsSizeWithinRange(buffer_size, min_declared_size, declared_size))
182 return nullptr;
183
184 // Now we copy the actual amount of the message.
185 *output_size = declared_size;
186 backing_mem = new char[declared_size];
187 copied_params = reinterpret_cast<CrossCallParamsEx*>(backing_mem);
188 memcpy(backing_mem, call_params, declared_size);
189
190 // Avoid compiler optimizations across this point. Any value stored in
191 // memory should be stored for real, and values previously read from memory
192 // should be actually read.
193 std::atomic_thread_fence(std::memory_order_seq_cst);
194
195 min_declared_size = GetMinDeclaredActualCallParamsSize(param_count);
196
197 // Check that the copied buffer is still valid.
198 if (copied_params->GetParamsCount() != param_count ||
199 GetActualBufferSize(param_count, backing_mem) != declared_size ||
200 !IsSizeWithinRange(buffer_size, min_declared_size, declared_size)) {
201 delete[] backing_mem;
202 return nullptr;
203 }
204
205 } __except (EXCEPTION_EXECUTE_HANDLER) {
206 // In case of a windows exception we know it occurred while touching the
207 // untrusted buffer so we bail out as is.
208 delete[] backing_mem;
209 return nullptr;
210 }
211
212 // Here and below we're making use of uintptr_t to have well-defined integer
213 // overflow when doing pointer arithmetic.
214 auto backing_mem_ptr = reinterpret_cast<uintptr_t>(backing_mem);
215 auto last_byte = reinterpret_cast<uintptr_t>(&backing_mem[declared_size]);
216 auto first_byte =
217 reinterpret_cast<uintptr_t>(&backing_mem[min_declared_size]);
218
219 // Verify here that all and each parameters make sense. This is done in the
220 // local copy.
221 for (uint32_t ix = 0; ix != param_count; ++ix) {
222 uint32_t size = 0;
223 ArgType type;
224 auto address = reinterpret_cast<uintptr_t>(
225 copied_params->GetRawParameter(ix, &size, &type));
226 if ((!address) || // No null params.
227 (INVALID_TYPE >= type) || (LAST_TYPE <= type) || // Unknown type.
228 (address < backing_mem_ptr) || // Start cannot point before buffer.
229 (address < first_byte) || // Start cannot point too low.
230 (address > last_byte) || // Start cannot point past buffer.
231 ((address + size) < address) || // Invalid size.
232 ((address + size) > last_byte)) { // End cannot point past buffer.
233 // Malformed.
234 delete[] backing_mem;
235 return nullptr;
236 }
237 }
238 // The parameter buffer looks good.
239 return copied_params;
240 }
241
242 // Accessors to the parameters in the raw buffer.
GetRawParameter(uint32_t index,uint32_t * size,ArgType * type)243 void* CrossCallParamsEx::GetRawParameter(uint32_t index,
244 uint32_t* size,
245 ArgType* type) {
246 if (index >= GetParamsCount())
247 return nullptr;
248 // The size is always computed from the parameter minus the next
249 // parameter, this works because the message has an extra parameter slot
250 *size = param_info_[index].size_;
251 *type = param_info_[index].type_;
252
253 return param_info_[index].offset_ + reinterpret_cast<char*>(this);
254 }
255
256 // Covers common case for 32 bit integers.
GetParameter32(uint32_t index,uint32_t * param)257 bool CrossCallParamsEx::GetParameter32(uint32_t index, uint32_t* param) {
258 uint32_t size = 0;
259 ArgType type;
260 void* start = GetRawParameter(index, &size, &type);
261 if (!start || (4 != size) || (UINT32_TYPE != type))
262 return false;
263 // Copy the 4 bytes.
264 *(reinterpret_cast<uint32_t*>(param)) = *(reinterpret_cast<uint32_t*>(start));
265 return true;
266 }
267
GetParameterVoidPtr(uint32_t index,void ** param)268 bool CrossCallParamsEx::GetParameterVoidPtr(uint32_t index, void** param) {
269 uint32_t size = 0;
270 ArgType type;
271 void* start = GetRawParameter(index, &size, &type);
272 if (!start || (sizeof(void*) != size) || (VOIDPTR_TYPE != type))
273 return false;
274 *param = *(reinterpret_cast<void**>(start));
275 return true;
276 }
277
278 // Covers the common case of reading a string. Note that the string is not
279 // scanned for invalid characters.
GetParameterStr(uint32_t index,std::wstring * string)280 bool CrossCallParamsEx::GetParameterStr(uint32_t index, std::wstring* string) {
281 DCHECK(string->empty());
282 uint32_t size = 0;
283 ArgType type;
284 void* start = GetRawParameter(index, &size, &type);
285 if (WCHAR_TYPE != type)
286 return false;
287
288 // Check if this is an empty string.
289 if (size == 0) {
290 *string = std::wstring();
291 return true;
292 }
293
294 if (!start || ((size % sizeof(wchar_t)) != 0))
295 return false;
296
297 string->assign(reinterpret_cast<const wchar_t*>(start),
298 size / sizeof(wchar_t));
299 return true;
300 }
301
GetParameterPtr(uint32_t index,uint32_t expected_size,void ** pointer)302 bool CrossCallParamsEx::GetParameterPtr(uint32_t index,
303 uint32_t expected_size,
304 void** pointer) {
305 uint32_t size = 0;
306 ArgType type;
307 void* start = GetRawParameter(index, &size, &type);
308
309 if ((size != expected_size) || (INOUTPTR_TYPE != type && INPTR_TYPE != type))
310 return false;
311
312 if (!start)
313 return false;
314
315 *pointer = start;
316 return true;
317 }
318
SetCallError(ResultCode error,CrossCallReturn * call_return)319 void SetCallError(ResultCode error, CrossCallReturn* call_return) {
320 call_return->call_outcome = error;
321 call_return->extended_count = 0;
322 }
323
SetCallSuccess(CrossCallReturn * call_return)324 void SetCallSuccess(CrossCallReturn* call_return) {
325 call_return->call_outcome = SBOX_ALL_OK;
326 }
327
OnMessageReady(IPCParams * ipc,CallbackGeneric * callback)328 Dispatcher* Dispatcher::OnMessageReady(IPCParams* ipc,
329 CallbackGeneric* callback) {
330 DCHECK(callback);
331 std::vector<IPCCall>::iterator it = ipc_calls_.begin();
332 for (; it != ipc_calls_.end(); ++it) {
333 if (it->params.Matches(ipc)) {
334 *callback = it->callback;
335 return this;
336 }
337 }
338 return nullptr;
339 }
340
Dispatcher()341 Dispatcher::Dispatcher() {}
342
~Dispatcher()343 Dispatcher::~Dispatcher() {}
344
345 } // namespace sandbox
346