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