summaryrefslogtreecommitdiffstats
path: root/sandbox/src/crosscall_server.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sandbox/src/crosscall_server.cc')
-rw-r--r--sandbox/src/crosscall_server.cc287
1 files changed, 287 insertions, 0 deletions
diff --git a/sandbox/src/crosscall_server.cc b/sandbox/src/crosscall_server.cc
new file mode 100644
index 0000000..c924e63
--- /dev/null
+++ b/sandbox/src/crosscall_server.cc
@@ -0,0 +1,287 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <string>
+#include <vector>
+
+#include "sandbox/src/crosscall_server.h"
+#include "sandbox/src/crosscall_params.h"
+#include "sandbox/src/crosscall_client.h"
+#include "base/logging.h"
+
+// This code performs the ipc message validation. Potential security flaws
+// on the ipc are likelier to be found in this code than in the rest of
+// the ipc code.
+
+namespace {
+ // The buffer for a message must match the max channel size.
+ const size_t kMaxBufferSize = sandbox::kIPCChannelSize;
+}
+
+namespace sandbox {
+
+// Returns the actual size for the parameters in an IPC buffer.
+void GetActualBufferSize(size_t param_count, void* buffer_base,
+ size_t* actual_size) {
+ // The template types are used to calculate the maximum expected size.
+ typedef ActualCallParams<1, kMaxBufferSize> ActualCP1;
+ typedef ActualCallParams<2, kMaxBufferSize> ActualCP2;
+ typedef ActualCallParams<3, kMaxBufferSize> ActualCP3;
+ typedef ActualCallParams<4, kMaxBufferSize> ActualCP4;
+ typedef ActualCallParams<5, kMaxBufferSize> ActualCP5;
+ typedef ActualCallParams<6, kMaxBufferSize> ActualCP6;
+ typedef ActualCallParams<7, kMaxBufferSize> ActualCP7;
+ typedef ActualCallParams<8, kMaxBufferSize> ActualCP8;
+ typedef ActualCallParams<9, kMaxBufferSize> ActualCP9;
+
+ // Retrieve the actual size and the maximum size of the params buffer.
+ switch (param_count) {
+ case 1:
+ *actual_size = reinterpret_cast<ActualCP1*>(buffer_base)->GetSize();
+ break;
+ case 2:
+ *actual_size = reinterpret_cast<ActualCP2*>(buffer_base)->GetSize();
+ break;
+ case 3:
+ *actual_size = reinterpret_cast<ActualCP3*>(buffer_base)->GetSize();
+ break;
+ case 4:
+ *actual_size = reinterpret_cast<ActualCP4*>(buffer_base)->GetSize();
+ break;
+ case 5:
+ *actual_size = reinterpret_cast<ActualCP5*>(buffer_base)->GetSize();
+ break;
+ case 6:
+ *actual_size = reinterpret_cast<ActualCP6*>(buffer_base)->GetSize();
+ break;
+ case 7:
+ *actual_size = reinterpret_cast<ActualCP7*>(buffer_base)->GetSize();
+ break;
+ case 8:
+ *actual_size = reinterpret_cast<ActualCP8*>(buffer_base)->GetSize();
+ break;
+ case 9:
+ *actual_size = reinterpret_cast<ActualCP9*>(buffer_base)->GetSize();
+ break;
+ default:
+ NOTREACHED();
+ *actual_size = 0;
+ }
+}
+
+CrossCallParamsEx::CrossCallParamsEx()
+ :CrossCallParams(0, 0) {
+}
+
+// We override the delete operator because the object's backing memory
+// is hand allocated in CreateFromBuffer. We don't override the new operator
+// because the constructors are private so there is no way to mismatch
+// new & delete.
+void CrossCallParamsEx::operator delete(void* raw_memory) throw() {
+ if (NULL == raw_memory) {
+ // C++ standard allows 'delete 0' behavior.
+ return;
+ }
+ delete[] reinterpret_cast<char*>(raw_memory);
+}
+
+// This function uses a SEH try block so cannot use C++ objects that
+// have destructors or else you get Compiler Error C2712. So no DCHECKs
+// inside this function.
+CrossCallParamsEx* CrossCallParamsEx::CreateFromBuffer(void* buffer_base,
+ size_t buffer_size,
+ size_t* output_size) {
+ if (NULL == buffer_base) {
+ return NULL;
+ }
+ if (buffer_size < sizeof(CrossCallParams)) {
+ return NULL;
+ }
+ if (buffer_size > kMaxBufferSize) {
+ return NULL;
+ }
+ char* backing_mem = NULL;
+ size_t param_count = 0;
+ CrossCallParamsEx* copied_params = NULL;
+
+ size_t actual_size = 0;
+
+ // Touching the untrusted buffer is done under a SEH try block. This
+ // will catch memory access violations so we don't crash.
+ __try {
+ CrossCallParams* call_params =
+ reinterpret_cast<CrossCallParams*>(buffer_base);
+ // Check against the minimum size given the number of stated params
+ // if too small we bail out.
+ param_count = call_params->GetParamsCount();
+ if ((buffer_size - sizeof(CrossCallParams)) <
+ (sizeof(ptrdiff_t) * (param_count + 1))) {
+ // Too small.
+ return NULL;
+ }
+
+ GetActualBufferSize(param_count, buffer_base, &actual_size);
+
+ if (actual_size > buffer_size) {
+ // It is too big.
+ return NULL;
+ }
+ // Now we copy the actual amount of the message.
+ actual_size += sizeof(ParamInfo); // To get the last offset.
+ *output_size = actual_size;
+ backing_mem = new char[actual_size];
+ memset(backing_mem, 0, actual_size);
+ // Note that this is a placement new.
+#pragma warning(push)
+#pragma warning(disable: 4291) // No matching operator delete.
+ // TODO(cpu): Remove this warning.
+ copied_params = new(backing_mem)CrossCallParamsEx();
+#pragma warning(pop)
+ memcpy(backing_mem, call_params, actual_size);
+
+ } __except(EXCEPTION_EXECUTE_HANDLER) {
+ // In case of a windows exception we know it occurred while touching the
+ // untrusted buffer so we bail out as is.
+ return NULL;
+ }
+
+ char* last_byte = &backing_mem[actual_size - 1];
+ // Verify here that all and each parameters make sense. This is done in the
+ // local copy.
+ for (size_t ix =0; ix != param_count; ++ix) {
+ size_t size = 0;
+ ArgType type;
+ char* address = reinterpret_cast<char*>(
+ copied_params->GetRawParameter(ix, &size, &type));
+ if ((NULL == address) || // No null params.
+ (INVALID_TYPE >= type) || (LAST_TYPE <= type) || // Unknown type.
+ (address < backing_mem) || // Start cannot point before buffer.
+ (address > last_byte) || // Start cannot point past buffer.
+ ((address + size) < address) || // Invalid size.
+ ((address + size) > last_byte)) { // End cannot point past buffer.
+ // Malformed.
+ delete[] backing_mem;
+ return NULL;
+ }
+ }
+ // The parameter buffer looks good.
+ return copied_params;
+}
+
+// Accessors to the parameters in the raw buffer.
+void* CrossCallParamsEx::GetRawParameter(size_t index, size_t* size,
+ ArgType* type) {
+ if (index > GetParamsCount()) {
+ return NULL;
+ }
+ // The size is always computed from the parameter minus the next
+ // parameter, this works because the message has an extra parameter slot
+ *size = param_info_[index].size_;
+ *type = param_info_[index].type_;
+
+ return param_info_[index].offset_ + reinterpret_cast<char*>(this);
+}
+
+// Covers common case for 32 bit integers.
+bool CrossCallParamsEx::GetParameter32(size_t index, void* param) {
+ size_t size = 0;
+ ArgType type;
+ void* start = GetRawParameter(index, &size, &type);
+ if ((NULL == start) || (4 != size) || (ULONG_TYPE != type)) {
+ return false;
+ }
+ // Copy the 4 bytes.
+ *(reinterpret_cast<uint32*>(param)) = *(reinterpret_cast<uint32*>(start));
+ return true;
+}
+
+// Covers the common case of reading a string. Note that the string is not
+// scanned for invalid characters.
+bool CrossCallParamsEx::GetParameterStr(size_t index, std::wstring* string) {
+ size_t size = 0;
+ ArgType type;
+ void* start = GetRawParameter(index, &size, &type);
+ if (WCHAR_TYPE != type) {
+ return false;
+ }
+
+ // Check if this is an empty string.
+ if (size == 0) {
+ *string = L"";
+ return true;
+ }
+
+ if ((NULL == start) || ((size % sizeof(wchar_t)) != 0)) {
+ return false;
+ }
+ string->append(reinterpret_cast<wchar_t*>(start), size/(sizeof(wchar_t)));
+ return true;
+}
+
+bool CrossCallParamsEx::GetParameterPtr(size_t index, size_t expected_size,
+ void** pointer) {
+ size_t size = 0;
+ ArgType type;
+ void* start = GetRawParameter(index, &size, &type);
+
+ if ((size != expected_size) || (INOUTPTR_TYPE != type)) {
+ return false;
+ }
+
+ if (NULL == start) {
+ return false;
+ }
+
+ *pointer = start;
+ return true;
+}
+
+void SetCallError(ResultCode error, CrossCallReturn* call_return) {
+ call_return->call_outcome = error;
+ call_return->extended_count = 0;
+}
+
+void SetCallSuccess(CrossCallReturn* call_return) {
+ call_return->call_outcome = SBOX_ALL_OK;
+}
+
+Dispatcher* Dispatcher::OnMessageReady(IPCParams* ipc,
+ CallbackGeneric* callback) {
+ DCHECK(callback);
+ std::vector<IPCCall>::iterator it = ipc_calls_.begin();
+ for (; it != ipc_calls_.end(); ++it) {
+ if (it->params.Matches(ipc)) {
+ *callback = it->callback;
+ return this;
+ }
+ }
+ return NULL;
+}
+
+} // namespace sandbox