Add a new method to check if an address point to the beginning of an user alloc
This will be useful to check if a block has been allocated without guards.
R=chrisha@chromium.org
BUG=
Review URL: https://codereview.appspot.com/131430043
git-svn-id: http://sawbuck.googlecode.com/svn/trunk@2275 15e8cca8-e42c-11de-a347-f34a4f72eb7d
diff --git a/syzygy/agent/asan/heap_managers/block_heap_manager.cc b/syzygy/agent/asan/heap_managers/block_heap_manager.cc
index d6c3b53..b63392b 100644
--- a/syzygy/agent/asan/heap_managers/block_heap_manager.cc
+++ b/syzygy/agent/asan/heap_managers/block_heap_manager.cc
@@ -146,10 +146,9 @@
DCHECK_NE(static_cast<HeapId>(NULL), heap_id);
BlockInfo block_info = {};
- BlockHeader* header = BlockGetHeaderFromBody(alloc);
- if (header == NULL || !Shadow::BlockInfoFromShadow(header, &block_info)) {
- // TODO(chrisha|sebmarchand): Handle invalid allocation addresses. Currently
- // we can't tell these apart from unguarded allocations.
+ if (!Shadow::IsBeginningOfBlockBody(alloc) ||
+ !Shadow::BlockInfoFromShadow(alloc, &block_info)) {
+ // TODO(chrisha|sebmarchand): Handle invalid allocation addresses.
// Assume that this block was allocated without guards.
return unguarded_allocation_heap_->Free(alloc);
diff --git a/syzygy/agent/asan/shadow.cc b/syzygy/agent/asan/shadow.cc
index e71c402..a56d36f 100644
--- a/syzygy/agent/asan/shadow.cc
+++ b/syzygy/agent/asan/shadow.cc
@@ -232,6 +232,13 @@
return true;
}
+bool Shadow::IsBeginningOfBlockBody(const void* addr) {
+ DCHECK_NE(static_cast<void*>(NULL), addr);
+ if (IsLeftRedzone(addr) || IsRightRedzone(addr))
+ return false;
+ return IsLeftRedzone(reinterpret_cast<const uint8*>(addr) - 1);
+}
+
void Shadow::CloneShadowRange(const void* src_pointer,
void* dst_pointer,
size_t size) {
diff --git a/syzygy/agent/asan/shadow.h b/syzygy/agent/asan/shadow.h
index 34c00d5..019737f 100644
--- a/syzygy/agent/asan/shadow.h
+++ b/syzygy/agent/asan/shadow.h
@@ -216,6 +216,13 @@
static bool ParentBlockInfoFromShadow(
const BlockInfo& nested, BlockInfo* info);
+ // Checks if the address @p addr corresponds to the beginning of a block's
+ // body, i.e. if it's preceded by a left redzone.
+ // @param addr The address that we want to check.
+ // @returns true if the address corresponds to the beginning of a block's
+ // body, false otherwise.
+ static bool IsBeginningOfBlockBody(const void* addr);
+
protected:
// Reset the shadow memory.
static void Reset();
diff --git a/syzygy/agent/asan/shadow_unittest.cc b/syzygy/agent/asan/shadow_unittest.cc
index bd1dabf..b3d7a81 100644
--- a/syzygy/agent/asan/shadow_unittest.cc
+++ b/syzygy/agent/asan/shadow_unittest.cc
@@ -15,6 +15,7 @@
#include "syzygy/agent/asan/shadow.h"
#include "base/rand_util.h"
+#include "base/memory/scoped_ptr.h"
#include "gtest/gtest.h"
#include "syzygy/common/align.h"
@@ -300,9 +301,9 @@
ASSERT_NE(0U, kAllocSize % kShadowRatio);
BlockPlanLayout(kShadowRatio, kShadowRatio, kAllocSize, 0, 0, &layout);
- uint8* data = new uint8[layout.block_size];
+ scoped_ptr<uint8> data(new uint8[layout.block_size]);
BlockInfo info = {};
- BlockInitialize(layout, data, false, &info);
+ BlockInitialize(layout, data.get(), false, &info);
Shadow::PoisonAllocatedBlock(info);
uint8* cursor = info.block;
@@ -321,7 +322,6 @@
}
Shadow::Unpoison(info.block, info.block_size);
- delete [] data;
}
@@ -406,6 +406,30 @@
EXPECT_NO_FATAL_FAILURE(TestBlockInfoFromShadow(layout2, layout0));
}
+TEST(ShadowTest, IsBeginningOfBlockBody) {
+ BlockLayout l = {};
+ BlockPlanLayout(kShadowRatio, kShadowRatio, 7, 0, 0, &l);
+
+ size_t data_size = l.block_size;
+ scoped_ptr<uint8> data(new uint8[data_size]);
+
+ BlockInfo block_info = {};
+ BlockInitialize(l, data.get(), false, &block_info);
+
+ Shadow::PoisonAllocatedBlock(block_info);
+
+ EXPECT_TRUE(Shadow::IsBeginningOfBlockBody(block_info.body));
+ EXPECT_FALSE(Shadow::IsBeginningOfBlockBody(data.get()));
+
+ block_info.header->state = QUARANTINED_BLOCK;
+ Shadow::MarkAsFreed(block_info.body, block_info.body_size);
+
+ EXPECT_TRUE(Shadow::IsBeginningOfBlockBody(block_info.body));
+ EXPECT_FALSE(Shadow::IsBeginningOfBlockBody(data.get()));
+
+ Shadow::Unpoison(data.get(), data_size);
+}
+
TEST(ShadowWalkerTest, WalksNonNestedBlocks) {
BlockLayout l = {};
BlockPlanLayout(kShadowRatio, kShadowRatio, 7, 0, 0, &l);