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

This commit is contained in:
Milan Burda 2019-07-03 17:05:45 +02:00 committed by John Kleinschmidt
parent 50b9c7051e
commit 69ea0b4ebf
10 changed files with 46 additions and 64 deletions

View file

@ -519,23 +519,18 @@ if (features.isDesktopCapturerEnabled()) {
const getPreloadScript = async function (preloadPath) { const getPreloadScript = async function (preloadPath) {
let preloadSrc = null let preloadSrc = null
let preloadError = null let preloadError = null
if (preloadPath) {
try { try {
preloadSrc = (await fs.promises.readFile(preloadPath)).toString() preloadSrc = (await fs.promises.readFile(preloadPath)).toString()
} catch (err) { } catch (err) {
preloadError = errorUtils.serialize(err) preloadError = errorUtils.serialize(err)
} }
}
return { preloadPath, preloadSrc, preloadError } return { preloadPath, preloadSrc, preloadError }
} }
ipcMainUtils.handle('ELECTRON_GET_CONTENT_SCRIPTS', () => getContentScripts()) ipcMainUtils.handle('ELECTRON_GET_CONTENT_SCRIPTS', () => getContentScripts())
ipcMainUtils.handle('ELECTRON_BROWSER_SANDBOX_LOAD', async function (event) { ipcMainUtils.handle('ELECTRON_BROWSER_SANDBOX_LOAD', async function (event) {
const preloadPaths = [ const preloadPaths = event.sender._getPreloadPaths()
...(event.sender.session ? event.sender.session.getPreloads() : []),
event.sender._getPreloadPath()
]
return { return {
contentScripts: getContentScripts(), contentScripts: getContentScripts(),

View file

@ -60,6 +60,7 @@
#include "shell/browser/lib/bluetooth_chooser.h" #include "shell/browser/lib/bluetooth_chooser.h"
#include "shell/browser/native_window.h" #include "shell/browser/native_window.h"
#include "shell/browser/net/atom_network_delegate.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/drag_util.h"
#include "shell/browser/ui/inspectable_web_contents.h" #include "shell/browser/ui/inspectable_web_contents.h"
#include "shell/browser/ui/inspectable_web_contents_view.h" #include "shell/browser/ui/inspectable_web_contents_view.h"
@ -2206,14 +2207,17 @@ void WebContents::HideAutofillPopup() {
CommonWebContentsDelegate::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())) { if (auto* web_preferences = WebContentsPreferences::From(web_contents())) {
base::FilePath::StringType preload; base::FilePath::StringType preload;
if (web_preferences->GetPreloadPath(&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( v8::Local<v8::Value> WebContents::GetWebPreferences(
@ -2437,7 +2441,7 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setZoomFactor", &WebContents::SetZoomFactor) .SetMethod("setZoomFactor", &WebContents::SetZoomFactor)
.SetMethod("getZoomFactor", &WebContents::GetZoomFactor) .SetMethod("getZoomFactor", &WebContents::GetZoomFactor)
.SetMethod("getType", &WebContents::GetType) .SetMethod("getType", &WebContents::GetType)
.SetMethod("_getPreloadPath", &WebContents::GetPreloadPath) .SetMethod("_getPreloadPaths", &WebContents::GetPreloadPaths)
.SetMethod("getWebPreferences", &WebContents::GetWebPreferences) .SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
.SetMethod("getLastWebPreferences", &WebContents::GetLastWebPreferences) .SetMethod("getLastWebPreferences", &WebContents::GetLastWebPreferences)
.SetMethod("_isRemoteModuleEnabled", &WebContents::IsRemoteModuleEnabled) .SetMethod("_isRemoteModuleEnabled", &WebContents::IsRemoteModuleEnabled)

View file

@ -285,7 +285,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
const scoped_refptr<network::ResourceRequestBody>& body); const scoped_refptr<network::ResourceRequestBody>& body);
// Returns the preload script path of current WebContents. // 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. // Returns the web preferences of current WebContents.
v8::Local<v8::Value> GetWebPreferences(v8::Isolate* isolate) const; v8::Local<v8::Value> GetWebPreferences(v8::Isolate* isolate) const;

View file

@ -151,6 +151,12 @@ void SetApplicationLocaleOnIOThread(const std::string& locale) {
g_io_thread_application_locale.Get() = 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 } // namespace
// static // static
@ -539,8 +545,12 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
if (web_preferences) if (web_preferences)
web_preferences->AppendCommandLineSwitches( web_preferences->AppendCommandLineSwitches(
command_line, IsRendererSubFrame(process_id)); command_line, IsRendererSubFrame(process_id));
SessionPreferences::AppendExtraCommandLineSwitches( auto preloads =
web_contents->GetBrowserContext(), command_line); SessionPreferences::GetValidPreloads(web_contents->GetBrowserContext());
if (!preloads.empty())
command_line->AppendSwitchNative(
switches::kPreloadScripts,
base::JoinString(preloads, kPathDelimiter));
if (CanUseCustomSiteInstance()) { if (CanUseCustomSiteInstance()) {
command_line->AppendSwitch( command_line->AppendSwitch(
switches::kDisableElectronSiteInstanceOverrides); switches::kDisableElectronSiteInstanceOverrides);

View file

@ -4,22 +4,8 @@
#include "shell/browser/session_preferences.h" #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 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 // static
int SessionPreferences::kLocatorKey = 0; int SessionPreferences::kLocatorKey = 0;
@ -36,26 +22,21 @@ SessionPreferences* SessionPreferences::FromBrowserContext(
} }
// static // static
void SessionPreferences::AppendExtraCommandLineSwitches( std::vector<base::FilePath::StringType> SessionPreferences::GetValidPreloads(
content::BrowserContext* context, content::BrowserContext* context) {
base::CommandLine* command_line) { std::vector<base::FilePath::StringType> result;
SessionPreferences* self = FromBrowserContext(context);
if (!self)
return;
base::FilePath::StringType preloads; if (auto* self = FromBrowserContext(context)) {
for (const auto& preload : self->preloads()) { for (const auto& preload : self->preloads()) {
if (!base::FilePath(preload).IsAbsolute()) { if (base::FilePath(preload).IsAbsolute()) {
result.emplace_back(preload);
} else {
LOG(ERROR) << "preload script must have absolute path: " << preload; LOG(ERROR) << "preload script must have absolute path: " << preload;
continue;
} }
if (preloads.empty())
preloads = preload;
else
preloads += kPathDelimiter + preload;
} }
if (!preloads.empty()) }
command_line->AppendSwitchNative(switches::kPreloadScripts, preloads);
return result;
} }
} // namespace electron } // namespace electron

View file

@ -11,18 +11,14 @@
#include "base/supports_user_data.h" #include "base/supports_user_data.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
namespace base {
class CommandLine;
}
namespace electron { namespace electron {
class SessionPreferences : public base::SupportsUserData::Data { class SessionPreferences : public base::SupportsUserData::Data {
public: public:
static SessionPreferences* FromBrowserContext( static SessionPreferences* FromBrowserContext(
content::BrowserContext* context); content::BrowserContext* context);
static void AppendExtraCommandLineSwitches(content::BrowserContext* context, static std::vector<base::FilePath::StringType> GetValidPreloads(
base::CommandLine* command_line); content::BrowserContext* context);
explicit SessionPreferences(content::BrowserContext* context); explicit SessionPreferences(content::BrowserContext* context);
~SessionPreferences() override; ~SessionPreferences() override;

View file

@ -545,7 +545,8 @@ describe('BrowserWindow module', () => {
describe('session preload scripts', function () { describe('session preload scripts', function () {
const preloads = [ const preloads = [
path.join(fixtures, 'module', 'set-global-preload-1.js'), 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 const defaultSession = session.defaultSession
@ -564,9 +565,10 @@ describe('BrowserWindow module', () => {
const generateSpecs = (description, sandbox) => { const generateSpecs = (description, sandbox) => {
describe(description, () => { describe(description, () => {
it('loads the script before other scripts in window including normal preloads', function (done) { 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(preload1).to.equal('preload-1')
expect(preload2).to.equal('preload-1-2') expect(preload2).to.equal('preload-1-2')
expect(preload3).to.be.null()
done() done()
}) })
w.destroy() w.destroy()

View file

@ -1,7 +0,0 @@
<html>
<body>
<script type="text/javascript" charset="utf-8">
require('electron').ipcRenderer.send('vars', preload1, preload2, preload3);
</script>
</body>
</html>

View file

@ -1 +1 @@
require('electron').ipcRenderer.send('vars', window.preload1, window.preload2) require('electron').ipcRenderer.send('vars', window.preload1, window.preload2, window.preload3)

View file

@ -0,0 +1 @@
window.preload3 = window.preload2 + '-3'