Skip to content

Commit

Permalink
IPC fuzzer: create message_lib library.
Browse files Browse the repository at this point in the history
Currently it can:
 - read / write IPC message files
 - translate message type <-> name

BUG=260848

Review URL: https://codereview.chromium.org/105083002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@239831 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
aedla@chromium.org committed Dec 10, 2013
1 parent e77acc0 commit ea24690
Show file tree
Hide file tree
Showing 14 changed files with 694 additions and 46 deletions.
3 changes: 3 additions & 0 deletions tools/ipc_fuzzer/DEPS
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include_rules = [
"+tools/ipc_fuzzer/message_lib",
]
8 changes: 8 additions & 0 deletions tools/ipc_fuzzer/message_lib/DEPS
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
include_rules = [
"+chrome/common",
"+components/autofill/core/common",
"+components/nacl/common",
"+components/tracing",
"+components/visitedlink/common",
"+content/common",
]
14 changes: 14 additions & 0 deletions tools/ipc_fuzzer/message_lib/all_messages.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Multiply-included file, hence no include guard.
// Inclusion of all message files recognized by message_lib. All messages
// received by RenderProcessHost should be included here for the IPC fuzzer.

#include "chrome/common/all_messages.h"
#include "components/autofill/core/common/autofill_messages.h"
#include "components/nacl/common/nacl_host_messages.h"
#include "components/tracing/tracing_messages.h"
#include "components/visitedlink/common/visitedlink_messages.h"
#include "content/common/all_messages.h"
32 changes: 32 additions & 0 deletions tools/ipc_fuzzer/message_lib/message_cracker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef TOOLS_IPC_FUZZER_MESSAGE_LIB_MESSAGE_CRACKER_H_
#define TOOLS_IPC_FUZZER_MESSAGE_LIB_MESSAGE_CRACKER_H_

#include <string.h>
#include "ipc/ipc_message.h"

// Means for updating protected message fields.
class MessageCracker : public IPC::Message {
public:
static void CopyMessageID(IPC::Message* dst, IPC::Message* src) {
memcpy(ToCracker(dst)->mutable_payload(),
ToCracker(src)->payload(),
sizeof(int));
}

static void SetMessageType(IPC::Message* message, uint32 type) {
ToCracker(message)->header()->type = type;
}

private:
static MessageCracker* ToCracker(IPC::Message* message) {
return reinterpret_cast<MessageCracker*>(message);
}

DISALLOW_COPY_AND_ASSIGN(MessageCracker);
};

#endif // TOOLS_IPC_FUZZER_MESSAGE_LIB_MESSAGE_CRACKER_H_
27 changes: 27 additions & 0 deletions tools/ipc_fuzzer/message_lib/message_file.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef TOOLS_IPC_FUZZER_MESSAGE_LIB_MESSAGE_FILE_H_
#define TOOLS_IPC_FUZZER_MESSAGE_LIB_MESSAGE_FILE_H_

#include "base/files/file_path.h"
#include "base/memory/scoped_vector.h"
#include "ipc/ipc_message.h"

namespace ipc_fuzzer {

typedef ScopedVector<IPC::Message> MessageVector;

class MessageFile {
public:
static bool Read(const base::FilePath& path, MessageVector* messages);
static bool Write(const base::FilePath& path, const MessageVector& messages);

private:
DISALLOW_COPY_AND_ASSIGN(MessageFile);
};

} // namespace ipc_fuzzer

#endif // TOOLS_IPC_FUZZER_MESSAGE_LIB_MESSAGE_FILE_H_
63 changes: 63 additions & 0 deletions tools/ipc_fuzzer/message_lib/message_file_format.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef TOOLS_IPC_FUZZER_MESSAGE_LIB_MESSAGE_FILE_FORMAT_H_
#define TOOLS_IPC_FUZZER_MESSAGE_LIB_MESSAGE_FILE_FORMAT_H_

#include "base/basictypes.h"

// Message file contains IPC messages and message names. Each message type
// has a NameTableEntry mapping the type to a name.
//
// |========================|
// | FileHeader |
// |========================|
// | Message |
// |------------------------|
// | Message |
// |------------------------|
// | ... |
// |========================|
// | NameTableEntry |
// |------------------------|
// | NameTableEntry |
// |------------------------|
// | ... |
// |------------------------|
// | type = 0x0002070f |
// | string_table_offset = ---.
// |------------------------| \
// | ... | |
// |========================| |
// | message name | |
// |------------------------| |
// | message name | |
// |------------------------| |
// | ... | |
// |------------------------| /
// | "ViewHostMsg_OpenURL" <--*
// |------------------------|
// | ... |
// |========================|

namespace ipc_fuzzer {

struct FileHeader {
static const uint32 kMagicValue = 0x1bcf11ee;
static const uint32 kCurrentVersion = 1;

uint32 magic;
uint32 version;
uint32 message_count;
uint32 name_count;
};

struct NameTableEntry {
uint32 type;
uint32 string_table_offset;
};

} // namespace ipc_fuzzer

#endif // TOOLS_IPC_FUZZER_MESSAGE_LIB_MESSAGE_FILE_FORMAT_H_
230 changes: 230 additions & 0 deletions tools/ipc_fuzzer/message_lib/message_file_reader.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <limits.h>

#include "base/files/file_path.h"
#include "base/files/memory_mapped_file.h"
#include "base/logging.h"
#include "base/strings/string_piece.h"
#include "ipc/ipc_message.h"
#include "tools/ipc_fuzzer/message_lib/message_cracker.h"
#include "tools/ipc_fuzzer/message_lib/message_file.h"
#include "tools/ipc_fuzzer/message_lib/message_file_format.h"
#include "tools/ipc_fuzzer/message_lib/message_names.h"

namespace ipc_fuzzer {

namespace {

// Helper class to read IPC message file into a MessageVector and
// fix message types.
class Reader {
public:
Reader(const base::FilePath& path);
bool Read(MessageVector* messages);

private:
template <typename T>
bool CutObject(const T** object);

// Reads the header, checks magic and version.
bool ReadHeader();

bool MapFile();
bool ReadMessages();

// Last part of the file is a string table for message names.
bool ReadStringTable();

// Reads type <-> name mapping into name_map_. References string table.
bool ReadNameTable();

// Removes obsolete messages from the vector.
bool RemoveUnknownMessages();

// Does type -> name -> correct_type fixup.
void FixMessageTypes();

// Raw data.
base::FilePath path_;
base::MemoryMappedFile mapped_file_;
base::StringPiece file_data_;
base::StringPiece string_table_;

// Parsed data.
const FileHeader* header_;
MessageVector* messages_;
MessageNames name_map_;

DISALLOW_COPY_AND_ASSIGN(Reader);
};

Reader::Reader(const base::FilePath& path)
: path_(path),
header_(NULL),
messages_(NULL) {
}

template <typename T>
bool Reader::CutObject(const T** object) {
if (file_data_.size() < sizeof(T)) {
LOG(ERROR) << "Unexpected EOF.";
return false;
}
*object = reinterpret_cast<const T*>(file_data_.data());
file_data_.remove_prefix(sizeof(T));
return true;
}

bool Reader::ReadHeader() {
if (!CutObject<FileHeader>(&header_))
return false;
if (header_->magic != FileHeader::kMagicValue) {
LOG(ERROR) << path_.value() << " is not an IPC message file.";
return false;
}
if (header_->version != FileHeader::kCurrentVersion) {
LOG(ERROR) << "Wrong version for message file " << path_.value() << ". "
<< "File version is " << header_->version << ", "
<< "current version is " << FileHeader::kCurrentVersion << ".";
return false;
}
return true;
}

bool Reader::MapFile() {
if (!mapped_file_.Initialize(path_)) {
LOG(ERROR) << "Failed to map testcase: " << path_.value();
return false;
}
const char* data = reinterpret_cast<const char*>(mapped_file_.data());
file_data_.set(data, mapped_file_.length());
return true;
}

bool Reader::ReadMessages() {
for (size_t i = 0; i < header_->message_count; ++i) {
const char* begin = file_data_.begin();
const char* end = file_data_.end();
const char* message_tail = IPC::Message::FindNext(begin, end);
if (!message_tail) {
LOG(ERROR) << "Failed to parse message.";
return false;
}

size_t msglen = message_tail - begin;
if (msglen > INT_MAX) {
LOG(ERROR) << "Message too large.";
return false;
}

// Copy is necessary to fix message type later.
IPC::Message const_message(begin, msglen);
IPC::Message* message = new IPC::Message(const_message);
messages_->push_back(message);
file_data_.remove_prefix(msglen);
}
return true;
}

bool Reader::ReadStringTable() {
size_t name_count = header_->name_count;
if (!name_count)
return true;
if (name_count > file_data_.size() / sizeof(NameTableEntry)) {
LOG(ERROR) << "Invalid name table size: " << name_count;
return false;
}

size_t string_table_offset = name_count * sizeof(NameTableEntry);
string_table_ = file_data_.substr(string_table_offset);
if (string_table_.empty()) {
LOG(ERROR) << "Missing string table.";
return false;
}
if (string_table_.end()[-1] != '\0') {
LOG(ERROR) << "String table doesn't end with NUL.";
return false;
}
return true;
}

bool Reader::ReadNameTable() {
for (size_t i = 0; i < header_->name_count; ++i) {
const NameTableEntry* entry;
if (!CutObject<NameTableEntry>(&entry))
return false;
size_t offset = entry->string_table_offset;
if (offset >= string_table_.size()) {
LOG(ERROR) << "Invalid string table offset: " << offset;
return false;
}
name_map_.Add(entry->type, std::string(string_table_.data() + offset));
}
return true;
}

bool Reader::RemoveUnknownMessages() {
MessageVector::iterator it = messages_->begin();
while (it != messages_->end()) {
uint32 type = (*it)->type();
if (!name_map_.TypeExists(type)) {
LOG(ERROR) << "Missing name table entry for type " << type;
return false;
}
const std::string& name = name_map_.TypeToName(type);
if (!MessageNames::GetInstance()->NameExists(name)) {
LOG(WARNING) << "Unknown message " << name;
it = messages_->erase(it);
} else {
++it;
}
}
return true;
}

// Message types are based on line numbers, so a minor edit of *_messages.h
// changes the types of messages in that file. The types are fixed here to
// increase the lifetime of message files. This is only a partial fix because
// message arguments and structure layouts can change as well.
void Reader::FixMessageTypes() {
for (MessageVector::iterator it = messages_->begin();
it != messages_->end(); ++it) {
uint32 type = (*it)->type();
const std::string& name = name_map_.TypeToName(type);
uint32 correct_type = MessageNames::GetInstance()->NameToType(name);
if (type != correct_type)
MessageCracker::SetMessageType(*it, correct_type);
}
}

bool Reader::Read(MessageVector* messages) {
messages_ = messages;

if (!MapFile())
return false;
if (!ReadHeader())
return false;
if (!ReadMessages())
return false;
if (!ReadStringTable())
return false;
if (!ReadNameTable())
return false;
if (!RemoveUnknownMessages())
return false;
FixMessageTypes();

return true;
}

} // namespace

bool MessageFile::Read(const base::FilePath& path, MessageVector* messages) {
Reader reader(path);
return reader.Read(messages);
}

} // namespace ipc_fuzzer
Loading

0 comments on commit ea24690

Please sign in to comment.