OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 "chrome/browser/child_process_security_policy.h" | 5 #include "chrome/browser/child_process_security_policy.h" |
6 | 6 |
7 #include "base/file_path.h" | 7 #include "base/file_path.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/platform_file.h" | 9 #include "base/platform_file.h" |
10 #include "base/stl_util-inl.h" | 10 #include "base/stl_util-inl.h" |
11 #include "base/string_util.h" | 11 #include "base/string_util.h" |
12 #include "chrome/common/bindings_policy.h" | 12 #include "chrome/common/bindings_policy.h" |
13 #include "chrome/common/url_constants.h" | 13 #include "chrome/common/url_constants.h" |
14 #include "googleurl/src/gurl.h" | 14 #include "googleurl/src/gurl.h" |
15 #include "net/url_request/url_request.h" | 15 #include "net/url_request/url_request.h" |
16 | 16 |
17 static const int kReadFilePermissions = | 17 static const int kReadFilePermissions = |
18 base::PLATFORM_FILE_OPEN | | 18 base::PLATFORM_FILE_OPEN | |
19 base::PLATFORM_FILE_READ | | 19 base::PLATFORM_FILE_READ | |
20 base::PLATFORM_FILE_EXCLUSIVE_READ | | 20 base::PLATFORM_FILE_EXCLUSIVE_READ | |
21 base::PLATFORM_FILE_ASYNC; | 21 base::PLATFORM_FILE_ASYNC; |
22 | 22 |
23 // The SecurityState class is used to maintain per-renderer security state | 23 // The SecurityState class is used to maintain per-child process security state |
24 // information. | 24 // information. |
25 class ChildProcessSecurityPolicy::SecurityState { | 25 class ChildProcessSecurityPolicy::SecurityState { |
26 public: | 26 public: |
27 SecurityState() | 27 SecurityState() |
28 : enabled_bindings_(0), | 28 : enabled_bindings_(0), |
29 can_read_raw_cookies_(false) { } | 29 can_read_raw_cookies_(false) { } |
30 ~SecurityState() { | 30 ~SecurityState() { |
31 scheme_policy_.clear(); | 31 scheme_policy_.clear(); |
32 } | 32 } |
33 | 33 |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 typedef std::map<std::string, bool> SchemeMap; | 104 typedef std::map<std::string, bool> SchemeMap; |
105 typedef std::map<FilePath, int> FileMap; // bit-set of PlatformFileFlags | 105 typedef std::map<FilePath, int> FileMap; // bit-set of PlatformFileFlags |
106 | 106 |
107 // Maps URL schemes to whether permission has been granted or revoked: | 107 // Maps URL schemes to whether permission has been granted or revoked: |
108 // |true| means the scheme has been granted. | 108 // |true| means the scheme has been granted. |
109 // |false| means the scheme has been revoked. | 109 // |false| means the scheme has been revoked. |
110 // If a scheme is not present in the map, then it has never been granted | 110 // If a scheme is not present in the map, then it has never been granted |
111 // or revoked. | 111 // or revoked. |
112 SchemeMap scheme_policy_; | 112 SchemeMap scheme_policy_; |
113 | 113 |
114 // The set of files the renderer is permited to upload to the web. | 114 // The set of files the child process is permited to upload to the web. |
115 FileMap file_permissions_; | 115 FileMap file_permissions_; |
116 | 116 |
117 int enabled_bindings_; | 117 int enabled_bindings_; |
118 | 118 |
119 bool can_read_raw_cookies_; | 119 bool can_read_raw_cookies_; |
120 | 120 |
121 DISALLOW_COPY_AND_ASSIGN(SecurityState); | 121 DISALLOW_COPY_AND_ASSIGN(SecurityState); |
122 }; | 122 }; |
123 | 123 |
124 ChildProcessSecurityPolicy::ChildProcessSecurityPolicy() { | 124 ChildProcessSecurityPolicy::ChildProcessSecurityPolicy() { |
(...skipping 18 matching lines...) Expand all Loading... |
143 STLDeleteContainerPairSecondPointers(security_state_.begin(), | 143 STLDeleteContainerPairSecondPointers(security_state_.begin(), |
144 security_state_.end()); | 144 security_state_.end()); |
145 security_state_.clear(); | 145 security_state_.clear(); |
146 } | 146 } |
147 | 147 |
148 // static | 148 // static |
149 ChildProcessSecurityPolicy* ChildProcessSecurityPolicy::GetInstance() { | 149 ChildProcessSecurityPolicy* ChildProcessSecurityPolicy::GetInstance() { |
150 return Singleton<ChildProcessSecurityPolicy>::get(); | 150 return Singleton<ChildProcessSecurityPolicy>::get(); |
151 } | 151 } |
152 | 152 |
153 void ChildProcessSecurityPolicy::Add(int renderer_id) { | 153 void ChildProcessSecurityPolicy::Add(int child_id) { |
154 AutoLock lock(lock_); | 154 AutoLock lock(lock_); |
155 if (security_state_.count(renderer_id) != 0) { | 155 if (security_state_.count(child_id) != 0) { |
156 NOTREACHED() << "Add renderers at most once."; | 156 NOTREACHED() << "Add child process at most once."; |
157 return; | 157 return; |
158 } | 158 } |
159 | 159 |
160 security_state_[renderer_id] = new SecurityState(); | 160 security_state_[child_id] = new SecurityState(); |
161 } | 161 } |
162 | 162 |
163 void ChildProcessSecurityPolicy::Remove(int renderer_id) { | 163 void ChildProcessSecurityPolicy::Remove(int child_id) { |
164 AutoLock lock(lock_); | 164 AutoLock lock(lock_); |
165 if (!security_state_.count(renderer_id)) | 165 if (!security_state_.count(child_id)) |
166 return; // May be called multiple times. | 166 return; // May be called multiple times. |
167 | 167 |
168 delete security_state_[renderer_id]; | 168 delete security_state_[child_id]; |
169 security_state_.erase(renderer_id); | 169 security_state_.erase(child_id); |
170 } | 170 } |
171 | 171 |
172 void ChildProcessSecurityPolicy::RegisterWebSafeScheme( | 172 void ChildProcessSecurityPolicy::RegisterWebSafeScheme( |
173 const std::string& scheme) { | 173 const std::string& scheme) { |
174 AutoLock lock(lock_); | 174 AutoLock lock(lock_); |
175 DCHECK(web_safe_schemes_.count(scheme) == 0) << "Add schemes at most once."; | 175 DCHECK(web_safe_schemes_.count(scheme) == 0) << "Add schemes at most once."; |
176 DCHECK(pseudo_schemes_.count(scheme) == 0) << "Web-safe implies not psuedo."; | 176 DCHECK(pseudo_schemes_.count(scheme) == 0) << "Web-safe implies not psuedo."; |
177 | 177 |
178 web_safe_schemes_.insert(scheme); | 178 web_safe_schemes_.insert(scheme); |
179 } | 179 } |
(...skipping 14 matching lines...) Expand all Loading... |
194 pseudo_schemes_.insert(scheme); | 194 pseudo_schemes_.insert(scheme); |
195 } | 195 } |
196 | 196 |
197 bool ChildProcessSecurityPolicy::IsPseudoScheme(const std::string& scheme) { | 197 bool ChildProcessSecurityPolicy::IsPseudoScheme(const std::string& scheme) { |
198 AutoLock lock(lock_); | 198 AutoLock lock(lock_); |
199 | 199 |
200 return (pseudo_schemes_.find(scheme) != pseudo_schemes_.end()); | 200 return (pseudo_schemes_.find(scheme) != pseudo_schemes_.end()); |
201 } | 201 } |
202 | 202 |
203 void ChildProcessSecurityPolicy::GrantRequestURL( | 203 void ChildProcessSecurityPolicy::GrantRequestURL( |
204 int renderer_id, const GURL& url) { | 204 int child_id, const GURL& url) { |
205 | 205 |
206 if (!url.is_valid()) | 206 if (!url.is_valid()) |
207 return; // Can't grant the capability to request invalid URLs. | 207 return; // Can't grant the capability to request invalid URLs. |
208 | 208 |
209 if (IsWebSafeScheme(url.scheme())) | 209 if (IsWebSafeScheme(url.scheme())) |
210 return; // The scheme has already been white-listed for every renderer. | 210 return; // The scheme has already been whitelisted for every child process. |
211 | 211 |
212 if (IsPseudoScheme(url.scheme())) { | 212 if (IsPseudoScheme(url.scheme())) { |
213 // The view-source scheme is a special case of a pseudo-URL that eventually | 213 // The view-source scheme is a special case of a pseudo-URL that eventually |
214 // results in requesting its embedded URL. | 214 // results in requesting its embedded URL. |
215 if (url.SchemeIs(chrome::kViewSourceScheme)) { | 215 if (url.SchemeIs(chrome::kViewSourceScheme)) { |
216 // URLs with the view-source scheme typically look like: | 216 // URLs with the view-source scheme typically look like: |
217 // view-source:http://www.google.com/a | 217 // view-source:http://www.google.com/a |
218 // In order to request these URLs, the renderer needs to be able to | 218 // In order to request these URLs, the child_id needs to be able to |
219 // request the embedded URL. | 219 // request the embedded URL. |
220 GrantRequestURL(renderer_id, GURL(url.path())); | 220 GrantRequestURL(child_id, GURL(url.path())); |
221 } | 221 } |
222 | 222 |
223 return; // Can't grant the capability to request pseudo schemes. | 223 return; // Can't grant the capability to request pseudo schemes. |
224 } | 224 } |
225 | 225 |
226 { | 226 { |
227 AutoLock lock(lock_); | 227 AutoLock lock(lock_); |
228 SecurityStateMap::iterator state = security_state_.find(renderer_id); | 228 SecurityStateMap::iterator state = security_state_.find(child_id); |
229 if (state == security_state_.end()) | 229 if (state == security_state_.end()) |
230 return; | 230 return; |
231 | 231 |
232 // If the renderer has been commanded to request a scheme, then we grant | 232 // If the child process has been commanded to request a scheme, then we |
233 // it the capability to request URLs of that scheme. | 233 // grant it the capability to request URLs of that scheme. |
234 state->second->GrantScheme(url.scheme()); | 234 state->second->GrantScheme(url.scheme()); |
235 } | 235 } |
236 } | 236 } |
237 | 237 |
238 void ChildProcessSecurityPolicy::GrantReadFile(int renderer_id, | 238 void ChildProcessSecurityPolicy::GrantReadFile(int child_id, |
239 const FilePath& file) { | 239 const FilePath& file) { |
240 GrantPermissionsForFile(renderer_id, file, kReadFilePermissions); | 240 GrantPermissionsForFile(child_id, file, kReadFilePermissions); |
241 } | 241 } |
242 | 242 |
243 void ChildProcessSecurityPolicy::GrantPermissionsForFile( | 243 void ChildProcessSecurityPolicy::GrantPermissionsForFile( |
244 int renderer_id, const FilePath& file, int permissions) { | 244 int child_id, const FilePath& file, int permissions) { |
245 AutoLock lock(lock_); | 245 AutoLock lock(lock_); |
246 | 246 |
247 SecurityStateMap::iterator state = security_state_.find(renderer_id); | 247 SecurityStateMap::iterator state = security_state_.find(child_id); |
248 if (state == security_state_.end()) | 248 if (state == security_state_.end()) |
249 return; | 249 return; |
250 | 250 |
251 state->second->GrantPermissionsForFile(file, permissions); | 251 state->second->GrantPermissionsForFile(file, permissions); |
252 } | 252 } |
253 | 253 |
254 void ChildProcessSecurityPolicy::RevokeAllPermissionsForFile( | 254 void ChildProcessSecurityPolicy::RevokeAllPermissionsForFile( |
255 int renderer_id, const FilePath& file) { | 255 int child_id, const FilePath& file) { |
256 AutoLock lock(lock_); | 256 AutoLock lock(lock_); |
257 | 257 |
258 SecurityStateMap::iterator state = security_state_.find(renderer_id); | 258 SecurityStateMap::iterator state = security_state_.find(child_id); |
259 if (state == security_state_.end()) | 259 if (state == security_state_.end()) |
260 return; | 260 return; |
261 | 261 |
262 state->second->RevokeAllPermissionsForFile(file); | 262 state->second->RevokeAllPermissionsForFile(file); |
263 } | 263 } |
264 | 264 |
265 void ChildProcessSecurityPolicy::GrantScheme(int renderer_id, | 265 void ChildProcessSecurityPolicy::GrantScheme(int child_id, |
266 const std::string& scheme) { | 266 const std::string& scheme) { |
267 AutoLock lock(lock_); | 267 AutoLock lock(lock_); |
268 | 268 |
269 SecurityStateMap::iterator state = security_state_.find(renderer_id); | 269 SecurityStateMap::iterator state = security_state_.find(child_id); |
270 if (state == security_state_.end()) | 270 if (state == security_state_.end()) |
271 return; | 271 return; |
272 | 272 |
273 state->second->GrantScheme(scheme); | 273 state->second->GrantScheme(scheme); |
274 } | 274 } |
275 | 275 |
276 void ChildProcessSecurityPolicy::GrantDOMUIBindings(int renderer_id) { | 276 void ChildProcessSecurityPolicy::GrantDOMUIBindings(int child_id) { |
277 AutoLock lock(lock_); | 277 AutoLock lock(lock_); |
278 | 278 |
279 SecurityStateMap::iterator state = security_state_.find(renderer_id); | 279 SecurityStateMap::iterator state = security_state_.find(child_id); |
280 if (state == security_state_.end()) | 280 if (state == security_state_.end()) |
281 return; | 281 return; |
282 | 282 |
283 state->second->GrantBindings(BindingsPolicy::DOM_UI); | 283 state->second->GrantBindings(BindingsPolicy::DOM_UI); |
284 | 284 |
285 // DOM UI bindings need the ability to request chrome: URLs. | 285 // DOM UI bindings need the ability to request chrome: URLs. |
286 state->second->GrantScheme(chrome::kChromeUIScheme); | 286 state->second->GrantScheme(chrome::kChromeUIScheme); |
287 | 287 |
288 // DOM UI pages can contain links to file:// URLs. | 288 // DOM UI pages can contain links to file:// URLs. |
289 state->second->GrantScheme(chrome::kFileScheme); | 289 state->second->GrantScheme(chrome::kFileScheme); |
290 } | 290 } |
291 | 291 |
292 void ChildProcessSecurityPolicy::GrantExtensionBindings(int renderer_id) { | 292 void ChildProcessSecurityPolicy::GrantExtensionBindings(int child_id) { |
293 AutoLock lock(lock_); | 293 AutoLock lock(lock_); |
294 | 294 |
295 SecurityStateMap::iterator state = security_state_.find(renderer_id); | 295 SecurityStateMap::iterator state = security_state_.find(child_id); |
296 if (state == security_state_.end()) | 296 if (state == security_state_.end()) |
297 return; | 297 return; |
298 | 298 |
299 state->second->GrantBindings(BindingsPolicy::EXTENSION); | 299 state->second->GrantBindings(BindingsPolicy::EXTENSION); |
300 } | 300 } |
301 | 301 |
302 void ChildProcessSecurityPolicy::GrantReadRawCookies(int renderer_id) { | 302 void ChildProcessSecurityPolicy::GrantReadRawCookies(int child_id) { |
303 AutoLock lock(lock_); | 303 AutoLock lock(lock_); |
304 | 304 |
305 SecurityStateMap::iterator state = security_state_.find(renderer_id); | 305 SecurityStateMap::iterator state = security_state_.find(child_id); |
306 if (state == security_state_.end()) | 306 if (state == security_state_.end()) |
307 return; | 307 return; |
308 | 308 |
309 state->second->GrantReadRawCookies(); | 309 state->second->GrantReadRawCookies(); |
310 } | 310 } |
311 | 311 |
312 void ChildProcessSecurityPolicy::RevokeReadRawCookies(int renderer_id) { | 312 void ChildProcessSecurityPolicy::RevokeReadRawCookies(int child_id) { |
313 AutoLock lock(lock_); | 313 AutoLock lock(lock_); |
314 | 314 |
315 SecurityStateMap::iterator state = security_state_.find(renderer_id); | 315 SecurityStateMap::iterator state = security_state_.find(child_id); |
316 if (state == security_state_.end()) | 316 if (state == security_state_.end()) |
317 return; | 317 return; |
318 | 318 |
319 state->second->RevokeReadRawCookies(); | 319 state->second->RevokeReadRawCookies(); |
320 } | 320 } |
321 | 321 |
322 bool ChildProcessSecurityPolicy::CanRequestURL( | 322 bool ChildProcessSecurityPolicy::CanRequestURL( |
323 int renderer_id, const GURL& url) { | 323 int child_id, const GURL& url) { |
324 if (!url.is_valid()) | 324 if (!url.is_valid()) |
325 return false; // Can't request invalid URLs. | 325 return false; // Can't request invalid URLs. |
326 | 326 |
327 if (IsWebSafeScheme(url.scheme())) | 327 if (IsWebSafeScheme(url.scheme())) |
328 return true; // The scheme has been white-listed for every renderer. | 328 return true; // The scheme has been white-listed for every child process. |
329 | 329 |
330 if (IsPseudoScheme(url.scheme())) { | 330 if (IsPseudoScheme(url.scheme())) { |
331 // There are a number of special cases for pseudo schemes. | 331 // There are a number of special cases for pseudo schemes. |
332 | 332 |
333 if (url.SchemeIs(chrome::kViewSourceScheme)) { | 333 if (url.SchemeIs(chrome::kViewSourceScheme)) { |
334 // A view-source URL is allowed if the renderer is permitted to request | 334 // A view-source URL is allowed if the child process is permitted to |
335 // the embedded URL. Careful to avoid pointless recursion. | 335 // request the embedded URL. Careful to avoid pointless recursion. |
336 GURL child_url(url.path()); | 336 GURL child_url(url.path()); |
337 if (child_url.SchemeIs(chrome::kViewSourceScheme) && | 337 if (child_url.SchemeIs(chrome::kViewSourceScheme) && |
338 url.SchemeIs(chrome::kViewSourceScheme)) | 338 url.SchemeIs(chrome::kViewSourceScheme)) |
339 return false; | 339 return false; |
340 | 340 |
341 return CanRequestURL(renderer_id, child_url); | 341 return CanRequestURL(child_id, child_url); |
342 } | 342 } |
343 | 343 |
344 if (LowerCaseEqualsASCII(url.spec(), chrome::kAboutBlankURL)) | 344 if (LowerCaseEqualsASCII(url.spec(), chrome::kAboutBlankURL)) |
345 return true; // Every renderer can request <about:blank>. | 345 return true; // Every child process can request <about:blank>. |
346 | 346 |
347 // URLs like <about:memory> and <about:crash> shouldn't be requestable by | 347 // URLs like <about:memory> and <about:crash> shouldn't be requestable by |
348 // any renderer. Also, this case covers <javascript:...>, which should be | 348 // any child process. Also, this case covers <javascript:...>, which should |
349 // handled internally by the renderer and not kicked up to the browser. | 349 // be handled internally by the process and not kicked up to the browser. |
350 return false; | 350 return false; |
351 } | 351 } |
352 | 352 |
353 if (!net::URLRequest::IsHandledURL(url)) | 353 if (!net::URLRequest::IsHandledURL(url)) |
354 return true; // This URL request is destined for ShellExecute. | 354 return true; // This URL request is destined for ShellExecute. |
355 | 355 |
356 { | 356 { |
357 AutoLock lock(lock_); | 357 AutoLock lock(lock_); |
358 | 358 |
359 SecurityStateMap::iterator state = security_state_.find(renderer_id); | 359 SecurityStateMap::iterator state = security_state_.find(child_id); |
360 if (state == security_state_.end()) | 360 if (state == security_state_.end()) |
361 return false; | 361 return false; |
362 | 362 |
363 // Otherwise, we consult the renderer's security state to see if it is | 363 // Otherwise, we consult the child process's security state to see if it is |
364 // allowed to request the URL. | 364 // allowed to request the URL. |
365 return state->second->CanRequestURL(url); | 365 return state->second->CanRequestURL(url); |
366 } | 366 } |
367 } | 367 } |
368 | 368 |
369 bool ChildProcessSecurityPolicy::CanReadFile(int renderer_id, | 369 bool ChildProcessSecurityPolicy::CanReadFile(int child_id, |
370 const FilePath& file) { | 370 const FilePath& file) { |
371 return HasPermissionsForFile(renderer_id, file, kReadFilePermissions); | 371 return HasPermissionsForFile(child_id, file, kReadFilePermissions); |
372 } | 372 } |
373 | 373 |
374 bool ChildProcessSecurityPolicy::HasPermissionsForFile( | 374 bool ChildProcessSecurityPolicy::HasPermissionsForFile( |
375 int renderer_id, const FilePath& file, int permissions) { | 375 int child_id, const FilePath& file, int permissions) { |
376 AutoLock lock(lock_); | 376 AutoLock lock(lock_); |
377 | 377 |
378 SecurityStateMap::iterator state = security_state_.find(renderer_id); | 378 SecurityStateMap::iterator state = security_state_.find(child_id); |
379 if (state == security_state_.end()) | 379 if (state == security_state_.end()) |
380 return false; | 380 return false; |
381 | 381 |
382 return state->second->HasPermissionsForFile(file, permissions); | 382 return state->second->HasPermissionsForFile(file, permissions); |
383 } | 383 } |
384 | 384 |
385 bool ChildProcessSecurityPolicy::HasDOMUIBindings(int renderer_id) { | 385 bool ChildProcessSecurityPolicy::HasDOMUIBindings(int child_id) { |
386 AutoLock lock(lock_); | 386 AutoLock lock(lock_); |
387 | 387 |
388 SecurityStateMap::iterator state = security_state_.find(renderer_id); | 388 SecurityStateMap::iterator state = security_state_.find(child_id); |
389 if (state == security_state_.end()) | 389 if (state == security_state_.end()) |
390 return false; | 390 return false; |
391 | 391 |
392 return state->second->has_dom_ui_bindings(); | 392 return state->second->has_dom_ui_bindings(); |
393 } | 393 } |
394 | 394 |
395 bool ChildProcessSecurityPolicy::HasExtensionBindings(int renderer_id) { | 395 bool ChildProcessSecurityPolicy::HasExtensionBindings(int child_id) { |
396 AutoLock lock(lock_); | 396 AutoLock lock(lock_); |
397 | 397 |
398 SecurityStateMap::iterator state = security_state_.find(renderer_id); | 398 SecurityStateMap::iterator state = security_state_.find(child_id); |
399 if (state == security_state_.end()) | 399 if (state == security_state_.end()) |
400 return false; | 400 return false; |
401 | 401 |
402 return state->second->has_extension_bindings(); | 402 return state->second->has_extension_bindings(); |
403 } | 403 } |
404 | 404 |
405 bool ChildProcessSecurityPolicy::CanReadRawCookies(int renderer_id) { | 405 bool ChildProcessSecurityPolicy::CanReadRawCookies(int child_id) { |
406 AutoLock lock(lock_); | 406 AutoLock lock(lock_); |
407 | 407 |
408 SecurityStateMap::iterator state = security_state_.find(renderer_id); | 408 SecurityStateMap::iterator state = security_state_.find(child_id); |
409 if (state == security_state_.end()) | 409 if (state == security_state_.end()) |
410 return false; | 410 return false; |
411 | 411 |
412 return state->second->can_read_raw_cookies(); | 412 return state->second->can_read_raw_cookies(); |
413 } | 413 } |
OLD | NEW |