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 #include <set> 7 8 #include "base/files/file.h" 9 #include "base/logging.h" 10 #include "tools/ipc_fuzzer/message_lib/message_file.h" 11 #include "tools/ipc_fuzzer/message_lib/message_file_format.h" 12 #include "tools/ipc_fuzzer/message_lib/message_names.h" 13 14 namespace ipc_fuzzer { 15 16 namespace { 17 18 // Helper class to write a MessageVector + message names to a file. 19 class Writer { 20 public: 21 Writer(const base::FilePath& path); 22 ~Writer() {} 23 bool Write(const MessageVector& messages); 24 25 private: 26 bool OpenFile(); 27 28 // Helper to append data to file_. 29 bool WriteBlob(const void *buffer, size_t size); 30 31 // Collects a set of MessageVector message types. Corresponding message 32 // names need to be included in the file. 33 bool CollectMessageTypes(); 34 35 bool WriteHeader(); 36 bool WriteMessages(); 37 38 // Each name table entry is a message type + string table offset. 39 bool WriteNameTable(); 40 41 // String table contains the actual message names. 42 bool WriteStringTable(); 43 44 typedef std::set<uint32> TypesSet; 45 base::FilePath path_; 46 base::File file_; 47 const MessageVector* messages_; 48 TypesSet types_; 49 50 DISALLOW_COPY_AND_ASSIGN(Writer); 51 }; 52 53 Writer::Writer(const base::FilePath& path) : path_(path), messages_(NULL) { 54 } 55 56 bool Writer::OpenFile() { 57 file_.Initialize(path_, 58 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); 59 if (!file_.IsValid()) { 60 LOG(ERROR) << "Failed to create IPC message file: " << path_.value(); 61 return false; 62 } 63 return true; 64 } 65 66 bool Writer::WriteBlob(const void *buffer, size_t size) { 67 if (size > INT_MAX) 68 return false; 69 const char* char_buffer = static_cast<const char*>(buffer); 70 int ret = file_.WriteAtCurrentPos(char_buffer, size); 71 if (ret != static_cast<int>(size)) { 72 LOG(ERROR) << "Failed to write " << size << " bytes."; 73 return false; 74 } 75 return true; 76 } 77 78 bool Writer::CollectMessageTypes() { 79 for (size_t i = 0; i < messages_->size(); ++i) { 80 uint32_t type = (*messages_)[i]->type(); 81 if (!MessageNames::GetInstance()->TypeExists(type)) { 82 LOG(ERROR) << "Unknown message type: " << type; 83 return false; 84 } 85 types_.insert(type); 86 } 87 return true; 88 } 89 90 bool Writer::WriteHeader() { 91 FileHeader header; 92 if (messages_->size() > UINT_MAX) 93 return false; 94 header.magic = FileHeader::kMagicValue; 95 header.version = FileHeader::kCurrentVersion; 96 header.message_count = messages_->size(); 97 header.name_count = types_.size(); 98 if (!WriteBlob(&header, sizeof(FileHeader))) 99 return false; 100 return true; 101 } 102 103 bool Writer::WriteMessages() { 104 for (size_t i = 0; i < messages_->size(); ++i) { 105 IPC::Message* message = (*messages_)[i]; 106 if (!WriteBlob(message->data(), message->size())) 107 return false; 108 } 109 return true; 110 } 111 112 bool Writer::WriteNameTable() { 113 size_t string_table_offset = 0; 114 NameTableEntry entry; 115 116 for (TypesSet::iterator it = types_.begin(); it != types_.end(); ++it) { 117 if (string_table_offset > UINT_MAX) 118 return false; 119 entry.type = *it; 120 entry.string_table_offset = string_table_offset; 121 if (!WriteBlob(&entry, sizeof(NameTableEntry))) 122 return false; 123 const std::string& name = MessageNames::GetInstance()->TypeToName(*it); 124 string_table_offset += name.length() + 1; 125 } 126 return true; 127 } 128 129 bool Writer::WriteStringTable() { 130 for (TypesSet::iterator it = types_.begin(); it != types_.end(); ++it) { 131 const std::string& name = MessageNames::GetInstance()->TypeToName(*it); 132 if (!WriteBlob(name.c_str(), name.length() + 1)) 133 return false; 134 } 135 return true; 136 } 137 138 bool Writer::Write(const MessageVector& messages) { 139 messages_ = &messages; 140 141 if (!OpenFile()) 142 return false; 143 if (!CollectMessageTypes()) 144 return false; 145 if (!WriteHeader()) 146 return false; 147 if (!WriteMessages()) 148 return false; 149 if (!WriteNameTable()) 150 return false; 151 if (!WriteStringTable()) 152 return false; 153 154 return true; 155 } 156 157 } // namespace 158 159 bool MessageFile::Write(const base::FilePath& path, 160 const MessageVector& messages) { 161 Writer writer(path); 162 return writer.Write(messages); 163 } 164 165 } // namespace ipc_fuzzer 166