OLD | NEW |
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/extension_function_dispatcher.h" | 5 #include "extensions/browser/extension_function_dispatcher.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/json/json_string_value_serializer.h" | 8 #include "base/json/json_string_value_serializer.h" |
9 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/memory/ref_counted.h" | 11 #include "base/memory/ref_counted.h" |
12 #include "base/metrics/sparse_histogram.h" | 12 #include "base/metrics/sparse_histogram.h" |
13 #include "base/process/process.h" | 13 #include "base/process/process.h" |
14 #include "base/values.h" | 14 #include "base/values.h" |
15 #include "build/build_config.h" | 15 #include "build/build_config.h" |
16 #include "content/public/browser/browser_thread.h" | 16 #include "content/public/browser/browser_thread.h" |
17 #include "content/public/browser/child_process_security_policy.h" | |
18 #include "content/public/browser/render_frame_host.h" | 17 #include "content/public/browser/render_frame_host.h" |
19 #include "content/public/browser/render_process_host.h" | 18 #include "content/public/browser/render_process_host.h" |
20 #include "content/public/browser/render_view_host.h" | 19 #include "content/public/browser/render_view_host.h" |
21 #include "content/public/browser/user_metrics.h" | 20 #include "content/public/browser/user_metrics.h" |
22 #include "content/public/browser/web_contents.h" | 21 #include "content/public/browser/web_contents.h" |
23 #include "content/public/browser/web_contents_observer.h" | 22 #include "content/public/browser/web_contents_observer.h" |
24 #include "content/public/common/result_codes.h" | 23 #include "content/public/common/result_codes.h" |
25 #include "extensions/browser/api_activity_monitor.h" | 24 #include "extensions/browser/api_activity_monitor.h" |
26 #include "extensions/browser/extension_function_registry.h" | 25 #include "extensions/browser/extension_function_registry.h" |
27 #include "extensions/browser/extension_message_filter.h" | 26 #include "extensions/browser/extension_message_filter.h" |
(...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
422 const ExtensionHostMsg_Request_Params& params, | 421 const ExtensionHostMsg_Request_Params& params, |
423 const ExtensionFunction::ResponseCallback& callback) { | 422 const ExtensionFunction::ResponseCallback& callback) { |
424 if (!function->HasPermission()) { | 423 if (!function->HasPermission()) { |
425 LOG(ERROR) << "Permission denied for " << params.name; | 424 LOG(ERROR) << "Permission denied for " << params.name; |
426 SendAccessDenied(callback); | 425 SendAccessDenied(callback); |
427 return false; | 426 return false; |
428 } | 427 } |
429 return true; | 428 return true; |
430 } | 429 } |
431 | 430 |
432 namespace { | |
433 | |
434 // Only COMPONENT hosted apps may call extension APIs, and they are limited | |
435 // to just the permissions they explicitly request. They should not have access | |
436 // to extension APIs like eg chrome.runtime, chrome.windows, etc. that normally | |
437 // are available without permission. | |
438 // TODO(mpcomplete): move this to ExtensionFunction::HasPermission (or remove | |
439 // it altogether). | |
440 bool AllowHostedAppAPICall(const Extension& extension, | |
441 const GURL& source_url, | |
442 const std::string& function_name) { | |
443 if (extension.location() != Manifest::COMPONENT) | |
444 return false; | |
445 | |
446 if (!extension.web_extent().MatchesURL(source_url)) | |
447 return false; | |
448 | |
449 // Note: Not BLESSED_WEB_PAGE_CONTEXT here because these component hosted app | |
450 // entities have traditionally been treated as blessed extensions, for better | |
451 // or worse. | |
452 Feature::Availability availability = | |
453 ExtensionAPI::GetSharedInstance()->IsAvailable( | |
454 function_name, &extension, Feature::BLESSED_EXTENSION_CONTEXT, | |
455 source_url); | |
456 return availability.is_available(); | |
457 } | |
458 | |
459 } // namespace | |
460 | |
461 | |
462 // static | 431 // static |
463 ExtensionFunction* ExtensionFunctionDispatcher::CreateExtensionFunction( | 432 ExtensionFunction* ExtensionFunctionDispatcher::CreateExtensionFunction( |
464 const ExtensionHostMsg_Request_Params& params, | 433 const ExtensionHostMsg_Request_Params& params, |
465 const Extension* extension, | 434 const Extension* extension, |
466 int requesting_process_id, | 435 int requesting_process_id, |
467 const ProcessMap& process_map, | 436 const ProcessMap& process_map, |
468 ExtensionAPI* api, | 437 ExtensionAPI* api, |
469 void* profile_id, | 438 void* profile_id, |
470 const ExtensionFunction::ResponseCallback& callback) { | 439 const ExtensionFunction::ResponseCallback& callback) { |
471 const char* disallowed_reason = NULL; | |
472 | |
473 if (extension) { | |
474 // Extension is calling this API. | |
475 if (extension->is_hosted_app() && | |
476 !AllowHostedAppAPICall(*extension, params.source_url, params.name)) { | |
477 // Most hosted apps can't call APIs. | |
478 disallowed_reason = "Hosted apps cannot call privileged APIs"; | |
479 } else if (!process_map.Contains(extension->id(), requesting_process_id) && | |
480 !api->IsAvailableInUntrustedContext(params.name, extension)) { | |
481 // Privileged APIs can only be called from the process the extension | |
482 // is running in. | |
483 disallowed_reason = | |
484 "Privileged APIs cannot be called from untrusted processes"; | |
485 } | |
486 } else if (content::ChildProcessSecurityPolicy::GetInstance() | |
487 ->HasWebUIBindings(requesting_process_id)) { | |
488 // WebUI is calling this API. | |
489 if (!api->IsAvailableToWebUI(params.name, params.source_url)) { | |
490 disallowed_reason = "WebUI can only call webui-enabled APIs"; | |
491 } | |
492 } else { | |
493 // Web page is calling this API. However, the APIs that are available to | |
494 // web pages (e.g. messaging) don't go through ExtensionFunctionDispatcher, | |
495 // so this should be impossible. | |
496 NOTREACHED(); | |
497 disallowed_reason = "Specified extension does not exist."; | |
498 } | |
499 | |
500 if (disallowed_reason != NULL) { | |
501 LOG(ERROR) << "Extension API call disallowed - name:" << params.name | |
502 << ", pid:" << requesting_process_id | |
503 << ", from URL: " << params.source_url.spec() | |
504 << ", reason: " << disallowed_reason; | |
505 SendAccessDenied(callback); | |
506 return NULL; | |
507 } | |
508 | |
509 ExtensionFunction* function = | 440 ExtensionFunction* function = |
510 ExtensionFunctionRegistry::GetInstance()->NewFunction(params.name); | 441 ExtensionFunctionRegistry::GetInstance()->NewFunction(params.name); |
511 if (!function) { | 442 if (!function) { |
512 LOG(ERROR) << "Unknown Extension API - " << params.name; | 443 LOG(ERROR) << "Unknown Extension API - " << params.name; |
513 SendAccessDenied(callback); | 444 SendAccessDenied(callback); |
514 return NULL; | 445 return NULL; |
515 } | 446 } |
516 | 447 |
517 function->SetArgs(¶ms.arguments); | 448 function->SetArgs(¶ms.arguments); |
518 function->set_source_url(params.source_url); | 449 function->set_source_url(params.source_url); |
519 function->set_request_id(params.request_id); | 450 function->set_request_id(params.request_id); |
520 function->set_has_callback(params.has_callback); | 451 function->set_has_callback(params.has_callback); |
521 function->set_user_gesture(params.user_gesture); | 452 function->set_user_gesture(params.user_gesture); |
522 function->set_extension(extension); | 453 function->set_extension(extension); |
523 function->set_profile_id(profile_id); | 454 function->set_profile_id(profile_id); |
524 function->set_response_callback(callback); | 455 function->set_response_callback(callback); |
525 function->set_source_tab_id(params.source_tab_id); | 456 function->set_source_tab_id(params.source_tab_id); |
| 457 function->set_source_context_type( |
| 458 process_map.GuessContextType(extension, requesting_process_id)); |
526 | 459 |
527 return function; | 460 return function; |
528 } | 461 } |
529 | 462 |
530 // static | 463 // static |
531 void ExtensionFunctionDispatcher::SendAccessDenied( | 464 void ExtensionFunctionDispatcher::SendAccessDenied( |
532 const ExtensionFunction::ResponseCallback& callback) { | 465 const ExtensionFunction::ResponseCallback& callback) { |
533 base::ListValue empty_list; | 466 base::ListValue empty_list; |
534 callback.Run(ExtensionFunction::FAILED, empty_list, | 467 callback.Run(ExtensionFunction::FAILED, empty_list, |
535 "Access to extension API denied."); | 468 "Access to extension API denied."); |
536 } | 469 } |
537 | 470 |
538 } // namespace extensions | 471 } // namespace extensions |
OLD | NEW |