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