ash: Extend launcher first button to include leading inset.
[chromium-blink-merge.git] / sandbox / src / crosscall_server.cc
blobf40b6778af64cd3a086624614e9ca965f015e158
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 <string>
6 #include <vector>
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"
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.
17 namespace {
19 // The buffer for a message must match the max channel size.
20 const size_t kMaxBufferSize = sandbox::kIPCChannelSize;
24 namespace sandbox {
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;
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;
68 CrossCallParamsEx::CrossCallParamsEx()
69 :CrossCallParams(0, 0) {
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;
81 delete[] reinterpret_cast<char*>(raw_memory);
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;
95 if (buffer_size < sizeof(CrossCallParams)) {
96 return NULL;
98 if (buffer_size > kMaxBufferSize) {
99 return NULL;
102 char* backing_mem = NULL;
103 uint32 param_count = 0;
104 uint32 declared_size;
105 uint32 min_declared_size;
106 CrossCallParamsEx* copied_params = NULL;
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);
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));
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;
127 // Retrieve the declared size which if it fails returns 0.
128 declared_size = GetActualBufferSize(param_count, buffer_base);
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;
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);
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;
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;
156 const char* last_byte = &backing_mem[declared_size];
157 const char* first_byte = &backing_mem[min_declared_size];
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;
178 // The parameter buffer looks good.
179 return copied_params;
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;
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_;
193 return param_info_[index].offset_ + reinterpret_cast<char*>(this);
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;
204 // Copy the 4 bytes.
205 *(reinterpret_cast<uint32*>(param)) = *(reinterpret_cast<uint32*>(start));
206 return true;
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;
216 *param = *(reinterpret_cast<void**>(start));
217 return true;
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;
230 // Check if this is an empty string.
231 if (size == 0) {
232 *string = L"";
233 return true;
236 if ((NULL == start) || ((size % sizeof(wchar_t)) != 0)) {
237 return false;
239 string->append(reinterpret_cast<wchar_t*>(start), size/(sizeof(wchar_t)));
240 return true;
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);
249 if ((size != expected_size) || (INOUTPTR_TYPE != type)) {
250 return false;
253 if (NULL == start) {
254 return false;
257 *pointer = start;
258 return true;
261 void SetCallError(ResultCode error, CrossCallReturn* call_return) {
262 call_return->call_outcome = error;
263 call_return->extended_count = 0;
266 void SetCallSuccess(CrossCallReturn* call_return) {
267 call_return->call_outcome = SBOX_ALL_OK;
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;
280 return NULL;
283 } // namespace sandbox