// Common code for sandbox startup. static void SetCurrentProcessSandbox(UniquePtr<sandbox::bpf_dsl::Policy> aPolicy) { MOZ_ASSERT(gSandboxCrashFunc); // Note: PolicyCompiler borrows the policy and registry for its // lifetime, but does not take ownership of them. sandbox::bpf_dsl::PolicyCompiler compiler(aPolicy.get(), sandbox::Trap::Registry()); auto program = compiler.Compile(); if (SandboxInfo::Get().Test(SandboxInfo::kVerbose)) { sandbox::bpf_dsl::DumpBPF::PrintProgram(*program); } InstallSigSysHandler(); #ifdef MOZ_ASAN __sanitizer_sandbox_arguments asanArgs; asanArgs.coverage_sandboxed = 1; asanArgs.coverage_fd = -1; asanArgs.coverage_max_block_size = 0; __sanitizer_sandbox_on_notify(&asanArgs); #endif // The syscall takes a C-style array, so copy the vector into one. size_t programLen = program->size(); UniquePtr<sock_filter[]> flatProgram(new sock_filter[programLen]); for (auto i = program->begin(); i != program->end(); ++i) { flatProgram[i - program->begin()] = *i; } sock_fprog fprog; fprog.filter = flatProgram.get(); fprog.len = static_cast<unsigned short>(programLen); MOZ_RELEASE_ASSERT(static_cast<size_t>(fprog.len) == programLen); const SandboxInfo info = SandboxInfo::Get(); if (info.Test(SandboxInfo::kHasSeccompTSync)) { if (info.Test(SandboxInfo::kVerbose)) { SANDBOX_LOG_ERROR("using seccomp tsync"); } ApplySandboxWithTSync(&fprog); } else { if (info.Test(SandboxInfo::kVerbose)) { SANDBOX_LOG_ERROR("no tsync support; using signal broadcast"); } BroadcastSetThreadSandbox(&fprog); } MOZ_RELEASE_ASSERT(!gChrootHelper, "forgot to chroot"); }
/* static */ void SandboxInfo::SubmitTelemetry() { SandboxInfo sandboxInfo = Get(); if (sandboxInfo.Test(SandboxInfo::kHasSeccompBPF)) { Telemetry::Accumulate(Telemetry::SANDBOX_CAPABILITIES_SECCOMP_BPF, true); } if (sandboxInfo.Test(SandboxInfo::kHasSeccompTSync)) { Telemetry::Accumulate(Telemetry::SANDBOX_CAPABILITIES_SECCOMP_TSYNC, true); } if (sandboxInfo.Test(SandboxInfo::kHasPrivilegedUserNamespaces)) { Telemetry::Accumulate( Telemetry::SANDBOX_CAPABILITIES_USER_NAMESPACES_PRIVILEGED, true); } if (sandboxInfo.Test(SandboxInfo::kHasUserNamespaces)) { Telemetry::Accumulate( Telemetry::SANDBOX_CAPABILITIES_USER_NAMESPACES, true); } if (sandboxInfo.Test(SandboxInfo::kEnabledForContent)) { Telemetry::Accumulate( Telemetry::SANDBOX_CAPABILITIES_ENABLED_CONTENT, true); } if (sandboxInfo.Test(SandboxInfo::kEnabledForMedia)) { Telemetry::Accumulate( Telemetry::SANDBOX_CAPABILITIES_ENABLED_MEDIA, true); } }
void SandboxEarlyInit(GeckoProcessType aType, bool aIsNuwa) { // Bug 1168555: Nuwa isn't reliably single-threaded at this point; // it starts an IPC I/O thread and then shuts it down before calling // the plugin-container entry point, but that thread may not have // finished exiting. If/when any type of sandboxing is used for the // Nuwa process (e.g., unsharing the network namespace there instead // of for each content process, to save memory), this will need to be // changed by moving the SandboxEarlyInit call to an earlier point. if (aIsNuwa) { return; } MOZ_RELEASE_ASSERT(IsSingleThreaded()); const SandboxInfo info = SandboxInfo::Get(); // Which kinds of resource isolation (of those that need to be set // up at this point) can be used by this process? bool canChroot = false; bool canUnshareNet = false; bool canUnshareIPC = false; switch (aType) { case GeckoProcessType_Default: MOZ_ASSERT(false, "SandboxEarlyInit in parent process"); return; #ifdef MOZ_GMP_SANDBOX case GeckoProcessType_GMPlugin: if (!info.Test(SandboxInfo::kEnabledForMedia)) { break; } canUnshareNet = true; canUnshareIPC = true; // Need seccomp-bpf to intercept open(). canChroot = info.Test(SandboxInfo::kHasSeccompBPF); break; #endif // In the future, content processes will be able to use some of // these. default: // Other cases intentionally left blank. break; } // If there's nothing to do, then we're done. if (!canChroot && !canUnshareNet && !canUnshareIPC) { return; } { LinuxCapabilities existingCaps; if (existingCaps.GetCurrent() && existingCaps.AnyEffective()) { SANDBOX_LOG_ERROR("PLEASE DO NOT RUN THIS AS ROOT. Strange things may" " happen when capabilities are dropped."); } } // If capabilities can't be gained, then nothing can be done. if (!info.Test(SandboxInfo::kHasUserNamespaces)) { // Drop any existing capabilities; unsharing the user namespace // would implicitly drop them, so if we're running in a broken // configuration where that would matter (e.g., running as root // from a non-root-owned mode-0700 directory) this means it will // break the same way on all kernels and be easier to troubleshoot. LinuxCapabilities().SetCurrent(); return; } // The failure cases for the various unshares, and setting up the // chroot helper, don't strictly need to be fatal -- but they also // shouldn't fail on any reasonable system, so let's take the small // risk of breakage over the small risk of quietly providing less // security than we expect. (Unlike in SandboxInfo, this is in the // child process, so crashing here isn't as severe a response to the // unexpected.) if (!UnshareUserNamespace()) { SANDBOX_LOG_ERROR("unshare(CLONE_NEWUSER): %s", strerror(errno)); // If CanCreateUserNamespace (SandboxInfo.cpp) returns true, then // the unshare shouldn't have failed. MOZ_CRASH("unshare(CLONE_NEWUSER)"); } // No early returns after this point! We need to drop the // capabilities that were gained by unsharing the user namesapce. if (canUnshareIPC && syscall(__NR_unshare, CLONE_NEWIPC) != 0) { SANDBOX_LOG_ERROR("unshare(CLONE_NEWIPC): %s", strerror(errno)); MOZ_CRASH("unshare(CLONE_NEWIPC)"); } if (canUnshareNet && syscall(__NR_unshare, CLONE_NEWNET) != 0) { SANDBOX_LOG_ERROR("unshare(CLONE_NEWNET): %s", strerror(errno)); MOZ_CRASH("unshare(CLONE_NEWNET)"); } if (canChroot) { gChrootHelper = MakeUnique<SandboxChroot>(); if (!gChrootHelper->Prepare()) { SANDBOX_LOG_ERROR("failed to set up chroot helper"); MOZ_CRASH("SandboxChroot::Prepare"); } } if (!LinuxCapabilities().SetCurrent()) { SANDBOX_LOG_ERROR("dropping capabilities: %s", strerror(errno)); MOZ_CRASH("can't drop capabilities"); } }
nsresult nsSystemInfo::Init() { nsresult rv; static const struct { PRSysInfo cmd; const char* name; } items[] = { { PR_SI_SYSNAME, "name" }, { PR_SI_HOSTNAME, "host" }, { PR_SI_ARCHITECTURE, "arch" }, { PR_SI_RELEASE, "version" } }; for (uint32_t i = 0; i < (sizeof(items) / sizeof(items[0])); i++) { char buf[SYS_INFO_BUFFER_LENGTH]; if (PR_GetSystemInfo(items[i].cmd, buf, sizeof(buf)) == PR_SUCCESS) { rv = SetPropertyAsACString(NS_ConvertASCIItoUTF16(items[i].name), nsDependentCString(buf)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } else { NS_WARNING("PR_GetSystemInfo failed"); } } #if defined(XP_WIN) && defined(MOZ_METRO) // Create "hasWindowsTouchInterface" property. nsAutoString version; rv = GetPropertyAsAString(NS_LITERAL_STRING("version"), version); NS_ENSURE_SUCCESS(rv, rv); double versionDouble = version.ToDouble(&rv); NS_ENSURE_SUCCESS(rv, rv); rv = SetPropertyAsBool(NS_ConvertASCIItoUTF16("hasWindowsTouchInterface"), versionDouble >= 6.2); NS_ENSURE_SUCCESS(rv, rv); #else rv = SetPropertyAsBool(NS_ConvertASCIItoUTF16("hasWindowsTouchInterface"), false); NS_ENSURE_SUCCESS(rv, rv); #endif // Additional informations not available through PR_GetSystemInfo. SetInt32Property(NS_LITERAL_STRING("pagesize"), PR_GetPageSize()); SetInt32Property(NS_LITERAL_STRING("pageshift"), PR_GetPageShift()); SetInt32Property(NS_LITERAL_STRING("memmapalign"), PR_GetMemMapAlignment()); SetInt32Property(NS_LITERAL_STRING("cpucount"), PR_GetNumberOfProcessors()); SetUint64Property(NS_LITERAL_STRING("memsize"), PR_GetPhysicalMemorySize()); SetUint32Property(NS_LITERAL_STRING("umask"), nsSystemInfo::gUserUmask); for (uint32_t i = 0; i < ArrayLength(cpuPropItems); i++) { rv = SetPropertyAsBool(NS_ConvertASCIItoUTF16(cpuPropItems[i].name), cpuPropItems[i].propfun()); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } #ifdef XP_WIN BOOL isWow64; BOOL gotWow64Value = IsWow64Process(GetCurrentProcess(), &isWow64); NS_WARN_IF_FALSE(gotWow64Value, "IsWow64Process failed"); if (gotWow64Value) { rv = SetPropertyAsBool(NS_LITERAL_STRING("isWow64"), !!isWow64); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } if (NS_FAILED(GetProfileHDDInfo())) { // We might have been called before profile-do-change. We'll observe that // event so that we can fill this in later. nsCOMPtr<nsIObserverService> obsService = do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } rv = obsService->AddObserver(this, "profile-do-change", false); if (NS_FAILED(rv)) { return rv; } } nsAutoCString hddModel, hddRevision; if (NS_SUCCEEDED(GetHDDInfo(NS_GRE_DIR, hddModel, hddRevision))) { rv = SetPropertyAsACString(NS_LITERAL_STRING("binHDDModel"), hddModel); NS_ENSURE_SUCCESS(rv, rv); rv = SetPropertyAsACString(NS_LITERAL_STRING("binHDDRevision"), hddRevision); NS_ENSURE_SUCCESS(rv, rv); } if (NS_SUCCEEDED(GetHDDInfo(NS_WIN_WINDOWS_DIR, hddModel, hddRevision))) { rv = SetPropertyAsACString(NS_LITERAL_STRING("winHDDModel"), hddModel); NS_ENSURE_SUCCESS(rv, rv); rv = SetPropertyAsACString(NS_LITERAL_STRING("winHDDRevision"), hddRevision); NS_ENSURE_SUCCESS(rv, rv); } #endif #if defined(MOZ_WIDGET_GTK) // This must be done here because NSPR can only separate OS's when compiled, not libraries. char* gtkver = PR_smprintf("GTK %u.%u.%u", gtk_major_version, gtk_minor_version, gtk_micro_version); if (gtkver) { rv = SetPropertyAsACString(NS_LITERAL_STRING("secondaryLibrary"), nsDependentCString(gtkver)); PR_smprintf_free(gtkver); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } #endif #ifdef MOZ_WIDGET_ANDROID if (mozilla::AndroidBridge::Bridge()) { nsAutoString str; if (mozilla::AndroidBridge::Bridge()->GetStaticStringField( "android/os/Build", "MODEL", str)) { SetPropertyAsAString(NS_LITERAL_STRING("device"), str); } if (mozilla::AndroidBridge::Bridge()->GetStaticStringField( "android/os/Build", "MANUFACTURER", str)) { SetPropertyAsAString(NS_LITERAL_STRING("manufacturer"), str); } if (mozilla::AndroidBridge::Bridge()->GetStaticStringField( "android/os/Build$VERSION", "RELEASE", str)) { SetPropertyAsAString(NS_LITERAL_STRING("release_version"), str); } int32_t version; if (!mozilla::AndroidBridge::Bridge()->GetStaticIntField( "android/os/Build$VERSION", "SDK_INT", &version)) { version = 0; } android_sdk_version = version; if (version >= 8 && mozilla::AndroidBridge::Bridge()->GetStaticStringField( "android/os/Build", "HARDWARE", str)) { SetPropertyAsAString(NS_LITERAL_STRING("hardware"), str); } bool isTablet = mozilla::widget::android::GeckoAppShell::IsTablet(); SetPropertyAsBool(NS_LITERAL_STRING("tablet"), isTablet); // NSPR "version" is the kernel version. For Android we want the Android version. // Rename SDK version to version and put the kernel version into kernel_version. rv = GetPropertyAsAString(NS_LITERAL_STRING("version"), str); if (NS_SUCCEEDED(rv)) { SetPropertyAsAString(NS_LITERAL_STRING("kernel_version"), str); } SetPropertyAsInt32(NS_LITERAL_STRING("version"), android_sdk_version); } #endif #ifdef MOZ_WIDGET_GONK char sdk[PROP_VALUE_MAX]; if (__system_property_get("ro.build.version.sdk", sdk)) { android_sdk_version = atoi(sdk); SetPropertyAsInt32(NS_LITERAL_STRING("sdk_version"), android_sdk_version); SetPropertyAsACString(NS_LITERAL_STRING("secondaryLibrary"), nsPrintfCString("SDK %u", android_sdk_version)); } char characteristics[PROP_VALUE_MAX]; if (__system_property_get("ro.build.characteristics", characteristics)) { if (!strcmp(characteristics, "tablet")) { SetPropertyAsBool(NS_LITERAL_STRING("tablet"), true); } } nsAutoString str; rv = GetPropertyAsAString(NS_LITERAL_STRING("version"), str); if (NS_SUCCEEDED(rv)) { SetPropertyAsAString(NS_LITERAL_STRING("kernel_version"), str); } const nsAdoptingString& b2g_os_name = mozilla::Preferences::GetString("b2g.osName"); if (b2g_os_name) { SetPropertyAsAString(NS_LITERAL_STRING("name"), b2g_os_name); } const nsAdoptingString& b2g_version = mozilla::Preferences::GetString("b2g.version"); if (b2g_version) { SetPropertyAsAString(NS_LITERAL_STRING("version"), b2g_version); } #endif #if defined(XP_LINUX) && defined(MOZ_SANDBOX) SandboxInfo sandInfo = SandboxInfo::Get(); SetPropertyAsBool(NS_LITERAL_STRING("hasSeccompBPF"), sandInfo.Test(SandboxInfo::kHasSeccompBPF)); if (sandInfo.Test(SandboxInfo::kEnabledForContent)) { SetPropertyAsBool(NS_LITERAL_STRING("canSandboxContent"), sandInfo.CanSandboxContent()); } if (sandInfo.Test(SandboxInfo::kEnabledForMedia)) { SetPropertyAsBool(NS_LITERAL_STRING("canSandboxMedia"), sandInfo.CanSandboxMedia()); } #endif // XP_LINUX && MOZ_SANDBOX return NS_OK; }
void SandboxEarlyInit(GeckoProcessType aType) { const SandboxInfo info = SandboxInfo::Get(); if (info.Test(SandboxInfo::kUnexpectedThreads)) { return; } MOZ_RELEASE_ASSERT(IsSingleThreaded()); // Which kinds of resource isolation (of those that need to be set // up at this point) can be used by this process? bool canChroot = false; bool canUnshareNet = false; bool canUnshareIPC = false; switch (aType) { case GeckoProcessType_Default: MOZ_ASSERT(false, "SandboxEarlyInit in parent process"); return; #ifdef MOZ_GMP_SANDBOX case GeckoProcessType_GMPlugin: if (!info.Test(SandboxInfo::kEnabledForMedia)) { break; } canUnshareNet = true; canUnshareIPC = true; // Need seccomp-bpf to intercept open(). canChroot = info.Test(SandboxInfo::kHasSeccompBPF); break; #endif // In the future, content processes will be able to use some of // these. default: // Other cases intentionally left blank. break; } // If TSYNC is not supported, set up signal handler // used to enable seccomp on each thread. if (!info.Test(SandboxInfo::kHasSeccompTSync)) { gSeccompTsyncBroadcastSignum = FindFreeSignalNumber(); if (gSeccompTsyncBroadcastSignum == 0) { SANDBOX_LOG_ERROR("No available signal numbers!"); MOZ_CRASH(); } void (*oldHandler)(int); oldHandler = signal(gSeccompTsyncBroadcastSignum, SetThreadSandboxHandler); if (oldHandler != SIG_DFL) { // See the comment on FindFreeSignalNumber about race conditions. SANDBOX_LOG_ERROR("signal %d in use by handler %p!\n", gSeccompTsyncBroadcastSignum, oldHandler); MOZ_CRASH(); } } // If there's nothing to do, then we're done. if (!canChroot && !canUnshareNet && !canUnshareIPC) { return; } { LinuxCapabilities existingCaps; if (existingCaps.GetCurrent() && existingCaps.AnyEffective()) { SANDBOX_LOG_ERROR("PLEASE DO NOT RUN THIS AS ROOT. Strange things may" " happen when capabilities are dropped."); } } // If capabilities can't be gained, then nothing can be done. if (!info.Test(SandboxInfo::kHasUserNamespaces)) { // Drop any existing capabilities; unsharing the user namespace // would implicitly drop them, so if we're running in a broken // configuration where that would matter (e.g., running as root // from a non-root-owned mode-0700 directory) this means it will // break the same way on all kernels and be easier to troubleshoot. LinuxCapabilities().SetCurrent(); return; } // The failure cases for the various unshares, and setting up the // chroot helper, don't strictly need to be fatal -- but they also // shouldn't fail on any reasonable system, so let's take the small // risk of breakage over the small risk of quietly providing less // security than we expect. (Unlike in SandboxInfo, this is in the // child process, so crashing here isn't as severe a response to the // unexpected.) if (!UnshareUserNamespace()) { SANDBOX_LOG_ERROR("unshare(CLONE_NEWUSER): %s", strerror(errno)); // If CanCreateUserNamespace (SandboxInfo.cpp) returns true, then // the unshare shouldn't have failed. MOZ_CRASH("unshare(CLONE_NEWUSER)"); } // No early returns after this point! We need to drop the // capabilities that were gained by unsharing the user namesapce. if (canUnshareIPC && syscall(__NR_unshare, CLONE_NEWIPC) != 0) { SANDBOX_LOG_ERROR("unshare(CLONE_NEWIPC): %s", strerror(errno)); MOZ_CRASH("unshare(CLONE_NEWIPC)"); } if (canUnshareNet && syscall(__NR_unshare, CLONE_NEWNET) != 0) { SANDBOX_LOG_ERROR("unshare(CLONE_NEWNET): %s", strerror(errno)); MOZ_CRASH("unshare(CLONE_NEWNET)"); } if (canChroot) { gChrootHelper = MakeUnique<SandboxChroot>(); if (!gChrootHelper->Prepare()) { SANDBOX_LOG_ERROR("failed to set up chroot helper"); MOZ_CRASH("SandboxChroot::Prepare"); } } if (!LinuxCapabilities().SetCurrent()) { SANDBOX_LOG_ERROR("dropping capabilities: %s", strerror(errno)); MOZ_CRASH("can't drop capabilities"); } }
nsresult nsSystemInfo::Init() { nsresult rv; static const struct { PRSysInfo cmd; const char* name; } items[] = { { PR_SI_SYSNAME, "name" }, { PR_SI_HOSTNAME, "host" }, { PR_SI_ARCHITECTURE, "arch" }, { PR_SI_RELEASE, "version" } }; for (uint32_t i = 0; i < (sizeof(items) / sizeof(items[0])); i++) { char buf[SYS_INFO_BUFFER_LENGTH]; if (PR_GetSystemInfo(items[i].cmd, buf, sizeof(buf)) == PR_SUCCESS) { rv = SetPropertyAsACString(NS_ConvertASCIItoUTF16(items[i].name), nsDependentCString(buf)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } else { NS_WARNING("PR_GetSystemInfo failed"); } } rv = SetPropertyAsBool(NS_ConvertASCIItoUTF16("hasWindowsTouchInterface"), false); NS_ENSURE_SUCCESS(rv, rv); // Additional informations not available through PR_GetSystemInfo. SetInt32Property(NS_LITERAL_STRING("pagesize"), PR_GetPageSize()); SetInt32Property(NS_LITERAL_STRING("pageshift"), PR_GetPageShift()); SetInt32Property(NS_LITERAL_STRING("memmapalign"), PR_GetMemMapAlignment()); SetUint64Property(NS_LITERAL_STRING("memsize"), PR_GetPhysicalMemorySize()); SetUint32Property(NS_LITERAL_STRING("umask"), nsSystemInfo::gUserUmask); uint64_t virtualMem = 0; nsAutoCString cpuVendor; int cpuSpeed = -1; int cpuFamily = -1; int cpuModel = -1; int cpuStepping = -1; int logicalCPUs = -1; int physicalCPUs = -1; int cacheSizeL2 = -1; int cacheSizeL3 = -1; #if defined (XP_WIN) // Virtual memory: MEMORYSTATUSEX memStat; memStat.dwLength = sizeof(memStat); if (GlobalMemoryStatusEx(&memStat)) { virtualMem = memStat.ullTotalVirtual; } // CPU speed HKEY key; static const WCHAR keyName[] = L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName , 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) { DWORD data, len, vtype; len = sizeof(data); if (RegQueryValueEx(key, L"~Mhz", 0, 0, reinterpret_cast<LPBYTE>(&data), &len) == ERROR_SUCCESS) { cpuSpeed = static_cast<int>(data); } // Limit to 64 double byte characters, should be plenty, but create // a buffer one larger as the result may not be null terminated. If // it is more than 64, we will not get the value. wchar_t cpuVendorStr[64+1]; len = sizeof(cpuVendorStr)-2; if (RegQueryValueExW(key, L"VendorIdentifier", 0, &vtype, reinterpret_cast<LPBYTE>(cpuVendorStr), &len) == ERROR_SUCCESS && vtype == REG_SZ && len % 2 == 0 && len > 1) { cpuVendorStr[len/2] = 0; // In case it isn't null terminated CopyUTF16toUTF8(nsDependentString(cpuVendorStr), cpuVendor); } RegCloseKey(key); } // Other CPU attributes: SYSTEM_INFO si; GetNativeSystemInfo(&si); logicalCPUs = si.dwNumberOfProcessors; GetProcessorInformation(&physicalCPUs, &cacheSizeL2, &cacheSizeL3); if (physicalCPUs <= 0) { physicalCPUs = logicalCPUs; } cpuFamily = si.wProcessorLevel; cpuModel = si.wProcessorRevision >> 8; cpuStepping = si.wProcessorRevision & 0xFF; #elif defined (XP_MACOSX) // CPU speed uint64_t sysctlValue64 = 0; uint32_t sysctlValue32 = 0; size_t len = 0; len = sizeof(sysctlValue64); if (!sysctlbyname("hw.cpufrequency_max", &sysctlValue64, &len, NULL, 0)) { cpuSpeed = static_cast<int>(sysctlValue64/1000000); } MOZ_ASSERT(sizeof(sysctlValue64) == len); len = sizeof(sysctlValue32); if (!sysctlbyname("hw.physicalcpu_max", &sysctlValue32, &len, NULL, 0)) { physicalCPUs = static_cast<int>(sysctlValue32); } MOZ_ASSERT(sizeof(sysctlValue32) == len); len = sizeof(sysctlValue32); if (!sysctlbyname("hw.logicalcpu_max", &sysctlValue32, &len, NULL, 0)) { logicalCPUs = static_cast<int>(sysctlValue32); } MOZ_ASSERT(sizeof(sysctlValue32) == len); len = sizeof(sysctlValue64); if (!sysctlbyname("hw.l2cachesize", &sysctlValue64, &len, NULL, 0)) { cacheSizeL2 = static_cast<int>(sysctlValue64/1024); } MOZ_ASSERT(sizeof(sysctlValue64) == len); len = sizeof(sysctlValue64); if (!sysctlbyname("hw.l3cachesize", &sysctlValue64, &len, NULL, 0)) { cacheSizeL3 = static_cast<int>(sysctlValue64/1024); } MOZ_ASSERT(sizeof(sysctlValue64) == len); if (!sysctlbyname("machdep.cpu.vendor", NULL, &len, NULL, 0)) { char* cpuVendorStr = new char[len]; if (!sysctlbyname("machdep.cpu.vendor", cpuVendorStr, &len, NULL, 0)) { cpuVendor = cpuVendorStr; } delete [] cpuVendorStr; } len = sizeof(sysctlValue32); if (!sysctlbyname("machdep.cpu.family", &sysctlValue32, &len, NULL, 0)) { cpuFamily = static_cast<int>(sysctlValue32); } MOZ_ASSERT(sizeof(sysctlValue32) == len); len = sizeof(sysctlValue32); if (!sysctlbyname("machdep.cpu.model", &sysctlValue32, &len, NULL, 0)) { cpuModel = static_cast<int>(sysctlValue32); } MOZ_ASSERT(sizeof(sysctlValue32) == len); len = sizeof(sysctlValue32); if (!sysctlbyname("machdep.cpu.stepping", &sysctlValue32, &len, NULL, 0)) { cpuStepping = static_cast<int>(sysctlValue32); } MOZ_ASSERT(sizeof(sysctlValue32) == len); #elif defined (MOZ_WIDGET_GTK) // Get vendor, family, model, stepping, physical cores, L3 cache size // from /proc/cpuinfo file { std::map<nsCString, nsCString> keyValuePairs; SimpleParseKeyValuePairs("/proc/cpuinfo", keyValuePairs); // cpuVendor from "vendor_id" cpuVendor.Assign(keyValuePairs[NS_LITERAL_CSTRING("vendor_id")]); { // cpuFamily from "cpu family" Tokenizer::Token t; Tokenizer p(keyValuePairs[NS_LITERAL_CSTRING("cpu family")]); if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER && t.AsInteger() <= INT32_MAX) { cpuFamily = static_cast<int>(t.AsInteger()); } } { // cpuModel from "model" Tokenizer::Token t; Tokenizer p(keyValuePairs[NS_LITERAL_CSTRING("model")]); if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER && t.AsInteger() <= INT32_MAX) { cpuModel = static_cast<int>(t.AsInteger()); } } { // cpuStepping from "stepping" Tokenizer::Token t; Tokenizer p(keyValuePairs[NS_LITERAL_CSTRING("stepping")]); if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER && t.AsInteger() <= INT32_MAX) { cpuStepping = static_cast<int>(t.AsInteger()); } } { // physicalCPUs from "cpu cores" Tokenizer::Token t; Tokenizer p(keyValuePairs[NS_LITERAL_CSTRING("cpu cores")]); if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER && t.AsInteger() <= INT32_MAX) { physicalCPUs = static_cast<int>(t.AsInteger()); } } { // cacheSizeL3 from "cache size" Tokenizer::Token t; Tokenizer p(keyValuePairs[NS_LITERAL_CSTRING("cache size")]); if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER && t.AsInteger() <= INT32_MAX) { cacheSizeL3 = static_cast<int>(t.AsInteger()); if (p.Next(t) && t.Type() == Tokenizer::TOKEN_WORD && t.AsString() != NS_LITERAL_CSTRING("KB")) { // If we get here, there was some text after the cache size value // and that text was not KB. For now, just don't report the // L3 cache. cacheSizeL3 = -1; } } } } { // Get cpuSpeed from another file. std::ifstream input("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq"); std::string line; if (getline(input, line)) { Tokenizer::Token t; Tokenizer p(line.c_str()); if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER && t.AsInteger() <= INT32_MAX) { cpuSpeed = static_cast<int>(t.AsInteger()/1000); } } } { // Get cacheSizeL2 from yet another file std::ifstream input("/sys/devices/system/cpu/cpu0/cache/index2/size"); std::string line; if (getline(input, line)) { Tokenizer::Token t; Tokenizer p(line.c_str(), nullptr, "K"); if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER && t.AsInteger() <= INT32_MAX) { cacheSizeL2 = static_cast<int>(t.AsInteger()); } } } SetInt32Property(NS_LITERAL_STRING("cpucount"), PR_GetNumberOfProcessors()); #else SetInt32Property(NS_LITERAL_STRING("cpucount"), PR_GetNumberOfProcessors()); #endif if (virtualMem) SetUint64Property(NS_LITERAL_STRING("virtualmemsize"), virtualMem); if (cpuSpeed >= 0) SetInt32Property(NS_LITERAL_STRING("cpuspeed"), cpuSpeed); if (!cpuVendor.IsEmpty()) SetPropertyAsACString(NS_LITERAL_STRING("cpuvendor"), cpuVendor); if (cpuFamily >= 0) SetInt32Property(NS_LITERAL_STRING("cpufamily"), cpuFamily); if (cpuModel >= 0) SetInt32Property(NS_LITERAL_STRING("cpumodel"), cpuModel); if (cpuStepping >= 0) SetInt32Property(NS_LITERAL_STRING("cpustepping"), cpuStepping); if (logicalCPUs >= 0) SetInt32Property(NS_LITERAL_STRING("cpucount"), logicalCPUs); if (physicalCPUs >= 0) SetInt32Property(NS_LITERAL_STRING("cpucores"), physicalCPUs); if (cacheSizeL2 >= 0) SetInt32Property(NS_LITERAL_STRING("cpucachel2"), cacheSizeL2); if (cacheSizeL3 >= 0) SetInt32Property(NS_LITERAL_STRING("cpucachel3"), cacheSizeL3); for (uint32_t i = 0; i < ArrayLength(cpuPropItems); i++) { rv = SetPropertyAsBool(NS_ConvertASCIItoUTF16(cpuPropItems[i].name), cpuPropItems[i].propfun()); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } #ifdef XP_WIN BOOL isWow64; BOOL gotWow64Value = IsWow64Process(GetCurrentProcess(), &isWow64); NS_WARN_IF_FALSE(gotWow64Value, "IsWow64Process failed"); if (gotWow64Value) { rv = SetPropertyAsBool(NS_LITERAL_STRING("isWow64"), !!isWow64); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } if (NS_FAILED(GetProfileHDDInfo())) { // We might have been called before profile-do-change. We'll observe that // event so that we can fill this in later. nsCOMPtr<nsIObserverService> obsService = do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } rv = obsService->AddObserver(this, "profile-do-change", false); if (NS_FAILED(rv)) { return rv; } } nsAutoCString hddModel, hddRevision; if (NS_SUCCEEDED(GetHDDInfo(NS_GRE_DIR, hddModel, hddRevision))) { rv = SetPropertyAsACString(NS_LITERAL_STRING("binHDDModel"), hddModel); NS_ENSURE_SUCCESS(rv, rv); rv = SetPropertyAsACString(NS_LITERAL_STRING("binHDDRevision"), hddRevision); NS_ENSURE_SUCCESS(rv, rv); } if (NS_SUCCEEDED(GetHDDInfo(NS_WIN_WINDOWS_DIR, hddModel, hddRevision))) { rv = SetPropertyAsACString(NS_LITERAL_STRING("winHDDModel"), hddModel); NS_ENSURE_SUCCESS(rv, rv); rv = SetPropertyAsACString(NS_LITERAL_STRING("winHDDRevision"), hddRevision); NS_ENSURE_SUCCESS(rv, rv); } nsAutoString countryCode; if (NS_SUCCEEDED(GetCountryCode(countryCode))) { rv = SetPropertyAsAString(NS_LITERAL_STRING("countryCode"), countryCode); NS_ENSURE_SUCCESS(rv, rv); } uint32_t installYear = 0; if (NS_SUCCEEDED(GetInstallYear(installYear))) { rv = SetPropertyAsUint32(NS_LITERAL_STRING("installYear"), installYear); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } #endif #if defined(XP_MACOSX) nsAutoString countryCode; if (NS_SUCCEEDED(GetSelectedCityInfo(countryCode))) { rv = SetPropertyAsAString(NS_LITERAL_STRING("countryCode"), countryCode); NS_ENSURE_SUCCESS(rv, rv); } #endif #if defined(MOZ_WIDGET_GTK) // This must be done here because NSPR can only separate OS's when compiled, not libraries. // 64 bytes is going to be well enough for "GTK " followed by 3 integers // separated with dots. char gtkver[64]; ssize_t gtkver_len = 0; #if MOZ_WIDGET_GTK == 2 extern int gtk_read_end_of_the_pipe; if (gtk_read_end_of_the_pipe != -1) { do { gtkver_len = read(gtk_read_end_of_the_pipe, >kver, sizeof(gtkver)); } while (gtkver_len < 0 && errno == EINTR); close(gtk_read_end_of_the_pipe); } #endif if (gtkver_len <= 0) { gtkver_len = snprintf(gtkver, sizeof(gtkver), "GTK %u.%u.%u", gtk_major_version, gtk_minor_version, gtk_micro_version); } nsAutoCString secondaryLibrary; if (gtkver_len > 0) { secondaryLibrary.Append(nsDependentCSubstring(gtkver, gtkver_len)); } void* libpulse = dlopen("libpulse.so.0", RTLD_LAZY); const char* libpulseVersion = "not-available"; if (libpulse) { auto pa_get_library_version = reinterpret_cast<const char* (*)()> (dlsym(libpulse, "pa_get_library_version")); if (pa_get_library_version) { libpulseVersion = pa_get_library_version(); } } secondaryLibrary.AppendPrintf(",libpulse %s", libpulseVersion); if (libpulse) { dlclose(libpulse); } rv = SetPropertyAsACString(NS_LITERAL_STRING("secondaryLibrary"), secondaryLibrary); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } #endif #ifdef MOZ_WIDGET_ANDROID AndroidSystemInfo info; if (XRE_IsContentProcess()) { dom::ContentChild* child = dom::ContentChild::GetSingleton(); if (child) { child->SendGetAndroidSystemInfo(&info); SetupAndroidInfo(info); } } else { GetAndroidSystemInfo(&info); SetupAndroidInfo(info); } #endif #ifdef MOZ_WIDGET_GONK char sdk[PROP_VALUE_MAX]; if (__system_property_get("ro.build.version.sdk", sdk)) { android_sdk_version = atoi(sdk); SetPropertyAsInt32(NS_LITERAL_STRING("sdk_version"), android_sdk_version); SetPropertyAsACString(NS_LITERAL_STRING("secondaryLibrary"), nsPrintfCString("SDK %u", android_sdk_version)); } char characteristics[PROP_VALUE_MAX]; if (__system_property_get("ro.build.characteristics", characteristics)) { if (!strcmp(characteristics, "tablet")) { SetPropertyAsBool(NS_LITERAL_STRING("tablet"), true); } else if (!strcmp(characteristics, "tv")) { SetPropertyAsBool(NS_LITERAL_STRING("tv"), true); } } nsAutoString str; rv = GetPropertyAsAString(NS_LITERAL_STRING("version"), str); if (NS_SUCCEEDED(rv)) { SetPropertyAsAString(NS_LITERAL_STRING("kernel_version"), str); } const nsAdoptingString& b2g_os_name = mozilla::Preferences::GetString("b2g.osName"); if (b2g_os_name) { SetPropertyAsAString(NS_LITERAL_STRING("name"), b2g_os_name); } const nsAdoptingString& b2g_version = mozilla::Preferences::GetString("b2g.version"); if (b2g_version) { SetPropertyAsAString(NS_LITERAL_STRING("version"), b2g_version); } #endif #if defined(XP_LINUX) && defined(MOZ_SANDBOX) SandboxInfo sandInfo = SandboxInfo::Get(); SetPropertyAsBool(NS_LITERAL_STRING("hasSeccompBPF"), sandInfo.Test(SandboxInfo::kHasSeccompBPF)); SetPropertyAsBool(NS_LITERAL_STRING("hasSeccompTSync"), sandInfo.Test(SandboxInfo::kHasSeccompTSync)); SetPropertyAsBool(NS_LITERAL_STRING("hasUserNamespaces"), sandInfo.Test(SandboxInfo::kHasUserNamespaces)); SetPropertyAsBool(NS_LITERAL_STRING("hasPrivilegedUserNamespaces"), sandInfo.Test(SandboxInfo::kHasPrivilegedUserNamespaces)); if (sandInfo.Test(SandboxInfo::kEnabledForContent)) { SetPropertyAsBool(NS_LITERAL_STRING("canSandboxContent"), sandInfo.CanSandboxContent()); } if (sandInfo.Test(SandboxInfo::kEnabledForMedia)) { SetPropertyAsBool(NS_LITERAL_STRING("canSandboxMedia"), sandInfo.CanSandboxMedia()); } #endif // XP_LINUX && MOZ_SANDBOX return NS_OK; }