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 14namespace ipc_fuzzer { 15 16namespace { 17 18// Helper class to write a MessageVector + message names to a file. 19class 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 53Writer::Writer(const base::FilePath& path) : path_(path), messages_(NULL) { 54} 55 56bool 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 66bool 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 78bool 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 90bool 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 103bool 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 112bool 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 129bool 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 138bool 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 159bool 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