mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-27 21:00:50 +00:00
Bug 1284897 - Hook GetSaveFileNameW/GetOpenFileNameW to record and grant a sandboxed process permission to access user-chosen files. r=jimm
This commit is contained in:
parent
3fd846f6a8
commit
32aabd5e62
@ -14,6 +14,9 @@ using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
|
||||
using class mac_plugin_interposing::NSCursorInfo from "mozilla/plugins/PluginMessageUtils.h";
|
||||
using struct nsID from "nsID.h";
|
||||
using struct mozilla::plugins::NPAudioDeviceChangeDetailsIPC from "mozilla/plugins/PluginMessageUtils.h";
|
||||
using mozilla::plugins::GetFileNameFunc from "mozilla/plugins/PluginMessageUtils.h";
|
||||
using mozilla::plugins::OpenFileNameIPC from "mozilla/plugins/PluginMessageUtils.h";
|
||||
using mozilla::plugins::OpenFileNameRetIPC from "mozilla/plugins/PluginMessageUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace plugins {
|
||||
@ -163,6 +166,10 @@ parent:
|
||||
|
||||
intr NPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(bool shouldRegister)
|
||||
returns (NPError result);
|
||||
|
||||
// Used to broker the GetOpenFileName/GetSaveFileName file pickers on Windows.
|
||||
intr GetFileName(GetFileNameFunc aFunc, OpenFileNameIPC aOfnIn)
|
||||
returns (OpenFileNameRetIPC aOfnOut, bool aResult);
|
||||
};
|
||||
|
||||
} // namespace plugins
|
||||
|
@ -151,5 +151,192 @@ void DeferNPVariantLastRelease(const NPNetscapeFuncs* f, NPVariant* v)
|
||||
VOID_TO_NPVARIANT(*v);
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
void
|
||||
OpenFileNameIPC::CopyFromOfn(LPOPENFILENAMEW aLpofn)
|
||||
{
|
||||
mHwndOwner = nullptr;
|
||||
|
||||
// Filter is double-NULL terminated. mFilter should include the double-NULL.
|
||||
mHasFilter = aLpofn->lpstrFilter != nullptr;
|
||||
if (mHasFilter) {
|
||||
uint32_t dNullIdx = 0;
|
||||
while (aLpofn->lpstrFilter[dNullIdx] != L'\0' ||
|
||||
aLpofn->lpstrFilter[dNullIdx+1] != L'\0') {
|
||||
dNullIdx++;
|
||||
}
|
||||
mFilter.assign(aLpofn->lpstrFilter, dNullIdx+2);
|
||||
}
|
||||
mHasCustomFilter = aLpofn->lpstrCustomFilter != nullptr;
|
||||
if (mHasCustomFilter) {
|
||||
mCustomFilterIn = std::wstring(aLpofn->lpstrCustomFilter);
|
||||
mNMaxCustFilterOut =
|
||||
aLpofn->nMaxCustFilter - (wcslen(aLpofn->lpstrCustomFilter) + 1);
|
||||
}
|
||||
else {
|
||||
mNMaxCustFilterOut = 0;
|
||||
}
|
||||
mFilterIndex = aLpofn->nFilterIndex;
|
||||
mFile = std::wstring(aLpofn->lpstrFile);
|
||||
mNMaxFile = aLpofn->nMaxFile;
|
||||
mNMaxFileTitle =
|
||||
aLpofn->lpstrFileTitle != nullptr ? aLpofn->nMaxFileTitle : 0;
|
||||
mHasInitialDir = aLpofn->lpstrInitialDir != nullptr;
|
||||
if (mHasInitialDir) {
|
||||
mInitialDir = std::wstring(aLpofn->lpstrInitialDir);
|
||||
}
|
||||
mHasTitle = aLpofn->lpstrTitle != nullptr;
|
||||
if (mHasTitle) {
|
||||
mTitle = std::wstring(aLpofn->lpstrTitle);
|
||||
}
|
||||
mHasDefExt = aLpofn->lpstrDefExt != nullptr;
|
||||
if (mHasDefExt) {
|
||||
mDefExt = std::wstring(aLpofn->lpstrDefExt);
|
||||
}
|
||||
|
||||
mFlags = aLpofn->Flags;
|
||||
// If the user sets OFN_ALLOWMULTISELECT then we require OFN_EXPLORER
|
||||
// as well. Without OFN_EXPLORER, the method has ancient legacy
|
||||
// behavior that we don't support.
|
||||
MOZ_ASSERT((mFlags & OFN_EXPLORER) || !(mFlags & OFN_ALLOWMULTISELECT));
|
||||
|
||||
// We ignore any visual customization and callbacks that the user set.
|
||||
mFlags &= ~(OFN_ENABLEHOOK | OFN_ENABLETEMPLATEHANDLE | OFN_ENABLETEMPLATE);
|
||||
|
||||
mFlagsEx = aLpofn->FlagsEx;
|
||||
}
|
||||
|
||||
void
|
||||
OpenFileNameIPC::AddToOfn(LPOPENFILENAMEW aLpofn) const
|
||||
{
|
||||
aLpofn->lStructSize = sizeof(OPENFILENAMEW);
|
||||
aLpofn->hwndOwner = mHwndOwner;
|
||||
if (mHasFilter) {
|
||||
memcpy(const_cast<LPWSTR>(aLpofn->lpstrFilter),
|
||||
mFilter.data(), mFilter.size() * sizeof(wchar_t));
|
||||
}
|
||||
if (mHasCustomFilter) {
|
||||
aLpofn->nMaxCustFilter = mCustomFilterIn.size() + 1 + mNMaxCustFilterOut;
|
||||
wcscpy(aLpofn->lpstrCustomFilter, mCustomFilterIn.c_str());
|
||||
memset(aLpofn->lpstrCustomFilter + mCustomFilterIn.size() + 1, 0,
|
||||
mNMaxCustFilterOut * sizeof(wchar_t));
|
||||
}
|
||||
else {
|
||||
aLpofn->nMaxCustFilter = 0;
|
||||
}
|
||||
aLpofn->nFilterIndex = mFilterIndex;
|
||||
wcscpy(aLpofn->lpstrFile, mFile.c_str());
|
||||
aLpofn->nMaxFile = mNMaxFile;
|
||||
aLpofn->nMaxFileTitle = mNMaxFileTitle;
|
||||
if (mHasInitialDir) {
|
||||
wcscpy(const_cast<LPWSTR>(aLpofn->lpstrInitialDir), mInitialDir.c_str());
|
||||
}
|
||||
if (mHasTitle) {
|
||||
wcscpy(const_cast<LPWSTR>(aLpofn->lpstrTitle), mTitle.c_str());
|
||||
}
|
||||
aLpofn->Flags = mFlags; /* TODO: Consider adding OFN_NOCHANGEDIR */
|
||||
if (mHasDefExt) {
|
||||
wcscpy(const_cast<LPWSTR>(aLpofn->lpstrDefExt), mDefExt.c_str());
|
||||
}
|
||||
aLpofn->FlagsEx = mFlagsEx;
|
||||
}
|
||||
|
||||
void
|
||||
OpenFileNameIPC::AllocateOfnStrings(LPOPENFILENAMEW aLpofn) const
|
||||
{
|
||||
if (mHasFilter) {
|
||||
// mFilter is double-NULL terminated and it includes the double-NULL in its length.
|
||||
aLpofn->lpstrFilter =
|
||||
static_cast<LPCTSTR>(moz_xmalloc(sizeof(wchar_t) * (mFilter.size())));
|
||||
}
|
||||
if (mHasCustomFilter) {
|
||||
aLpofn->lpstrCustomFilter =
|
||||
static_cast<LPTSTR>(moz_xmalloc(sizeof(wchar_t) * (mCustomFilterIn.size() + 1) + mNMaxCustFilterOut));
|
||||
}
|
||||
aLpofn->lpstrFile =
|
||||
static_cast<LPTSTR>(moz_xmalloc(sizeof(wchar_t) * mNMaxFile));
|
||||
if (mNMaxFileTitle > 0) {
|
||||
aLpofn->lpstrFileTitle =
|
||||
static_cast<LPTSTR>(moz_xmalloc(sizeof(wchar_t) * mNMaxFileTitle));
|
||||
}
|
||||
if (mHasInitialDir) {
|
||||
aLpofn->lpstrInitialDir =
|
||||
static_cast<LPCTSTR>(moz_xmalloc(sizeof(wchar_t) * (mInitialDir.size() + 1)));
|
||||
}
|
||||
if (mHasTitle) {
|
||||
aLpofn->lpstrTitle =
|
||||
static_cast<LPCTSTR>(moz_xmalloc(sizeof(wchar_t) * (mTitle.size() + 1)));
|
||||
}
|
||||
if (mHasDefExt) {
|
||||
aLpofn->lpstrDefExt =
|
||||
static_cast<LPCTSTR>(moz_xmalloc(sizeof(wchar_t) * (mDefExt.size() + 1)));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OpenFileNameIPC::FreeOfnStrings(LPOPENFILENAMEW aLpofn) const
|
||||
{
|
||||
if (aLpofn->lpstrFilter) {
|
||||
free(const_cast<LPWSTR>(aLpofn->lpstrFilter));
|
||||
}
|
||||
if (aLpofn->lpstrCustomFilter) {
|
||||
free(aLpofn->lpstrCustomFilter);
|
||||
}
|
||||
if (aLpofn->lpstrFile) {
|
||||
free(aLpofn->lpstrFile);
|
||||
}
|
||||
if (aLpofn->lpstrFileTitle) {
|
||||
free(aLpofn->lpstrFileTitle);
|
||||
}
|
||||
if (aLpofn->lpstrInitialDir) {
|
||||
free(const_cast<LPWSTR>(aLpofn->lpstrInitialDir));
|
||||
}
|
||||
if (aLpofn->lpstrTitle) {
|
||||
free(const_cast<LPWSTR>(aLpofn->lpstrTitle));
|
||||
}
|
||||
if (aLpofn->lpstrDefExt) {
|
||||
free(const_cast<LPWSTR>(aLpofn->lpstrDefExt));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OpenFileNameRetIPC::CopyFromOfn(LPOPENFILENAMEW aLpofn)
|
||||
{
|
||||
if (aLpofn->lpstrCustomFilter != nullptr) {
|
||||
mCustomFilterOut =
|
||||
std::wstring(aLpofn->lpstrCustomFilter + wcslen(aLpofn->lpstrCustomFilter) + 1);
|
||||
}
|
||||
mFile.assign(aLpofn->lpstrFile, aLpofn->nMaxFile);
|
||||
if (aLpofn->lpstrFileTitle != nullptr) {
|
||||
mFileTitle.assign(aLpofn->lpstrFileTitle, wcslen(aLpofn->lpstrFileTitle) + 1);
|
||||
}
|
||||
mFileOffset = aLpofn->nFileOffset;
|
||||
mFileExtension = aLpofn->nFileExtension;
|
||||
}
|
||||
|
||||
void
|
||||
OpenFileNameRetIPC::AddToOfn(LPOPENFILENAMEW aLpofn) const
|
||||
{
|
||||
if (aLpofn->lpstrCustomFilter) {
|
||||
LPWSTR secondString =
|
||||
aLpofn->lpstrCustomFilter + wcslen(aLpofn->lpstrCustomFilter) + 1;
|
||||
const wchar_t* customFilterOut = mCustomFilterOut.c_str();
|
||||
MOZ_ASSERT(wcslen(aLpofn->lpstrCustomFilter) + 1 +
|
||||
wcslen(customFilterOut) + 1 + 1 <= aLpofn->nMaxCustFilter);
|
||||
wcscpy(secondString, customFilterOut);
|
||||
secondString[wcslen(customFilterOut) + 1] = L'\0'; // terminated with two NULLs
|
||||
}
|
||||
MOZ_ASSERT(mFile.size() <= aLpofn->nMaxFile);
|
||||
memcpy(aLpofn->lpstrFile,
|
||||
mFile.data(), mFile.size() * sizeof(wchar_t));
|
||||
if (aLpofn->lpstrFileTitle != nullptr) {
|
||||
MOZ_ASSERT(mFileTitle.size() + 1 < aLpofn->nMaxFileTitle);
|
||||
wcscpy(aLpofn->lpstrFileTitle, mFileTitle.c_str());
|
||||
}
|
||||
aLpofn->nFileOffset = mFileOffset;
|
||||
aLpofn->nFileExtension = mFileExtension;
|
||||
}
|
||||
#endif // XP_WIN
|
||||
|
||||
} // namespace plugins
|
||||
} // namespace mozilla
|
||||
|
@ -32,6 +32,9 @@
|
||||
namespace mac_plugin_interposing { class NSCursorInfo { }; }
|
||||
#endif
|
||||
using mac_plugin_interposing::NSCursorInfo;
|
||||
#ifdef XP_WIN
|
||||
#include "commdlg.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace plugins {
|
||||
@ -123,9 +126,59 @@ typedef intptr_t NativeWindowHandle; // never actually used, will always be 0
|
||||
#ifdef XP_WIN
|
||||
typedef base::SharedMemoryHandle WindowsSharedMemoryHandle;
|
||||
typedef HANDLE DXGISharedSurfaceHandle;
|
||||
#else
|
||||
|
||||
// Values indicate GetOpenFileNameW and GetSaveFileNameW.
|
||||
enum GetFileNameFunc { OPEN_FUNC, SAVE_FUNC };
|
||||
|
||||
// IPC-capable version of the Windows OPENFILENAMEW struct.
|
||||
typedef struct _OpenFileNameIPC
|
||||
{
|
||||
// Allocates memory for the strings in this object. This should usually
|
||||
// be used with a zeroed out OPENFILENAMEW structure.
|
||||
void AllocateOfnStrings(LPOPENFILENAMEW aLpofn) const;
|
||||
void FreeOfnStrings(LPOPENFILENAMEW aLpofn) const;
|
||||
void AddToOfn(LPOPENFILENAMEW aLpofn) const;
|
||||
void CopyFromOfn(LPOPENFILENAMEW aLpofn);
|
||||
|
||||
NativeWindowHandle mHwndOwner;
|
||||
std::wstring mFilter; // Double-NULL terminated (i.e. L"\0\0") if mHasFilter is true
|
||||
bool mHasFilter;
|
||||
std::wstring mCustomFilterIn;
|
||||
bool mHasCustomFilter;
|
||||
uint32_t mNMaxCustFilterOut;
|
||||
uint32_t mFilterIndex;
|
||||
std::wstring mFile;
|
||||
uint32_t mNMaxFile;
|
||||
uint32_t mNMaxFileTitle;
|
||||
std::wstring mInitialDir;
|
||||
bool mHasInitialDir;
|
||||
std::wstring mTitle;
|
||||
bool mHasTitle;
|
||||
uint32_t mFlags;
|
||||
std::wstring mDefExt;
|
||||
bool mHasDefExt;
|
||||
uint32_t mFlagsEx;
|
||||
} OpenFileNameIPC;
|
||||
|
||||
// GetOpenFileNameW and GetSaveFileNameW overwrite fields of their OPENFILENAMEW
|
||||
// parameter. This represents those values so that they can be returned via IPC.
|
||||
typedef struct _OpenFileNameRetIPC
|
||||
{
|
||||
void CopyFromOfn(LPOPENFILENAMEW aLpofn);
|
||||
void AddToOfn(LPOPENFILENAMEW aLpofn) const;
|
||||
|
||||
std::wstring mCustomFilterOut;
|
||||
std::wstring mFile; // Double-NULL terminated (i.e. L"\0\0")
|
||||
std::wstring mFileTitle;
|
||||
uint16_t mFileOffset;
|
||||
uint16_t mFileExtension;
|
||||
} OpenFileNameRetIPC;
|
||||
#else // XP_WIN
|
||||
typedef mozilla::null_t WindowsSharedMemoryHandle;
|
||||
typedef mozilla::null_t DXGISharedSurfaceHandle;
|
||||
typedef mozilla::null_t GetFileNameFunc;
|
||||
typedef mozilla::null_t OpenFileNameIPC;
|
||||
typedef mozilla::null_t OpenFileNameRetIPC;
|
||||
#endif
|
||||
|
||||
// XXX maybe not the best place for these. better one?
|
||||
@ -723,6 +776,129 @@ struct ParamTraits<mozilla::plugins::NPAudioDeviceChangeDetailsIPC>
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef XP_WIN
|
||||
template <>
|
||||
struct ParamTraits<mozilla::plugins::_OpenFileNameIPC>
|
||||
{
|
||||
typedef mozilla::plugins::_OpenFileNameIPC paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mHwndOwner);
|
||||
WriteParam(aMsg, aParam.mFilter);
|
||||
WriteParam(aMsg, aParam.mHasFilter);
|
||||
WriteParam(aMsg, aParam.mCustomFilterIn);
|
||||
WriteParam(aMsg, aParam.mHasCustomFilter);
|
||||
WriteParam(aMsg, aParam.mNMaxCustFilterOut);
|
||||
WriteParam(aMsg, aParam.mFilterIndex);
|
||||
WriteParam(aMsg, aParam.mFile);
|
||||
WriteParam(aMsg, aParam.mNMaxFile);
|
||||
WriteParam(aMsg, aParam.mNMaxFileTitle);
|
||||
WriteParam(aMsg, aParam.mInitialDir);
|
||||
WriteParam(aMsg, aParam.mHasInitialDir);
|
||||
WriteParam(aMsg, aParam.mTitle);
|
||||
WriteParam(aMsg, aParam.mHasTitle);
|
||||
WriteParam(aMsg, aParam.mFlags);
|
||||
WriteParam(aMsg, aParam.mDefExt);
|
||||
WriteParam(aMsg, aParam.mHasDefExt);
|
||||
WriteParam(aMsg, aParam.mFlagsEx);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
|
||||
{
|
||||
if (ReadParam(aMsg, aIter, &aResult->mHwndOwner) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mFilter) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mHasFilter) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mCustomFilterIn) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mHasCustomFilter) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mNMaxCustFilterOut) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mFilterIndex) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mFile) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mNMaxFile) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mNMaxFileTitle) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mInitialDir) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mHasInitialDir) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mTitle) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mHasTitle) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mFlags) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mDefExt) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mHasDefExt) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mFlagsEx)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Log(const paramType& aParam, std::wstring* aLog)
|
||||
{
|
||||
aLog->append(StringPrintf(L"[%S, %S, %S, %S]", aParam.mFilter.c_str(),
|
||||
aParam.mCustomFilterIn.c_str(), aParam.mFile.c_str(),
|
||||
aParam.mTitle.c_str()));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::plugins::_OpenFileNameRetIPC>
|
||||
{
|
||||
typedef mozilla::plugins::_OpenFileNameRetIPC paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mCustomFilterOut);
|
||||
WriteParam(aMsg, aParam.mFile);
|
||||
WriteParam(aMsg, aParam.mFileTitle);
|
||||
WriteParam(aMsg, aParam.mFileOffset);
|
||||
WriteParam(aMsg, aParam.mFileExtension);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
|
||||
{
|
||||
if (ReadParam(aMsg, aIter, &aResult->mCustomFilterOut) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mFile) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mFileTitle) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mFileOffset) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mFileExtension)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Log(const paramType& aParam, std::wstring* aLog)
|
||||
{
|
||||
aLog->append(StringPrintf(L"[%S, %S, %S, %d, %d]", aParam.mCustomFilterOut.c_str(),
|
||||
aParam.mFile.c_str(), aParam.mFileTitle.c_str(),
|
||||
aParam.mFileOffset, aParam.mFileExtension));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::plugins::GetFileNameFunc>
|
||||
{
|
||||
typedef mozilla::plugins::GetFileNameFunc paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, static_cast<uint32_t>(aParam));
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
|
||||
{
|
||||
uint32_t result;
|
||||
if (ReadParam(aMsg, aIter, &result)) {
|
||||
*aResult = static_cast<paramType>(result);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Log(const paramType& aParam, std::wstring* aLog)
|
||||
{
|
||||
aLog->append(StringPrintf(L"[%S]",
|
||||
aParam == mozilla::plugins::OPEN_FUNC ? "GetOpenFileName" : "GetSaveFileName"));
|
||||
}
|
||||
};
|
||||
#endif // XP_WIN
|
||||
|
||||
} /* namespace IPC */
|
||||
|
||||
|
||||
|
@ -97,6 +97,17 @@ static HWND sBrowserHwnd = nullptr;
|
||||
// sandbox process doesn't get current key states. So we need get it on chrome.
|
||||
typedef SHORT (WINAPI *GetKeyStatePtr)(int);
|
||||
static GetKeyStatePtr sGetKeyStatePtrStub = nullptr;
|
||||
|
||||
static WindowsDllInterceptor sComDlg32Intercept;
|
||||
|
||||
// proxy GetSaveFileName/GetOpenFileName on chrome so that we can know which
|
||||
// files the user has given permission to access
|
||||
// We count on GetOpenFileNameA/GetSaveFileNameA calling
|
||||
// GetOpenFileNameW/GetSaveFileNameW so we don't proxy them explicitly.
|
||||
typedef BOOL (WINAPI *GetOpenFileNameWPtr)(LPOPENFILENAMEW lpofn);
|
||||
static GetOpenFileNameWPtr sGetOpenFileNameWPtrStub = nullptr;
|
||||
typedef BOOL (WINAPI *GetSaveFileNameWPtr)(LPOPENFILENAMEW lpofn);
|
||||
static GetSaveFileNameWPtr sGetSaveFileNameWPtrStub = nullptr;
|
||||
#endif
|
||||
|
||||
/* static */
|
||||
@ -2112,6 +2123,124 @@ PMCGetKeyState(int aVirtKey)
|
||||
}
|
||||
return sGetKeyStatePtrStub(aVirtKey);
|
||||
}
|
||||
|
||||
BOOL WINAPI PMCGetSaveFileNameW(LPOPENFILENAMEW lpofn);
|
||||
BOOL WINAPI PMCGetOpenFileNameW(LPOPENFILENAMEW lpofn);
|
||||
|
||||
// Runnable that performs GetOpenFileNameW and GetSaveFileNameW
|
||||
// on the main thread so that the call can be
|
||||
// synchronously run on the PluginModuleParent via IPC.
|
||||
// The task alerts the given semaphore when it is finished.
|
||||
class GetFileNameTask : public Runnable
|
||||
{
|
||||
BOOL* mReturnValue;
|
||||
void* mLpOpenFileName;
|
||||
HANDLE mSemaphore;
|
||||
GetFileNameFunc mFunc;
|
||||
|
||||
public:
|
||||
explicit GetFileNameTask(GetFileNameFunc func, void* aLpOpenFileName,
|
||||
HANDLE aSemaphore, BOOL* aReturnValue) :
|
||||
mLpOpenFileName(aLpOpenFileName), mSemaphore(aSemaphore),
|
||||
mReturnValue(aReturnValue), mFunc(func)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_METHOD;
|
||||
AssertPluginThread();
|
||||
switch (mFunc) {
|
||||
case OPEN_FUNC:
|
||||
*mReturnValue =
|
||||
PMCGetOpenFileNameW(static_cast<LPOPENFILENAMEW>(mLpOpenFileName));
|
||||
break;
|
||||
case SAVE_FUNC:
|
||||
*mReturnValue =
|
||||
PMCGetSaveFileNameW(static_cast<LPOPENFILENAMEW>(mLpOpenFileName));
|
||||
break;
|
||||
}
|
||||
if (!ReleaseSemaphore(mSemaphore, 1, nullptr)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
// static
|
||||
BOOL
|
||||
PostToPluginThread(GetFileNameFunc aFunc, void* aLpofn)
|
||||
{
|
||||
MOZ_ASSERT(!IsPluginThread());
|
||||
|
||||
// Synchronously run GetFileNameTask from the main thread.
|
||||
// Start a semaphore at 0. We release the semaphore (bringing its
|
||||
// count to 1) when the synchronous call is done.
|
||||
nsAutoHandle semaphore(CreateSemaphore(NULL, 0, 1, NULL));
|
||||
if (semaphore == nullptr) {
|
||||
MOZ_ASSERT(semaphore != nullptr);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL returnValue = FALSE;
|
||||
RefPtr<GetFileNameTask> task =
|
||||
new GetFileNameTask(aFunc, aLpofn, semaphore, &returnValue);
|
||||
ProcessChild::message_loop()->PostTask(task.forget());
|
||||
DWORD err = WaitForSingleObject(semaphore, INFINITE);
|
||||
if (err != WAIT_FAILED) {
|
||||
return returnValue;
|
||||
}
|
||||
PLUGIN_LOG_DEBUG(("Error while waiting for semaphore: %d",
|
||||
GetLastError()));
|
||||
MOZ_ASSERT(err != WAIT_FAILED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// static
|
||||
BOOL WINAPI
|
||||
PMCGetFileNameW(GetFileNameFunc aFunc, LPOPENFILENAMEW aLpofn)
|
||||
{
|
||||
if (!IsPluginThread()) {
|
||||
return PostToPluginThread(aFunc, aLpofn);
|
||||
}
|
||||
|
||||
PluginModuleChild* chromeInstance = PluginModuleChild::GetChrome();
|
||||
if (chromeInstance) {
|
||||
bool ret = FALSE;
|
||||
OpenFileNameIPC inputOfn;
|
||||
inputOfn.CopyFromOfn(aLpofn);
|
||||
OpenFileNameRetIPC outputOfn;
|
||||
if (chromeInstance->CallGetFileName(aFunc, inputOfn,
|
||||
&outputOfn, &ret)) {
|
||||
if (ret) {
|
||||
outputOfn.AddToOfn(aLpofn);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (aFunc) {
|
||||
case OPEN_FUNC:
|
||||
return sGetOpenFileNameWPtrStub(aLpofn);
|
||||
case SAVE_FUNC:
|
||||
return sGetSaveFileNameWPtrStub(aLpofn);
|
||||
}
|
||||
|
||||
MOZ_ASSERT_UNREACHABLE("Illegal GetFileNameFunc value");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// static
|
||||
BOOL WINAPI
|
||||
PMCGetSaveFileNameW(LPOPENFILENAMEW aLpofn)
|
||||
{
|
||||
return PMCGetFileNameW(SAVE_FUNC, aLpofn);
|
||||
}
|
||||
// static
|
||||
BOOL WINAPI
|
||||
PMCGetOpenFileNameW(LPOPENFILENAMEW aLpofn)
|
||||
{
|
||||
return PMCGetFileNameW(OPEN_FUNC, aLpofn);
|
||||
}
|
||||
#endif
|
||||
|
||||
PPluginInstanceChild*
|
||||
@ -2144,6 +2273,17 @@ PluginModuleChild::AllocPPluginInstanceChild(const nsCString& aMimeType,
|
||||
sUser32Intercept.AddHook("GetKeyState", reinterpret_cast<intptr_t>(PMCGetKeyState),
|
||||
(void**) &sGetKeyStatePtrStub);
|
||||
}
|
||||
|
||||
sComDlg32Intercept.Init("comdlg32.dll");
|
||||
if (!sGetSaveFileNameWPtrStub) {
|
||||
sComDlg32Intercept.AddHook("GetSaveFileNameW", reinterpret_cast<intptr_t>(PMCGetSaveFileNameW),
|
||||
(void**) &sGetSaveFileNameWPtrStub);
|
||||
}
|
||||
|
||||
if (!sGetOpenFileNameWPtrStub) {
|
||||
sComDlg32Intercept.AddHook("GetOpenFileNameW", reinterpret_cast<intptr_t>(PMCGetOpenFileNameW),
|
||||
(void**) &sGetOpenFileNameWPtrStub);
|
||||
}
|
||||
#endif
|
||||
|
||||
return new PluginInstanceChild(&mFunctions, aMimeType, aMode, aNames,
|
||||
|
@ -810,6 +810,10 @@ PluginModuleChromeParent::~PluginModuleChromeParent()
|
||||
false);
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
|
||||
mSandboxPermissions.RemovePermissionsForProcess(OtherPid());
|
||||
#endif
|
||||
|
||||
if (!mShutdown) {
|
||||
NS_WARNING("Plugin host deleted the module without shutting down.");
|
||||
NPError err;
|
||||
@ -3403,3 +3407,69 @@ PluginModuleChromeParent::AnswerGetKeyState(const int32_t& aVirtKey,
|
||||
return PluginModuleParent::AnswerGetKeyState(aVirtKey, aRet);
|
||||
#endif
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
PluginModuleChromeParent::AnswerGetFileName(const GetFileNameFunc& aFunc,
|
||||
const OpenFileNameIPC& aOfnIn,
|
||||
OpenFileNameRetIPC* aOfnOut,
|
||||
bool* aResult)
|
||||
{
|
||||
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
|
||||
OPENFILENAMEW ofn;
|
||||
memset(&ofn, 0, sizeof(ofn));
|
||||
aOfnIn.AllocateOfnStrings(&ofn);
|
||||
aOfnIn.AddToOfn(&ofn);
|
||||
switch (aFunc) {
|
||||
case OPEN_FUNC:
|
||||
*aResult = GetOpenFileName(&ofn);
|
||||
break;
|
||||
case SAVE_FUNC:
|
||||
*aResult = GetSaveFileName(&ofn);
|
||||
break;
|
||||
}
|
||||
if (*aResult) {
|
||||
if (ofn.Flags & OFN_ALLOWMULTISELECT) {
|
||||
// We only support multiselect with the OFN_EXPLORER flag.
|
||||
// This guarantees that ofn.lpstrFile follows the pattern below.
|
||||
MOZ_ASSERT(ofn.Flags & OFN_EXPLORER);
|
||||
|
||||
// lpstrFile is one of two things:
|
||||
// 1. A null terminated full path to a file, or
|
||||
// 2. A path to a folder, followed by a NULL, followed by a
|
||||
// list of file names, each NULL terminated, followed by an
|
||||
// additional NULL (so it is also double-NULL terminated).
|
||||
std::wstring path = std::wstring(ofn.lpstrFile);
|
||||
MOZ_ASSERT(ofn.nFileOffset > 0);
|
||||
// For condition #1, nFileOffset points to the file name in the path.
|
||||
// It will be preceeded by a non-NULL character from the path.
|
||||
if (ofn.lpstrFile[ofn.nFileOffset-1] != L'\0') {
|
||||
mSandboxPermissions.GrantFileAccess(OtherPid(), path.c_str(),
|
||||
aFunc == SAVE_FUNC);
|
||||
}
|
||||
else {
|
||||
// This is condition #2
|
||||
wchar_t* nextFile = ofn.lpstrFile + path.size() + 1;
|
||||
while (*nextFile != L'\0') {
|
||||
std::wstring nextFileStr(nextFile);
|
||||
std::wstring fullPath =
|
||||
path + std::wstring(L"\\") + nextFileStr;
|
||||
mSandboxPermissions.GrantFileAccess(OtherPid(), fullPath.c_str(),
|
||||
aFunc == SAVE_FUNC);
|
||||
nextFile += nextFileStr.size() + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
mSandboxPermissions.GrantFileAccess(OtherPid(), ofn.lpstrFile,
|
||||
aFunc == SAVE_FUNC);
|
||||
}
|
||||
aOfnOut->CopyFromOfn(&ofn);
|
||||
}
|
||||
aOfnIn.FreeOfnStrings(&ofn);
|
||||
return IPC_OK();
|
||||
#else
|
||||
MOZ_ASSERT_UNREACHABLE("GetFileName IPC message is only available on "
|
||||
"Windows builds with sandbox.");
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
#endif
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "nsIObserver.h"
|
||||
#ifdef XP_WIN
|
||||
#include "nsWindowsHelpers.h"
|
||||
#include "sandboxPermissions.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
@ -194,6 +195,14 @@ protected:
|
||||
const bool& shouldRegister,
|
||||
NPError* result) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
AnswerGetFileName(const GetFileNameFunc& aFunc,
|
||||
const OpenFileNameIPC& aOfnIn,
|
||||
OpenFileNameRetIPC* aOfnOut, bool* aResult) override
|
||||
{
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
protected:
|
||||
void SetChildTimeout(const int32_t aChildTimeout);
|
||||
static void TimeoutChanged(const char* aPref, void* aModule);
|
||||
@ -509,6 +518,12 @@ class PluginModuleChromeParent
|
||||
virtual mozilla::ipc::IPCResult
|
||||
AnswerGetKeyState(const int32_t& aVirtKey, int16_t* aRet) override;
|
||||
|
||||
// Proxy GetOpenFileName/GetSaveFileName on Windows.
|
||||
virtual mozilla::ipc::IPCResult
|
||||
AnswerGetFileName(const GetFileNameFunc& aFunc,
|
||||
const OpenFileNameIPC& aOfnIn,
|
||||
OpenFileNameRetIPC* aOfnOut, bool* aResult) override;
|
||||
|
||||
private:
|
||||
virtual void
|
||||
EnteredCxxStack() override;
|
||||
@ -662,6 +677,9 @@ private:
|
||||
nsCString mProfile;
|
||||
bool mIsBlocklisted;
|
||||
static bool sInstantiated;
|
||||
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
|
||||
mozilla::SandboxPermissions mSandboxPermissions;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace plugins
|
||||
|
@ -97,13 +97,6 @@ AddSandboxAllowedFiles(int32_t aSandboxLevel,
|
||||
return;
|
||||
}
|
||||
|
||||
// Higher than level 2 currently removes the users own rights.
|
||||
if (aSandboxLevel > 2) {
|
||||
AddSandboxAllowedFile(aAllowedFilesRead, dirSvc, NS_WIN_HOME_DIR);
|
||||
AddSandboxAllowedFile(aAllowedFilesRead, dirSvc, NS_WIN_HOME_DIR,
|
||||
NS_LITERAL_STRING("\\*"));
|
||||
}
|
||||
|
||||
// Level 2 and above is now using low integrity, so we need to give write
|
||||
// access to the Flash directories.
|
||||
// This should be made Flash specific (Bug 1171396).
|
||||
|
@ -129,6 +129,7 @@ if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':
|
||||
LOCAL_INCLUDES += [
|
||||
'/security/sandbox/chromium',
|
||||
'/security/sandbox/chromium-shim',
|
||||
'/security/sandbox/win/src/sandboxpermissions',
|
||||
]
|
||||
|
||||
DEFINES['FORCE_PR_LOG'] = True
|
||||
|
Loading…
x
Reference in New Issue
Block a user