| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include <limits.h> |
| 6 |
| 7 #include "base/files/file_path.h" |
| 8 #include "base/files/memory_mapped_file.h" |
| 9 #include "base/logging.h" |
| 10 #include "base/strings/string_piece.h" |
| 11 #include "ipc/ipc_message.h" |
| 12 #include "tools/ipc_fuzzer/message_lib/message_cracker.h" |
| 13 #include "tools/ipc_fuzzer/message_lib/message_file.h" |
| 14 #include "tools/ipc_fuzzer/message_lib/message_file_format.h" |
| 15 #include "tools/ipc_fuzzer/message_lib/message_names.h" |
| 16 |
| 17 namespace ipc_fuzzer { |
| 18 |
| 19 namespace { |
| 20 |
| 21 // Helper class to read IPC message file into a MessageVector and |
| 22 // fix message types. |
| 23 class Reader { |
| 24 public: |
| 25 Reader(const base::FilePath& path); |
| 26 bool Read(MessageVector* messages); |
| 27 |
| 28 private: |
| 29 template <typename T> |
| 30 bool CutObject(const T** object); |
| 31 |
| 32 // Reads the header, checks magic and version. |
| 33 bool ReadHeader(); |
| 34 |
| 35 bool MapFile(); |
| 36 bool ReadMessages(); |
| 37 |
| 38 // Last part of the file is a string table for message names. |
| 39 bool ReadStringTable(); |
| 40 |
| 41 // Reads type <-> name mapping into name_map_. References string table. |
| 42 bool ReadNameTable(); |
| 43 |
| 44 // Removes obsolete messages from the vector. |
| 45 bool RemoveUnknownMessages(); |
| 46 |
| 47 // Does type -> name -> correct_type fixup. |
| 48 void FixMessageTypes(); |
| 49 |
| 50 // Raw data. |
| 51 base::FilePath path_; |
| 52 base::MemoryMappedFile mapped_file_; |
| 53 base::StringPiece file_data_; |
| 54 base::StringPiece string_table_; |
| 55 |
| 56 // Parsed data. |
| 57 const FileHeader* header_; |
| 58 MessageVector* messages_; |
| 59 MessageNames name_map_; |
| 60 |
| 61 DISALLOW_COPY_AND_ASSIGN(Reader); |
| 62 }; |
| 63 |
| 64 Reader::Reader(const base::FilePath& path) |
| 65 : path_(path), |
| 66 header_(NULL), |
| 67 messages_(NULL) { |
| 68 } |
| 69 |
| 70 template <typename T> |
| 71 bool Reader::CutObject(const T** object) { |
| 72 if (file_data_.size() < sizeof(T)) { |
| 73 LOG(ERROR) << "Unexpected EOF."; |
| 74 return false; |
| 75 } |
| 76 *object = reinterpret_cast<const T*>(file_data_.data()); |
| 77 file_data_.remove_prefix(sizeof(T)); |
| 78 return true; |
| 79 } |
| 80 |
| 81 bool Reader::ReadHeader() { |
| 82 if (!CutObject<FileHeader>(&header_)) |
| 83 return false; |
| 84 if (header_->magic != FileHeader::kMagicValue) { |
| 85 LOG(ERROR) << path_.value() << " is not an IPC message file."; |
| 86 return false; |
| 87 } |
| 88 if (header_->version != FileHeader::kCurrentVersion) { |
| 89 LOG(ERROR) << "Wrong version for message file " << path_.value() << ". " |
| 90 << "File version is " << header_->version << ", " |
| 91 << "current version is " << FileHeader::kCurrentVersion << "."; |
| 92 return false; |
| 93 } |
| 94 return true; |
| 95 } |
| 96 |
| 97 bool Reader::MapFile() { |
| 98 if (!mapped_file_.Initialize(path_)) { |
| 99 LOG(ERROR) << "Failed to map testcase: " << path_.value(); |
| 100 return false; |
| 101 } |
| 102 const char* data = reinterpret_cast<const char*>(mapped_file_.data()); |
| 103 file_data_.set(data, mapped_file_.length()); |
| 104 return true; |
| 105 } |
| 106 |
| 107 bool Reader::ReadMessages() { |
| 108 for (size_t i = 0; i < header_->message_count; ++i) { |
| 109 const char* begin = file_data_.begin(); |
| 110 const char* end = file_data_.end(); |
| 111 const char* message_tail = IPC::Message::FindNext(begin, end); |
| 112 if (!message_tail) { |
| 113 LOG(ERROR) << "Failed to parse message."; |
| 114 return false; |
| 115 } |
| 116 |
| 117 size_t msglen = message_tail - begin; |
| 118 if (msglen > INT_MAX) { |
| 119 LOG(ERROR) << "Message too large."; |
| 120 return false; |
| 121 } |
| 122 |
| 123 // Copy is necessary to fix message type later. |
| 124 IPC::Message const_message(begin, msglen); |
| 125 IPC::Message* message = new IPC::Message(const_message); |
| 126 messages_->push_back(message); |
| 127 file_data_.remove_prefix(msglen); |
| 128 } |
| 129 return true; |
| 130 } |
| 131 |
| 132 bool Reader::ReadStringTable() { |
| 133 size_t name_count = header_->name_count; |
| 134 if (!name_count) |
| 135 return true; |
| 136 if (name_count > file_data_.size() / sizeof(NameTableEntry)) { |
| 137 LOG(ERROR) << "Invalid name table size: " << name_count; |
| 138 return false; |
| 139 } |
| 140 |
| 141 size_t string_table_offset = name_count * sizeof(NameTableEntry); |
| 142 string_table_ = file_data_.substr(string_table_offset); |
| 143 if (string_table_.empty()) { |
| 144 LOG(ERROR) << "Missing string table."; |
| 145 return false; |
| 146 } |
| 147 if (string_table_.end()[-1] != '\0') { |
| 148 LOG(ERROR) << "String table doesn't end with NUL."; |
| 149 return false; |
| 150 } |
| 151 return true; |
| 152 } |
| 153 |
| 154 bool Reader::ReadNameTable() { |
| 155 for (size_t i = 0; i < header_->name_count; ++i) { |
| 156 const NameTableEntry* entry; |
| 157 if (!CutObject<NameTableEntry>(&entry)) |
| 158 return false; |
| 159 size_t offset = entry->string_table_offset; |
| 160 if (offset >= string_table_.size()) { |
| 161 LOG(ERROR) << "Invalid string table offset: " << offset; |
| 162 return false; |
| 163 } |
| 164 name_map_.Add(entry->type, std::string(string_table_.data() + offset)); |
| 165 } |
| 166 return true; |
| 167 } |
| 168 |
| 169 bool Reader::RemoveUnknownMessages() { |
| 170 MessageVector::iterator it = messages_->begin(); |
| 171 while (it != messages_->end()) { |
| 172 uint32 type = (*it)->type(); |
| 173 if (!name_map_.TypeExists(type)) { |
| 174 LOG(ERROR) << "Missing name table entry for type " << type; |
| 175 return false; |
| 176 } |
| 177 const std::string& name = name_map_.TypeToName(type); |
| 178 if (!MessageNames::GetInstance()->NameExists(name)) { |
| 179 LOG(WARNING) << "Unknown message " << name; |
| 180 it = messages_->erase(it); |
| 181 } else { |
| 182 ++it; |
| 183 } |
| 184 } |
| 185 return true; |
| 186 } |
| 187 |
| 188 // Message types are based on line numbers, so a minor edit of *_messages.h |
| 189 // changes the types of messages in that file. The types are fixed here to |
| 190 // increase the lifetime of message files. This is only a partial fix because |
| 191 // message arguments and structure layouts can change as well. |
| 192 void Reader::FixMessageTypes() { |
| 193 for (MessageVector::iterator it = messages_->begin(); |
| 194 it != messages_->end(); ++it) { |
| 195 uint32 type = (*it)->type(); |
| 196 const std::string& name = name_map_.TypeToName(type); |
| 197 uint32 correct_type = MessageNames::GetInstance()->NameToType(name); |
| 198 if (type != correct_type) |
| 199 MessageCracker::SetMessageType(*it, correct_type); |
| 200 } |
| 201 } |
| 202 |
| 203 bool Reader::Read(MessageVector* messages) { |
| 204 messages_ = messages; |
| 205 |
| 206 if (!MapFile()) |
| 207 return false; |
| 208 if (!ReadHeader()) |
| 209 return false; |
| 210 if (!ReadMessages()) |
| 211 return false; |
| 212 if (!ReadStringTable()) |
| 213 return false; |
| 214 if (!ReadNameTable()) |
| 215 return false; |
| 216 if (!RemoveUnknownMessages()) |
| 217 return false; |
| 218 FixMessageTypes(); |
| 219 |
| 220 return true; |
| 221 } |
| 222 |
| 223 } // namespace |
| 224 |
| 225 bool MessageFile::Read(const base::FilePath& path, MessageVector* messages) { |
| 226 Reader reader(path); |
| 227 return reader.Read(messages); |
| 228 } |
| 229 |
| 230 } // namespace ipc_fuzzer |
| OLD | NEW |