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

Side by Side Diff: mojo/shell/shell.cc

Issue 1776513003: Allow client process information to be passed via Connector::Connect(). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: . Created 4 years, 9 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
« no previous file with comments | « mojo/shell/shell.h ('k') | mojo/shell/tests/lifecycle/lifecycle_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "mojo/shell/shell.h" 5 #include "mojo/shell/shell.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include <utility> 9 #include <utility>
10 10
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
118 if (source) { 118 if (source) {
119 interfaces = GetAllowedInterfaces(source->filter_, identity_); 119 interfaces = GetAllowedInterfaces(source->filter_, identity_);
120 source_id = source->id(); 120 source_id = source->id();
121 } 121 }
122 shell_client_->AcceptConnection( 122 shell_client_->AcceptConnection(
123 mojom::Identity::From(params->source()), source_id, 123 mojom::Identity::From(params->source()), source_id,
124 params->TakeRemoteInterfaces(), params->TakeLocalInterfaces(), 124 params->TakeRemoteInterfaces(), params->TakeLocalInterfaces(),
125 Array<String>::From(interfaces), params->target().name()); 125 Array<String>::From(interfaces), params->target().name());
126 } 126 }
127 127
128 scoped_ptr<NativeRunner> StartWithFileURL(const GURL& file_url, 128 void StartWithClientProcessConnection(
129 mojom::ShellClientRequest request, 129 mojom::ShellClientRequest request,
130 bool start_sandboxed, 130 mojom::ClientProcessConnectionPtr client_process_connection) {
131 NativeRunnerFactory* factory) { 131 factory_.Bind(mojom::ShellClientFactoryPtrInfo(
132 base::FilePath path = util::UrlToFilePath(file_url); 132 std::move(client_process_connection->shell_client_factory), 0u));
133 scoped_ptr<NativeRunner> runner = factory->Create(path); 133 pid_receiver_binding_.Bind(
134 runner_ = runner.get(); 134 std::move(client_process_connection->pid_receiver_request));
135 runner_->Start(path, identity_, start_sandboxed, std::move(request), 135 factory_->CreateShellClient(std::move(request), identity_.name());
136 base::Bind(&Instance::PIDAvailable, 136 }
137 weak_factory_.GetWeakPtr()), 137
138 base::Bind(&mojo::shell::Shell::CleanupRunner, 138 void StartWithFilePath(mojom::ShellClientRequest request,
139 shell_->weak_ptr_factory_.GetWeakPtr(), 139 const base::FilePath& path) {
140 runner_)); 140 scoped_ptr<NativeRunner> runner =
141 return runner; 141 shell_->native_runner_factory_->Create(path);
142 bool start_sandboxed = false;
143 runner->Start(path, identity_, start_sandboxed, std::move(request),
144 base::Bind(&Instance::PIDAvailable,
145 weak_factory_.GetWeakPtr()),
146 base::Bind(&mojo::shell::Shell::CleanupRunner,
147 shell_->weak_ptr_factory_.GetWeakPtr(),
148 runner.get()));
149 shell_->native_runners_.push_back(std::move(runner));
142 } 150 }
143 151
144 mojom::InstanceInfoPtr CreateInstanceInfo() const { 152 mojom::InstanceInfoPtr CreateInstanceInfo() const {
145 mojom::InstanceInfoPtr info(mojom::InstanceInfo::New()); 153 mojom::InstanceInfoPtr info(mojom::InstanceInfo::New());
146 info->id = id_; 154 info->id = id_;
147 info->identity = mojom::Identity::From(identity_); 155 info->identity = mojom::Identity::From(identity_);
148 info->pid = pid_; 156 info->pid = pid_;
149 return info; 157 return info;
150 } 158 }
151 159
152 const Identity& identity() const { return identity_; } 160 const Identity& identity() const { return identity_; }
153 uint32_t id() const { return id_; } 161 uint32_t id() const { return id_; }
154 162
155 // ShellClient: 163 // ShellClient:
156 bool AcceptConnection(Connection* connection) override { 164 bool AcceptConnection(Connection* connection) override {
157 connection->AddInterface<mojom::Shell>(this); 165 connection->AddInterface<mojom::Shell>(this);
158 return true; 166 return true;
159 } 167 }
160 168
161 private: 169 private:
162 // mojom::Connector implementation: 170 // mojom::Connector implementation:
163 void Connect(mojom::IdentityPtr target, 171 void Connect(mojom::IdentityPtr target_ptr,
164 mojom::InterfaceProviderRequest remote_interfaces, 172 mojom::InterfaceProviderRequest remote_interfaces,
165 mojom::InterfaceProviderPtr local_interfaces, 173 mojom::InterfaceProviderPtr local_interfaces,
174 mojom::ClientProcessConnectionPtr client_process_connection,
166 const ConnectCallback& callback) override { 175 const ConnectCallback& callback) override {
167 if (!IsValidName(target->name)) { 176 Identity target = target_ptr.To<Identity>();
168 LOG(ERROR) << "Error: invalid Name: " << target->name; 177 if (!ValidateIdentity(target, callback))
169 callback.Run(mojom::ConnectResult::INVALID_ARGUMENT, 178 return;
170 mojom::kInheritUserID, mojom::kInvalidInstanceID); 179 if (!ValidateClientProcessConnection(&client_process_connection, target,
180 callback)) {
171 return; 181 return;
172 } 182 }
173 if (!base::IsValidGUID(target->user_id)) { 183 // TODO(beng): Need to do the following additional policy validation of
174 LOG(ERROR) << "Error: invalid user_id: " << target->user_id; 184 // whether this instance is allowed to connect using:
175 callback.Run(mojom::ConnectResult::INVALID_ARGUMENT, 185 // - a user id other than its own, kInheritUserID or kRootUserID.
176 mojom::kInheritUserID, mojom::kInvalidInstanceID); 186 // - a non-empty instance name.
187 // - a non-null client_process_connection.
188 if (!ValidateCapabilityFilter(target, callback))
177 return; 189 return;
178 } 190
179 // TODO(beng): perform checking on policy of whether this instance is 191 scoped_ptr<ConnectParams> params(new ConnectParams);
180 // allowed to pass different user_ids. 192 params->set_source(identity_);
181 // TODO(beng): perform checking on policy of whether this instance is 193 params->set_target(target);
182 // allowed to pass non-empty instance identifiers. 194 params->set_remote_interfaces(std::move(remote_interfaces));
183 if (allow_any_application_ || filter_.find(target->name) != filter_.end()) { 195 params->set_local_interfaces(std::move(local_interfaces));
184 scoped_ptr<ConnectParams> params(new ConnectParams); 196 params->set_client_process_connection(std::move(client_process_connection));
185 params->set_source(identity_); 197 params->set_connect_callback(callback);
186 params->set_target(target.To<Identity>()); 198 shell_->Connect(std::move(params));
187 params->set_remote_interfaces(std::move(remote_interfaces));
188 params->set_local_interfaces(std::move(local_interfaces));
189 params->set_connect_callback(callback);
190 shell_->Connect(std::move(params));
191 } else {
192 LOG(WARNING) << "CapabilityFilter prevented connection from: " <<
193 identity_.name() << " to: " << target->name;
194 callback.Run(mojom::ConnectResult::ACCESS_DENIED,
195 mojom::kInheritUserID, mojom::kInvalidInstanceID);
196 }
197 } 199 }
198 void Clone(mojom::ConnectorRequest request) override { 200 void Clone(mojom::ConnectorRequest request) override {
199 connectors_.AddBinding(this, std::move(request)); 201 connectors_.AddBinding(this, std::move(request));
200 } 202 }
201 203
202 // mojom::PIDReceiver: 204 // mojom::PIDReceiver:
203 void SetPID(uint32_t pid) override { 205 void SetPID(uint32_t pid) override {
204 PIDAvailable(pid); 206 PIDAvailable(pid);
205 } 207 }
206 208
207 // InterfaceFactory<mojom::Shell>: 209 // InterfaceFactory<mojom::Shell>:
208 void Create(Connection* connection, 210 void Create(Connection* connection,
209 mojom::ShellRequest request) override { 211 mojom::ShellRequest request) override {
210 shell_bindings_.AddBinding(this, std::move(request)); 212 shell_bindings_.AddBinding(this, std::move(request));
211 } 213 }
212 214
213 // mojom::Shell implementation: 215 // mojom::Shell implementation:
214 void CreateInstance(mojom::ShellClientFactoryPtr factory,
215 mojom::IdentityPtr target,
216 mojom::PIDReceiverRequest pid_receiver,
217 const CreateInstanceCallback& callback) override {
218 // We need to bounce through the package manager to load the
219 // CapabilityFilter.
220 std::string name = target->name;
221 shell_->shell_resolver_->ResolveMojoName(name, base::Bind(
222 &mojo::shell::Shell::Instance::OnResolvedNameForCreateInstance,
223 weak_factory_.GetWeakPtr(), base::Passed(std::move(factory)),
224 base::Passed(std::move(target)), base::Passed(std::move(pid_receiver)),
225 callback));
226 }
227 void AddInstanceListener(mojom::InstanceListenerPtr listener) override { 216 void AddInstanceListener(mojom::InstanceListenerPtr listener) override {
228 // TODO(beng): this should only track the instances matching this user, and 217 // TODO(beng): this should only track the instances matching this user, and
229 // root. 218 // root.
230 shell_->AddInstanceListener(std::move(listener)); 219 shell_->AddInstanceListener(std::move(listener));
231 } 220 }
232 221
233 void OnResolvedNameForCreateInstance(mojom::ShellClientFactoryPtr factory, 222 bool ValidateIdentity(const Identity& identity,
234 mojom::IdentityPtr target, 223 const ConnectCallback& callback) {
235 mojom::PIDReceiverRequest pid_receiver, 224 if (!IsValidName(identity.name())) {
236 const CreateInstanceCallback& callback, 225 LOG(ERROR) << "Error: invalid Name: " << identity.name();
237 const String& resolved_name, 226 callback.Run(mojom::ConnectResult::INVALID_ARGUMENT,
238 const String& resolved_instance, 227 mojom::kInheritUserID, mojom::kInvalidInstanceID);
239 mojom::CapabilityFilterPtr filter, 228 return false;
240 const String& file_url) { 229 }
241 if (!base::IsValidGUID(target->user_id)) 230 if (!base::IsValidGUID(identity.user_id())) {
242 callback.Run(mojom::ConnectResult::INVALID_ARGUMENT); 231 LOG(ERROR) << "Error: invalid user_id: " << identity.user_id();
232 callback.Run(mojom::ConnectResult::INVALID_ARGUMENT,
233 mojom::kInheritUserID, mojom::kInvalidInstanceID);
234 return false;
235 }
236 return true;
237 }
243 238
244 Identity target_id = target.To<Identity>(); 239 bool ValidateClientProcessConnection(
240 mojom::ClientProcessConnectionPtr* client_process_connection,
241 const Identity& identity,
242 const ConnectCallback& callback) {
243 if (!client_process_connection->is_null()) {
244 if (!(*client_process_connection)->shell_client_factory.is_valid() ||
245 !(*client_process_connection)->pid_receiver_request.is_valid()) {
246 LOG(ERROR) << "Error: must supply both shell_client_factory AND "
247 << "pid_receiver_request when sending "
248 << "client_process_connection.";
249 callback.Run(mojom::ConnectResult::INVALID_ARGUMENT,
250 mojom::kInheritUserID, mojom::kInvalidInstanceID);
251 return false;
252 }
253 if (shell_->GetExistingOrRootInstance(identity)) {
254 LOG(ERROR) << "Error: Cannot client process matching existing identity:"
255 << "Name: " << identity.name() << " User: "
256 << identity.user_id() << " Instance: "
257 << identity.instance();
258 callback.Run(mojom::ConnectResult::INVALID_ARGUMENT,
259 mojom::kInheritUserID, mojom::kInvalidInstanceID);
260 return false;
261 }
262 }
263 return true;
264 }
245 265
246 // TODO(beng): perform checking on policy of whether this instance is 266 bool ValidateCapabilityFilter(const Identity& target,
247 // allowed to pass different user_ids. 267 const ConnectCallback& callback) {
248 if (target_id.user_id() == mojom::kInheritUserID) 268 if (allow_any_application_ ||
249 target_id.set_user_id(identity_.user_id()); 269 filter_.find(target.name()) != filter_.end()) {
250 270 return true;
251 mojom::ShellClientRequest request; 271 }
252 Instance* instance = shell_->CreateInstance( 272 LOG(ERROR) << "CapabilityFilter prevented connection from: " <<
253 target_id, filter->filter.To<CapabilityFilter>(), &request); 273 identity_.name() << " to: " << target.name();
254 instance->pid_receiver_binding_.Bind(std::move(pid_receiver)); 274 callback.Run(mojom::ConnectResult::ACCESS_DENIED,
255 instance->factory_ = std::move(factory); 275 mojom::kInheritUserID, mojom::kInvalidInstanceID);
256 instance->factory_->CreateShellClient(std::move(request), target->name); 276 return false;
257 callback.Run(mojom::ConnectResult::SUCCEEDED);
258 // We don't call ConnectToClient() here since the instance was created
259 // manually by other code, not in response to a Connect() request. The newly
260 // created instance is identified by |name| and may be subsequently reached
261 // by client code using this identity.
262 } 277 }
263 278
264 uint32_t GenerateUniqueID() const { 279 uint32_t GenerateUniqueID() const {
265 static uint32_t id = mojom::kInvalidInstanceID; 280 static uint32_t id = mojom::kInvalidInstanceID;
266 ++id; 281 ++id;
267 CHECK_NE(mojom::kInvalidInstanceID, id); 282 CHECK_NE(mojom::kInvalidInstanceID, id);
268 return id; 283 return id;
269 } 284 }
270 285
271 void PIDAvailable(base::ProcessId pid) { 286 void PIDAvailable(base::ProcessId pid) {
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 }); 464 });
450 if (!instance_quit_callback_.is_null()) 465 if (!instance_quit_callback_.is_null())
451 instance_quit_callback_.Run(identity); 466 instance_quit_callback_.Run(identity);
452 } 467 }
453 468
454 Shell::Instance* Shell::GetExistingInstance(const Identity& identity) const { 469 Shell::Instance* Shell::GetExistingInstance(const Identity& identity) const {
455 const auto& it = identity_to_instance_.find(identity); 470 const auto& it = identity_to_instance_.find(identity);
456 return it != identity_to_instance_.end() ? it->second : nullptr; 471 return it != identity_to_instance_.end() ? it->second : nullptr;
457 } 472 }
458 473
474 Shell::Instance* Shell::GetExistingOrRootInstance(
475 const Identity& identity) const {
476 Instance* instance = GetExistingInstance(identity);
477 if (!instance) {
478 Identity root_identity = identity;
479 root_identity.set_user_id(mojom::kRootUserID);
480 instance = GetExistingInstance(root_identity);
481 }
482 return instance;
483 }
484
459 void Shell::NotifyPIDAvailable(uint32_t id, base::ProcessId pid) { 485 void Shell::NotifyPIDAvailable(uint32_t id, base::ProcessId pid) {
460 instance_listeners_.ForAllPtrs([id, pid](mojom::InstanceListener* listener) { 486 instance_listeners_.ForAllPtrs([id, pid](mojom::InstanceListener* listener) {
461 listener->InstancePIDAvailable(id, pid); 487 listener->InstancePIDAvailable(id, pid);
462 }); 488 });
463 } 489 }
464 490
465 bool Shell::ConnectToExistingInstance(scoped_ptr<ConnectParams>* params) { 491 bool Shell::ConnectToExistingInstance(scoped_ptr<ConnectParams>* params) {
466 Instance* instance = GetExistingInstance((*params)->target()); 492 Instance* instance = GetExistingOrRootInstance((*params)->target());
467 if (!instance) { 493 if (instance)
468 Identity root_identity = (*params)->target(); 494 instance->ConnectToClient(std::move(*params));
469 root_identity.set_user_id(mojom::kRootUserID); 495 return !!instance;
470 instance = GetExistingInstance(root_identity);
471 if (!instance) return false;
472 }
473 instance->ConnectToClient(std::move(*params));
474 return true;
475 } 496 }
476 497
477 Shell::Instance* Shell::CreateInstance(const Identity& target_id, 498 Shell::Instance* Shell::CreateInstance(const Identity& target_id,
478 const CapabilityFilter& filter, 499 const CapabilityFilter& filter,
479 mojom::ShellClientRequest* request) { 500 mojom::ShellClientRequest* request) {
480 CHECK(target_id.user_id() != mojom::kInheritUserID); 501 CHECK(target_id.user_id() != mojom::kInheritUserID);
481 mojom::ShellClientPtr shell_client; 502 mojom::ShellClientPtr shell_client;
482 *request = GetProxy(&shell_client); 503 *request = GetProxy(&shell_client);
483 Instance* instance = 504 Instance* instance =
484 new Instance(std::move(shell_client), this, target_id, filter); 505 new Instance(std::move(shell_client), this, target_id, filter);
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
560 if (ConnectToExistingInstance(&params)) 581 if (ConnectToExistingInstance(&params))
561 return; 582 return;
562 583
563 Identity source = params->source(); 584 Identity source = params->source();
564 // |base_filter| can be null when there is no manifest, e.g. for URL types 585 // |base_filter| can be null when there is no manifest, e.g. for URL types
565 // not resolvable by the resolver. 586 // not resolvable by the resolver.
566 CapabilityFilter filter = GetPermissiveCapabilityFilter(); 587 CapabilityFilter filter = GetPermissiveCapabilityFilter();
567 if (!base_filter.is_null()) 588 if (!base_filter.is_null())
568 filter = base_filter->filter.To<CapabilityFilter>(); 589 filter = base_filter->filter.To<CapabilityFilter>();
569 590
591 mojom::ClientProcessConnectionPtr client_process_connection =
592 params->TakeClientProcessConnection();
570 mojom::ShellClientRequest request; 593 mojom::ShellClientRequest request;
571 Instance* instance = CreateInstance(target, filter, &request); 594 Instance* instance = CreateInstance(target, filter, &request);
572 instance->ConnectToClient(std::move(params)); 595 instance->ConnectToClient(std::move(params));
573 596
574 if (LoadWithLoader(target, &request)) 597 if (LoadWithLoader(target, &request))
575 return; 598 return;
576 599
577 CHECK(!file_url.is_null() && !base_filter.is_null()); 600 CHECK(!file_url.is_null() && !base_filter.is_null());
578 601
579 if (target.name() != resolved_name) { 602 if (target.name() != resolved_name) {
580 // In cases where a package alias is resolved, we have to use the instance 603 // In cases where a package alias is resolved, we have to use the instance
581 // from the original request rather than for the package itself, which will 604 // from the original request rather than for the package itself, which will
582 // always be the same. 605 // always be the same.
583 CreateShellClient( 606 CreateShellClient(
584 source, Identity(resolved_name, target.user_id(), instance_name), 607 source, Identity(resolved_name, target.user_id(), instance_name),
585 target.name(), std::move(request)); 608 target.name(), std::move(request));
586 } else { 609 } else {
587 bool start_sandboxed = false; 610 if (!client_process_connection.is_null()) {
588 native_runners_.push_back( 611 // The client already started a process for this instance, use it.
589 instance->StartWithFileURL(file_url.To<GURL>(), std::move(request), 612 instance->StartWithClientProcessConnection(
590 start_sandboxed, 613 std::move(request), std::move(client_process_connection));
591 native_runner_factory_.get())); 614 } else {
615 // Otherwise we make our own process.
616 instance->StartWithFilePath(std::move(request),
617 util::UrlToFilePath(file_url.To<GURL>()));
618 }
592 } 619 }
593 } 620 }
594 621
595 bool Shell::LoadWithLoader(const Identity& target, 622 bool Shell::LoadWithLoader(const Identity& target,
596 mojom::ShellClientRequest* request) { 623 mojom::ShellClientRequest* request) {
597 Loader* loader = GetLoaderForName(target.name()); 624 Loader* loader = GetLoaderForName(target.name());
598 if (!loader) 625 if (!loader)
599 return false; 626 return false;
600 loader->Load(target.name(), std::move(*request)); 627 loader->Load(target.name(), std::move(*request));
601 return true; 628 return true;
(...skipping 10 matching lines...) Expand all
612 for (auto it = native_runners_.begin(); it != native_runners_.end(); ++it) { 639 for (auto it = native_runners_.begin(); it != native_runners_.end(); ++it) {
613 if (it->get() == runner) { 640 if (it->get() == runner) {
614 native_runners_.erase(it); 641 native_runners_.erase(it);
615 return; 642 return;
616 } 643 }
617 } 644 }
618 } 645 }
619 646
620 } // namespace shell 647 } // namespace shell
621 } // namespace mojo 648 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/shell/shell.h ('k') | mojo/shell/tests/lifecycle/lifecycle_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698