diff options
author | cpu@chromium.org <cpu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-22 23:38:14 +0000 |
---|---|---|
committer | cpu@chromium.org <cpu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-22 23:38:14 +0000 |
commit | e9b676190a37d4f1f57cc6b9f2f3bad634449101 (patch) | |
tree | 814cdb0287b1fece49be866bbc8a221f0106ed0b /sandbox | |
parent | da17b37430e97d518b7d640b98831c8e338b478c (diff) | |
download | chromium_src-e9b676190a37d4f1f57cc6b9f2f3bad634449101.zip chromium_src-e9b676190a37d4f1f57cc6b9f2f3bad634449101.tar.gz chromium_src-e9b676190a37d4f1f57cc6b9f2f3bad634449101.tar.bz2 |
Fix integer overflow in sbox
BUG=32915
TEST= unit test included
Review URL: http://codereview.chromium.org/553061
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@36923 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox')
-rw-r--r-- | sandbox/src/crosscall_params.h | 7 | ||||
-rw-r--r-- | sandbox/src/crosscall_server.cc | 50 | ||||
-rw-r--r-- | sandbox/src/ipc_unittest.cc | 39 |
3 files changed, 67 insertions, 29 deletions
diff --git a/sandbox/src/crosscall_params.h b/sandbox/src/crosscall_params.h index 5e562cc..f6de823 100644 --- a/sandbox/src/crosscall_params.h +++ b/sandbox/src/crosscall_params.h @@ -202,6 +202,13 @@ class ActualCallParams : public CrossCallParams { param_info_[0].offset_ = parameters_ - reinterpret_cast<char*>(this); } + // Testing-only constructor. Allows setting the |number_params| to a + // wrong value. + ActualCallParams(uint32 tag, uint32 number_params) + : CrossCallParams(tag, number_params) { + param_info_[0].offset_ = parameters_ - reinterpret_cast<char*>(this); + } + // Copies each paramter into the internal buffer. For each you must supply: // index: 0 for the first param, 1 for the next an so on bool CopyParamIn(size_t index, const void* parameter_address, size_t size, diff --git a/sandbox/src/crosscall_server.cc b/sandbox/src/crosscall_server.cc index aff1ff4..35e80f4 100644 --- a/sandbox/src/crosscall_server.cc +++ b/sandbox/src/crosscall_server.cc @@ -21,9 +21,9 @@ namespace { 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) { +// Returns the actual size for the parameters in an IPC buffer. Returns +// zero if the |param_count| is zero or too big. +size_t GetActualBufferSize(size_t param_count, void* buffer_base) { // The template types are used to calculate the maximum expected size. typedef ActualCallParams<1, kMaxBufferSize> ActualCP1; typedef ActualCallParams<2, kMaxBufferSize> ActualCP2; @@ -37,36 +37,29 @@ void GetActualBufferSize(size_t param_count, void* buffer_base, // Retrieve the actual size and the maximum size of the params buffer. switch (param_count) { + case 0: + return 0; case 1: - *actual_size = reinterpret_cast<ActualCP1*>(buffer_base)->GetSize(); - break; + return reinterpret_cast<ActualCP1*>(buffer_base)->GetSize(); case 2: - *actual_size = reinterpret_cast<ActualCP2*>(buffer_base)->GetSize(); - break; + return reinterpret_cast<ActualCP2*>(buffer_base)->GetSize(); case 3: - *actual_size = reinterpret_cast<ActualCP3*>(buffer_base)->GetSize(); - break; + return reinterpret_cast<ActualCP3*>(buffer_base)->GetSize(); case 4: - *actual_size = reinterpret_cast<ActualCP4*>(buffer_base)->GetSize(); - break; + return reinterpret_cast<ActualCP4*>(buffer_base)->GetSize(); case 5: - *actual_size = reinterpret_cast<ActualCP5*>(buffer_base)->GetSize(); - break; + return reinterpret_cast<ActualCP5*>(buffer_base)->GetSize(); case 6: - *actual_size = reinterpret_cast<ActualCP6*>(buffer_base)->GetSize(); - break; + return reinterpret_cast<ActualCP6*>(buffer_base)->GetSize(); case 7: - *actual_size = reinterpret_cast<ActualCP7*>(buffer_base)->GetSize(); - break; + return reinterpret_cast<ActualCP7*>(buffer_base)->GetSize(); case 8: - *actual_size = reinterpret_cast<ActualCP8*>(buffer_base)->GetSize(); - break; + return reinterpret_cast<ActualCP8*>(buffer_base)->GetSize(); case 9: - *actual_size = reinterpret_cast<ActualCP9*>(buffer_base)->GetSize(); - break; + return reinterpret_cast<ActualCP9*>(buffer_base)->GetSize(); default: NOTREACHED(); - *actual_size = 0; + return 0; } } @@ -104,8 +97,7 @@ CrossCallParamsEx* CrossCallParamsEx::CreateFromBuffer(void* buffer_base, char* backing_mem = NULL; size_t param_count = 0; CrossCallParamsEx* copied_params = NULL; - - size_t actual_size = 0; + size_t actual_size; // Touching the untrusted buffer is done under a SEH try block. This // will catch memory access violations so we don't crash. @@ -117,16 +109,16 @@ CrossCallParamsEx* CrossCallParamsEx::CreateFromBuffer(void* buffer_base, param_count = call_params->GetParamsCount(); if ((buffer_size - sizeof(CrossCallParams)) < (sizeof(ptrdiff_t) * (param_count + 1))) { - // Too small. + // This test is subject to integer overflow but the next is not. return NULL; } - GetActualBufferSize(param_count, buffer_base, &actual_size); - - if (actual_size > buffer_size) { - // It is too big. + actual_size = GetActualBufferSize(param_count, buffer_base); + if ((actual_size > buffer_size) || (0 == actual_size)) { + // It is too big or too many declared parameters. return NULL; } + // Now we copy the actual amount of the message. actual_size += sizeof(ParamInfo); // To get the last offset. *output_size = actual_size; diff --git a/sandbox/src/ipc_unittest.cc b/sandbox/src/ipc_unittest.cc index 60f326c..cb9e81c 100644 --- a/sandbox/src/ipc_unittest.cc +++ b/sandbox/src/ipc_unittest.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/basictypes.h" #include "sandbox/src/crosscall_client.h" #include "sandbox/src/crosscall_server.h" #include "sandbox/src/sharedmem_ipc_client.h" @@ -214,6 +215,44 @@ TEST(IPCTest, CrossCallStrPacking) { delete [] reinterpret_cast<char*>(client_control); } +TEST(IPCTest, CrossCallValidation) { + // First a sanity test with a well formed parameter object. + unsigned long value = 124816; + const uint32 kTag = 33; + ActualCallParams<1, 128> params_1(kTag); + params_1.CopyParamIn(0, &value, sizeof(value), false, ULONG_TYPE); + void* buffer = const_cast<void*>(params_1.GetBuffer()); + + size_t out_size = 0; + CrossCallParamsEx* ccp = 0; + ccp = CrossCallParamsEx::CreateFromBuffer(buffer, params_1.GetSize(), + &out_size); + ASSERT_TRUE(NULL != ccp); + EXPECT_TRUE(ccp->GetBuffer() != buffer); + EXPECT_EQ(kTag, ccp->GetTag()); + EXPECT_EQ(1, ccp->GetParamsCount()); + delete[] (reinterpret_cast<char*>(ccp)); + +#if defined(NDEBUG) + // Test hat we handle integer overflow on the number of params + // correctly. We use a test-only ctor for ActualCallParams that + // allows to create malformed cross-call buffers. + const int32 kPtrDiffSz = sizeof(ptrdiff_t); + for (int32 ix = -1; ix != 3; ++ix) { + uint32 fake_num_params = (kuint32max / kPtrDiffSz) + ix; + ActualCallParams<1, 128> params_2(kTag, fake_num_params); + params_2.CopyParamIn(0, &value, sizeof(value), false, ULONG_TYPE); + buffer = const_cast<void*>(params_2.GetBuffer()); + + EXPECT_TRUE(NULL != buffer); + ccp = CrossCallParamsEx::CreateFromBuffer(buffer, params_2.GetSize(), + &out_size); + // If the buffer is malformed the return is NULL. + EXPECT_TRUE(NULL == ccp); + } +#endif // defined(NDEBUG) +} + // This structure is passed to the mock server threads to simulate // the server side IPC so it has the required kernel objects. struct ServerEvents { |