Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: ignore non-absolute session preload script paths when sandboxed #19066

Merged
merged 1 commit into from
Jul 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions lib/browser/rpc-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -519,23 +519,18 @@ if (features.isDesktopCapturerEnabled()) {
const getPreloadScript = async function (preloadPath) {
let preloadSrc = null
let preloadError = null
if (preloadPath) {
try {
preloadSrc = (await fs.promises.readFile(preloadPath)).toString()
} catch (err) {
preloadError = errorUtils.serialize(err)
}
try {
preloadSrc = (await fs.promises.readFile(preloadPath)).toString()
} catch (err) {
preloadError = errorUtils.serialize(err)
}
return { preloadPath, preloadSrc, preloadError }
}

ipcMainUtils.handle('ELECTRON_GET_CONTENT_SCRIPTS', () => getContentScripts())

ipcMainUtils.handle('ELECTRON_BROWSER_SANDBOX_LOAD', async function (event) {
const preloadPaths = [
...(event.sender.session ? event.sender.session.getPreloads() : []),
event.sender._getPreloadPath()
]
const preloadPaths = event.sender._getPreloadPaths()

return {
contentScripts: getContentScripts(),
Expand Down
12 changes: 8 additions & 4 deletions shell/browser/api/atom_api_web_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
#include "shell/browser/lib/bluetooth_chooser.h"
#include "shell/browser/native_window.h"
#include "shell/browser/net/atom_network_delegate.h"
#include "shell/browser/session_preferences.h"
#include "shell/browser/ui/drag_util.h"
#include "shell/browser/ui/inspectable_web_contents.h"
#include "shell/browser/ui/inspectable_web_contents_view.h"
Expand Down Expand Up @@ -2206,14 +2207,17 @@ void WebContents::HideAutofillPopup() {
CommonWebContentsDelegate::HideAutofillPopup();
}

v8::Local<v8::Value> WebContents::GetPreloadPath(v8::Isolate* isolate) const {
std::vector<base::FilePath::StringType> WebContents::GetPreloadPaths() const {
auto result = SessionPreferences::GetValidPreloads(GetBrowserContext());

if (auto* web_preferences = WebContentsPreferences::From(web_contents())) {
base::FilePath::StringType preload;
if (web_preferences->GetPreloadPath(&preload)) {
return mate::ConvertToV8(isolate, preload);
result.emplace_back(preload);
}
}
return v8::Null(isolate);

return result;
}

v8::Local<v8::Value> WebContents::GetWebPreferences(
Expand Down Expand Up @@ -2437,7 +2441,7 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setZoomFactor", &WebContents::SetZoomFactor)
.SetMethod("getZoomFactor", &WebContents::GetZoomFactor)
.SetMethod("getType", &WebContents::GetType)
.SetMethod("_getPreloadPath", &WebContents::GetPreloadPath)
.SetMethod("_getPreloadPaths", &WebContents::GetPreloadPaths)
.SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
.SetMethod("getLastWebPreferences", &WebContents::GetLastWebPreferences)
.SetMethod("_isRemoteModuleEnabled", &WebContents::IsRemoteModuleEnabled)
Expand Down
2 changes: 1 addition & 1 deletion shell/browser/api/atom_api_web_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
const scoped_refptr<network::ResourceRequestBody>& body);

// Returns the preload script path of current WebContents.
v8::Local<v8::Value> GetPreloadPath(v8::Isolate* isolate) const;
std::vector<base::FilePath::StringType> GetPreloadPaths() const;

// Returns the web preferences of current WebContents.
v8::Local<v8::Value> GetWebPreferences(v8::Isolate* isolate) const;
Expand Down
14 changes: 12 additions & 2 deletions shell/browser/atom_browser_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,12 @@ void SetApplicationLocaleOnIOThread(const std::string& locale) {
g_io_thread_application_locale.Get() = locale;
}

#if defined(OS_WIN)
const base::FilePath::StringPieceType kPathDelimiter = FILE_PATH_LITERAL(";");
#else
const base::FilePath::StringPieceType kPathDelimiter = FILE_PATH_LITERAL(":");
#endif

} // namespace

// static
Expand Down Expand Up @@ -524,8 +530,12 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
if (web_preferences)
web_preferences->AppendCommandLineSwitches(
command_line, IsRendererSubFrame(process_id));
SessionPreferences::AppendExtraCommandLineSwitches(
web_contents->GetBrowserContext(), command_line);
auto preloads =
SessionPreferences::GetValidPreloads(web_contents->GetBrowserContext());
if (!preloads.empty())
command_line->AppendSwitchNative(
switches::kPreloadScripts,
base::JoinString(preloads, kPathDelimiter));
if (CanUseCustomSiteInstance()) {
command_line->AppendSwitch(
switches::kDisableElectronSiteInstanceOverrides);
Expand Down
45 changes: 13 additions & 32 deletions shell/browser/session_preferences.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,8 @@

#include "shell/browser/session_preferences.h"

#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "shell/common/options_switches.h"

namespace electron {

namespace {

#if defined(OS_WIN)
const base::FilePath::CharType kPathDelimiter = FILE_PATH_LITERAL(';');
#else
const base::FilePath::CharType kPathDelimiter = FILE_PATH_LITERAL(':');
#endif

} // namespace

// static
int SessionPreferences::kLocatorKey = 0;

Expand All @@ -36,26 +22,21 @@ SessionPreferences* SessionPreferences::FromBrowserContext(
}

// static
void SessionPreferences::AppendExtraCommandLineSwitches(
content::BrowserContext* context,
base::CommandLine* command_line) {
SessionPreferences* self = FromBrowserContext(context);
if (!self)
return;

base::FilePath::StringType preloads;
for (const auto& preload : self->preloads()) {
if (!base::FilePath(preload).IsAbsolute()) {
LOG(ERROR) << "preload script must have absolute path: " << preload;
continue;
std::vector<base::FilePath::StringType> SessionPreferences::GetValidPreloads(
content::BrowserContext* context) {
std::vector<base::FilePath::StringType> result;

if (auto* self = FromBrowserContext(context)) {
for (const auto& preload : self->preloads()) {
if (base::FilePath(preload).IsAbsolute()) {
result.emplace_back(preload);
} else {
LOG(ERROR) << "preload script must have absolute path: " << preload;
}
}
if (preloads.empty())
preloads = preload;
else
preloads += kPathDelimiter + preload;
}
if (!preloads.empty())
command_line->AppendSwitchNative(switches::kPreloadScripts, preloads);

return result;
}

} // namespace electron
8 changes: 2 additions & 6 deletions shell/browser/session_preferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,14 @@
#include "base/supports_user_data.h"
#include "content/public/browser/browser_context.h"

namespace base {
class CommandLine;
}

namespace electron {

class SessionPreferences : public base::SupportsUserData::Data {
public:
static SessionPreferences* FromBrowserContext(
content::BrowserContext* context);
static void AppendExtraCommandLineSwitches(content::BrowserContext* context,
base::CommandLine* command_line);
static std::vector<base::FilePath::StringType> GetValidPreloads(
content::BrowserContext* context);

explicit SessionPreferences(content::BrowserContext* context);
~SessionPreferences() override;
Expand Down
6 changes: 4 additions & 2 deletions spec/api-browser-window-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,8 @@ describe('BrowserWindow module', () => {
describe('session preload scripts', function () {
const preloads = [
path.join(fixtures, 'module', 'set-global-preload-1.js'),
path.join(fixtures, 'module', 'set-global-preload-2.js')
path.join(fixtures, 'module', 'set-global-preload-2.js'),
path.relative(process.cwd(), path.join(fixtures, 'module', 'set-global-preload-3.js'))
]
const defaultSession = session.defaultSession

Expand All @@ -564,9 +565,10 @@ describe('BrowserWindow module', () => {
const generateSpecs = (description, sandbox) => {
describe(description, () => {
it('loads the script before other scripts in window including normal preloads', function (done) {
ipcMain.once('vars', function (event, preload1, preload2) {
ipcMain.once('vars', function (event, preload1, preload2, preload3) {
expect(preload1).to.equal('preload-1')
expect(preload2).to.equal('preload-1-2')
expect(preload3).to.be.null()
done()
})
w.destroy()
Expand Down
7 changes: 0 additions & 7 deletions spec/fixtures/api/preloads.html

This file was deleted.

2 changes: 1 addition & 1 deletion spec/fixtures/module/get-global-preload.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
require('electron').ipcRenderer.send('vars', window.preload1, window.preload2)
require('electron').ipcRenderer.send('vars', window.preload1, window.preload2, window.preload3)
1 change: 1 addition & 0 deletions spec/fixtures/module/set-global-preload-3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
window.preload3 = window.preload2 + '-3'