1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef EXTENSIONS_BROWSER_PROCESS_MAP_H_
#define EXTENSIONS_BROWSER_PROCESS_MAP_H_
#include <stddef.h>
#include <set>
#include <string>
#include "base/macros.h"
#include "components/keyed_service/core/keyed_service.h"
#include "content/public/browser/site_instance.h"
#include "extensions/common/features/feature.h"
namespace content {
class BrowserContext;
}
namespace extensions {
class Extension;
// Contains information about which extensions are assigned to which processes.
//
// The relationship between extensions and processes is complex:
//
// - Extensions can be either "split" mode or "spanning" mode.
// - In spanning mode, extensions *generally* share a single process between all
// incognito and normal windows. This was the original mode for extensions.
// - In split mode, extensions have separate processes in incognito windows.
// - There are also hosted apps, which are a kind of extensions, and those
// usually have a process model similar to normal web sites: multiple
// processes per-profile.
// - A single hosted app can have more than one SiteInstance in the same process
// if we're over the process limit and force them to share a process.
// - An extension can also opt into Cross Origin Isolation in which case it can
// have multiple processes per profile since cross-origin-isolated and
// non-cross-origin-isolated contexts don't share a process.
//
// In general, we seem to play with the process model of extensions a lot, so
// it is safest to assume it is many-to-many in most places in the codebase.
//
// Note that because of content scripts, frames, and other edge cases in
// Chrome's process isolation, extension code can still end up running outside
// an assigned process.
//
// But we only allow high-privilege operations to be performed by an extension
// when it is running in an assigned process.
//
// ===========================================================================
// WARNINGS - PLEASE UNDERSTAND THESE BEFORE CALLING OR MODIFYING THIS CLASS
// ===========================================================================
//
// 1. This class contains the processes for hosted apps as well as extensions
// and packaged apps. Just because a process is present here *does not* mean
// it is an "extension process" (e.g., for UI purposes). It may contain only
// hosted apps. See crbug.com/102533.
//
// 2. An extension can show up in multiple processes. That is why there is no
// GetExtensionProcess() method here. There are multiple such cases:
// a) The extension is actually a hosted app.
// b) There is an incognito window open and the extension is "split mode".
// c) The extension is cross origin isolated but has
// non-cross-origin-isolated contexts.
// It is *not safe* to assume that there is one process per extension.
//
// 3. The process ids contained in this class are *not limited* to the Profile
// you got this map from. They can also be associated with that profile's
// incognito/normal twin. If you care about this, use
// RenderProcessHost::FromID() and check the profile of the resulting object.
//
// TODO(aa): The above warnings suggest this class could use improvement :).
//
// TODO(kalman): This class is not threadsafe, but is used on both the UI and IO
// threads. Somebody should fix that, either make it threadsafe or
// enforce single thread. Investigation required.
class ProcessMap : public KeyedService {
public:
ProcessMap();
~ProcessMap() override;
// Returns the instance for |browser_context|. An instance is shared between
// an incognito and a regular context.
static ProcessMap* Get(content::BrowserContext* browser_context);
size_t size() const { return items_.size(); }
bool Insert(const std::string& extension_id,
int process_id,
content::SiteInstanceId site_instance_id);
bool Remove(const std::string& extension_id,
int process_id,
content::SiteInstanceId site_instance_id);
int RemoveAllFromProcess(int process_id);
bool Contains(const std::string& extension_id, int process_id) const;
bool Contains(int process_id) const;
std::set<std::string> GetExtensionsInProcess(int process_id) const;
// Gets the most likely context type for the process with ID |process_id|
// which hosts Extension |extension|, if any (may be nullptr). Context types
// are renderer (JavaScript) concepts but the browser can do a decent job in
// guessing what the process hosts.
//
// For Context types with no |extension| e.g. untrusted WebUIs, we use |url|
// which should correspond to the URL where the API is running.|url| could be
// the frame's URL, the Content Script's URL, or the URL where a Content
// Script is running. So |url| should only be used when there is no
// |extension|. |url| may be also be nullptr when running in Service Workers.
// Currently, the |url| provided by event_router.cc is passed from the
// renderer process and therefore can't be fully trusted.
// TODO(ortuno): Change call sites to only pass in a URL when |extension| is
// nullptr and only use a URL retrieved from the browser process.
//
// |extension| is the funky part - unfortunately we need to trust the
// caller of this method to be correct that indeed the context does feature
// an extension. This matters for iframes, where an extension could be
// hosted in another extension's process (privilege level needs to be
// downgraded) or in a web page's process (privilege level needs to be
// upgraded).
//
// The latter of these is slightly problematic from a security perspective;
// if a web page renderer gets owned it could try to pretend it's an
// extension and get access to some unprivileged APIs. Luckly, when OOP
// iframes lauch, it won't be an issue.
//
// Anyhow, the expected behaviour is:
// - For hosted app processes, this will be blessed_web_page.
// - For processes of platform apps running on lock screen, this will be
// lock_screen_extension.
// - For other extension processes, this will be blessed_extension.
// - For WebUI processes, this will be a webui.
// - For chrome-untrusted:// URLs, this will be a webui_untrusted_context.
// - For any other extension we have the choice of unblessed_extension or
// content_script. Since content scripts are more common, guess that.
// We *could* in theory track which web processes have extension frames
// in them, and those would be unblessed_extension, but we don't at the
// moment, and once OOP iframes exist then there won't even be such a
// thing as an unblessed_extension context.
// - For anything else, web_page.
Feature::Context GetMostLikelyContextType(const Extension* extension,
int process_id,
const GURL* url) const;
void set_is_lock_screen_context(bool is_lock_screen_context) {
is_lock_screen_context_ = is_lock_screen_context;
}
private:
struct Item;
typedef std::set<Item> ItemSet;
ItemSet items_;
// Whether the process map belongs to the browser context used on Chrome OS
// lock screen.
bool is_lock_screen_context_ = false;
DISALLOW_COPY_AND_ASSIGN(ProcessMap);
};
} // namespace extensions
#endif // EXTENSIONS_BROWSER_PROCESS_MAP_H_
|