void CheckFileContents(const FilePath& rel_path, const string& expected_content) { string actual_contents; FilePath actual_path = outputDir_.Append(rel_path); if (!ReadFileToString(actual_path, &actual_contents)) { FAIL() << "Failed to read expected output file: " << rel_path.value(); } if (actual_contents != expected_content) { // When the match fails, display a diff of what's wrong. This greatly // aids in debugging. FilePath expected_path; EXPECT_TRUE(CreateTemporaryFileInDir(tmpDir_, &expected_path)); WriteFile(expected_path, expected_content.c_str(), expected_content.length()); const size_t buf_len = strlen(kDiffTemplate) + actual_path.value().length() + expected_path.value().length() + 1; unique_ptr<char[]> diff_cmd(new char[buf_len]); EXPECT_GT(snprintf(diff_cmd.get(), buf_len, kDiffTemplate, expected_path.value().c_str(), actual_path.value().c_str()), 0); system(diff_cmd.get()); FAIL() << "Actual contents of " << rel_path.value() << " did not match expected content"; } }
errno_t EasyDecrypt(const string& filename, const string& key, string *outFilename) { LOGPOS(); FilePath inFilePath(filename); FileReader reader; if (reader.Open(inFilePath.value()) != CPT_OK) { LOGW("Open file %s failed!", inFilePath.value().c_str()); return CPT_ERROR; } Decrypt decrypt; if (decrypt.SetReader(&reader) != CPT_OK) { LOGW("Decrypt set reader failed!"); return CPT_ERROR; } if (decrypt.LoadHeader() != CPT_OK) { LOGW("Decrypt load header failed!"); return CPT_ERROR; } FileHeader *fileHeader = decrypt.DecryptHeader(key.c_str(), key.length()); if (fileHeader == NULL) { LOGW("LoadHeader error"); return CPT_ERROR; } FilePath outFilePath = inFilePath.ReplaceExtension(fileHeader->GetFormat()); *outFilename = outFilePath.value(); FileWriter writer; if (writer.Open(outFilePath.value()) != CPT_OK) { LOGW("Create file %s failed!", outFilePath.value().c_str()); return CPT_ERROR; } if (decrypt.SetWriter(dynamic_cast<Writer*>(&writer)) != CPT_OK) { LOGW("Decrypt set writer failed!"); return CPT_ERROR; } int err = decrypt.PreDecrypt(); ASSERT(err == CPT_OK); if (decrypt.DoDecrypt(key.c_str(), key.length())) { LOGW("Decrypt decrypt file failed!"); return CPT_ERROR; } err = decrypt.PostDecrypt(); ASSERT(err == CPT_OK); return CPT_OK; }
void handleINT(int sig) { FilePath homedirpath; PathService::Get(chrome::DIR_USER_DATA,&homedirpath); FilePath child = homedirpath.AppendASCII("SingletonLock"); unlink(child.value().c_str()); exit(-sig); }
Result<Ok, nsresult> MemMapSnapshot::Create(size_t aSize) { FilePath path; ScopedCloseFile fd(file_util::CreateAndOpenTemporaryShmemFile(&path)); if (!fd) { return Err(NS_ERROR_FAILURE); } if (HANDLE_EINTR(ftruncate(fileno(fd), aSize)) != 0) { return Err(NS_ERROR_FAILURE); } MOZ_TRY(mMem.init(FILEToFileDescriptor(fd), PR_PROT_READWRITE)); mPath.Assign(path.value().data(), path.value().length()); return Ok(); }
bool OpenItemViaShellNoZoneCheck(const FilePath& full_path) { SHELLEXECUTEINFO sei = { sizeof(sei) }; sei.fMask = SEE_MASK_NOZONECHECKS | SEE_MASK_FLAG_DDEWAIT; sei.nShow = SW_SHOWNORMAL; sei.lpVerb = NULL; sei.lpFile = full_path.value().c_str(); if(::ShellExecuteExW(&sei)) { return true; } LONG_PTR error = reinterpret_cast<LONG_PTR>(sei.hInstApp); if((error == SE_ERR_NOASSOC)) { return OpenItemWithExternalApp(full_path.value()); } return false; }
// Open an item via a shell execute command. Error code checking and casting // explanation: http://msdn2.microsoft.com/en-us/library/ms647732.aspx bool OpenItemViaShell(const FilePath& full_path) { HINSTANCE h = ::ShellExecuteW( NULL, NULL, full_path.value().c_str(), NULL, full_path.DirName().value().c_str(), SW_SHOWNORMAL); LONG_PTR error = reinterpret_cast<LONG_PTR>(h); if(error > 32) { return true; } if((error == SE_ERR_NOASSOC)) { return OpenItemWithExternalApp(full_path.value()); } return false; }
STDMETHODIMP SilverlightView::GetBaseUrl(BSTR* pbstrUrl) { if(pbstrUrl == NULL) { return E_POINTER; } FilePath path; PathService::Get(base::DIR_EXE, &path); std::wstring path_string = path.value(); path_string += L'\\'; // WLW NOTE: hack it. fix later. *pbstrUrl = SysAllocString(path_string.c_str()); return S_OK; }
// static int64 SysInfo::AmountOfFreeDiskSpace(const FilePath& path) { ULARGE_INTEGER available, total, free; if(!GetDiskFreeSpaceExW(path.value().c_str(), &available, &total, &free)) { return -1; } int64 rv = static_cast<int64>(available.QuadPart); if(rv < 0) { rv = kint64max; } return rv; }
uint32_t GeckoChildProcessHost::GetSupportedArchitecturesForProcessType(GeckoProcessType type) { #ifdef MOZ_WIDGET_COCOA if (type == GeckoProcessType_Plugin) { // Cache this, it shouldn't ever change. static uint32_t pluginContainerArchs = 0; if (pluginContainerArchs == 0) { FilePath exePath; GetPathToBinary(exePath); nsresult rv = GetArchitecturesForBinary(exePath.value().c_str(), &pluginContainerArchs); NS_ASSERTION(NS_SUCCEEDED(rv) && pluginContainerArchs != 0, "Getting architecture of plugin container failed!"); if (NS_FAILED(rv) || pluginContainerArchs == 0) { pluginContainerArchs = base::GetCurrentProcessArchitecture(); } } return pluginContainerArchs; } #endif return base::GetCurrentProcessArchitecture(); }
void CommandLine::AppendArgPath(const FilePath& path) { AppendArgNative(path.value()); }
void CommandLine::AppendSwitchPath(const std::string& switch_string, const FilePath& path) { AppendSwitchNative(switch_string, path.value()); }
void CommandLine::SetProgram(const FilePath& program) { //TrimWhitespace(program.value(), TRIM_ALL, &argv_[0]); argv_[0] = program.value(); base::trim(argv_[0]); }
bool GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExtraOpts, base::ProcessArchitecture arch) { // We rely on the fact that InitializeChannel() has already been processed // on the IO thread before this point is reached. if (!GetChannel()) { return false; } base::ProcessHandle process = 0; // send the child the PID so that it can open a ProcessHandle back to us. // probably don't want to do this in the long run char pidstring[32]; SprintfLiteral(pidstring,"%d", base::Process::Current().pid()); const char* const childProcessType = XRE_ChildProcessTypeToString(mProcessType); //-------------------------------------------------- #if defined(OS_POSIX) // For POSIX, we have to be extremely anal about *not* using // std::wstring in code compiled with Mozilla's -fshort-wchar // configuration, because chromium is compiled with -fno-short-wchar // and passing wstrings from one config to the other is unsafe. So // we split the logic here. #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_BSD) || defined(OS_SOLARIS) base::environment_map newEnvVars; ChildPrivileges privs = mPrivileges; if (privs == base::PRIVILEGES_DEFAULT || privs == base::PRIVILEGES_FILEREAD) { privs = DefaultChildPrivileges(); } #if defined(MOZ_WIDGET_GTK) if (mProcessType == GeckoProcessType_Content) { // disable IM module to avoid sandbox violation newEnvVars["GTK_IM_MODULE"] = "gtk-im-context-simple"; // Disable ATK accessibility code in content processes because it conflicts // with the sandbox, and we proxy that information through the main process // anyway. newEnvVars["NO_AT_BRIDGE"] = "1"; } #endif // XPCOM may not be initialized in some subprocesses. We don't want // to initialize XPCOM just for the directory service, especially // since LD_LIBRARY_PATH is already set correctly in subprocesses // (meaning that we don't need to set that up in the environment). if (ShouldHaveDirectoryService()) { MOZ_ASSERT(gGREBinPath); nsCString path; NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path); # if defined(OS_LINUX) || defined(OS_BSD) const char *ld_library_path = PR_GetEnv("LD_LIBRARY_PATH"); nsCString new_ld_lib_path(path.get()); # if (MOZ_WIDGET_GTK == 3) if (mProcessType == GeckoProcessType_Plugin) { new_ld_lib_path.Append("/gtk2:"); new_ld_lib_path.Append(path.get()); } #endif if (ld_library_path && *ld_library_path) { new_ld_lib_path.Append(':'); new_ld_lib_path.Append(ld_library_path); } newEnvVars["LD_LIBRARY_PATH"] = new_ld_lib_path.get(); # elif OS_MACOSX newEnvVars["DYLD_LIBRARY_PATH"] = path.get(); // XXX DYLD_INSERT_LIBRARIES should only be set when launching a plugin // process, and has no effect on other subprocesses (the hooks in // libplugin_child_interpose.dylib become noops). But currently it // gets set when launching any kind of subprocess. // // Trigger "dyld interposing" for the dylib that contains // plugin_child_interpose.mm. This allows us to hook OS calls in the // plugin process (ones that don't work correctly in a background // process). Don't break any other "dyld interposing" that has already // been set up by whatever may have launched the browser. const char* prevInterpose = PR_GetEnv("DYLD_INSERT_LIBRARIES"); nsCString interpose; if (prevInterpose && strlen(prevInterpose) > 0) { interpose.Assign(prevInterpose); interpose.Append(':'); } interpose.Append(path.get()); interpose.AppendLiteral("/libplugin_child_interpose.dylib"); newEnvVars["DYLD_INSERT_LIBRARIES"] = interpose.get(); # endif // OS_LINUX } #endif // OS_LINUX || OS_MACOSX FilePath exePath; BinaryPathType pathType = GetPathToBinary(exePath, mProcessType); #ifdef MOZ_WIDGET_GONK if (const char *ldPreloadPath = getenv("LD_PRELOAD")) { newEnvVars["LD_PRELOAD"] = ldPreloadPath; } #endif // MOZ_WIDGET_GONK #if defined(XP_LINUX) && defined(MOZ_SANDBOX) // Preload libmozsandbox.so so that sandbox-related interpositions // can be defined there instead of in the executable. // (This could be made conditional on intent to use sandboxing, but // it's harmless for non-sandboxed processes.) { nsAutoCString preload; // Prepend this, because people can and do preload libpthread. // (See bug 1222500.) preload.AssignLiteral("libmozsandbox.so"); if (const char* oldPreload = PR_GetEnv("LD_PRELOAD")) { // Doesn't matter if oldPreload is ""; extra separators are ignored. preload.Append(' '); preload.Append(oldPreload); } // Explicitly construct the std::string to make it clear that this // isn't retaining a pointer to the nsCString's buffer. newEnvVars["LD_PRELOAD"] = std::string(preload.get()); } #endif // remap the IPC socket fd to a well-known int, as the OS does for // STDOUT_FILENO, for example int srcChannelFd, dstChannelFd; channel().GetClientFileDescriptorMapping(&srcChannelFd, &dstChannelFd); mFileMap.push_back(std::pair<int,int>(srcChannelFd, dstChannelFd)); // no need for kProcessChannelID, the child process inherits the // other end of the socketpair() from us std::vector<std::string> childArgv; childArgv.push_back(exePath.value()); if (pathType == BinaryPathType::Self) { childArgv.push_back("-contentproc"); } childArgv.insert(childArgv.end(), aExtraOpts.begin(), aExtraOpts.end()); if (Omnijar::IsInitialized()) { // Make sure that child processes can find the omnijar // See XRE_InitCommandLine in nsAppRunner.cpp nsAutoCString path; nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE); if (file && NS_SUCCEEDED(file->GetNativePath(path))) { childArgv.push_back("-greomni"); childArgv.push_back(path.get()); } file = Omnijar::GetPath(Omnijar::APP); if (file && NS_SUCCEEDED(file->GetNativePath(path))) { childArgv.push_back("-appomni"); childArgv.push_back(path.get()); } } // Add the application directory path (-appdir path) AddAppDirToCommandLine(childArgv); childArgv.push_back(pidstring); #if defined(MOZ_CRASHREPORTER) # if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS) int childCrashFd, childCrashRemapFd; if (!CrashReporter::CreateNotificationPipeForChild( &childCrashFd, &childCrashRemapFd)) return false; if (0 <= childCrashFd) { mFileMap.push_back(std::pair<int,int>(childCrashFd, childCrashRemapFd)); // "true" == crash reporting enabled childArgv.push_back("true"); } else { // "false" == crash reporting disabled childArgv.push_back("false"); } # elif defined(MOZ_WIDGET_COCOA) childArgv.push_back(CrashReporter::GetChildNotificationPipe()); # endif // OS_LINUX || OS_BSD || OS_SOLARIS #endif #if defined(XP_LINUX) && defined(MOZ_SANDBOX) { int srcFd, dstFd; SandboxReporter::Singleton() ->GetClientFileDescriptorMapping(&srcFd, &dstFd); mFileMap.push_back(std::make_pair(srcFd, dstFd)); } #endif #ifdef MOZ_WIDGET_COCOA // Add a mach port to the command line so the child can communicate its // 'task_t' back to the parent. // // Put a random number into the channel name, so that a compromised renderer // can't pretend being the child that's forked off. std::string mach_connection_name = StringPrintf("org.mozilla.machname.%d", base::RandInt(0, std::numeric_limits<int>::max())); childArgv.push_back(mach_connection_name.c_str()); #endif childArgv.push_back(childProcessType); #if defined(MOZ_WIDGET_ANDROID) LaunchAndroidService(childProcessType, childArgv, mFileMap, &process); #else base::LaunchApp(childArgv, mFileMap, #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_BSD) || defined(OS_SOLARIS) newEnvVars, privs, #endif false, &process, arch); #endif // defined(MOZ_WIDGET_ANDROID) // We're in the parent and the child was launched. Close the child FD in the // parent as soon as possible, which will allow the parent to detect when the // child closes its FD (either due to normal exit or due to crash). GetChannel()->CloseClientFileDescriptor(); #ifdef MOZ_WIDGET_COCOA // Wait for the child process to send us its 'task_t' data. const int kTimeoutMs = 10000; MachReceiveMessage child_message; ReceivePort parent_recv_port(mach_connection_name.c_str()); kern_return_t err = parent_recv_port.WaitForMessage(&child_message, kTimeoutMs); if (err != KERN_SUCCESS) { std::string errString = StringPrintf("0x%x %s", err, mach_error_string(err)); CHROMIUM_LOG(ERROR) << "parent WaitForMessage() failed: " << errString; return false; } task_t child_task = child_message.GetTranslatedPort(0); if (child_task == MACH_PORT_NULL) { CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(0) failed."; return false; } if (child_message.GetTranslatedPort(1) == MACH_PORT_NULL) { CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(1) failed."; return false; } MachPortSender parent_sender(child_message.GetTranslatedPort(1)); if (child_message.GetTranslatedPort(2) == MACH_PORT_NULL) { CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(2) failed."; } auto* parent_recv_port_memory_ack = new MachPortSender(child_message.GetTranslatedPort(2)); if (child_message.GetTranslatedPort(3) == MACH_PORT_NULL) { CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(3) failed."; } auto* parent_send_port_memory = new MachPortSender(child_message.GetTranslatedPort(3)); MachSendMessage parent_message(/* id= */0); if (!parent_message.AddDescriptor(MachMsgPortDescriptor(bootstrap_port))) { CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << bootstrap_port << ") failed."; return false; } auto* parent_recv_port_memory = new ReceivePort(); if (!parent_message.AddDescriptor(MachMsgPortDescriptor(parent_recv_port_memory->GetPort()))) { CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << parent_recv_port_memory->GetPort() << ") failed."; return false; } auto* parent_send_port_memory_ack = new ReceivePort(); if (!parent_message.AddDescriptor(MachMsgPortDescriptor(parent_send_port_memory_ack->GetPort()))) { CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << parent_send_port_memory_ack->GetPort() << ") failed."; return false; } err = parent_sender.SendMessage(parent_message, kTimeoutMs); if (err != KERN_SUCCESS) { std::string errString = StringPrintf("0x%x %s", err, mach_error_string(err)); CHROMIUM_LOG(ERROR) << "parent SendMessage() failed: " << errString; return false; } SharedMemoryBasic::SetupMachMemory(process, parent_recv_port_memory, parent_recv_port_memory_ack, parent_send_port_memory, parent_send_port_memory_ack, false); #endif //-------------------------------------------------- #elif defined(OS_WIN) FilePath exePath; BinaryPathType pathType = GetPathToBinary(exePath, mProcessType); CommandLine cmdLine(exePath.ToWStringHack()); if (pathType == BinaryPathType::Self) { cmdLine.AppendLooseValue(UTF8ToWide("-contentproc")); } cmdLine.AppendSwitchWithValue(switches::kProcessChannelID, channel_id()); for (std::vector<std::string>::iterator it = aExtraOpts.begin(); it != aExtraOpts.end(); ++it) { cmdLine.AppendLooseValue(UTF8ToWide(*it)); } if (Omnijar::IsInitialized()) { // Make sure the child process can find the omnijar // See XRE_InitCommandLine in nsAppRunner.cpp nsAutoString path; nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE); if (file && NS_SUCCEEDED(file->GetPath(path))) { cmdLine.AppendLooseValue(UTF8ToWide("-greomni")); cmdLine.AppendLooseValue(path.get()); } file = Omnijar::GetPath(Omnijar::APP); if (file && NS_SUCCEEDED(file->GetPath(path))) { cmdLine.AppendLooseValue(UTF8ToWide("-appomni")); cmdLine.AppendLooseValue(path.get()); } } #if defined(XP_WIN) && defined(MOZ_SANDBOX) bool shouldSandboxCurrentProcess = false; // XXX: Bug 1124167: We should get rid of the process specific logic for // sandboxing in this class at some point. Unfortunately it will take a bit // of reorganizing so I don't think this patch is the right time. switch (mProcessType) { case GeckoProcessType_Content: #if defined(MOZ_CONTENT_SANDBOX) if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX")) { // For now we treat every failure as fatal in SetSecurityLevelForContentProcess // and just crash there right away. Should this change in the future then we // should also handle the error here. mSandboxBroker.SetSecurityLevelForContentProcess(mSandboxLevel, mPrivileges); shouldSandboxCurrentProcess = true; } #endif // MOZ_CONTENT_SANDBOX break; case GeckoProcessType_Plugin: if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_NPAPI_SANDBOX")) { bool ok = mSandboxBroker.SetSecurityLevelForPluginProcess(mSandboxLevel); if (!ok) { return false; } shouldSandboxCurrentProcess = true; } break; case GeckoProcessType_IPDLUnitTest: // XXX: We don't sandbox this process type yet break; case GeckoProcessType_GMPlugin: if (!PR_GetEnv("MOZ_DISABLE_GMP_SANDBOX")) { // The Widevine CDM on Windows can only load at USER_RESTRICTED, // not at USER_LOCKDOWN. So look in the command line arguments // to see if we're loading the path to the Widevine CDM, and if // so use sandbox level USER_RESTRICTED instead of USER_LOCKDOWN. bool isWidevine = std::any_of(aExtraOpts.begin(), aExtraOpts.end(), [](const std::string arg) { return arg.find("gmp-widevinecdm") != std::string::npos; }); auto level = isWidevine ? SandboxBroker::Restricted : SandboxBroker::LockDown; bool ok = mSandboxBroker.SetSecurityLevelForGMPlugin(level); if (!ok) { return false; } shouldSandboxCurrentProcess = true; } break; case GeckoProcessType_GPU: if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_GPU_SANDBOX")) { // For now we treat every failure as fatal in SetSecurityLevelForGPUProcess // and just crash there right away. Should this change in the future then we // should also handle the error here. mSandboxBroker.SetSecurityLevelForGPUProcess(mSandboxLevel); shouldSandboxCurrentProcess = true; } break; case GeckoProcessType_Default: default: MOZ_CRASH("Bad process type in GeckoChildProcessHost"); break; }; if (shouldSandboxCurrentProcess) { for (auto it = mAllowedFilesRead.begin(); it != mAllowedFilesRead.end(); ++it) { mSandboxBroker.AllowReadFile(it->c_str()); } for (auto it = mAllowedFilesReadWrite.begin(); it != mAllowedFilesReadWrite.end(); ++it) { mSandboxBroker.AllowReadWriteFile(it->c_str()); } for (auto it = mAllowedDirectories.begin(); it != mAllowedDirectories.end(); ++it) { mSandboxBroker.AllowDirectory(it->c_str()); } } #endif // XP_WIN && MOZ_SANDBOX // Add the application directory path (-appdir path) AddAppDirToCommandLine(cmdLine); // XXX Command line params past this point are expected to be at // the end of the command line string, and in a specific order. // See XRE_InitChildProcess in nsEmbedFunction. // Win app model id cmdLine.AppendLooseValue(mGroupId.get()); // Process id cmdLine.AppendLooseValue(UTF8ToWide(pidstring)); #if defined(MOZ_CRASHREPORTER) cmdLine.AppendLooseValue( UTF8ToWide(CrashReporter::GetChildNotificationPipe())); #endif // Process type cmdLine.AppendLooseValue(UTF8ToWide(childProcessType)); #if defined(XP_WIN) && defined(MOZ_SANDBOX) if (shouldSandboxCurrentProcess) { if (mSandboxBroker.LaunchApp(cmdLine.program().c_str(), cmdLine.command_line_string().c_str(), mEnableSandboxLogging, &process)) { EnvironmentLog("MOZ_PROCESS_LOG").print( "==> process %d launched child process %d (%S)\n", base::GetCurrentProcId(), base::GetProcId(process), cmdLine.command_line_string().c_str()); } } else #endif { base::LaunchApp(cmdLine, false, false, &process); #ifdef MOZ_SANDBOX // We need to be able to duplicate handles to some types of non-sandboxed // child processes. if (mProcessType == GeckoProcessType_Content || mProcessType == GeckoProcessType_GPU || mProcessType == GeckoProcessType_GMPlugin) { if (!mSandboxBroker.AddTargetPeer(process)) { NS_WARNING("Failed to add content process as target peer."); } } #endif } #else # error Sorry #endif if (!process) { return false; } // NB: on OS X, we block much longer than we need to in order to // reach this call, waiting for the child process's task_t. The // best way to fix that is to refactor this file, hard. #if defined(MOZ_WIDGET_COCOA) mChildTask = child_task; #endif if (!OpenPrivilegedHandle(base::GetProcId(process)) #ifdef XP_WIN // If we failed in opening the process handle, try harder by duplicating // one. && !::DuplicateHandle(::GetCurrentProcess(), process, ::GetCurrentProcess(), &mChildProcessHandle, PROCESS_DUP_HANDLE | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | SYNCHRONIZE, FALSE, 0) #endif ) { MOZ_CRASH("cannot open handle to child process"); } MonitorAutoLock lock(mMonitor); mProcessState = PROCESS_CREATED; lock.Notify(); return true; }
bool GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExtraOpts, base::ProcessArchitecture arch) { // We rely on the fact that InitializeChannel() has already been processed // on the IO thread before this point is reached. if (!GetChannel()) { return false; } base::ProcessHandle process; // send the child the PID so that it can open a ProcessHandle back to us. // probably don't want to do this in the long run char pidstring[32]; PR_snprintf(pidstring, sizeof(pidstring) - 1, "%ld", base::Process::Current().pid()); const char* const childProcessType = XRE_ChildProcessTypeToString(mProcessType); //-------------------------------------------------- #if defined(OS_POSIX) // For POSIX, we have to be extremely anal about *not* using // std::wstring in code compiled with Mozilla's -fshort-wchar // configuration, because chromium is compiled with -fno-short-wchar // and passing wstrings from one config to the other is unsafe. So // we split the logic here. #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_BSD) base::environment_map newEnvVars; ChildPrivileges privs = mPrivileges; if (privs == base::PRIVILEGES_DEFAULT) { privs = kLowRightsSubprocesses ? base::PRIVILEGES_UNPRIVILEGED : base::PRIVILEGES_INHERIT; } // XPCOM may not be initialized in some subprocesses. We don't want // to initialize XPCOM just for the directory service, especially // since LD_LIBRARY_PATH is already set correctly in subprocesses // (meaning that we don't need to set that up in the environment). if (ShouldHaveDirectoryService()) { nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID)); NS_ASSERTION(directoryService, "Expected XPCOM to be available"); if (directoryService) { nsCOMPtr<nsIFile> greDir; nsresult rv = directoryService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile), getter_AddRefs(greDir)); if (NS_SUCCEEDED(rv)) { nsCString path; greDir->GetNativePath(path); # if defined(OS_LINUX) || defined(OS_BSD) # if defined(MOZ_WIDGET_ANDROID) || defined(OS_BSD) path += "/lib"; # endif // MOZ_WIDGET_ANDROID const char *ld_library_path = PR_GetEnv("LD_LIBRARY_PATH"); nsCString new_ld_lib_path; if (ld_library_path && *ld_library_path) { new_ld_lib_path.Assign(path.get()); new_ld_lib_path.AppendLiteral(":"); new_ld_lib_path.Append(ld_library_path); newEnvVars["LD_LIBRARY_PATH"] = new_ld_lib_path.get(); } else { newEnvVars["LD_LIBRARY_PATH"] = path.get(); } # elif OS_MACOSX newEnvVars["DYLD_LIBRARY_PATH"] = path.get(); // XXX DYLD_INSERT_LIBRARIES should only be set when launching a plugin // process, and has no effect on other subprocesses (the hooks in // libplugin_child_interpose.dylib become noops). But currently it // gets set when launching any kind of subprocess. // // Trigger "dyld interposing" for the dylib that contains // plugin_child_interpose.mm. This allows us to hook OS calls in the // plugin process (ones that don't work correctly in a background // process). Don't break any other "dyld interposing" that has already // been set up by whatever may have launched the browser. const char* prevInterpose = PR_GetEnv("DYLD_INSERT_LIBRARIES"); nsCString interpose; if (prevInterpose) { interpose.Assign(prevInterpose); interpose.AppendLiteral(":"); } interpose.Append(path.get()); interpose.AppendLiteral("/libplugin_child_interpose.dylib"); newEnvVars["DYLD_INSERT_LIBRARIES"] = interpose.get(); # endif // OS_LINUX } } } #endif // OS_LINUX || OS_MACOSX FilePath exePath; GetPathToBinary(exePath); #ifdef MOZ_WIDGET_ANDROID // The java wrapper unpacks this for us but can't make it executable chmod(exePath.value().c_str(), 0700); int cacheCount = 0; const struct lib_cache_info * cache = getLibraryCache(); nsCString cacheStr; while (cache && cacheCount++ < MAX_LIB_CACHE_ENTRIES && strlen(cache->name)) { mFileMap.push_back(std::pair<int,int>(cache->fd, cache->fd)); cacheStr.Append(cache->name); cacheStr.AppendPrintf(":%d;", cache->fd); cache++; } // fill the last arg with something if there's no cache if (cacheStr.IsEmpty()) cacheStr.AppendLiteral("-"); #endif // MOZ_WIDGET_ANDROID #ifdef ANDROID // Remap the Android property workspace to a well-known int, // and update the environment to reflect the new value for the // child process. const char *apws = getenv("ANDROID_PROPERTY_WORKSPACE"); if (apws) { int fd = atoi(apws); mFileMap.push_back(std::pair<int, int>(fd, kMagicAndroidSystemPropFd)); char buf[32]; char *szptr = strchr(apws, ','); snprintf(buf, sizeof(buf), "%d%s", kMagicAndroidSystemPropFd, szptr); newEnvVars["ANDROID_PROPERTY_WORKSPACE"] = buf; } #endif // ANDROID #ifdef MOZ_WIDGET_GONK if (const char *ldPreloadPath = getenv("LD_PRELOAD")) { newEnvVars["LD_PRELOAD"] = ldPreloadPath; } #endif // MOZ_WIDGET_GONK // remap the IPC socket fd to a well-known int, as the OS does for // STDOUT_FILENO, for example int srcChannelFd, dstChannelFd; channel().GetClientFileDescriptorMapping(&srcChannelFd, &dstChannelFd); mFileMap.push_back(std::pair<int,int>(srcChannelFd, dstChannelFd)); // no need for kProcessChannelID, the child process inherits the // other end of the socketpair() from us std::vector<std::string> childArgv; childArgv.push_back(exePath.value()); childArgv.insert(childArgv.end(), aExtraOpts.begin(), aExtraOpts.end()); if (Omnijar::IsInitialized()) { // Make sure that child processes can find the omnijar // See XRE_InitCommandLine in nsAppRunner.cpp nsAutoCString path; nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE); if (file && NS_SUCCEEDED(file->GetNativePath(path))) { childArgv.push_back("-greomni"); childArgv.push_back(path.get()); } file = Omnijar::GetPath(Omnijar::APP); if (file && NS_SUCCEEDED(file->GetNativePath(path))) { childArgv.push_back("-appomni"); childArgv.push_back(path.get()); } } childArgv.push_back(pidstring); #if defined(MOZ_CRASHREPORTER) # if defined(OS_LINUX) || defined(OS_BSD) int childCrashFd, childCrashRemapFd; if (!CrashReporter::CreateNotificationPipeForChild( &childCrashFd, &childCrashRemapFd)) return false; if (0 <= childCrashFd) { mFileMap.push_back(std::pair<int,int>(childCrashFd, childCrashRemapFd)); // "true" == crash reporting enabled childArgv.push_back("true"); } else { // "false" == crash reporting disabled childArgv.push_back("false"); } # elif defined(MOZ_WIDGET_COCOA) childArgv.push_back(CrashReporter::GetChildNotificationPipe()); # endif // OS_LINUX #endif #ifdef MOZ_WIDGET_COCOA // Add a mach port to the command line so the child can communicate its // 'task_t' back to the parent. // // Put a random number into the channel name, so that a compromised renderer // can't pretend being the child that's forked off. std::string mach_connection_name = StringPrintf("org.mozilla.machname.%d", base::RandInt(0, std::numeric_limits<int>::max())); childArgv.push_back(mach_connection_name.c_str()); #endif childArgv.push_back(childProcessType); #ifdef MOZ_WIDGET_ANDROID childArgv.push_back(cacheStr.get()); #endif base::LaunchApp(childArgv, mFileMap, #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_BSD) newEnvVars, privs, #endif false, &process, arch); #ifdef MOZ_WIDGET_COCOA // Wait for the child process to send us its 'task_t' data. const int kTimeoutMs = 10000; MachReceiveMessage child_message; ReceivePort parent_recv_port(mach_connection_name.c_str()); kern_return_t err = parent_recv_port.WaitForMessage(&child_message, kTimeoutMs); if (err != KERN_SUCCESS) { std::string errString = StringPrintf("0x%x %s", err, mach_error_string(err)); LOG(ERROR) << "parent WaitForMessage() failed: " << errString; return false; } task_t child_task = child_message.GetTranslatedPort(0); if (child_task == MACH_PORT_NULL) { LOG(ERROR) << "parent GetTranslatedPort(0) failed."; return false; } if (child_message.GetTranslatedPort(1) == MACH_PORT_NULL) { LOG(ERROR) << "parent GetTranslatedPort(1) failed."; return false; } MachPortSender parent_sender(child_message.GetTranslatedPort(1)); MachSendMessage parent_message(/* id= */0); if (!parent_message.AddDescriptor(bootstrap_port)) { LOG(ERROR) << "parent AddDescriptor(" << bootstrap_port << ") failed."; return false; } err = parent_sender.SendMessage(parent_message, kTimeoutMs); if (err != KERN_SUCCESS) { std::string errString = StringPrintf("0x%x %s", err, mach_error_string(err)); LOG(ERROR) << "parent SendMessage() failed: " << errString; return false; } #endif //-------------------------------------------------- #elif defined(OS_WIN) FilePath exePath; GetPathToBinary(exePath); CommandLine cmdLine(exePath.ToWStringHack()); cmdLine.AppendSwitchWithValue(switches::kProcessChannelID, channel_id()); for (std::vector<std::string>::iterator it = aExtraOpts.begin(); it != aExtraOpts.end(); ++it) { cmdLine.AppendLooseValue(UTF8ToWide(*it)); } cmdLine.AppendLooseValue(std::wstring(mGroupId.get())); if (Omnijar::IsInitialized()) { // Make sure the child process can find the omnijar // See XRE_InitCommandLine in nsAppRunner.cpp nsAutoString path; nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE); if (file && NS_SUCCEEDED(file->GetPath(path))) { cmdLine.AppendLooseValue(UTF8ToWide("-greomni")); cmdLine.AppendLooseValue(path.get()); } file = Omnijar::GetPath(Omnijar::APP); if (file && NS_SUCCEEDED(file->GetPath(path))) { cmdLine.AppendLooseValue(UTF8ToWide("-appomni")); cmdLine.AppendLooseValue(path.get()); } } cmdLine.AppendLooseValue(UTF8ToWide(pidstring)); #if defined(MOZ_CRASHREPORTER) cmdLine.AppendLooseValue( UTF8ToWide(CrashReporter::GetChildNotificationPipe())); #endif cmdLine.AppendLooseValue(UTF8ToWide(childProcessType)); base::LaunchApp(cmdLine, false, false, &process); #else # error Sorry #endif if (!process) { MonitorAutoLock lock(mMonitor); mProcessState = PROCESS_ERROR; lock.Notify(); return false; } // NB: on OS X, we block much longer than we need to in order to // reach this call, waiting for the child process's task_t. The // best way to fix that is to refactor this file, hard. SetHandle(process); #if defined(MOZ_WIDGET_COCOA) mChildTask = child_task; #endif OpenPrivilegedHandle(base::GetProcId(process)); { MonitorAutoLock lock(mMonitor); mProcessState = PROCESS_CREATED; lock.Notify(); } return true; }
bool GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExtraOpts, base::ProcessArchitecture arch) { // We rely on the fact that InitializeChannel() has already been processed // on the IO thread before this point is reached. if (!GetChannel()) { return false; } base::ProcessHandle process = 0; // send the child the PID so that it can open a ProcessHandle back to us. // probably don't want to do this in the long run char pidstring[32]; PR_snprintf(pidstring, sizeof(pidstring) - 1, "%ld", base::Process::Current().pid()); const char* const childProcessType = XRE_ChildProcessTypeToString(mProcessType); //-------------------------------------------------- #if defined(OS_POSIX) // For POSIX, we have to be extremely anal about *not* using // std::wstring in code compiled with Mozilla's -fshort-wchar // configuration, because chromium is compiled with -fno-short-wchar // and passing wstrings from one config to the other is unsafe. So // we split the logic here. #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_BSD) base::environment_map newEnvVars; ChildPrivileges privs = mPrivileges; if (privs == base::PRIVILEGES_DEFAULT) { privs = DefaultChildPrivileges(); } // XPCOM may not be initialized in some subprocesses. We don't want // to initialize XPCOM just for the directory service, especially // since LD_LIBRARY_PATH is already set correctly in subprocesses // (meaning that we don't need to set that up in the environment). if (ShouldHaveDirectoryService()) { MOZ_ASSERT(gGREBinPath); nsCString path; NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path); # if defined(OS_LINUX) || defined(OS_BSD) # if defined(MOZ_WIDGET_ANDROID) path += "/lib"; # endif // MOZ_WIDGET_ANDROID const char *ld_library_path = PR_GetEnv("LD_LIBRARY_PATH"); nsCString new_ld_lib_path; if (ld_library_path && *ld_library_path) { new_ld_lib_path.Assign(path.get()); new_ld_lib_path.Append(':'); new_ld_lib_path.Append(ld_library_path); newEnvVars["LD_LIBRARY_PATH"] = new_ld_lib_path.get(); } else { newEnvVars["LD_LIBRARY_PATH"] = path.get(); } # if (MOZ_WIDGET_GTK == 3) if (mProcessType == GeckoProcessType_Plugin) { const char *ld_preload = PR_GetEnv("LD_PRELOAD"); nsCString new_ld_preload; new_ld_preload.Assign(path.get()); new_ld_preload.AppendLiteral("/" DLL_PREFIX "mozgtk2" DLL_SUFFIX); if (ld_preload && *ld_preload) { new_ld_preload.AppendLiteral(":"); new_ld_preload.Append(ld_preload); } newEnvVars["LD_PRELOAD"] = new_ld_preload.get(); } # endif // MOZ_WIDGET_GTK # elif OS_MACOSX newEnvVars["DYLD_LIBRARY_PATH"] = path.get(); // XXX DYLD_INSERT_LIBRARIES should only be set when launching a plugin // process, and has no effect on other subprocesses (the hooks in // libplugin_child_interpose.dylib become noops). But currently it // gets set when launching any kind of subprocess. // // Trigger "dyld interposing" for the dylib that contains // plugin_child_interpose.mm. This allows us to hook OS calls in the // plugin process (ones that don't work correctly in a background // process). Don't break any other "dyld interposing" that has already // been set up by whatever may have launched the browser. const char* prevInterpose = PR_GetEnv("DYLD_INSERT_LIBRARIES"); nsCString interpose; if (prevInterpose) { interpose.Assign(prevInterpose); interpose.Append(':'); } interpose.Append(path.get()); interpose.AppendLiteral("/libplugin_child_interpose.dylib"); newEnvVars["DYLD_INSERT_LIBRARIES"] = interpose.get(); # endif // OS_LINUX } #endif // OS_LINUX || OS_MACOSX FilePath exePath; GetPathToBinary(exePath); #ifdef MOZ_WIDGET_ANDROID // The java wrapper unpacks this for us but can't make it executable chmod(exePath.value().c_str(), 0700); #endif // MOZ_WIDGET_ANDROID #ifdef ANDROID // Remap the Android property workspace to a well-known int, // and update the environment to reflect the new value for the // child process. const char *apws = getenv("ANDROID_PROPERTY_WORKSPACE"); if (apws) { int fd = atoi(apws); mFileMap.push_back(std::pair<int, int>(fd, kMagicAndroidSystemPropFd)); char buf[32]; char *szptr = strchr(apws, ','); snprintf(buf, sizeof(buf), "%d%s", kMagicAndroidSystemPropFd, szptr); newEnvVars["ANDROID_PROPERTY_WORKSPACE"] = buf; } #endif // ANDROID #ifdef MOZ_WIDGET_GONK if (const char *ldPreloadPath = getenv("LD_PRELOAD")) { newEnvVars["LD_PRELOAD"] = ldPreloadPath; } #endif // MOZ_WIDGET_GONK // remap the IPC socket fd to a well-known int, as the OS does for // STDOUT_FILENO, for example int srcChannelFd, dstChannelFd; channel().GetClientFileDescriptorMapping(&srcChannelFd, &dstChannelFd); mFileMap.push_back(std::pair<int,int>(srcChannelFd, dstChannelFd)); // no need for kProcessChannelID, the child process inherits the // other end of the socketpair() from us std::vector<std::string> childArgv; childArgv.push_back(exePath.value()); childArgv.insert(childArgv.end(), aExtraOpts.begin(), aExtraOpts.end()); if (Omnijar::IsInitialized()) { // Make sure that child processes can find the omnijar // See XRE_InitCommandLine in nsAppRunner.cpp nsAutoCString path; nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE); if (file && NS_SUCCEEDED(file->GetNativePath(path))) { childArgv.push_back("-greomni"); childArgv.push_back(path.get()); } file = Omnijar::GetPath(Omnijar::APP); if (file && NS_SUCCEEDED(file->GetNativePath(path))) { childArgv.push_back("-appomni"); childArgv.push_back(path.get()); } } // Add the application directory path (-appdir path) AddAppDirToCommandLine(childArgv); childArgv.push_back(pidstring); #if defined(MOZ_CRASHREPORTER) # if defined(OS_LINUX) || defined(OS_BSD) int childCrashFd, childCrashRemapFd; if (!CrashReporter::CreateNotificationPipeForChild( &childCrashFd, &childCrashRemapFd)) return false; if (0 <= childCrashFd) { mFileMap.push_back(std::pair<int,int>(childCrashFd, childCrashRemapFd)); // "true" == crash reporting enabled childArgv.push_back("true"); } else { // "false" == crash reporting disabled childArgv.push_back("false"); } # elif defined(MOZ_WIDGET_COCOA) childArgv.push_back(CrashReporter::GetChildNotificationPipe()); # endif // OS_LINUX #endif #ifdef MOZ_WIDGET_COCOA // Add a mach port to the command line so the child can communicate its // 'task_t' back to the parent. // // Put a random number into the channel name, so that a compromised renderer // can't pretend being the child that's forked off. std::string mach_connection_name = StringPrintf("org.mozilla.machname.%d", base::RandInt(0, std::numeric_limits<int>::max())); childArgv.push_back(mach_connection_name.c_str()); #endif childArgv.push_back(childProcessType); base::LaunchApp(childArgv, mFileMap, #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_BSD) newEnvVars, privs, #endif false, &process, arch); // We're in the parent and the child was launched. Close the child FD in the // parent as soon as possible, which will allow the parent to detect when the // child closes its FD (either due to normal exit or due to crash). GetChannel()->CloseClientFileDescriptor(); #ifdef MOZ_WIDGET_COCOA // Wait for the child process to send us its 'task_t' data. const int kTimeoutMs = 10000; MachReceiveMessage child_message; ReceivePort parent_recv_port(mach_connection_name.c_str()); kern_return_t err = parent_recv_port.WaitForMessage(&child_message, kTimeoutMs); if (err != KERN_SUCCESS) { std::string errString = StringPrintf("0x%x %s", err, mach_error_string(err)); CHROMIUM_LOG(ERROR) << "parent WaitForMessage() failed: " << errString; return false; } task_t child_task = child_message.GetTranslatedPort(0); if (child_task == MACH_PORT_NULL) { CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(0) failed."; return false; } if (child_message.GetTranslatedPort(1) == MACH_PORT_NULL) { CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(1) failed."; return false; } MachPortSender parent_sender(child_message.GetTranslatedPort(1)); MachSendMessage parent_message(/* id= */0); if (!parent_message.AddDescriptor(MachMsgPortDescriptor(bootstrap_port))) { CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << bootstrap_port << ") failed."; return false; } err = parent_sender.SendMessage(parent_message, kTimeoutMs); if (err != KERN_SUCCESS) { std::string errString = StringPrintf("0x%x %s", err, mach_error_string(err)); CHROMIUM_LOG(ERROR) << "parent SendMessage() failed: " << errString; return false; } #endif //-------------------------------------------------- #elif defined(OS_WIN) FilePath exePath; GetPathToBinary(exePath); CommandLine cmdLine(exePath.ToWStringHack()); cmdLine.AppendSwitchWithValue(switches::kProcessChannelID, channel_id()); for (std::vector<std::string>::iterator it = aExtraOpts.begin(); it != aExtraOpts.end(); ++it) { cmdLine.AppendLooseValue(UTF8ToWide(*it)); } if (Omnijar::IsInitialized()) { // Make sure the child process can find the omnijar // See XRE_InitCommandLine in nsAppRunner.cpp nsAutoString path; nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE); if (file && NS_SUCCEEDED(file->GetPath(path))) { cmdLine.AppendLooseValue(UTF8ToWide("-greomni")); cmdLine.AppendLooseValue(path.get()); } file = Omnijar::GetPath(Omnijar::APP); if (file && NS_SUCCEEDED(file->GetPath(path))) { cmdLine.AppendLooseValue(UTF8ToWide("-appomni")); cmdLine.AppendLooseValue(path.get()); } } #if defined(XP_WIN) bool shouldSandboxCurrentProcess = false; switch (mProcessType) { case GeckoProcessType_Content: #if defined(MOZ_CONTENT_SANDBOX) if (!PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX")) { mSandboxBroker.SetSecurityLevelForContentProcess(); cmdLine.AppendLooseValue(UTF8ToWide("-sandbox")); shouldSandboxCurrentProcess = true; } #endif // MOZ_CONTENT_SANDBOX break; case GeckoProcessType_Plugin: // XXX: We don't sandbox this process type yet // mSandboxBroker.SetSecurityLevelForPluginProcess(); // cmdLine.AppendLooseValue(UTF8ToWide("-sandbox")); // shouldSandboxCurrentProcess = true; break; case GeckoProcessType_IPDLUnitTest: // XXX: We don't sandbox this process type yet // mSandboxBroker.SetSecurityLevelForIPDLUnitTestProcess(); // cmdLine.AppendLooseValue(UTF8ToWide("-sandbox")); // shouldSandboxCurrentProcess = true; break; case GeckoProcessType_GMPlugin: #ifdef MOZ_SANDBOX if (!PR_GetEnv("MOZ_DISABLE_GMP_SANDBOX")) { mSandboxBroker.SetSecurityLevelForGMPlugin(); cmdLine.AppendLooseValue(UTF8ToWide("-sandbox")); shouldSandboxCurrentProcess = true; } #endif break; case GeckoProcessType_Default: default: MOZ_CRASH("Bad process type in GeckoChildProcessHost"); break; }; if (shouldSandboxCurrentProcess) { for (auto it = mAllowedFilesRead.begin(); it != mAllowedFilesRead.end(); ++it) { mSandboxBroker.AllowReadFile(it->c_str()); } } #endif // XP_WIN // Add the application directory path (-appdir path) AddAppDirToCommandLine(cmdLine); // XXX Command line params past this point are expected to be at // the end of the command line string, and in a specific order. // See XRE_InitChildProcess in nsEmbedFunction. // Win app model id cmdLine.AppendLooseValue(mGroupId.get()); // Process id cmdLine.AppendLooseValue(UTF8ToWide(pidstring)); #if defined(MOZ_CRASHREPORTER) cmdLine.AppendLooseValue( UTF8ToWide(CrashReporter::GetChildNotificationPipe())); #endif // Process type cmdLine.AppendLooseValue(UTF8ToWide(childProcessType)); #if defined(XP_WIN) && defined(MOZ_SANDBOX) if (shouldSandboxCurrentProcess) { mSandboxBroker.LaunchApp(cmdLine.program().c_str(), cmdLine.command_line_string().c_str(), &process); } else #endif { base::LaunchApp(cmdLine, false, false, &process); } #else # error Sorry #endif if (!process) { MonitorAutoLock lock(mMonitor); mProcessState = PROCESS_ERROR; lock.Notify(); return false; } // NB: on OS X, we block much longer than we need to in order to // reach this call, waiting for the child process's task_t. The // best way to fix that is to refactor this file, hard. SetHandle(process); #if defined(MOZ_WIDGET_COCOA) mChildTask = child_task; #endif OpenPrivilegedHandle(base::GetProcId(process)); { MonitorAutoLock lock(mMonitor); mProcessState = PROCESS_CREATED; lock.Notify(); } return true; }
bool GeckoChildProcessHost::PerformAsyncLaunch(std::vector<std::string> aExtraOpts) { // FIXME/cjones: make this work from non-IO threads, too // We rely on the fact that InitializeChannel() has already been processed // on the IO thread before this point is reached. if (!GetChannel()) { return false; } base::ProcessHandle process; // send the child the PID so that it can open a ProcessHandle back to us. // probably don't want to do this in the long run char pidstring[32]; PR_snprintf(pidstring, sizeof(pidstring) - 1, "%ld", base::Process::Current().pid()); const char* const childProcessType = XRE_ChildProcessTypeToString(mProcessType); //-------------------------------------------------- #if defined(OS_POSIX) // For POSIX, we have to be extremely anal about *not* using // std::wstring in code compiled with Mozilla's -fshort-wchar // configuration, because chromium is compiled with -fno-short-wchar // and passing wstrings from one config to the other is unsafe. So // we split the logic here. FilePath exePath; #ifdef OS_LINUX base::environment_map newEnvVars; #endif nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID)); nsCOMPtr<nsIFile> greDir; nsresult rv = directoryService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile), getter_AddRefs(greDir)); if (NS_SUCCEEDED(rv)) { nsCString path; greDir->GetNativePath(path); exePath = FilePath(path.get()); #ifdef OS_LINUX newEnvVars["LD_LIBRARY_PATH"] = path.get(); #endif } else { exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]); exePath = exePath.DirName(); } exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_NAME); // remap the IPC socket fd to a well-known int, as the OS does for // STDOUT_FILENO, for example int srcChannelFd, dstChannelFd; channel().GetClientFileDescriptorMapping(&srcChannelFd, &dstChannelFd); mFileMap.push_back(std::pair<int,int>(srcChannelFd, dstChannelFd)); // no need for kProcessChannelID, the child process inherits the // other end of the socketpair() from us std::vector<std::string> childArgv; childArgv.push_back(exePath.value()); childArgv.insert(childArgv.end(), aExtraOpts.begin(), aExtraOpts.end()); childArgv.push_back(pidstring); childArgv.push_back(childProcessType); #if defined(MOZ_CRASHREPORTER) int childCrashFd, childCrashRemapFd; if (!CrashReporter::CreateNotificationPipeForChild( &childCrashFd, &childCrashRemapFd)) return false; if (0 <= childCrashFd) { mFileMap.push_back(std::pair<int,int>(childCrashFd, childCrashRemapFd)); // "true" == crash reporting enabled childArgv.push_back("true"); } else { // "false" == crash reporting disabled childArgv.push_back("false"); } #endif base::LaunchApp(childArgv, mFileMap, #ifdef OS_LINUX newEnvVars, #endif false, &process); //-------------------------------------------------- #elif defined(OS_WIN) FilePath exePath = FilePath::FromWStringHack(CommandLine::ForCurrentProcess()->program()); exePath = exePath.DirName(); exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_NAME); CommandLine cmdLine(exePath.ToWStringHack()); cmdLine.AppendSwitchWithValue(switches::kProcessChannelID, channel_id()); for (std::vector<std::string>::iterator it = aExtraOpts.begin(); it != aExtraOpts.end(); ++it) { cmdLine.AppendLooseValue(UTF8ToWide(*it)); } cmdLine.AppendLooseValue(UTF8ToWide(pidstring)); cmdLine.AppendLooseValue(UTF8ToWide(childProcessType)); #if defined(MOZ_CRASHREPORTER) cmdLine.AppendLooseValue( UTF8ToWide(CrashReporter::GetChildNotificationPipe())); #endif base::LaunchApp(cmdLine, false, false, &process); #else # error Sorry #endif if (!process) { return false; } SetHandle(process); return true; }
bool Root::init(FileString homeDirectory, FileString subprocessDirectory, unsigned int extra_argc, const char* extra_argv[] ) { new base::AtExitManager(); FilePath subprocess; // convert extra arguments in a more useful form std::vector< std::string > extra_args; if( extra_argc > 0 ) { for( unsigned int arg_idx = 0; arg_idx < extra_argc; ++arg_idx ) { const char* raw_arg = extra_argv[ arg_idx ]; assert( raw_arg ); extra_args.push_back( raw_arg ); } } { // From <base/command_line.h>: // Initialize the current process CommandLine singleton. On Windows, // ignores its arguments (we instead parse GetCommandLineW() // directly) because we don't trust the CRT's parsing of the command // line, but it still must be called to set up the command line. // This means that on windows, we have to call ::Init with whatever we feel // like (since this is the only way to create the static CommandLine instance), // and then we have manually call ParseFromString. // (InitFromArgv does not exist on OS_WIN!) #if defined(OS_WIN) FilePath module_dir; if (subprocessDirectory.size()) { module_dir = FilePath(subprocessDirectory.get<FilePath::StringType>()); } else { PathService::Get(base::DIR_MODULE, &module_dir); } #ifdef _DEBUG subprocess = module_dir.Append(L"berkelium_d.exe"); #else subprocess = module_dir.Append(L"berkelium.exe"); #endif std::wstring subprocess_str = L"berkelium --enable-webgl --browser-subprocess-path="; subprocess_str += L"\""; subprocess_str += subprocess.value(); subprocess_str += L"\""; // add extra arguments if any if( !extra_args.empty() ) { for( unsigned int arg_idx = 0, arg_count = extra_args.size(); arg_idx < arg_count; ++arg_idx ) { const std::string& str_arg = extra_args[ arg_idx ]; std::wstring wstr_arg( str_arg.begin(), str_arg.end() ); subprocess_str += L" " + wstr_arg; } } //std::wcout << "Berkelium subprocess_str : " << subprocess_str; CommandLine::Init(0, NULL); CommandLine::ForCurrentProcess()->ParseFromString(subprocess_str); #elif defined(OS_MACOSX) FilePath app_contents; PathService::Get(base::FILE_EXE, &app_contents); FilePath module_dir; if (subprocessDirectory.size()) { module_dir = FilePath(subprocessDirectory.get<FilePath::StringType>()); } else { module_dir = app_contents.DirName(); } subprocess = module_dir.Append("berkelium"); std::string subprocess_str = "--browser-subprocess-path="; subprocess_str += subprocess.value(); std::vector<const char*> argv; argv.push_back( "berkelium" ); argv.push_back( subprocess_str.c_str() ); argv.push_back( "--enable-webgl" ); for( std::vector<std::string>::iterator it = extra_args.begin(); it != extra_args.end(); ++it ) { argv.push_back( it->c_str() ); } //for( std::vector<const char*>::iterator it = argv.begin(); it != argv.end(); ++it ) // std::cout << "Berkelium arg : " << *it; CommandLine::Init( argv.size(), &argv[0] ); #elif defined(OS_POSIX) FilePath module_file; PathService::Get(base::FILE_EXE, &module_file); FilePath module_dir; if (subprocessDirectory.size()) { module_dir = FilePath(subprocessDirectory.get<FilePath::StringType>()); } else { module_dir = module_file.DirName(); } subprocess = module_dir.Append("berkelium"); std::string subprocess_str = "--browser-subprocess-path="; subprocess_str += subprocess.value(); std::vector<const char*> argv; argv.push_back( "berkelium" ); argv.push_back( subprocess_str.c_str() ); argv.push_back( "--enable-webgl" ); for( std::vector<std::string>::iterator it = extra_args.begin(); it != extra_args.end(); ++it ) { argv.push_back( it->c_str() ); } //for( std::vector<const char*>::iterator it = argv.begin(); it != argv.end(); ++it ) // std::cout << "Berkelium arg : " << *it; CommandLine::Init( argv.size(), &argv[0]) ; #endif } PathService::Override(base::FILE_EXE, subprocess); #if !defined(OS_WIN) /// Temporary SingletonLock fix: // Do not do this for child processes--they should only be initialized. // Children should never delete the lock. if (signal(SIGINT, handleINT) == SIG_IGN) { signal(SIGINT, SIG_IGN); } if (signal(SIGHUP, handleINT) == SIG_IGN) { signal(SIGHUP, SIG_IGN); } if (signal(SIGTERM, handleINT) == SIG_IGN) { signal(SIGTERM, SIG_IGN); } #endif chrome::RegisterPathProvider(); ui::RegisterPathProvider(); FilePath homedirpath; if (homeDirectory.data() && homeDirectory.length()) { FilePath homeDirectoryPath(homeDirectory.get<FilePath::StringType>()); PathService::Override(chrome::DIR_USER_DATA, homeDirectoryPath); PathService::Override(chrome::DIR_LOGS, homeDirectoryPath); #if defined(OS_POSIX) PathService::Override(base::DIR_CACHE, homeDirectoryPath); #endif } else { mTempProfileDir.reset(new ScopedTempDir()); if (mTempProfileDir->CreateUniqueTempDir()) { PathService::Override(chrome::DIR_USER_DATA, mTempProfileDir->path()); PathService::Override(chrome::DIR_LOGS, mTempProfileDir->path()); #if defined(OS_POSIX) PathService::Override(base::DIR_CACHE, mTempProfileDir->path()); #endif } } PathService::Get(chrome::DIR_USER_DATA,&homedirpath); bool SINGLE_PROCESS=false; #if defined(OS_MACOSX) base::mac::SetOverrideAppBundlePath(chrome::GetFrameworkBundlePath()); if (SINGLE_PROCESS) { InitWebCoreSystemInterface(); //CGColorSpaceCreateDeviceRGB(); } #endif // OS_MACOSX if (SINGLE_PROCESS) { RenderProcessHost::set_run_renderer_in_process(true); } mMessageLoop.reset(new MessageLoop(MessageLoop::TYPE_UI)); mSysMon.reset(new ui::SystemMonitor); mTimerMgr.reset(new HighResolutionTimerManager); mUIThread.reset(new BrowserThread(BrowserThread::UI, mMessageLoop.get())); mErrorHandler = 0; #if defined(OS_LINUX) if (!g_thread_supported ()) // the client application might have already setup glib { g_thread_init(NULL); // Glib type system initialization. Needed at least for gconf, // used in net/proxy/proxy_config_service_linux.cc. Most likely // this is superfluous as gtk_init() ought to do this. It's // definitely harmless, so retained as a reminder of this // requirement for gconf. g_type_init(); // gtk_init() can change |argc| and |argv|. char argv0data[] = "[Berkelium]"; char *argv0 = argv0data; char **argv = &argv0; int argc = 1; gtk_init(&argc, &argv); } SetUpGLibLogHandler(); #endif mProcessSingleton.reset(new ProcessSingleton(homedirpath)); BrowserProcessImpl *browser_process; browser_process=new BrowserProcessImpl(*CommandLine::ForCurrentProcess()); browser_process->local_state()->RegisterStringPref(prefs::kApplicationLocale, ""); browser_process->local_state()->RegisterBooleanPref(prefs::kMetricsReportingEnabled, false); assert(g_browser_process == browser_process); #ifdef OS_WIN logging::InitLogging( L"chrome.log", logging::LOG_NONE, logging::DONT_LOCK_LOG_FILE, logging::DELETE_OLD_LOG_FILE, logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS ); #else logging::InitLogging( "chrome.log", logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG, logging::DONT_LOCK_LOG_FILE, logging::DELETE_OLD_LOG_FILE, logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS ); #endif logging::InitChromeLogging( *CommandLine::ForCurrentProcess(), logging::DELETE_OLD_LOG_FILE); //APPEND_TO_OLD_LOG_FILE chrome::RegisterChromeSchemes(); // Required for "chrome-extension://" in InitExtensions #if defined(OS_LINUX) const char* sandbox_binary = NULL; struct stat st; // In Chromium branded builds, developers can set an environment variable to // use the development sandbox. See // http://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment if (stat("/proc/self/exe", &st) == 0 && st.st_uid == getuid()) sandbox_binary = getenv("CHROME_DEVEL_SANDBOX"); std::string sandbox_cmd; if (sandbox_binary && !CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoSandbox)) sandbox_cmd = sandbox_binary; // Tickle the sandbox host and zygote host so they fork now. RenderSandboxHostLinux* shost = RenderSandboxHostLinux::GetInstance(); shost->Init(sandbox_cmd); ZygoteHost* zhost = ZygoteHost::GetInstance(); zhost->Init(sandbox_cmd); // We want to be sure to init NSPR on the main thread. base::EnsureNSPRInit(); #endif // defined(OS_LINUX) SandboxInitWrapper sandbox_wrapper; #if defined(OS_WIN) // Get the interface pointer to the BrokerServices or TargetServices, // depending who we are. sandbox::SandboxInterfaceInfo sandbox_info = {0}; sandbox_info.broker_services = sandbox::BrokerServicesBase::GetInstance(); sandbox::InitBrokerServices(sandbox_info.broker_services); if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoSandbox)) { bool use_winsta = !CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableAltWinstation); // Precreate the desktop and window station used by the renderers. sandbox::TargetPolicy* policy = sandbox_info.broker_services->CreatePolicy(); sandbox::ResultCode result = policy->CreateAlternateDesktop(use_winsta); CHECK(sandbox::SBOX_ERROR_FAILED_TO_SWITCH_BACK_WINSTATION != result); policy->Release(); } sandbox_wrapper.SetServices(&sandbox_info); #endif sandbox_wrapper.InitializeSandbox(*CommandLine::ForCurrentProcess(), ""); bool icu_result = icu_util::Initialize(); CHECK(icu_result); mRenderViewHostFactory.reset(new MemoryRenderViewHostFactory); // mNotificationService=new NotificationService(); // ChildProcess* coreProcess=new ChildProcess; // coreProcess->set_main_thread(new ChildThread); g_browser_process->SetApplicationLocale("en-US"); ResourceBundle::InitSharedInstance("en-US");// FIXME: lookup locale // We only load the theme dll in the browser process. net::CookieMonster::EnableFileScheme(); browser_process->profile_manager(); browser_process->db_thread(); browser_process->file_thread(); browser_process->process_launcher_thread(); browser_process->cache_thread(); browser_process->io_thread(); // Initialize histogram synchronizer system. This is a singleton and is used // for posting tasks via NewRunnableMethod. Its deleted when it goes out of // scope. Even though NewRunnableMethod does AddRef and Release, the object // will not be deleted after the Task is executed. mHistogramSynchronizer= (new HistogramSynchronizer()); browser::RegisterLocalState(g_browser_process->local_state()); ProfileManager* profile_manager = browser_process->profile_manager(); homedirpath = homedirpath.Append(profile_manager->GetCurrentProfileDir()); { //std::cout << "Profile path: " << homedirpath.value() << std::endl; FilePath prefs_path (ProfileManager::GetProfilePrefsPath(homedirpath)); FILE *fp = file_util::OpenFile(prefs_path, "a"); file_util::CloseFile(fp); FilePath history_path (homedirpath); history_path = history_path.Append(chrome::kHistoryFilename); //std::cout << " Profile exists: " << ProfileManager::IsProfile(homedirpath) << std::endl; } mProf = profile_manager->GetProfile(homedirpath, false); if (!mProf) { mProcessSingleton.reset(); return false; } mProf->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled, false); mProf->GetPrefs()->RegisterStringPref(prefs::kSafeBrowsingClientKey, ""); mProf->GetPrefs()->RegisterStringPref(prefs::kSafeBrowsingWrappedKey, ""); mProf->InitExtensions(); PrefService* user_prefs = mProf->GetPrefs(); DCHECK(user_prefs); // browser_process->local_state()->SetString(prefs::kApplicationLocale,std::wstring()); mProcessSingleton->Create(); mDNSPrefetch.reset(new chrome_browser_net::PredictorInit( user_prefs, browser_process->local_state(), CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePreconnect))); BrowserURLHandler::InitURLHandlers(); // From chrome/browser/browser_main.cc // Register our global network handler for chrome:// and // chrome-extension:// URLs. ChromeURLDataManagerBackend::Register(); /* RegisterExtensionProtocols(); RegisterMetadataURLRequestHandler(); RegisterBlobURLRequestJobFactory(); RegisterFileSystemURLRequestJobFactory(); */ { FilePath plugindata = homedirpath.AppendASCII("plugin_"); if (!file_util::CreateDirectory(plugindata)) { return false; } PluginService::GetInstance()->SetChromePluginDataDir(plugindata); } PluginService::GetInstance()->LoadChromePlugins( g_browser_process->resource_dispatcher_host()); mDefaultRequestContext=mProf->GetRequestContext(); if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kRemoteDebuggingPort)) { std::string debugging_port_str = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kRemoteDebuggingPort); int64 debugging_port = -1; bool has_debugging_port = base::StringToInt64(debugging_port_str, &debugging_port); if (has_debugging_port && debugging_port > 0 && debugging_port < 65535) { devtools_http_handler_ = Berkelium::DevToolsHttpProtocolHandler::Start( "127.0.0.1", static_cast<int>(debugging_port), "" ); } } return true; }
void CommandLine::SetProgram(const FilePath& program) { TrimString(program.value(), L" \t", &argv_.front()); }
PlatformFile CreatePlatformFile(const FilePath& name, int flags, bool* created, PlatformFileError* error_code) { ThreadRestrictions::AssertIOAllowed(); DWORD disposition = 0; if(created) { *created = false; } if(flags & PLATFORM_FILE_OPEN) { disposition = OPEN_EXISTING; } if(flags & PLATFORM_FILE_CREATE) { DCHECK(!disposition); disposition = CREATE_NEW; } if(flags & PLATFORM_FILE_OPEN_ALWAYS) { DCHECK(!disposition); disposition = OPEN_ALWAYS; } if(flags & PLATFORM_FILE_CREATE_ALWAYS) { DCHECK(!disposition); disposition = CREATE_ALWAYS; } if(flags & PLATFORM_FILE_TRUNCATE) { DCHECK(!disposition); DCHECK(flags & PLATFORM_FILE_WRITE); disposition = TRUNCATE_EXISTING; } if(!disposition) { NOTREACHED(); return NULL; } DWORD access = (flags & PLATFORM_FILE_READ) ? GENERIC_READ : 0; if(flags & PLATFORM_FILE_WRITE) { access |= GENERIC_WRITE; } if(flags & PLATFORM_FILE_WRITE_ATTRIBUTES) { access |= FILE_WRITE_ATTRIBUTES; } DWORD sharing = (flags & PLATFORM_FILE_EXCLUSIVE_READ) ? 0 : FILE_SHARE_READ; if(!(flags & PLATFORM_FILE_EXCLUSIVE_WRITE)) { sharing |= FILE_SHARE_WRITE; } if(flags & PLATFORM_FILE_SHARE_DELETE) { sharing |= FILE_SHARE_DELETE; } DWORD create_flags = 0; if(flags & PLATFORM_FILE_ASYNC) { create_flags |= FILE_FLAG_OVERLAPPED; } if(flags & PLATFORM_FILE_TEMPORARY) { create_flags |= FILE_ATTRIBUTE_TEMPORARY; } if(flags & PLATFORM_FILE_HIDDEN) { create_flags |= FILE_ATTRIBUTE_HIDDEN; } if(flags & PLATFORM_FILE_DELETE_ON_CLOSE) { create_flags |= FILE_FLAG_DELETE_ON_CLOSE; } HANDLE file = CreateFile(name.value().c_str(), access, sharing, NULL, disposition, create_flags, NULL); if(created && (INVALID_HANDLE_VALUE != file)) { if(flags & (PLATFORM_FILE_OPEN_ALWAYS)) { *created = (ERROR_ALREADY_EXISTS != GetLastError()); } else if(flags & (PLATFORM_FILE_CREATE_ALWAYS|PLATFORM_FILE_CREATE)) { *created = true; } } if(error_code) { if(file != kInvalidPlatformFileValue) { *error_code = PLATFORM_FILE_OK; } else { DWORD last_error = GetLastError(); switch(last_error) { case ERROR_SHARING_VIOLATION: *error_code = PLATFORM_FILE_ERROR_IN_USE; break; case ERROR_FILE_EXISTS: *error_code = PLATFORM_FILE_ERROR_EXISTS; break; case ERROR_FILE_NOT_FOUND: *error_code = PLATFORM_FILE_ERROR_NOT_FOUND; break; case ERROR_ACCESS_DENIED: *error_code = PLATFORM_FILE_ERROR_ACCESS_DENIED; break; default: *error_code = PLATFORM_FILE_ERROR_FAILED; } } } return file; }
void CommandLine::SetProgram(const FilePath& program) { TrimWhitespace(program.value(), TRIM_ALL, &argv_[0]); }