Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / common / component_flash_hint_file_linux.cc
blob160c8e83568b213873afaef7f57f1d1d2c27af69
1 // Copyright 2015 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.
5 #include "chrome/common/component_flash_hint_file_linux.h"
7 #include <fcntl.h>
8 #include <sys/mman.h>
10 #include "base/base64.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/files/important_file_writer.h"
14 #include "base/files/memory_mapped_file.h"
15 #include "base/files/scoped_file.h"
16 #include "base/json/json_string_value_serializer.h"
17 #include "base/path_service.h"
18 #include "base/posix/eintr_wrapper.h"
19 #include "base/stl_util.h"
20 #include "base/values.h"
21 #include "chrome/common/chrome_paths.h"
22 #include "crypto/secure_hash.h"
23 #include "crypto/secure_util.h"
24 #include "crypto/sha2.h"
26 namespace component_flash_hint_file {
28 namespace {
30 // The current version of the hints file.
31 const int kCurrentHintFileVersion = 0x10;
32 // The earliest version of the hints file.
33 const int kEarliestHintFileVersion = 0x10;
34 // The Version field in the JSON encoded file.
35 const char kVersionField[] = "Version";
36 // The HashAlgorithm field in the JSON encoded file.
37 const char kHashAlgoField[] = "HashAlgorithm";
38 // The Hash field in the JSON encoded file.
39 const char kHashField[] = "Hash";
40 // The PluginPath field in the JSON encoded file.
41 const char kPluginPath[] = "PluginPath";
42 // The PluginVersion field in the JSON encoded file.
43 const char kPluginVersion[] = "PluginVersion";
44 // For use with the scoped_ptr of an mmap-ed buffer
45 struct MmapDeleter {
46 explicit MmapDeleter(size_t map_size) : map_size_(map_size) { }
47 inline void operator()(uint8_t* ptr) const {
48 if (ptr != MAP_FAILED)
49 munmap(ptr, map_size_);
52 private:
53 size_t map_size_;
56 // Hashes the plugin file and returns the result in the out params.
57 // |mapped_file| is the file to be hashed.
58 // |result| is the buffer, which must be of size crypto::kSHA256Length, which
59 // will contain the hash.
60 // |len| is the size of the buffer, which must be crypto::kSHA256Length.
61 void SHA256Hash(const base::MemoryMappedFile& mapped_file,
62 void* result,
63 size_t len) {
64 CHECK_EQ(crypto::kSHA256Length, len);
65 scoped_ptr<crypto::SecureHash> secure_hash(
66 crypto::SecureHash::Create(crypto::SecureHash::SHA256));
67 secure_hash->Update(mapped_file.data(), mapped_file.length());
68 secure_hash->Finish(result, len);
71 // This will serialize the file to disk as JSON. The format is:
72 // {
73 // "Version": 0x10,
74 // "HashAlgorithm": SecureHash::SHA256,
75 // "Hash": <Base64 Encoded Hash>,
76 // "PluginPath": /path/to/component/updated/flash.so,
77 // "PluginVersion": "1.0.0.1"
78 // }
79 bool WriteToDisk(const int version,
80 const crypto::SecureHash::Algorithm algorithm,
81 const std::string& hash,
82 const base::FilePath& plugin_path,
83 const std::string& flash_version) {
84 base::FilePath hint_file_path;
85 if (!PathService::Get(chrome::FILE_COMPONENT_FLASH_HINT, &hint_file_path))
86 return false;
88 std::string encoded_hash;
89 base::Base64Encode(hash, &encoded_hash);
91 // Now construct a Value object to convert to JSON.
92 base::DictionaryValue dict;
93 dict.SetInteger(kVersionField, version);
94 dict.SetInteger(kHashAlgoField, crypto::SecureHash::SHA256);
95 dict.SetString(kHashField, encoded_hash);
96 dict.SetString(kPluginPath, plugin_path.value());
97 dict.SetString(kPluginVersion, flash_version);
98 // Do the serialization of the DictionaryValue to JSON.
99 std::string json_string;
100 JSONStringValueSerializer serializer(&json_string);
101 if (!serializer.Serialize(dict))
102 return false;
104 return base::ImportantFileWriter::WriteFileAtomically(hint_file_path,
105 json_string);
108 } // namespace
110 bool TestExecutableMapping(const base::FilePath& path) {
111 const base::ScopedFD fd(
112 HANDLE_EINTR(open(path.value().c_str(), O_RDONLY | O_CLOEXEC)));
113 if (!fd.is_valid())
114 return false;
115 const size_t map_size = sizeof(uint8_t);
116 const MmapDeleter deleter(map_size);
117 scoped_ptr<uint8_t, MmapDeleter> buf_ptr(
118 reinterpret_cast<uint8_t*>(mmap(nullptr, map_size, PROT_READ | PROT_EXEC,
119 MAP_PRIVATE, fd.get(), 0)),
120 deleter);
121 return buf_ptr.get() != MAP_FAILED;
124 bool RecordFlashUpdate(const base::FilePath& unpacked_plugin,
125 const base::FilePath& moved_plugin,
126 const std::string& version) {
127 base::MemoryMappedFile mapped_file;
128 if (!mapped_file.Initialize(unpacked_plugin))
129 return false;
131 std::string hash(crypto::kSHA256Length, 0);
132 SHA256Hash(mapped_file, string_as_array(&hash), hash.size());
134 return WriteToDisk(kCurrentHintFileVersion,
135 crypto::SecureHash::Algorithm::SHA256, hash, moved_plugin,
136 version);
139 bool DoesHintFileExist() {
140 base::FilePath hint_file_path;
141 if (!PathService::Get(chrome::FILE_COMPONENT_FLASH_HINT, &hint_file_path))
142 return false;
143 return base::PathExists(hint_file_path);
146 bool VerifyAndReturnFlashLocation(base::FilePath* path,
147 std::string* flash_version) {
148 base::FilePath hint_file_path;
149 if (!PathService::Get(chrome::FILE_COMPONENT_FLASH_HINT, &hint_file_path))
150 return false;
152 std::string json_string;
153 if (!base::ReadFileToString(hint_file_path, &json_string))
154 return false;
156 int error_code;
157 std::string error_message;
158 JSONStringValueDeserializer deserializer(json_string);
159 const scoped_ptr<base::Value> value(
160 deserializer.Deserialize(&error_code, &error_message));
162 if (!value) {
163 LOG(ERROR)
164 << "Could not deserialize the component updated Flash hint file. Error "
165 << error_code << ": " << error_message;
166 return false;
169 base::DictionaryValue* dict = nullptr;
170 if (!value->GetAsDictionary(&dict))
171 return false;
173 int version;
174 if (!dict->GetInteger(kVersionField, &version))
175 return false;
176 if (version < kEarliestHintFileVersion || version > kCurrentHintFileVersion)
177 return false;
179 int hash_algorithm;
180 if (!dict->GetInteger(kHashAlgoField, &hash_algorithm))
181 return false;
182 if (hash_algorithm != crypto::SecureHash::SHA256)
183 return false;
185 std::string hash;
186 if (!dict->GetString(kHashField, &hash))
187 return false;
189 std::string plugin_path_str;
190 if (!dict->GetString(kPluginPath, &plugin_path_str))
191 return false;
193 std::string plugin_version_str;
194 if (!dict->GetString(kPluginVersion, &plugin_version_str))
195 return false;
197 std::string decoded_hash;
198 if (!base::Base64Decode(hash, &decoded_hash))
199 return false;
201 const base::FilePath plugin_path(plugin_path_str);
202 base::MemoryMappedFile plugin_file;
203 if (!plugin_file.Initialize(plugin_path))
204 return false;
206 std::vector<uint8_t> file_hash(crypto::kSHA256Length, 0);
207 SHA256Hash(plugin_file, &file_hash[0], file_hash.size());
208 if (!crypto::SecureMemEqual(&file_hash[0], string_as_array(&decoded_hash),
209 crypto::kSHA256Length)) {
210 LOG(ERROR)
211 << "The hash recorded in the component flash hint file does not "
212 "match the actual hash of the flash plugin found on disk. The "
213 "component flash plugin will not be loaded.";
214 return false;
217 *path = plugin_path;
218 flash_version->assign(plugin_version_str);
219 return true;
222 } // namespace component_flash_hint_file