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:
@@ -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 class mac_plugin_interposing::NSCursorInfo from "mozilla/plugins/PluginMessageUtils.h";
|
||||||
using struct nsID from "nsID.h";
|
using struct nsID from "nsID.h";
|
||||||
using struct mozilla::plugins::NPAudioDeviceChangeDetailsIPC from "mozilla/plugins/PluginMessageUtils.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 mozilla {
|
||||||
namespace plugins {
|
namespace plugins {
|
||||||
@@ -163,6 +166,10 @@ parent:
|
|||||||
|
|
||||||
intr NPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(bool shouldRegister)
|
intr NPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(bool shouldRegister)
|
||||||
returns (NPError result);
|
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
|
} // namespace plugins
|
||||||
|
|||||||
@@ -151,5 +151,192 @@ void DeferNPVariantLastRelease(const NPNetscapeFuncs* f, NPVariant* v)
|
|||||||
VOID_TO_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 plugins
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|||||||
@@ -32,6 +32,9 @@
|
|||||||
namespace mac_plugin_interposing { class NSCursorInfo { }; }
|
namespace mac_plugin_interposing { class NSCursorInfo { }; }
|
||||||
#endif
|
#endif
|
||||||
using mac_plugin_interposing::NSCursorInfo;
|
using mac_plugin_interposing::NSCursorInfo;
|
||||||
|
#ifdef XP_WIN
|
||||||
|
#include "commdlg.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace plugins {
|
namespace plugins {
|
||||||
@@ -123,9 +126,59 @@ typedef intptr_t NativeWindowHandle; // never actually used, will always be 0
|
|||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
typedef base::SharedMemoryHandle WindowsSharedMemoryHandle;
|
typedef base::SharedMemoryHandle WindowsSharedMemoryHandle;
|
||||||
typedef HANDLE DXGISharedSurfaceHandle;
|
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 WindowsSharedMemoryHandle;
|
||||||
typedef mozilla::null_t DXGISharedSurfaceHandle;
|
typedef mozilla::null_t DXGISharedSurfaceHandle;
|
||||||
|
typedef mozilla::null_t GetFileNameFunc;
|
||||||
|
typedef mozilla::null_t OpenFileNameIPC;
|
||||||
|
typedef mozilla::null_t OpenFileNameRetIPC;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// XXX maybe not the best place for these. better one?
|
// 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 */
|
} /* namespace IPC */
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -96,6 +96,17 @@ static HWND sBrowserHwnd = nullptr;
|
|||||||
// sandbox process doesn't get current key states. So we need get it on chrome.
|
// sandbox process doesn't get current key states. So we need get it on chrome.
|
||||||
typedef SHORT (WINAPI *GetKeyStatePtr)(int);
|
typedef SHORT (WINAPI *GetKeyStatePtr)(int);
|
||||||
static GetKeyStatePtr sGetKeyStatePtrStub = nullptr;
|
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
|
#endif
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
@@ -2111,6 +2122,124 @@ PMCGetKeyState(int aVirtKey)
|
|||||||
}
|
}
|
||||||
return sGetKeyStatePtrStub(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
|
#endif
|
||||||
|
|
||||||
PPluginInstanceChild*
|
PPluginInstanceChild*
|
||||||
@@ -2143,6 +2272,17 @@ PluginModuleChild::AllocPPluginInstanceChild(const nsCString& aMimeType,
|
|||||||
sUser32Intercept.AddHook("GetKeyState", reinterpret_cast<intptr_t>(PMCGetKeyState),
|
sUser32Intercept.AddHook("GetKeyState", reinterpret_cast<intptr_t>(PMCGetKeyState),
|
||||||
(void**) &sGetKeyStatePtrStub);
|
(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
|
#endif
|
||||||
|
|
||||||
return new PluginInstanceChild(&mFunctions, aMimeType, aMode, aNames,
|
return new PluginInstanceChild(&mFunctions, aMimeType, aMode, aNames,
|
||||||
|
|||||||
@@ -810,6 +810,10 @@ PluginModuleChromeParent::~PluginModuleChromeParent()
|
|||||||
false);
|
false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
|
||||||
|
mSandboxPermissions.RemovePermissionsForProcess(OtherPid());
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!mShutdown) {
|
if (!mShutdown) {
|
||||||
NS_WARNING("Plugin host deleted the module without shutting down.");
|
NS_WARNING("Plugin host deleted the module without shutting down.");
|
||||||
NPError err;
|
NPError err;
|
||||||
@@ -3433,3 +3437,69 @@ PluginModuleChromeParent::AnswerGetKeyState(const int32_t& aVirtKey,
|
|||||||
return PluginModuleParent::AnswerGetKeyState(aVirtKey, aRet);
|
return PluginModuleParent::AnswerGetKeyState(aVirtKey, aRet);
|
||||||
#endif
|
#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"
|
#include "nsIObserver.h"
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
#include "nsWindowsHelpers.h"
|
#include "nsWindowsHelpers.h"
|
||||||
|
#include "sandboxPermissions.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MOZ_CRASHREPORTER
|
#ifdef MOZ_CRASHREPORTER
|
||||||
@@ -194,6 +195,14 @@ protected:
|
|||||||
const bool& shouldRegister,
|
const bool& shouldRegister,
|
||||||
NPError* result) override;
|
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:
|
protected:
|
||||||
void SetChildTimeout(const int32_t aChildTimeout);
|
void SetChildTimeout(const int32_t aChildTimeout);
|
||||||
static void TimeoutChanged(const char* aPref, void* aModule);
|
static void TimeoutChanged(const char* aPref, void* aModule);
|
||||||
@@ -509,6 +518,12 @@ class PluginModuleChromeParent
|
|||||||
virtual mozilla::ipc::IPCResult
|
virtual mozilla::ipc::IPCResult
|
||||||
AnswerGetKeyState(const int32_t& aVirtKey, int16_t* aRet) override;
|
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:
|
private:
|
||||||
virtual void
|
virtual void
|
||||||
EnteredCxxStack() override;
|
EnteredCxxStack() override;
|
||||||
@@ -662,6 +677,9 @@ private:
|
|||||||
nsCString mProfile;
|
nsCString mProfile;
|
||||||
bool mIsBlocklisted;
|
bool mIsBlocklisted;
|
||||||
static bool sInstantiated;
|
static bool sInstantiated;
|
||||||
|
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
|
||||||
|
mozilla::SandboxPermissions mSandboxPermissions;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace plugins
|
} // namespace plugins
|
||||||
|
|||||||
@@ -97,13 +97,6 @@ AddSandboxAllowedFiles(int32_t aSandboxLevel,
|
|||||||
return;
|
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
|
// Level 2 and above is now using low integrity, so we need to give write
|
||||||
// access to the Flash directories.
|
// access to the Flash directories.
|
||||||
// This should be made Flash specific (Bug 1171396).
|
// This should be made Flash specific (Bug 1171396).
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':
|
|||||||
LOCAL_INCLUDES += [
|
LOCAL_INCLUDES += [
|
||||||
'/security/sandbox/chromium',
|
'/security/sandbox/chromium',
|
||||||
'/security/sandbox/chromium-shim',
|
'/security/sandbox/chromium-shim',
|
||||||
|
'/security/sandbox/win/src/sandboxpermissions',
|
||||||
]
|
]
|
||||||
|
|
||||||
DEFINES['FORCE_PR_LOG'] = True
|
DEFINES['FORCE_PR_LOG'] = True
|
||||||
|
|||||||
Reference in New Issue
Block a user