1 // Copyright 2017 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 "content/browser/interface_provider_filtering.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/stl_util.h"
11 #include "base/strings/strcat.h"
12 #include "base/task/post_task.h"
13 #include "content/public/app/content_browser_manifest.h"
14 #include "content/public/browser/browser_task_traits.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/content_browser_client.h"
17 #include "content/public/common/content_client.h"
18 #include "content/public/common/service_names.mojom.h"
19 #include "mojo/public/cpp/bindings/message.h"
20 #include "mojo/public/cpp/bindings/pending_remote.h"
21 #include "mojo/public/cpp/bindings/receiver.h"
22 #include "mojo/public/cpp/bindings/remote.h"
23 #include "services/service_manager/public/cpp/manifest.h"
24 
25 namespace content {
26 namespace {
27 
28 bool g_bypass_interface_filtering_for_testing = false;
29 
30 // The capability name used in the browser manifest for each renderer-exposed
31 // interface filter.
32 const char kRendererCapabilityName[] = "renderer";
33 
GetInterfacesForSpec(const char * spec)34 service_manager::Manifest::InterfaceNameSet GetInterfacesForSpec(
35     const char* spec) {
36   service_manager::Manifest manifest = GetContentBrowserManifest();
37   base::Optional<service_manager::Manifest> overlay =
38       GetContentClient()->browser()->GetServiceManifestOverlay(
39           mojom::kBrowserServiceName);
40   if (overlay)
41     manifest.Amend(*overlay);
42   const auto& filters = manifest.exposed_interface_filter_capabilities;
43   auto filter_iter = filters.find(spec);
44   if (filter_iter == filters.end())
45     return {};
46   const auto& capabilities = filter_iter->second;
47   auto capability_iter = capabilities.find(kRendererCapabilityName);
48   if (capability_iter == capabilities.end())
49     return {};
50   return capability_iter->second;
51 }
52 
53 // A simple InterfaceProvider implementation which forwards to another
54 // InterfaceProvider after applying a named interface filter for
55 // renderer-exposed interfaces in the browser.
56 class InterfaceFilterImpl : public service_manager::mojom::InterfaceProvider {
57  public:
58   InterfaceFilterImpl(const InterfaceFilterImpl&) = delete;
59   ~InterfaceFilterImpl() override = default;
60   InterfaceFilterImpl& operator=(const InterfaceFilterImpl&) = delete;
61 
Create(service_manager::Manifest::InterfaceNameSet allowed_interfaces,mojo::PendingReceiver<service_manager::mojom::InterfaceProvider> receiver,mojo::PendingRemote<service_manager::mojom::InterfaceProvider> target)62   static void Create(
63       service_manager::Manifest::InterfaceNameSet allowed_interfaces,
64       mojo::PendingReceiver<service_manager::mojom::InterfaceProvider> receiver,
65       mojo::PendingRemote<service_manager::mojom::InterfaceProvider> target) {
66     // Owns itself. Destroyed when either InterfaceProvider endpoint is
67     // disconnected.
68     new InterfaceFilterImpl(std::move(allowed_interfaces), std::move(receiver),
69                             std::move(target));
70   }
71 
72   // service_manager::mojom::InterfaceFilter implementation:
GetInterface(const std::string & interface_name,mojo::ScopedMessagePipeHandle interface_pipe)73   void GetInterface(const std::string& interface_name,
74                     mojo::ScopedMessagePipeHandle interface_pipe) override {
75     if (!base::Contains(allowed_interfaces_, interface_name)) {
76       mojo::ReportBadMessage(
77           base::StrCat({"Interface not allowed: ", interface_name}));
78       return;
79     }
80 
81     target_->GetInterface(interface_name, std::move(interface_pipe));
82   }
83 
84  private:
InterfaceFilterImpl(service_manager::Manifest::InterfaceNameSet allowed_interfaces,mojo::PendingReceiver<service_manager::mojom::InterfaceProvider> receiver,mojo::PendingRemote<service_manager::mojom::InterfaceProvider> target)85   InterfaceFilterImpl(
86       service_manager::Manifest::InterfaceNameSet allowed_interfaces,
87       mojo::PendingReceiver<service_manager::mojom::InterfaceProvider> receiver,
88       mojo::PendingRemote<service_manager::mojom::InterfaceProvider> target)
89       : allowed_interfaces_(std::move(allowed_interfaces)),
90         receiver_(this, std::move(receiver)),
91         target_(std::move(target)) {
92     receiver_.set_disconnect_handler(base::BindOnce(
93         &InterfaceFilterImpl::DeleteThis, base::Unretained(this)));
94     target_.set_disconnect_handler(base::BindOnce(
95         &InterfaceFilterImpl::DeleteThis, base::Unretained(this)));
96   }
97 
DeleteThis()98   void DeleteThis() { delete this; }
99 
100   const service_manager::Manifest::InterfaceNameSet allowed_interfaces_;
101   mojo::Receiver<service_manager::mojom::InterfaceProvider> receiver_;
102   mojo::Remote<service_manager::mojom::InterfaceProvider> target_;
103 };
104 
105 }  // namespace
106 
107 mojo::PendingReceiver<service_manager::mojom::InterfaceProvider>
FilterRendererExposedInterfaces(const char * spec,int process_id,mojo::PendingReceiver<service_manager::mojom::InterfaceProvider> receiver)108 FilterRendererExposedInterfaces(
109     const char* spec,
110     int process_id,
111     mojo::PendingReceiver<service_manager::mojom::InterfaceProvider> receiver) {
112   if (g_bypass_interface_filtering_for_testing)
113     return receiver;
114 
115   mojo::PendingRemote<service_manager::mojom::InterfaceProvider> provider;
116   auto filtered_receiver = provider.InitWithNewPipeAndPassReceiver();
117 
118   service_manager::Manifest::InterfaceNameSet allowed_interfaces =
119       GetInterfacesForSpec(spec);
120   if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
121     base::PostTask(FROM_HERE, {BrowserThread::IO},
122                    base::BindOnce(&InterfaceFilterImpl::Create,
123                                   std::move(allowed_interfaces),
124                                   std::move(receiver), std::move(provider)));
125   } else {
126     InterfaceFilterImpl::Create(std::move(allowed_interfaces),
127                                 std::move(receiver), std::move(provider));
128   }
129   return filtered_receiver;
130 }
131 
132 namespace test {
133 
ScopedInterfaceFilterBypass()134 ScopedInterfaceFilterBypass::ScopedInterfaceFilterBypass() {
135   // Nesting not supported.
136   DCHECK(!g_bypass_interface_filtering_for_testing);
137   g_bypass_interface_filtering_for_testing = true;
138 }
139 
~ScopedInterfaceFilterBypass()140 ScopedInterfaceFilterBypass::~ScopedInterfaceFilterBypass() {
141   g_bypass_interface_filtering_for_testing = false;
142 }
143 
144 }  // namespace test
145 
146 }  // namespace content
147