Skip to content
This repository has been archived by the owner on Aug 4, 2022. It is now read-only.

Commit

Permalink
Bug 1334550 - Part 1 - Proxy moz-extension protocol requests to the p…
Browse files Browse the repository at this point in the history
…arent process; r=jimm,mayhemer

Changes ExtensionProtocolHandler to use remote streams for
moz-extension loads of file and JAR URI's to allow for
filesystem read-access sandboxing.

Adds messaging to PNecko to allow child processes to
request an input stream or file descriptor for moz-extension
URI's.

Add ExtensionProtocolHandler singleton so that NeckoParent can
call methods directly and ExtensionProtocolHandler::NewFD
can use a new member variable |mFileOpenerThread| to open files.

Adds FileDescriptorFile, a limited implementation of nsIFile
that wraps a file descriptor, to be sideloaded into
nsJARChannels so that extension JAR files can be read
using a file descriptor without accessing the filesystem
directly.

MozReview-Commit-ID: 1pcnIpjz2yR
  • Loading branch information
hafta committed Jun 24, 2017
1 parent d92d2f6 commit 85f218d
Show file tree
Hide file tree
Showing 14 changed files with 1,409 additions and 11 deletions.
5 changes: 4 additions & 1 deletion modules/libjar/nsIJARChannel.idl
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ interface nsIJARChannel : nsIChannel

/**
* Returns the JAR file. May be null if the jar is remote.
* Setting the JAR file is optional and overrides the JAR
* file used for local file JARs. Setting the JAR file after
* the channel has been opened is not permitted.
*/
readonly attribute nsIFile jarFile;
attribute nsIFile jarFile;

/**
* Returns the zip entry if the file is synchronously accessible.
Expand Down
17 changes: 17 additions & 0 deletions modules/libjar/nsJARChannel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,12 @@ nsJARChannel::LookupFile(bool aAllowAsync)
// have e.g. spaces in their filenames.
NS_UnescapeURL(mJarEntry);

if (mJarFileOverride) {
mJarFile = mJarFileOverride;
LOG(("nsJARChannel::LookupFile [this=%p] Overriding mJarFile\n", this));
return NS_OK;
}

// try to get a nsIFile directly from the url, which will often succeed.
{
nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(mJarBaseURI);
Expand Down Expand Up @@ -884,6 +890,17 @@ nsJARChannel::GetJarFile(nsIFile **aFile)
return NS_OK;
}

NS_IMETHODIMP
nsJARChannel::SetJarFile(nsIFile *aFile)
{
if (mOpened) {
return NS_ERROR_IN_PROGRESS;
}
mJarFileOverride = aFile;
return NS_OK;
}


NS_IMETHODIMP
nsJARChannel::GetZipEntry(nsIZipEntry **aZipEntry)
{
Expand Down
3 changes: 3 additions & 0 deletions modules/libjar/nsJARChannel.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ class nsJARChannel final : public nsIJARChannel

nsresult Init(nsIURI *uri);

void SetFile(nsIFile *file);

private:
virtual ~nsJARChannel();

Expand Down Expand Up @@ -98,6 +100,7 @@ class nsJARChannel final : public nsIJARChannel
// to the request if we get called back via RetargetDeliveryTo.
nsCOMPtr<nsIRequest> mRequest;
nsCOMPtr<nsIFile> mJarFile;
nsCOMPtr<nsIFile> mJarFileOverride;
nsCOMPtr<nsIURI> mJarBaseURI;
nsCString mJarEntry;
nsCString mInnerJarEntry;
Expand Down
2 changes: 2 additions & 0 deletions modules/libpref/init/all.js
Original file line number Diff line number Diff line change
Expand Up @@ -4874,6 +4874,8 @@ pref("extensions.webextensions.identity.redirectDomain", "extensions.allizom.org
pref("extensions.webextensions.themes.enabled", false);
pref("extensions.webextensions.themes.icons.enabled", false);
pref("extensions.webextensions.remote", false);
// Whether or not the moz-extension resource loads are remoted
pref("extensions.webextensions.protocol.remote", true);

pref("layers.popups.compositing.enabled", false);

Expand Down
3 changes: 2 additions & 1 deletion netwerk/build/nsNetModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,8 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NamedPipeService, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsResProtocolHandler, Init)

namespace mozilla {
NS_GENERIC_FACTORY_CONSTRUCTOR(ExtensionProtocolHandler)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(ExtensionProtocolHandler,
ExtensionProtocolHandler::GetSingleton)
NS_GENERIC_FACTORY_CONSTRUCTOR(SubstitutingURL)
} // namespace mozilla
#endif
Expand Down
101 changes: 101 additions & 0 deletions netwerk/ipc/NeckoParent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include "necko-config.h"
#include "nsHttp.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/ipc/IPCStreamUtils.h"
#include "mozilla/net/ExtensionProtocolHandler.h"
#include "mozilla/net/NeckoParent.h"
#include "mozilla/net/HttpChannelParent.h"
#include "mozilla/net/CookieServiceParent.h"
Expand Down Expand Up @@ -38,6 +40,7 @@
#include "mozilla/dom/network/UDPSocketParent.h"
#include "mozilla/dom/workers/ServiceWorkerManager.h"
#include "mozilla/LoadContext.h"
#include "mozilla/MozPromise.h"
#include "nsPrintfCString.h"
#include "nsHTMLDNSPrefetch.h"
#include "nsEscape.h"
Expand All @@ -62,8 +65,10 @@ using mozilla::dom::TCPServerSocketParent;
using mozilla::net::PUDPSocketParent;
using mozilla::dom::UDPSocketParent;
using mozilla::dom::workers::ServiceWorkerManager;
using mozilla::ipc::AutoIPCStream;
using mozilla::ipc::OptionalPrincipalInfo;
using mozilla::ipc::PrincipalInfo;
using mozilla::ipc::LoadInfoArgsToLoadInfo;
using IPC::SerializedLoadContext;

namespace mozilla {
Expand Down Expand Up @@ -955,5 +960,101 @@ NeckoParent::RecvNotifyCurrentTopLevelOuterContentWindowId(const uint64_t& aWind
return IPC_OK();
}

mozilla::ipc::IPCResult
NeckoParent::RecvGetExtensionStream(const URIParams& aURI,
const LoadInfoArgs& aLoadInfo,
GetExtensionStreamResolver&& aResolve)
{
nsCOMPtr<nsIURI> deserializedURI = DeserializeURI(aURI);
if (!deserializedURI) {
return IPC_FAIL_NO_REASON(this);
}

nsCOMPtr<nsILoadInfo> deserializedLoadInfo;
nsresult rv;
rv = LoadInfoArgsToLoadInfo(aLoadInfo, getter_AddRefs(deserializedLoadInfo));
if (NS_FAILED(rv)) {
return IPC_FAIL_NO_REASON(this);
}

RefPtr<ExtensionProtocolHandler> ph(ExtensionProtocolHandler::GetSingleton());
MOZ_ASSERT(ph);

// Ask the ExtensionProtocolHandler to give us a new input stream for
// this URI. The request comes from an ExtensionProtocolHandler in the
// child process, but is not guaranteed to be a valid moz-extension URI,
// and not guaranteed to represent a resource that the child should be
// allowed to access. The ExtensionProtocolHandler is responsible for
// validating the request. Specifically, only URI's for local files that
// an extension is allowed to access via moz-extension URI's should be
// accepted.
AutoIPCStream autoStream;
nsCOMPtr<nsIInputStream> inputStream;
bool terminateSender = true;
auto inputStreamOrReason = ph->NewStream(deserializedURI,
deserializedLoadInfo,
&terminateSender);
if (inputStreamOrReason.isOk()) {
inputStream = inputStreamOrReason.unwrap();
ContentParent* contentParent = static_cast<ContentParent*>(Manager());
Unused << autoStream.Serialize(inputStream, contentParent);
}

// If NewStream failed, we send back an invalid stream to the child so
// it can handle the error. MozPromise rejection is reserved for channel
// errors/disconnects.
aResolve(autoStream.TakeOptionalValue());

if (terminateSender) {
return IPC_FAIL_NO_REASON(this);
} else {
return IPC_OK();
}
}

mozilla::ipc::IPCResult
NeckoParent::RecvGetExtensionFD(const URIParams& aURI,
const OptionalLoadInfoArgs& aLoadInfo,
GetExtensionFDResolver&& aResolve)
{
nsCOMPtr<nsIURI> deserializedURI = DeserializeURI(aURI);
if (!deserializedURI) {
return IPC_FAIL_NO_REASON(this);
}

nsCOMPtr<nsILoadInfo> deserializedLoadInfo;
nsresult rv;
rv = LoadInfoArgsToLoadInfo(aLoadInfo, getter_AddRefs(deserializedLoadInfo));
if (NS_FAILED(rv)) {
return IPC_FAIL_NO_REASON(this);
}

RefPtr<ExtensionProtocolHandler> ph(ExtensionProtocolHandler::GetSingleton());
MOZ_ASSERT(ph);

// Ask the ExtensionProtocolHandler to give us a new input stream for
// this URI. The request comes from an ExtensionProtocolHandler in the
// child process, but is not guaranteed to be a valid moz-extension URI,
// and not guaranteed to represent a resource that the child should be
// allowed to access. The ExtensionProtocolHandler is responsible for
// validating the request. Specifically, only URI's for local files that
// an extension is allowed to access via moz-extension URI's should be
// accepted.
bool terminateSender = true;
auto result = ph->NewFD(deserializedURI, deserializedLoadInfo,
&terminateSender, aResolve);

if (result.isErr() && terminateSender) {
return IPC_FAIL_NO_REASON(this);
}

if (result.isErr()) {
FileDescriptor invalidFD;
aResolve(invalidFD);
}

return IPC_OK();
}

} // namespace net
} // namespace mozilla
11 changes: 11 additions & 0 deletions netwerk/ipc/NeckoParent.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,17 @@ class NeckoParent
virtual mozilla::ipc::IPCResult RecvRemoveRequestContext(const uint64_t& rcid) override;

virtual mozilla::ipc::IPCResult RecvNotifyCurrentTopLevelOuterContentWindowId(const uint64_t& aWindowId) override;

/* WebExtensions */
virtual mozilla::ipc::IPCResult
RecvGetExtensionStream(const URIParams& aURI,
const LoadInfoArgs& aLoadInfo,
GetExtensionStreamResolver&& aResolve) override;

virtual mozilla::ipc::IPCResult
RecvGetExtensionFD(const URIParams& aURI,
const OptionalLoadInfoArgs& aLoadInfo,
GetExtensionFDResolver&& aResolve) override;
};

} // namespace net
Expand Down
9 changes: 9 additions & 0 deletions netwerk/ipc/PNecko.ipdl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ include protocol PFileChannel;

include protocol PRtspController;
include protocol PRtspChannel;
include IPCStream;
include URIParams;
include NeckoChannelParams;
include PBrowserOrId;
Expand Down Expand Up @@ -127,6 +128,14 @@ parent:

prio(high) async NotifyCurrentTopLevelOuterContentWindowId(uint64_t windowId);

/**
* WebExtension-specific remote resource loading
*/
async GetExtensionStream(URIParams uri, LoadInfoArgs loadInfo) returns
(OptionalIPCStream stream);
async GetExtensionFD(URIParams uri, OptionalLoadInfoArgs loadInfo) returns
(FileDescriptor fd);

child:
/*
* Bring up the http auth prompt for a nested remote mozbrowser.
Expand Down
Loading

0 comments on commit 85f218d

Please sign in to comment.