Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(337)

Side by Side Diff: extensions/browser/content_verifier.cc

Issue 329303007: Fix several problems with the content verification code (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: ready Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "extensions/browser/content_verifier.h" 5 #include "extensions/browser/content_verifier.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/files/file_path.h" 10 #include "base/files/file_path.h"
(...skipping 14 matching lines...) Expand all
25 25
26 } // namespace 26 } // namespace
27 27
28 namespace extensions { 28 namespace extensions {
29 29
30 ContentVerifier::ContentVerifier(content::BrowserContext* context, 30 ContentVerifier::ContentVerifier(content::BrowserContext* context,
31 ContentVerifierDelegate* delegate) 31 ContentVerifierDelegate* delegate)
32 : mode_(GetMode()), 32 : mode_(GetMode()),
33 context_(context), 33 context_(context),
34 delegate_(delegate), 34 delegate_(delegate),
35 fetcher_(new ContentHashFetcher(context, delegate)) { 35 fetcher_(new ContentHashFetcher(
36 context,
37 delegate,
38 base::Bind(&ContentVerifier::OnFetchComplete, this))) {
36 } 39 }
37 40
38 ContentVerifier::~ContentVerifier() { 41 ContentVerifier::~ContentVerifier() {
39 } 42 }
40 43
41 void ContentVerifier::Start() { 44 void ContentVerifier::Start() {
42 if (mode_ >= BOOTSTRAP) 45 if (mode_ >= BOOTSTRAP)
43 fetcher_->Start(); 46 fetcher_->Start();
44 } 47 }
45 48
46 void ContentVerifier::Shutdown() { 49 void ContentVerifier::Shutdown() {
47 fetcher_.reset(); 50 fetcher_.reset();
48 delegate_.reset(); 51 delegate_.reset();
49 } 52 }
50 53
51 ContentVerifyJob* ContentVerifier::CreateJobFor( 54 ContentVerifyJob* ContentVerifier::CreateJobFor(
52 const std::string& extension_id, 55 const std::string& extension_id,
53 const base::FilePath& extension_root, 56 const base::FilePath& extension_root,
54 const base::FilePath& relative_path) { 57 const base::FilePath& relative_path) {
55 if (mode_ < BOOTSTRAP || !delegate_) 58 if (mode_ < BOOTSTRAP || !delegate_)
56 return NULL; 59 return NULL;
57 60
58 ExtensionRegistry* registry = ExtensionRegistry::Get(context_); 61 ExtensionRegistry* registry = ExtensionRegistry::Get(context_);
59 const Extension* extension = 62 const Extension* extension =
60 registry->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING); 63 registry->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
61 64
62 if (!extension || !extension->version() || 65 std::set<base::FilePath> paths;
63 !delegate_->ShouldBeVerified(*extension)) 66 paths.insert(relative_path);
67 if (!ShouldVerifyAnyPaths(extension, paths))
64 return NULL; 68 return NULL;
65 69
66 // Images used in the browser get transcoded during install, so skip checking
67 // them for now. TODO(asargent) - see if we can cache this list for a given
68 // extension id/version pair.
69 std::set<base::FilePath> browser_images =
70 delegate_->GetBrowserImagePaths(extension);
71 if (ContainsKey(browser_images, relative_path))
72 return NULL;
73
74 base::FilePath locales_dir = extension_root.Append(kLocaleFolder);
75 base::FilePath full_path = extension_root.Append(relative_path);
76 if (locales_dir.IsParent(full_path)) {
77 // TODO(asargent) - see if we can cache this list to avoid having to fetch
78 // it every time. Maybe it can never change at runtime? (Or if it can,
79 // maybe there is an event we can listen for to know to drop our cache).
80 std::set<std::string> all_locales;
81 extension_l10n_util::GetAllLocales(&all_locales);
82 // Since message catalogs get transcoded during installation, we want to
83 // ignore only those paths that the localization transcoding *did* ignore.
84 if (!extension_l10n_util::ShouldSkipValidation(
85 locales_dir, full_path, all_locales))
86 return NULL;
87 }
88
89 // TODO(asargent) - we can probably get some good performance wins by having 70 // TODO(asargent) - we can probably get some good performance wins by having
90 // a cache of ContentHashReader's that we hold onto past the end of each job. 71 // a cache of ContentHashReader's that we hold onto past the end of each job.
91 return new ContentVerifyJob( 72 return new ContentVerifyJob(
92 new ContentHashReader(extension_id, 73 new ContentHashReader(extension_id,
93 *extension->version(), 74 *extension->version(),
94 extension_root, 75 extension_root,
95 relative_path, 76 relative_path,
96 delegate_->PublicKey()), 77 delegate_->PublicKey()),
97 base::Bind(&ContentVerifier::VerifyFailed, this, extension->id())); 78 base::Bind(&ContentVerifier::VerifyFailed, this, extension->id()));
98 } 79 }
99 80
100 void ContentVerifier::VerifyFailed(const std::string& extension_id, 81 void ContentVerifier::VerifyFailed(const std::string& extension_id,
101 ContentVerifyJob::FailureReason reason) { 82 ContentVerifyJob::FailureReason reason) {
102 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { 83 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
103 content::BrowserThread::PostTask( 84 content::BrowserThread::PostTask(
104 content::BrowserThread::UI, 85 content::BrowserThread::UI,
105 FROM_HERE, 86 FROM_HERE,
106 base::Bind(&ContentVerifier::VerifyFailed, this, extension_id, reason)); 87 base::Bind(&ContentVerifier::VerifyFailed, this, extension_id, reason));
107 return; 88 return;
108 } 89 }
109 90
110 if (!delegate_ || mode_ < ENFORCE) 91 VLOG(1) << "VerifyFailed " << extension_id << " reason:" << reason;
92
93 if (!delegate_ || !fetcher_.get() || mode_ < ENFORCE)
111 return; 94 return;
112 95
113 if (reason == ContentVerifyJob::NO_HASHES && mode_ < ENFORCE_STRICT && 96 if (reason == ContentVerifyJob::MISSING_ALL_HASHES) {
114 fetcher_.get()) {
115 // If we failed because there were no hashes yet for this extension, just 97 // If we failed because there were no hashes yet for this extension, just
116 // request some. 98 // request some.
117 ExtensionRegistry* registry = ExtensionRegistry::Get(context_); 99 ExtensionRegistry* registry = ExtensionRegistry::Get(context_);
118 const Extension* extension = 100 const Extension* extension =
119 registry->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING); 101 registry->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
120 if (extension) 102 if (extension)
121 fetcher_->DoFetch(extension); 103 fetcher_->DoFetch(extension, true /* force */);
104 } else {
105 delegate_->VerifyFailed(extension_id);
106 }
107 }
108
109 void ContentVerifier::OnFetchComplete(
110 const std::string& extension_id,
111 bool success,
112 bool was_force_check,
113 const std::set<base::FilePath>& hash_mismatch_paths) {
114 VLOG(1) << "OnFetchComplete " << extension_id << " success:" << success;
115
116 if (!delegate_ || mode_ < ENFORCE)
122 return; 117 return;
118
119 if (!success && mode_ < ENFORCE_STRICT)
120 return;
121
122 ExtensionRegistry* registry = ExtensionRegistry::Get(context_);
123 const Extension* extension =
124 registry->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
125 if (!extension)
126 return;
127
128 if ((was_force_check && !success) ||
129 ShouldVerifyAnyPaths(extension, hash_mismatch_paths))
130 delegate_->VerifyFailed(extension_id);
131 }
132
133 bool ContentVerifier::ShouldVerifyAnyPaths(
134 const Extension* extension,
135 const std::set<base::FilePath>& relative_paths) {
136 if (!extension || !extension->version() ||
137 !delegate_->ShouldBeVerified(*extension))
138 return false;
139
140 // Images used in the browser get transcoded during install, so skip
141 // checking them for now. TODO(asargent) - see if we can cache this list
142 // for a given extension id/version pair.
143 std::set<base::FilePath> browser_images =
144 delegate_->GetBrowserImagePaths(extension);
145
146 base::FilePath locales_dir = extension->path().Append(kLocaleFolder);
147 scoped_ptr<std::set<std::string> > all_locales;
148
149 for (std::set<base::FilePath>::const_iterator i = relative_paths.begin();
150 i != relative_paths.end();
151 ++i) {
152 const base::FilePath& relative_path = *i;
153
154 if (relative_path == base::FilePath(kManifestFilename))
155 continue;
156
157 if (ContainsKey(browser_images, relative_path))
158 continue;
159
160 base::FilePath full_path = extension->path().Append(relative_path);
161 if (locales_dir.IsParent(full_path)) {
162 if (!all_locales) {
163 // TODO(asargent) - see if we can cache this list longer to avoid
164 // having to fetch it more than once for a given run of the
165 // browser. Maybe it can never change at runtime? (Or if it can, maybe
166 // there is an event we can listen for to know to drop our cache).
167 all_locales.reset(new std::set<std::string>);
168 extension_l10n_util::GetAllLocales(all_locales.get());
169 }
170
171 // Since message catalogs get transcoded during installation, we want
172 // to skip those paths.
173 if (full_path.DirName().DirName() == locales_dir &&
174 !extension_l10n_util::ShouldSkipValidation(
175 locales_dir, full_path.DirName(), *all_locales))
176 continue;
177 }
178 return true;
123 } 179 }
124 delegate_->VerifyFailed(extension_id); 180 return false;
125 } 181 }
126 182
127 // static 183 // static
128 ContentVerifier::Mode ContentVerifier::GetMode() { 184 ContentVerifier::Mode ContentVerifier::GetMode() {
129 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); 185 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
130 186
131 Mode experiment_value = NONE; 187 Mode experiment_value = NONE;
132 const std::string group = base::FieldTrialList::FindFullName(kExperimentName); 188 const std::string group = base::FieldTrialList::FindFullName(kExperimentName);
133 if (group == "EnforceStrict") 189 if (group == "EnforceStrict")
134 experiment_value = ENFORCE_STRICT; 190 experiment_value = ENFORCE_STRICT;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
166 cmdline_value = ENFORCE; 222 cmdline_value = ENFORCE;
167 } 223 }
168 224
169 // We don't want to allow the command-line flags to eg disable enforcement if 225 // We don't want to allow the command-line flags to eg disable enforcement if
170 // the experiment group says it should be on, or malware may just modify the 226 // the experiment group says it should be on, or malware may just modify the
171 // command line flags. So return the more restrictive of the 2 values. 227 // command line flags. So return the more restrictive of the 2 values.
172 return std::max(experiment_value, cmdline_value); 228 return std::max(experiment_value, cmdline_value);
173 } 229 }
174 230
175 } // namespace extensions 231 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698