Add ICU message format support
[chromium-blink-merge.git] / sandbox / win / src / crosscall_server.cc
blob6f8bd744f20ead53a84881fb1b6bb7525717ab82
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.
5 #include "sandbox/win/src/crosscall_server.h"
7 #include <string>
8 #include <vector>
10 #include "sandbox/win/src/crosscall_params.h"
11 #include "sandbox/win/src/crosscall_client.h"
12 #include "base/logging.h"
14 // This code performs the ipc message validation. Potential security flaws
15 // on the ipc are likelier to be found in this code than in the rest of
16 // the ipc code.
18 namespace {
20 // The buffer for a message must match the max channel size.
21 const size_t kMaxBufferSize = sandbox::kIPCChannelSize;
25 namespace sandbox {
27 // Returns the actual size for the parameters in an IPC buffer. Returns
28 // zero if the |param_count| is zero or too big.
29 uint32 GetActualBufferSize(uint32 param_count, void* buffer_base) {
30 // The template types are used to calculate the maximum expected size.
31 typedef ActualCallParams<1, kMaxBufferSize> ActualCP1;
32 typedef ActualCallParams<2, kMaxBufferSize> ActualCP2;
33 typedef ActualCallParams<3, kMaxBufferSize> ActualCP3;
34 typedef ActualCallParams<4, kMaxBufferSize> ActualCP4;
35 typedef ActualCallParams<5, kMaxBufferSize> ActualCP5;
36 typedef ActualCallParams<6, kMaxBufferSize> ActualCP6;
37 typedef ActualCallParams<7, kMaxBufferSize> ActualCP7;
38 typedef ActualCallParams<8, kMaxBufferSize> ActualCP8;
39 typedef ActualCallParams<9, kMaxBufferSize> ActualCP9;
41 // Retrieve the actual size and the maximum size of the params buffer.
42 switch (param_count) {
43 case 0:
44 return 0;
45 case 1:
46 return reinterpret_cast<ActualCP1*>(buffer_base)->GetSize();
47 case 2:
48 return reinterpret_cast<ActualCP2*>(buffer_base)->GetSize();
49 case 3:
50 return reinterpret_cast<ActualCP3*>(buffer_base)->GetSize();
51 case 4:
52 return reinterpret_cast<ActualCP4*>(buffer_base)->GetSize();
53 case 5:
54 return reinterpret_cast<ActualCP5*>(buffer_base)->GetSize();
55 case 6:
56 return reinterpret_cast<ActualCP6*>(buffer_base)->GetSize();
57 case 7:
58 return reinterpret_cast<ActualCP7*>(buffer_base)->GetSize();
59 case 8:
60 return reinterpret_cast<ActualCP8*>(buffer_base)->GetSize();
61 case 9:
62 return reinterpret_cast<ActualCP9*>(buffer_base)->GetSize();
63 default:
64 return 0;
68 // Verifies that the declared sizes of an IPC buffer are within range.
69 bool IsSizeWithinRange(uint32 buffer_size, uint32 min_declared_size,
70 uint32 declared_size) {
71 if ((buffer_size < min_declared_size) ||
72 (sizeof(CrossCallParamsEx) > min_declared_size)) {
73 // Minimal computed size bigger than existing buffer or param_count
74 // integer overflow.
75 return false;
78 if ((declared_size > buffer_size) || (declared_size < min_declared_size)) {
79 // Declared size is bigger than buffer or smaller than computed size
80 // or param_count is equal to 0 or bigger than 9.
81 return false;
84 return true;
87 CrossCallParamsEx::CrossCallParamsEx()
88 :CrossCallParams(0, 0) {
91 // We override the delete operator because the object's backing memory
92 // is hand allocated in CreateFromBuffer. We don't override the new operator
93 // because the constructors are private so there is no way to mismatch
94 // new & delete.
95 void CrossCallParamsEx::operator delete(void* raw_memory) throw() {
96 if (NULL == raw_memory) {
97 // C++ standard allows 'delete 0' behavior.
98 return;
100 delete[] reinterpret_cast<char*>(raw_memory);
103 // This function uses a SEH try block so cannot use C++ objects that
104 // have destructors or else you get Compiler Error C2712. So no DCHECKs
105 // inside this function.
106 CrossCallParamsEx* CrossCallParamsEx::CreateFromBuffer(void* buffer_base,
107 uint32 buffer_size,
108 uint32* output_size) {
109 // IMPORTANT: Everything inside buffer_base and derived from it such
110 // as param_count and declared_size is untrusted.
111 if (NULL == buffer_base) {
112 return NULL;
114 if (buffer_size < sizeof(CrossCallParams)) {
115 return NULL;
117 if (buffer_size > kMaxBufferSize) {
118 return NULL;
121 char* backing_mem = NULL;
122 uint32 param_count = 0;
123 uint32 declared_size;
124 uint32 min_declared_size;
125 CrossCallParamsEx* copied_params = NULL;
127 // Touching the untrusted buffer is done under a SEH try block. This
128 // will catch memory access violations so we don't crash.
129 __try {
130 CrossCallParams* call_params =
131 reinterpret_cast<CrossCallParams*>(buffer_base);
133 // Check against the minimum size given the number of stated params
134 // if too small we bail out.
135 param_count = call_params->GetParamsCount();
136 min_declared_size = sizeof(CrossCallParams) +
137 ((param_count + 1) * sizeof(ParamInfo));
139 // Retrieve the declared size which if it fails returns 0.
140 declared_size = GetActualBufferSize(param_count, buffer_base);
142 if (!IsSizeWithinRange(buffer_size, min_declared_size, declared_size))
143 return NULL;
145 // Now we copy the actual amount of the message.
146 *output_size = declared_size;
147 backing_mem = new char[declared_size];
148 copied_params = reinterpret_cast<CrossCallParamsEx*>(backing_mem);
149 memcpy(backing_mem, call_params, declared_size);
151 // Avoid compiler optimizations across this point. Any value stored in
152 // memory should be stored for real, and values previously read from memory
153 // should be actually read.
154 _ReadWriteBarrier();
156 min_declared_size = sizeof(CrossCallParams) +
157 ((param_count + 1) * sizeof(ParamInfo));
159 // Check that the copied buffer is still valid.
160 if (copied_params->GetParamsCount() != param_count ||
161 GetActualBufferSize(param_count, backing_mem) != declared_size ||
162 !IsSizeWithinRange(buffer_size, min_declared_size, declared_size)) {
163 delete [] backing_mem;
164 return NULL;
167 } __except(EXCEPTION_EXECUTE_HANDLER) {
168 // In case of a windows exception we know it occurred while touching the
169 // untrusted buffer so we bail out as is.
170 delete [] backing_mem;
171 return NULL;
174 const char* last_byte = &backing_mem[declared_size];
175 const char* first_byte = &backing_mem[min_declared_size];
177 // Verify here that all and each parameters make sense. This is done in the
178 // local copy.
179 for (uint32 ix =0; ix != param_count; ++ix) {
180 uint32 size = 0;
181 ArgType type;
182 char* address = reinterpret_cast<char*>(
183 copied_params->GetRawParameter(ix, &size, &type));
184 if ((NULL == address) || // No null params.
185 (INVALID_TYPE >= type) || (LAST_TYPE <= type) || // Unknown type.
186 (address < backing_mem) || // Start cannot point before buffer.
187 (address < first_byte) || // Start cannot point too low.
188 (address > last_byte) || // Start cannot point past buffer.
189 ((address + size) < address) || // Invalid size.
190 ((address + size) > last_byte)) { // End cannot point past buffer.
191 // Malformed.
192 delete[] backing_mem;
193 return NULL;
196 // The parameter buffer looks good.
197 return copied_params;
200 // Accessors to the parameters in the raw buffer.
201 void* CrossCallParamsEx::GetRawParameter(uint32 index, uint32* size,
202 ArgType* type) {
203 if (index >= GetParamsCount()) {
204 return NULL;
206 // The size is always computed from the parameter minus the next
207 // parameter, this works because the message has an extra parameter slot
208 *size = param_info_[index].size_;
209 *type = param_info_[index].type_;
211 return param_info_[index].offset_ + reinterpret_cast<char*>(this);
214 // Covers common case for 32 bit integers.
215 bool CrossCallParamsEx::GetParameter32(uint32 index, uint32* param) {
216 uint32 size = 0;
217 ArgType type;
218 void* start = GetRawParameter(index, &size, &type);
219 if ((NULL == start) || (4 != size) || (UINT32_TYPE != type)) {
220 return false;
222 // Copy the 4 bytes.
223 *(reinterpret_cast<uint32*>(param)) = *(reinterpret_cast<uint32*>(start));
224 return true;
227 bool CrossCallParamsEx::GetParameterVoidPtr(uint32 index, void** param) {
228 uint32 size = 0;
229 ArgType type;
230 void* start = GetRawParameter(index, &size, &type);
231 if ((NULL == start) || (sizeof(void*) != size) || (VOIDPTR_TYPE != type)) {
232 return false;
234 *param = *(reinterpret_cast<void**>(start));
235 return true;
238 // Covers the common case of reading a string. Note that the string is not
239 // scanned for invalid characters.
240 bool CrossCallParamsEx::GetParameterStr(uint32 index, base::string16* string) {
241 uint32 size = 0;
242 ArgType type;
243 void* start = GetRawParameter(index, &size, &type);
244 if (WCHAR_TYPE != type) {
245 return false;
248 // Check if this is an empty string.
249 if (size == 0) {
250 *string = L"";
251 return true;
254 if ((NULL == start) || ((size % sizeof(wchar_t)) != 0)) {
255 return false;
257 string->append(reinterpret_cast<wchar_t*>(start), size/(sizeof(wchar_t)));
258 return true;
261 bool CrossCallParamsEx::GetParameterPtr(uint32 index, uint32 expected_size,
262 void** pointer) {
263 uint32 size = 0;
264 ArgType type;
265 void* start = GetRawParameter(index, &size, &type);
267 if ((size != expected_size) || (INOUTPTR_TYPE != type)) {
268 return false;
271 if (NULL == start) {
272 return false;
275 *pointer = start;
276 return true;
279 void SetCallError(ResultCode error, CrossCallReturn* call_return) {
280 call_return->call_outcome = error;
281 call_return->extended_count = 0;
284 void SetCallSuccess(CrossCallReturn* call_return) {
285 call_return->call_outcome = SBOX_ALL_OK;
288 Dispatcher* Dispatcher::OnMessageReady(IPCParams* ipc,
289 CallbackGeneric* callback) {
290 DCHECK(callback);
291 std::vector<IPCCall>::iterator it = ipc_calls_.begin();
292 for (; it != ipc_calls_.end(); ++it) {
293 if (it->params.Matches(ipc)) {
294 *callback = it->callback;
295 return this;
298 return NULL;
301 Dispatcher::Dispatcher() {
304 Dispatcher::~Dispatcher() {
307 } // namespace sandbox