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"
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
{
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
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_
);
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
,
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:
74 // "HashAlgorithm": SecureHash::SHA256,
75 // "Hash": <Base64 Encoded Hash>,
76 // "PluginPath": /path/to/component/updated/flash.so,
77 // "PluginVersion": "1.0.0.1"
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
))
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
))
104 return base::ImportantFileWriter::WriteFileAtomically(hint_file_path
,
110 bool TestExecutableMapping(const base::FilePath
& path
) {
111 const base::ScopedFD
fd(
112 HANDLE_EINTR(open(path
.value().c_str(), O_RDONLY
| O_CLOEXEC
)));
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)),
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
))
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
,
139 bool DoesHintFileExist() {
140 base::FilePath hint_file_path
;
141 if (!PathService::Get(chrome::FILE_COMPONENT_FLASH_HINT
, &hint_file_path
))
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
))
152 std::string json_string
;
153 if (!base::ReadFileToString(hint_file_path
, &json_string
))
157 std::string error_message
;
158 JSONStringValueDeserializer
deserializer(json_string
);
159 const scoped_ptr
<base::Value
> value(
160 deserializer
.Deserialize(&error_code
, &error_message
));
164 << "Could not deserialize the component updated Flash hint file. Error "
165 << error_code
<< ": " << error_message
;
169 base::DictionaryValue
* dict
= nullptr;
170 if (!value
->GetAsDictionary(&dict
))
174 if (!dict
->GetInteger(kVersionField
, &version
))
176 if (version
< kEarliestHintFileVersion
|| version
> kCurrentHintFileVersion
)
180 if (!dict
->GetInteger(kHashAlgoField
, &hash_algorithm
))
182 if (hash_algorithm
!= crypto::SecureHash::SHA256
)
186 if (!dict
->GetString(kHashField
, &hash
))
189 std::string plugin_path_str
;
190 if (!dict
->GetString(kPluginPath
, &plugin_path_str
))
193 std::string plugin_version_str
;
194 if (!dict
->GetString(kPluginVersion
, &plugin_version_str
))
197 std::string decoded_hash
;
198 if (!base::Base64Decode(hash
, &decoded_hash
))
201 const base::FilePath
plugin_path(plugin_path_str
);
202 base::MemoryMappedFile plugin_file
;
203 if (!plugin_file
.Initialize(plugin_path
))
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
)) {
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.";
218 flash_version
->assign(plugin_version_str
);
222 } // namespace component_flash_hint_file