OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 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 "chrome/browser/install_module_verifier_win.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/basictypes.h" | |
10 #include "base/bind.h" | |
11 #include "base/callback.h" | |
12 #include "base/logging.h" | |
13 #include "base/md5.h" | |
14 #include "base/memory/scoped_ptr.h" | |
15 #include "base/metrics/sparse_histogram.h" | |
16 #include "base/strings/string_number_conversions.h" | |
17 #include "base/strings/string_tokenizer.h" | |
18 #include "base/strings/string_util.h" | |
19 #include "base/values.h" | |
20 #include "chrome/browser/chrome_notification_types.h" | |
21 #include "chrome/browser/enumerate_modules_model_win.h" | |
22 #include "content/public/browser/browser_thread.h" | |
23 #include "content/public/browser/notification_observer.h" | |
24 #include "content/public/browser/notification_registrar.h" | |
25 #include "content/public/browser/notification_service.h" | |
26 #include "content/public/browser/notification_source.h" | |
27 #include "grit/browser_resources.h" | |
28 #include "ui/base/resource/resource_bundle.h" | |
29 | |
30 namespace { | |
31 | |
32 struct { size_t id; const char* module_name_digest; } | |
33 kExpectedInstallModules[] = { | |
34 {1u, "c8cc47613e155f2129f480c6ced84549"}, // chrome.dll | |
35 {2u, "49b78a23b0d8d5d8fb60d4e472b22764"}, // chrome_child.dll | |
36 }; | |
37 | |
38 // Callback for VerifyModules that reports matching module IDs via UMA. | |
39 void OnModuleMatch(size_t module_index) { | |
40 UMA_HISTOGRAM_SPARSE_SLOWLY("InstallVerifier.ModuleMatch", module_index); | |
41 } | |
42 | |
43 // Helper to extract canonical loaded module names from the EnumerateModulesWin | |
44 // output and then verify the results. | |
45 void VerifyEnumeratedModules(const base::ListValue& module_list) { | |
46 std::set<std::string> module_name_digests; | |
47 ExtractLoadedModuleNameDigests(module_list, &module_name_digests); | |
48 | |
49 AdditionalModules additional_modules; | |
50 ParseAdditionalModules( | |
51 ResourceBundle::GetSharedInstance().GetRawDataResource( | |
52 IDR_ADDITIONAL_MODULES_LIST), | |
53 &additional_modules); | |
54 VerifyModules(module_name_digests, | |
55 additional_modules, | |
56 base::Bind(&OnModuleMatch)); | |
57 } | |
58 | |
59 // Waits for NOTIFICATION_MODULE_LIST_ENUMERATED, which indicates that | |
60 // EnumerateModulesWin has completed its work. Retrieves the enumerated module | |
61 // list and processes it. | |
62 class InstallModuleVerifier : public content::NotificationObserver { | |
63 public: | |
64 // Creates an instance that will wait for module enumeration to complete, | |
65 // process the results, and then delete itself. | |
66 static void WaitForModuleList() { | |
67 // Will delete itself when scan results are available. | |
68 new InstallModuleVerifier(); | |
69 } | |
70 | |
71 private: | |
72 // content::NotificationObserver implementation. | |
73 virtual void Observe(int type, | |
74 const content::NotificationSource& source, | |
75 const content::NotificationDetails& details) OVERRIDE { | |
76 DCHECK_EQ(type, chrome::NOTIFICATION_MODULE_LIST_ENUMERATED); | |
77 EnumerateModulesModel* model = | |
78 content::Source<EnumerateModulesModel>(source).ptr(); | |
79 scoped_ptr<base::ListValue> module_list(model->GetModuleList()); | |
80 | |
81 if (module_list.get()) | |
82 VerifyEnumeratedModules(*module_list); | |
83 | |
84 delete this; | |
85 } | |
86 | |
87 InstallModuleVerifier() { | |
sky
2013/10/04 19:21:54
nit: constructor/destructor before other methods i
erikwright (departed)
2013/10/04 20:39:38
Done.
| |
88 notification_registrar_.Add(this, | |
89 chrome::NOTIFICATION_MODULE_LIST_ENUMERATED, | |
90 content::NotificationService::AllSources()); | |
91 } | |
92 | |
93 ~InstallModuleVerifier() {} | |
94 | |
95 content::NotificationRegistrar notification_registrar_; | |
96 | |
97 DISALLOW_COPY_AND_ASSIGN(InstallModuleVerifier); | |
98 }; | |
99 | |
100 } // namespace | |
101 | |
102 void BeginModuleVerification() { | |
103 scoped_ptr<base::ListValue> module_list( | |
104 EnumerateModulesModel::GetInstance()->GetModuleList()); | |
105 if (module_list.get()) { | |
106 VerifyEnumeratedModules(*module_list); | |
107 } else { | |
108 InstallModuleVerifier::WaitForModuleList(); | |
109 EnumerateModulesModel::GetInstance()->ScanNow(); | |
110 } | |
111 } | |
112 | |
113 void ExtractLoadedModuleNameDigests( | |
114 const base::ListValue& module_list, | |
115 std::set<std::string>* module_name_digests) { | |
116 DCHECK(module_name_digests); | |
117 | |
118 // EnumerateModulesModel produces a list of dictionaries. | |
119 // Each dictionary corresponds to a module and exposes a number of properties. | |
120 // We care only about 'type' and 'name'. | |
121 for (size_t i = 0; i < module_list.GetSize(); ++i) { | |
122 const base::DictionaryValue* module_dictionary = NULL; | |
123 if (!module_list.GetDictionary(i, &module_dictionary)) | |
124 continue; | |
125 ModuleEnumerator::ModuleType module_type = | |
126 ModuleEnumerator::LOADED_MODULE; | |
127 if (!module_dictionary->GetInteger( | |
128 "type", reinterpret_cast<int*>(&module_type)) || | |
129 module_type != ModuleEnumerator::LOADED_MODULE) { | |
130 continue; | |
131 } | |
132 std::string module_name; | |
133 if (!module_dictionary->GetString("name", &module_name)) | |
134 continue; | |
135 StringToLowerASCII(&module_name); | |
136 module_name_digests->insert(base::MD5String(module_name)); | |
137 } | |
138 } | |
139 | |
140 void VerifyModules( | |
141 const std::set<std::string>& module_name_digests, | |
142 const AdditionalModules& additional_modules, | |
143 const base::Callback<void(size_t)>& delegate) { | |
144 for (size_t i = 0; i < arraysize(kExpectedInstallModules); ++i) { | |
145 if (module_name_digests.find( | |
146 kExpectedInstallModules[i].module_name_digest) != | |
147 module_name_digests.end()) { | |
148 delegate.Run(kExpectedInstallModules[i].id); | |
149 } | |
150 } | |
151 | |
152 for (AdditionalModules::const_iterator it = additional_modules.begin(); | |
153 it != additional_modules.end(); ++it) { | |
154 std::string additional_module = it->second.as_string(); | |
155 StringToLowerASCII(&additional_module); | |
156 | |
157 if (module_name_digests.find(additional_module) | |
158 != module_name_digests.end()) { | |
159 delegate.Run(it->first); | |
160 } | |
161 } | |
162 } | |
163 | |
164 namespace { | |
165 | |
166 // Parses a line consisting of a positive decimal number and a 32-digit | |
167 // hexadecimal number, separated by a space. Inserts the output, if valid, into | |
168 // |additional_modules|. Unexpected leading or trailing characters will cause | |
169 // the line to be ignored, as will invalid decimal/hexadecimal characters. | |
170 void ParseAdditionalModuleLine( | |
171 const base::StringPiece& line, | |
172 AdditionalModules* additional_modules) { | |
robertshield
2013/10/04 19:12:14
DCHECK(additional_modules);
erikwright (departed)
2013/10/04 20:39:38
Done.
| |
173 base::CStringTokenizer line_tokenizer(line.begin(), line.end(), " "); | |
174 | |
175 if (!line_tokenizer.GetNext()) | |
176 return; // Empty string. | |
177 base::StringPiece id_piece(line_tokenizer.token_piece()); | |
178 | |
179 if (!line_tokenizer.GetNext()) | |
180 return; // No delimiter (' '). | |
181 base::StringPiece digest_piece(line_tokenizer.token_piece()); | |
182 | |
183 if (line_tokenizer.GetNext()) | |
184 return; // Unexpected trailing characters. | |
185 | |
186 unsigned id = 0; | |
187 if (!StringToUint(id_piece, &id)) | |
188 return; // First token was not decimal. | |
189 | |
190 if (digest_piece.length() != 32) | |
191 return; // Second token is not the right length. | |
192 | |
193 for (base::StringPiece::const_iterator it = digest_piece.begin(); | |
194 it != digest_piece.end(); ++it) { | |
195 if (!IsHexDigit(*it)) | |
196 return; // Second token has invalid characters. | |
197 } | |
198 | |
199 // This is a valid line. | |
200 additional_modules->push_back(std::make_pair(id, digest_piece)); | |
201 } | |
202 | |
203 } // namespace | |
204 | |
205 void ParseAdditionalModules( | |
206 const base::StringPiece& raw_data, | |
207 AdditionalModules* additional_modules) { | |
208 base::CStringTokenizer file_tokenizer(raw_data.begin(), raw_data.end(), "\n"); | |
209 while (file_tokenizer.GetNext()) { | |
210 ParseAdditionalModuleLine(base::StringPiece(file_tokenizer.token_piece()), | |
211 additional_modules); | |
212 } | |
213 } | |
OLD | NEW |