| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "sandbox/win/src/crosscall_server.h" | 5 #include "sandbox/win/src/crosscall_server.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "sandbox/win/src/crosscall_params.h" | 10 #include "sandbox/win/src/crosscall_params.h" |
| 11 #include "sandbox/win/src/crosscall_client.h" | 11 #include "sandbox/win/src/crosscall_client.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 | 13 |
| 14 // This code performs the ipc message validation. Potential security flaws | 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 | 15 // on the ipc are likelier to be found in this code than in the rest of |
| 16 // the ipc code. | 16 // the ipc code. |
| 17 | 17 |
| 18 namespace { | 18 namespace { |
| 19 | 19 |
| 20 // The buffer for a message must match the max channel size. | 20 // The buffer for a message must match the max channel size. |
| 21 const size_t kMaxBufferSize = sandbox::kIPCChannelSize; | 21 const size_t kMaxBufferSize = sandbox::kIPCChannelSize; |
| 22 | 22 |
| 23 } | 23 } |
| 24 | 24 |
| 25 namespace sandbox { | 25 namespace sandbox { |
| 26 | 26 |
| 27 // Returns the actual size for the parameters in an IPC buffer. Returns | 27 // Returns the actual size for the parameters in an IPC buffer. Returns |
| 28 // zero if the |param_count| is zero or too big. | 28 // zero if the |param_count| is zero or too big. |
| 29 uint32 GetActualBufferSize(uint32 param_count, void* buffer_base) { | 29 uint32_t GetActualBufferSize(uint32_t param_count, void* buffer_base) { |
| 30 // The template types are used to calculate the maximum expected size. | 30 // The template types are used to calculate the maximum expected size. |
| 31 typedef ActualCallParams<1, kMaxBufferSize> ActualCP1; | 31 typedef ActualCallParams<1, kMaxBufferSize> ActualCP1; |
| 32 typedef ActualCallParams<2, kMaxBufferSize> ActualCP2; | 32 typedef ActualCallParams<2, kMaxBufferSize> ActualCP2; |
| 33 typedef ActualCallParams<3, kMaxBufferSize> ActualCP3; | 33 typedef ActualCallParams<3, kMaxBufferSize> ActualCP3; |
| 34 typedef ActualCallParams<4, kMaxBufferSize> ActualCP4; | 34 typedef ActualCallParams<4, kMaxBufferSize> ActualCP4; |
| 35 typedef ActualCallParams<5, kMaxBufferSize> ActualCP5; | 35 typedef ActualCallParams<5, kMaxBufferSize> ActualCP5; |
| 36 typedef ActualCallParams<6, kMaxBufferSize> ActualCP6; | 36 typedef ActualCallParams<6, kMaxBufferSize> ActualCP6; |
| 37 typedef ActualCallParams<7, kMaxBufferSize> ActualCP7; | 37 typedef ActualCallParams<7, kMaxBufferSize> ActualCP7; |
| 38 typedef ActualCallParams<8, kMaxBufferSize> ActualCP8; | 38 typedef ActualCallParams<8, kMaxBufferSize> ActualCP8; |
| 39 typedef ActualCallParams<9, kMaxBufferSize> ActualCP9; | 39 typedef ActualCallParams<9, kMaxBufferSize> ActualCP9; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 59 case 8: | 59 case 8: |
| 60 return reinterpret_cast<ActualCP8*>(buffer_base)->GetSize(); | 60 return reinterpret_cast<ActualCP8*>(buffer_base)->GetSize(); |
| 61 case 9: | 61 case 9: |
| 62 return reinterpret_cast<ActualCP9*>(buffer_base)->GetSize(); | 62 return reinterpret_cast<ActualCP9*>(buffer_base)->GetSize(); |
| 63 default: | 63 default: |
| 64 return 0; | 64 return 0; |
| 65 } | 65 } |
| 66 } | 66 } |
| 67 | 67 |
| 68 // Verifies that the declared sizes of an IPC buffer are within range. | 68 // Verifies that the declared sizes of an IPC buffer are within range. |
| 69 bool IsSizeWithinRange(uint32 buffer_size, uint32 min_declared_size, | 69 bool IsSizeWithinRange(uint32_t buffer_size, |
| 70 uint32 declared_size) { | 70 uint32_t min_declared_size, |
| 71 uint32_t declared_size) { |
| 71 if ((buffer_size < min_declared_size) || | 72 if ((buffer_size < min_declared_size) || |
| 72 (sizeof(CrossCallParamsEx) > min_declared_size)) { | 73 (sizeof(CrossCallParamsEx) > min_declared_size)) { |
| 73 // Minimal computed size bigger than existing buffer or param_count | 74 // Minimal computed size bigger than existing buffer or param_count |
| 74 // integer overflow. | 75 // integer overflow. |
| 75 return false; | 76 return false; |
| 76 } | 77 } |
| 77 | 78 |
| 78 if ((declared_size > buffer_size) || (declared_size < min_declared_size)) { | 79 if ((declared_size > buffer_size) || (declared_size < min_declared_size)) { |
| 79 // Declared size is bigger than buffer or smaller than computed size | 80 // Declared size is bigger than buffer or smaller than computed size |
| 80 // or param_count is equal to 0 or bigger than 9. | 81 // or param_count is equal to 0 or bigger than 9. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 97 // C++ standard allows 'delete 0' behavior. | 98 // C++ standard allows 'delete 0' behavior. |
| 98 return; | 99 return; |
| 99 } | 100 } |
| 100 delete[] reinterpret_cast<char*>(raw_memory); | 101 delete[] reinterpret_cast<char*>(raw_memory); |
| 101 } | 102 } |
| 102 | 103 |
| 103 // This function uses a SEH try block so cannot use C++ objects that | 104 // 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 // have destructors or else you get Compiler Error C2712. So no DCHECKs |
| 105 // inside this function. | 106 // inside this function. |
| 106 CrossCallParamsEx* CrossCallParamsEx::CreateFromBuffer(void* buffer_base, | 107 CrossCallParamsEx* CrossCallParamsEx::CreateFromBuffer(void* buffer_base, |
| 107 uint32 buffer_size, | 108 uint32_t buffer_size, |
| 108 uint32* output_size) { | 109 uint32_t* output_size) { |
| 109 // IMPORTANT: Everything inside buffer_base and derived from it such | 110 // IMPORTANT: Everything inside buffer_base and derived from it such |
| 110 // as param_count and declared_size is untrusted. | 111 // as param_count and declared_size is untrusted. |
| 111 if (NULL == buffer_base) { | 112 if (NULL == buffer_base) { |
| 112 return NULL; | 113 return NULL; |
| 113 } | 114 } |
| 114 if (buffer_size < sizeof(CrossCallParams)) { | 115 if (buffer_size < sizeof(CrossCallParams)) { |
| 115 return NULL; | 116 return NULL; |
| 116 } | 117 } |
| 117 if (buffer_size > kMaxBufferSize) { | 118 if (buffer_size > kMaxBufferSize) { |
| 118 return NULL; | 119 return NULL; |
| 119 } | 120 } |
| 120 | 121 |
| 121 char* backing_mem = NULL; | 122 char* backing_mem = NULL; |
| 122 uint32 param_count = 0; | 123 uint32_t param_count = 0; |
| 123 uint32 declared_size; | 124 uint32_t declared_size; |
| 124 uint32 min_declared_size; | 125 uint32_t min_declared_size; |
| 125 CrossCallParamsEx* copied_params = NULL; | 126 CrossCallParamsEx* copied_params = NULL; |
| 126 | 127 |
| 127 // Touching the untrusted buffer is done under a SEH try block. This | 128 // Touching the untrusted buffer is done under a SEH try block. This |
| 128 // will catch memory access violations so we don't crash. | 129 // will catch memory access violations so we don't crash. |
| 129 __try { | 130 __try { |
| 130 CrossCallParams* call_params = | 131 CrossCallParams* call_params = |
| 131 reinterpret_cast<CrossCallParams*>(buffer_base); | 132 reinterpret_cast<CrossCallParams*>(buffer_base); |
| 132 | 133 |
| 133 // Check against the minimum size given the number of stated params | 134 // Check against the minimum size given the number of stated params |
| 134 // if too small we bail out. | 135 // if too small we bail out. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 // untrusted buffer so we bail out as is. | 170 // untrusted buffer so we bail out as is. |
| 170 delete [] backing_mem; | 171 delete [] backing_mem; |
| 171 return NULL; | 172 return NULL; |
| 172 } | 173 } |
| 173 | 174 |
| 174 const char* last_byte = &backing_mem[declared_size]; | 175 const char* last_byte = &backing_mem[declared_size]; |
| 175 const char* first_byte = &backing_mem[min_declared_size]; | 176 const char* first_byte = &backing_mem[min_declared_size]; |
| 176 | 177 |
| 177 // Verify here that all and each parameters make sense. This is done in the | 178 // Verify here that all and each parameters make sense. This is done in the |
| 178 // local copy. | 179 // local copy. |
| 179 for (uint32 ix =0; ix != param_count; ++ix) { | 180 for (uint32_t ix = 0; ix != param_count; ++ix) { |
| 180 uint32 size = 0; | 181 uint32_t size = 0; |
| 181 ArgType type; | 182 ArgType type; |
| 182 char* address = reinterpret_cast<char*>( | 183 char* address = reinterpret_cast<char*>( |
| 183 copied_params->GetRawParameter(ix, &size, &type)); | 184 copied_params->GetRawParameter(ix, &size, &type)); |
| 184 if ((NULL == address) || // No null params. | 185 if ((NULL == address) || // No null params. |
| 185 (INVALID_TYPE >= type) || (LAST_TYPE <= type) || // Unknown type. | 186 (INVALID_TYPE >= type) || (LAST_TYPE <= type) || // Unknown type. |
| 186 (address < backing_mem) || // Start cannot point before buffer. | 187 (address < backing_mem) || // Start cannot point before buffer. |
| 187 (address < first_byte) || // Start cannot point too low. | 188 (address < first_byte) || // Start cannot point too low. |
| 188 (address > last_byte) || // Start cannot point past buffer. | 189 (address > last_byte) || // Start cannot point past buffer. |
| 189 ((address + size) < address) || // Invalid size. | 190 ((address + size) < address) || // Invalid size. |
| 190 ((address + size) > last_byte)) { // End cannot point past buffer. | 191 ((address + size) > last_byte)) { // End cannot point past buffer. |
| 191 // Malformed. | 192 // Malformed. |
| 192 delete[] backing_mem; | 193 delete[] backing_mem; |
| 193 return NULL; | 194 return NULL; |
| 194 } | 195 } |
| 195 } | 196 } |
| 196 // The parameter buffer looks good. | 197 // The parameter buffer looks good. |
| 197 return copied_params; | 198 return copied_params; |
| 198 } | 199 } |
| 199 | 200 |
| 200 // Accessors to the parameters in the raw buffer. | 201 // Accessors to the parameters in the raw buffer. |
| 201 void* CrossCallParamsEx::GetRawParameter(uint32 index, uint32* size, | 202 void* CrossCallParamsEx::GetRawParameter(uint32_t index, |
| 203 uint32_t* size, |
| 202 ArgType* type) { | 204 ArgType* type) { |
| 203 if (index >= GetParamsCount()) { | 205 if (index >= GetParamsCount()) { |
| 204 return NULL; | 206 return NULL; |
| 205 } | 207 } |
| 206 // The size is always computed from the parameter minus the next | 208 // The size is always computed from the parameter minus the next |
| 207 // parameter, this works because the message has an extra parameter slot | 209 // parameter, this works because the message has an extra parameter slot |
| 208 *size = param_info_[index].size_; | 210 *size = param_info_[index].size_; |
| 209 *type = param_info_[index].type_; | 211 *type = param_info_[index].type_; |
| 210 | 212 |
| 211 return param_info_[index].offset_ + reinterpret_cast<char*>(this); | 213 return param_info_[index].offset_ + reinterpret_cast<char*>(this); |
| 212 } | 214 } |
| 213 | 215 |
| 214 // Covers common case for 32 bit integers. | 216 // Covers common case for 32 bit integers. |
| 215 bool CrossCallParamsEx::GetParameter32(uint32 index, uint32* param) { | 217 bool CrossCallParamsEx::GetParameter32(uint32_t index, uint32_t* param) { |
| 216 uint32 size = 0; | 218 uint32_t size = 0; |
| 217 ArgType type; | 219 ArgType type; |
| 218 void* start = GetRawParameter(index, &size, &type); | 220 void* start = GetRawParameter(index, &size, &type); |
| 219 if ((NULL == start) || (4 != size) || (UINT32_TYPE != type)) { | 221 if ((NULL == start) || (4 != size) || (UINT32_TYPE != type)) { |
| 220 return false; | 222 return false; |
| 221 } | 223 } |
| 222 // Copy the 4 bytes. | 224 // Copy the 4 bytes. |
| 223 *(reinterpret_cast<uint32*>(param)) = *(reinterpret_cast<uint32*>(start)); | 225 *(reinterpret_cast<uint32_t*>(param)) = *(reinterpret_cast<uint32_t*>(start)); |
| 224 return true; | 226 return true; |
| 225 } | 227 } |
| 226 | 228 |
| 227 bool CrossCallParamsEx::GetParameterVoidPtr(uint32 index, void** param) { | 229 bool CrossCallParamsEx::GetParameterVoidPtr(uint32_t index, void** param) { |
| 228 uint32 size = 0; | 230 uint32_t size = 0; |
| 229 ArgType type; | 231 ArgType type; |
| 230 void* start = GetRawParameter(index, &size, &type); | 232 void* start = GetRawParameter(index, &size, &type); |
| 231 if ((NULL == start) || (sizeof(void*) != size) || (VOIDPTR_TYPE != type)) { | 233 if ((NULL == start) || (sizeof(void*) != size) || (VOIDPTR_TYPE != type)) { |
| 232 return false; | 234 return false; |
| 233 } | 235 } |
| 234 *param = *(reinterpret_cast<void**>(start)); | 236 *param = *(reinterpret_cast<void**>(start)); |
| 235 return true; | 237 return true; |
| 236 } | 238 } |
| 237 | 239 |
| 238 // Covers the common case of reading a string. Note that the string is not | 240 // Covers the common case of reading a string. Note that the string is not |
| 239 // scanned for invalid characters. | 241 // scanned for invalid characters. |
| 240 bool CrossCallParamsEx::GetParameterStr(uint32 index, base::string16* string) { | 242 bool CrossCallParamsEx::GetParameterStr(uint32_t index, |
| 241 uint32 size = 0; | 243 base::string16* string) { |
| 244 uint32_t size = 0; |
| 242 ArgType type; | 245 ArgType type; |
| 243 void* start = GetRawParameter(index, &size, &type); | 246 void* start = GetRawParameter(index, &size, &type); |
| 244 if (WCHAR_TYPE != type) { | 247 if (WCHAR_TYPE != type) { |
| 245 return false; | 248 return false; |
| 246 } | 249 } |
| 247 | 250 |
| 248 // Check if this is an empty string. | 251 // Check if this is an empty string. |
| 249 if (size == 0) { | 252 if (size == 0) { |
| 250 *string = L""; | 253 *string = L""; |
| 251 return true; | 254 return true; |
| 252 } | 255 } |
| 253 | 256 |
| 254 if ((NULL == start) || ((size % sizeof(wchar_t)) != 0)) { | 257 if ((NULL == start) || ((size % sizeof(wchar_t)) != 0)) { |
| 255 return false; | 258 return false; |
| 256 } | 259 } |
| 257 string->append(reinterpret_cast<wchar_t*>(start), size/(sizeof(wchar_t))); | 260 string->append(reinterpret_cast<wchar_t*>(start), size/(sizeof(wchar_t))); |
| 258 return true; | 261 return true; |
| 259 } | 262 } |
| 260 | 263 |
| 261 bool CrossCallParamsEx::GetParameterPtr(uint32 index, uint32 expected_size, | 264 bool CrossCallParamsEx::GetParameterPtr(uint32_t index, |
| 265 uint32_t expected_size, |
| 262 void** pointer) { | 266 void** pointer) { |
| 263 uint32 size = 0; | 267 uint32_t size = 0; |
| 264 ArgType type; | 268 ArgType type; |
| 265 void* start = GetRawParameter(index, &size, &type); | 269 void* start = GetRawParameter(index, &size, &type); |
| 266 | 270 |
| 267 if ((size != expected_size) || (INOUTPTR_TYPE != type)) { | 271 if ((size != expected_size) || (INOUTPTR_TYPE != type)) { |
| 268 return false; | 272 return false; |
| 269 } | 273 } |
| 270 | 274 |
| 271 if (NULL == start) { | 275 if (NULL == start) { |
| 272 return false; | 276 return false; |
| 273 } | 277 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 298 return NULL; | 302 return NULL; |
| 299 } | 303 } |
| 300 | 304 |
| 301 Dispatcher::Dispatcher() { | 305 Dispatcher::Dispatcher() { |
| 302 } | 306 } |
| 303 | 307 |
| 304 Dispatcher::~Dispatcher() { | 308 Dispatcher::~Dispatcher() { |
| 305 } | 309 } |
| 306 | 310 |
| 307 } // namespace sandbox | 311 } // namespace sandbox |
| OLD | NEW |