mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1051633: Make sure magic file descriptors in the content process will not be taken for other uses. r=khuey
--HG-- extra : rebase_source : 5e2dedb855dd5e0e6637d6f42c80c69df8081971
This commit is contained in:
parent
b0cdc6c892
commit
1d61b4360f
@ -26,7 +26,6 @@
|
||||
|
||||
#define ASSERT(x) if (!(x)) { MOZ_CRASH(); }
|
||||
|
||||
|
||||
// Functions being loaded by XPCOMGlue
|
||||
XRE_ProcLoaderServiceRunType XRE_ProcLoaderServiceRun;
|
||||
XRE_ProcLoaderClientInitType XRE_ProcLoaderClientInit;
|
||||
@ -43,6 +42,10 @@ static const nsDynamicFunctionLoad kXULFuncs[] = {
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
typedef mozilla::Vector<int> FdArray;
|
||||
static const int kReservedFileDescriptors = 5;
|
||||
static const int kBeginReserveFileDescriptor = STDERR_FILENO + 1;
|
||||
|
||||
static int
|
||||
GetDirnameSlash(const char *aPath, char *aOutDir, int aMaxLen)
|
||||
{
|
||||
@ -69,7 +72,7 @@ GetXPCOMPath(const char *aProgram, char *aOutPath, int aMaxLen)
|
||||
int len = GetDirnameSlash(progBuf, aOutPath, aMaxLen);
|
||||
NS_ENSURE_TRUE(!!len, false);
|
||||
|
||||
NS_ENSURE_TRUE((len + sizeof(XPCOM_DLL)) < aMaxLen, false);
|
||||
NS_ENSURE_TRUE((len + sizeof(XPCOM_DLL)) < (unsigned)aMaxLen, false);
|
||||
char *afterSlash = aOutPath + len;
|
||||
strcpy(afterSlash, XPCOM_DLL);
|
||||
return true;
|
||||
@ -181,7 +184,7 @@ LoadStaticData(int argc, const char *argv[])
|
||||
* The parent is the b2g process and child for Nuwa.
|
||||
*/
|
||||
static int
|
||||
RunProcesses(int argc, const char *argv[])
|
||||
RunProcesses(int argc, const char *argv[], FdArray& aReservedFds)
|
||||
{
|
||||
/*
|
||||
* The original main() of the b2g process. It is renamed to
|
||||
@ -212,15 +215,50 @@ RunProcesses(int argc, const char *argv[])
|
||||
* The b2g process would send a IPC message of loading Nuwa
|
||||
* as the replacement of forking and executing plugin-container.
|
||||
*/
|
||||
return XRE_ProcLoaderServiceRun(getppid(), childSock, argc, argv);
|
||||
return XRE_ProcLoaderServiceRun(getppid(), childSock, argc, argv,
|
||||
aReservedFds);
|
||||
}
|
||||
|
||||
// The b2g process
|
||||
int childPid = pid;
|
||||
XRE_ProcLoaderClientInit(childPid, parentSock);
|
||||
XRE_ProcLoaderClientInit(childPid, parentSock, aReservedFds);
|
||||
return b2g_main(argc, argv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserve the file descriptors that shouldn't be taken for other use for the
|
||||
* child process.
|
||||
*/
|
||||
static void
|
||||
ReserveFileDescriptors(FdArray& aReservedFds)
|
||||
{
|
||||
for (int i = 0; i < kReservedFileDescriptors; i++) {
|
||||
struct stat fileState;
|
||||
int target = kBeginReserveFileDescriptor + i;
|
||||
if (fstat(target, &fileState) == 0) {
|
||||
MOZ_CRASH("ProcLoader error: a magic file descriptor is occupied.");
|
||||
}
|
||||
|
||||
int fd = open("/dev/null", O_RDWR);
|
||||
if (fd == -1) {
|
||||
MOZ_CRASH("ProcLoader error: failed to reserve a magic file descriptor.");
|
||||
}
|
||||
|
||||
aReservedFds.append(target);
|
||||
|
||||
if (fd == target) {
|
||||
// No need to call dup2(). We already occupy the desired file descriptor.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dup2(fd, target)) {
|
||||
MOZ_CRASH("ProcLoader error: failed to reserve a magic file descriptor.");
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* B2G Loader is responsible for loading the b2g process and the
|
||||
* Nuwa process. It forks into the parent process, for the b2g
|
||||
@ -234,7 +272,12 @@ RunProcesses(int argc, const char *argv[])
|
||||
int
|
||||
main(int argc, const char* argv[])
|
||||
{
|
||||
const char *program = argv[0];
|
||||
/**
|
||||
* Reserve file descriptors before loading static data.
|
||||
*/
|
||||
FdArray reservedFds;
|
||||
ReserveFileDescriptors(reservedFds);
|
||||
|
||||
/*
|
||||
* Before fork(), libxul and static data of Gecko are loaded for
|
||||
* sharing.
|
||||
@ -244,5 +287,5 @@ main(int argc, const char* argv[])
|
||||
return 255;
|
||||
}
|
||||
|
||||
return RunProcesses(argc, argv);
|
||||
return RunProcesses(argc, argv, reservedFds);
|
||||
}
|
||||
|
@ -27,7 +27,10 @@
|
||||
#include "base/file_descriptor_shuffle.h"
|
||||
#include "mozilla/BackgroundHangMonitor.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "base/process_util.h"
|
||||
#include "base/eintr_wrapper.h"
|
||||
|
||||
#include "prenv.h"
|
||||
|
||||
@ -37,11 +40,12 @@
|
||||
|
||||
int content_process_main(int argc, char *argv[]);
|
||||
|
||||
extern bool gDisableAndroidLog;
|
||||
typedef mozilla::Vector<int> FdArray;
|
||||
|
||||
#endif /* MOZ_B2G_LOADER */
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace ipc {
|
||||
|
||||
void SetThisProcessName(const char *aName)
|
||||
@ -98,9 +102,18 @@ static pid_t sProcLoaderPid = 0;
|
||||
static int sProcLoaderChannelFd = -1;
|
||||
static PProcLoaderParent *sProcLoaderParent = nullptr;
|
||||
static MessageLoop *sProcLoaderLoop = nullptr;
|
||||
static mozilla::UniquePtr<FdArray> sReservedFds;
|
||||
|
||||
static void ProcLoaderClientDeinit();
|
||||
|
||||
/**
|
||||
* Some file descriptors, like the child IPC channel FD, must be opened at
|
||||
* specific numbers. To ensure this, we pre-reserve kReservedFileDescriptors FDs
|
||||
* starting from kBeginReserveFileDescriptor so that operations like
|
||||
* __android_log_print() won't take these magic FDs.
|
||||
*/
|
||||
static const int kReservedFileDescriptors = 5;
|
||||
static const int kBeginReserveFileDescriptor = STDERR_FILENO + 1;
|
||||
|
||||
class ProcLoaderParent : public PProcLoaderParent
|
||||
{
|
||||
@ -139,6 +152,14 @@ ProcLoaderParent::RecvLoadComplete(const int32_t &aPid,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
CloseFileDescriptors(FdArray& aFds)
|
||||
{
|
||||
for (size_t i = 0; i < aFds.length(); i++) {
|
||||
unused << HANDLE_EINTR(close(aFds[i]));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ProcLoaderParent::OnChannelError()
|
||||
{
|
||||
@ -292,6 +313,7 @@ class ProcLoaderRunnerBase
|
||||
{
|
||||
public:
|
||||
virtual int DoWork() = 0;
|
||||
virtual ~ProcLoaderRunnerBase() {}
|
||||
};
|
||||
|
||||
|
||||
@ -305,7 +327,6 @@ ProcLoaderNoopRunner::DoWork() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The runner to load Nuwa at the current process.
|
||||
*/
|
||||
@ -336,9 +357,12 @@ ProcLoaderLoadRunner::ShuffleFds()
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
MOZ_ASSERT(mFdsRemap.Length() <= kReservedFileDescriptors);
|
||||
|
||||
InjectiveMultimap fd_shuffle1, fd_shuffle2;
|
||||
fd_shuffle1.reserve(mFdsRemap.Length());
|
||||
fd_shuffle2.reserve(mFdsRemap.Length());
|
||||
|
||||
for (i = 0; i < mFdsRemap.Length(); i++) {
|
||||
const FDRemap *map = &mFdsRemap[i];
|
||||
int fd = map->fd().PlatformHandle();
|
||||
@ -346,12 +370,28 @@ ProcLoaderLoadRunner::ShuffleFds()
|
||||
|
||||
fd_shuffle1.push_back(InjectionArc(fd, tofd, false));
|
||||
fd_shuffle2.push_back(InjectionArc(fd, tofd, false));
|
||||
|
||||
// Erase from sReservedFds we will use.
|
||||
for (int* toErase = sReservedFds->begin();
|
||||
toErase < sReservedFds->end();
|
||||
toErase++) {
|
||||
if (tofd == *toErase) {
|
||||
sReservedFds->erase(toErase);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DebugOnly<bool> ok = ShuffleFileDescriptors(&fd_shuffle1);
|
||||
MOZ_ASSERT(ok, "ShuffleFileDescriptors failed");
|
||||
|
||||
CloseSuperfluousFds(fd_shuffle2);
|
||||
// Close the FDs that are reserved but not used after
|
||||
// ShuffleFileDescriptors().
|
||||
MOZ_ASSERT(sReservedFds);
|
||||
CloseFileDescriptors(*sReservedFds);
|
||||
sReservedFds = nullptr;
|
||||
|
||||
// Note that we don'e call ::base::CloseSuperfluousFds() here, assuming that
|
||||
// The file descriptor inherited from the parent are also necessary for us.
|
||||
}
|
||||
|
||||
int
|
||||
@ -482,8 +522,13 @@ public:
|
||||
*/
|
||||
static int
|
||||
ProcLoaderServiceRun(pid_t aPeerPid, int aFd,
|
||||
int aArgc, const char *aArgv[])
|
||||
int aArgc, const char *aArgv[],
|
||||
FdArray& aReservedFds)
|
||||
{
|
||||
// Make a copy of aReservedFds. It will be used when we dup() the magic file
|
||||
// descriptors when ProcLoaderChild::RecvLoad() runs.
|
||||
sReservedFds = MakeUnique<FdArray>(mozilla::Move(aReservedFds));
|
||||
|
||||
ScopedLogging logging;
|
||||
|
||||
char **_argv;
|
||||
@ -498,11 +543,8 @@ ProcLoaderServiceRun(pid_t aPeerPid, int aFd,
|
||||
gArgc = aArgc;
|
||||
|
||||
{
|
||||
gDisableAndroidLog = true;
|
||||
|
||||
nsresult rv = XRE_InitCommandLine(aArgc, _argv);
|
||||
if (NS_FAILED(rv)) {
|
||||
gDisableAndroidLog = false;
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
@ -530,8 +572,6 @@ ProcLoaderServiceRun(pid_t aPeerPid, int aFd,
|
||||
BackgroundHangMonitor::Allow();
|
||||
|
||||
XRE_DeinitCommandLine();
|
||||
|
||||
gDisableAndroidLog = false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(sProcLoaderDispatchedTask != nullptr);
|
||||
@ -555,16 +595,22 @@ ProcLoaderServiceRun(pid_t aPeerPid, int aFd,
|
||||
|
||||
#ifdef MOZ_B2G_LOADER
|
||||
void
|
||||
XRE_ProcLoaderClientInit(pid_t aPeerPid, int aChannelFd)
|
||||
XRE_ProcLoaderClientInit(pid_t aPeerPid, int aChannelFd, FdArray& aReservedFds)
|
||||
{
|
||||
// We already performed fork(). It's safe to free the "danger zone" of file
|
||||
// descriptors .
|
||||
mozilla::ipc::CloseFileDescriptors(aReservedFds);
|
||||
|
||||
mozilla::ipc::ProcLoaderClientInit(aPeerPid, aChannelFd);
|
||||
}
|
||||
|
||||
int
|
||||
XRE_ProcLoaderServiceRun(pid_t aPeerPid, int aFd,
|
||||
int aArgc, const char *aArgv[])
|
||||
int aArgc, const char *aArgv[],
|
||||
FdArray& aReservedFds)
|
||||
{
|
||||
return mozilla::ipc::ProcLoaderServiceRun(aPeerPid, aFd,
|
||||
aArgc, aArgv);
|
||||
aArgc, aArgv,
|
||||
aReservedFds);
|
||||
}
|
||||
#endif /* MOZ_B2G_LOADER */
|
||||
|
@ -201,7 +201,12 @@ StatusMsg(const char* aFmt, ...)
|
||||
va_list ap;
|
||||
va_start(ap, aFmt);
|
||||
#ifdef ANDROID
|
||||
__android_log_vprint(ANDROID_LOG_INFO, "DMD", aFmt, ap);
|
||||
#ifdef MOZ_B2G_LOADER
|
||||
// Don't call __android_log_vprint() during initialization, or the magic file
|
||||
// descriptors will be occupied by android logcat.
|
||||
if (gIsDMDRunning)
|
||||
#endif
|
||||
__android_log_vprint(ANDROID_LOG_INFO, "DMD", aFmt, ap);
|
||||
#else
|
||||
// The +64 is easily enough for the "DMD[<pid>] " prefix and the NUL.
|
||||
char* fmt = (char*) InfallibleAllocPolicy::malloc_(strlen(aFmt) + 64);
|
||||
|
@ -102,13 +102,6 @@ Break(const char* aMsg);
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_LOADER
|
||||
/* Avoid calling Android logger/logd temporarily while running
|
||||
* B2GLoader to start the child process.
|
||||
*/
|
||||
bool gDisableAndroidLog = false;
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static const char* sMultiprocessDescription = nullptr;
|
||||
@ -391,9 +384,6 @@ NS_DebugBreak(uint32_t aSeverity, const char* aStr, const char* aExpr,
|
||||
#endif
|
||||
|
||||
#ifdef ANDROID
|
||||
#ifdef MOZ_B2G_LOADER
|
||||
if (!gDisableAndroidLog)
|
||||
#endif
|
||||
__android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", buf.buffer);
|
||||
#endif
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Vector.h"
|
||||
|
||||
/**
|
||||
* A directory service key which provides the platform-correct "application
|
||||
@ -470,9 +471,11 @@ XRE_API(WindowsEnvironmentType,
|
||||
|
||||
#ifdef MOZ_B2G_LOADER
|
||||
XRE_API(int,
|
||||
XRE_ProcLoaderServiceRun, (pid_t, int, int argc, const char* argv[]));
|
||||
XRE_ProcLoaderServiceRun, (pid_t, int, int argc, const char* argv[],
|
||||
mozilla::Vector<int>& aReservedFds));
|
||||
XRE_API(void,
|
||||
XRE_ProcLoaderClientInit, (pid_t, int));
|
||||
XRE_ProcLoaderClientInit, (pid_t, int,
|
||||
mozilla::Vector<int>& aReservedFds));
|
||||
XRE_API(void,
|
||||
XRE_ProcLoaderPreload, (const char* aProgramDir,
|
||||
const nsXREAppData* aAppData));
|
||||
|
Loading…
Reference in New Issue
Block a user