summaryrefslogtreecommitdiffstats
path: root/build/win32
diff options
context:
space:
mode:
Diffstat (limited to 'build/win32')
-rw-r--r--build/win32/__init__.py0
-rw-r--r--build/win32/autowinchecksec.py85
-rw-r--r--build/win32/crashinject.cpp94
-rw-r--r--build/win32/crashinjectdll/crashinjectdll.cpp29
-rw-r--r--build/win32/crashinjectdll/crashinjectdll.def7
-rw-r--r--build/win32/crashinjectdll/moz.build16
-rw-r--r--build/win32/dummy_libs.py24
-rw-r--r--build/win32/moz.build32
-rw-r--r--build/win32/mozconfig.vs-latest3
-rw-r--r--build/win32/mozconfig.vs201910
-rw-r--r--build/win32/nsis-no-insert-timestamp.patch27
-rw-r--r--build/win32/nsis-no-underscore.patch34
-rw-r--r--build/win32/nsis-scons.patch23
13 files changed, 384 insertions, 0 deletions
diff --git a/build/win32/__init__.py b/build/win32/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/build/win32/__init__.py
diff --git a/build/win32/autowinchecksec.py b/build/win32/autowinchecksec.py
new file mode 100644
index 0000000000..1803d407e8
--- /dev/null
+++ b/build/win32/autowinchecksec.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# run the Winchecksec tool (https://github.com/trailofbits/winchecksec)
+# against a given Windows binary.
+
+import json
+import subprocess
+import sys
+
+import buildconfig
+
+# usage
+if len(sys.argv) != 2:
+ print("""usage : autowinchecksec.by path_to_binary""")
+ sys.exit(0)
+
+binary_path = sys.argv[1]
+
+# execute winchecksec against the binary, using the WINCHECKSEC environment
+# variable as the path to winchecksec.exe
+try:
+ winchecksec_path = buildconfig.substs["WINCHECKSEC"]
+except KeyError:
+ print(
+ "TEST-UNEXPECTED-FAIL | autowinchecksec.py | WINCHECKSEC environment variable is "
+ "not set, can't check DEP/ASLR etc. status."
+ )
+ sys.exit(1)
+
+wine = buildconfig.substs.get("WINE")
+if wine and winchecksec_path.lower().endswith(".exe"):
+ cmd = [wine, winchecksec_path]
+else:
+ cmd = [winchecksec_path]
+
+try:
+ result = subprocess.check_output(cmd + ["-j", binary_path], universal_newlines=True)
+
+except subprocess.CalledProcessError as e:
+ print(
+ "TEST-UNEXPECTED-FAIL | autowinchecksec.py | Winchecksec returned error code %d:\n%s"
+ % (e.returncode, e.output)
+ )
+ sys.exit(1)
+
+
+result = json.loads(result)
+
+checks = [
+ "aslr",
+ "cfg",
+ "dynamicBase",
+ "gs",
+ "isolation",
+ "nx",
+ "seh",
+]
+
+if buildconfig.substs["TARGET_CPU"] == "x86":
+ checks += [
+ "safeSEH",
+ ]
+else:
+ checks += [
+ "highEntropyVA",
+ ]
+
+failed = [c for c in checks if result.get(c) is False]
+
+if failed:
+ print(
+ "TEST-UNEXPECTED-FAIL | autowinchecksec.py | Winchecksec reported %d error(s) for %s"
+ % (len(failed), binary_path)
+ )
+ print(
+ "TEST-UNEXPECTED-FAIL | autowinchecksec.py | The following check(s) failed: %s"
+ % (", ".join(failed))
+ )
+ sys.exit(1)
+else:
+ print("TEST-PASS | autowinchecksec.py | %s succeeded" % binary_path)
diff --git a/build/win32/crashinject.cpp b/build/win32/crashinject.cpp
new file mode 100644
index 0000000000..076e5a12a2
--- /dev/null
+++ b/build/win32/crashinject.cpp
@@ -0,0 +1,94 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Given a PID, this program attempts to inject a DLL into the process
+ * with that PID. The DLL it attempts to inject, "crashinjectdll.dll",
+ * must exist alongside this exe. The DLL will then crash the process.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <windows.h>
+
+int main(int argc, char** argv) {
+ if (argc != 2) {
+ fprintf(stderr, "Usage: crashinject <PID>\n");
+ return 1;
+ }
+
+ int pid = atoi(argv[1]);
+ if (pid <= 0) {
+ fprintf(stderr, "Usage: crashinject <PID>\n");
+ return 1;
+ }
+
+ // find our DLL to inject
+ wchar_t filename[_MAX_PATH];
+ if (GetModuleFileNameW(nullptr, filename,
+ sizeof(filename) / sizeof(wchar_t)) == 0)
+ return 1;
+
+ wchar_t* slash = wcsrchr(filename, L'\\');
+ if (slash == nullptr) return 1;
+
+ slash++;
+ wcscpy(slash, L"crashinjectdll.dll");
+
+ // now find our target process
+ HANDLE targetProc =
+ OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE |
+ PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION,
+ FALSE, pid);
+ if (targetProc == nullptr) {
+ fprintf(stderr, "Error %lu opening target process\n", GetLastError());
+ return 1;
+ }
+
+ /*
+ * This is sort of insane, but we're implementing a technique described here:
+ * http://www.codeproject.com/KB/threads/winspy.aspx#section_2
+ *
+ * The gist is to use CreateRemoteThread to create a thread in the other
+ * process, but cheat and make the thread function kernel32!LoadLibrary,
+ * so that the only remote data we have to pass to the other process
+ * is the path to the library we want to load. The library we're loading
+ * will then do its dirty work inside the other process.
+ */
+ HMODULE hKernel32 = GetModuleHandleW(L"Kernel32");
+ // allocate some memory to hold the path in the remote process
+ void* pLibRemote = VirtualAllocEx(targetProc, nullptr, sizeof(filename),
+ MEM_COMMIT, PAGE_READWRITE);
+ if (pLibRemote == nullptr) {
+ fprintf(stderr, "Error %lu in VirtualAllocEx\n", GetLastError());
+ CloseHandle(targetProc);
+ return 1;
+ }
+
+ if (!WriteProcessMemory(targetProc, pLibRemote, (void*)filename,
+ sizeof(filename), nullptr)) {
+ fprintf(stderr, "Error %lu in WriteProcessMemory\n", GetLastError());
+ VirtualFreeEx(targetProc, pLibRemote, sizeof(filename), MEM_RELEASE);
+ CloseHandle(targetProc);
+ return 1;
+ }
+ // Now create a thread in the target process that will load our DLL
+ HANDLE hThread = CreateRemoteThread(
+ targetProc, nullptr, 0,
+ (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "LoadLibraryW"),
+ pLibRemote, 0, nullptr);
+ if (hThread == nullptr) {
+ fprintf(stderr, "Error %lu in CreateRemoteThread\n", GetLastError());
+ VirtualFreeEx(targetProc, pLibRemote, sizeof(filename), MEM_RELEASE);
+ CloseHandle(targetProc);
+ return 1;
+ }
+ WaitForSingleObject(hThread, INFINITE);
+ // Cleanup, not that it's going to matter at this point
+ CloseHandle(hThread);
+ VirtualFreeEx(targetProc, pLibRemote, sizeof(filename), MEM_RELEASE);
+ CloseHandle(targetProc);
+
+ return 0;
+}
diff --git a/build/win32/crashinjectdll/crashinjectdll.cpp b/build/win32/crashinjectdll/crashinjectdll.cpp
new file mode 100644
index 0000000000..7ee7e6812d
--- /dev/null
+++ b/build/win32/crashinjectdll/crashinjectdll.cpp
@@ -0,0 +1,29 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <stdio.h>
+#include <windows.h>
+
+// make sure we only ever spawn one thread
+DWORD tid = -1;
+
+DWORD WINAPI CrashingThread(LPVOID lpParameter) {
+ // not a very friendly DLL
+ volatile int* x = (int*)0x0;
+ *x = 1;
+ return 0;
+}
+
+BOOL WINAPI DllMain(HANDLE hinstDLL, DWORD dwReason, LPVOID lpvReserved) {
+ if (tid == (DWORD)-1)
+ // we have to crash on another thread because LoadLibrary() will
+ // catch memory access errors and return failure to the calling process
+ CreateThread(nullptr, // default security attributes
+ 0, // use default stack size
+ CrashingThread, // thread function name
+ nullptr, // argument to thread function
+ 0, // use default creation flags
+ &tid); // returns the thread identifier
+ return TRUE;
+}
diff --git a/build/win32/crashinjectdll/crashinjectdll.def b/build/win32/crashinjectdll/crashinjectdll.def
new file mode 100644
index 0000000000..d1ea5602da
--- /dev/null
+++ b/build/win32/crashinjectdll/crashinjectdll.def
@@ -0,0 +1,7 @@
+;+# This Source Code Form is subject to the terms of the Mozilla Public
+;+# License, v. 2.0. If a copy of the MPL was not distributed with this
+;+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+LIBRARY crashinjectdll
+EXPORTS
+ DllMain
diff --git a/build/win32/crashinjectdll/moz.build b/build/win32/crashinjectdll/moz.build
new file mode 100644
index 0000000000..ff113f61e6
--- /dev/null
+++ b/build/win32/crashinjectdll/moz.build
@@ -0,0 +1,16 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+SOURCES += [
+ "crashinjectdll.cpp",
+]
+
+SharedLibrary("crashinjectdll")
+
+DEFFILE = "crashinjectdll.def"
+
+USE_STATIC_LIBS = True
+NO_PGO = True
diff --git a/build/win32/dummy_libs.py b/build/win32/dummy_libs.py
new file mode 100644
index 0000000000..16947c6c84
--- /dev/null
+++ b/build/win32/dummy_libs.py
@@ -0,0 +1,24 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import os
+import subprocess
+
+from buildconfig import substs
+
+
+def main(output, *other_libs):
+ output.close()
+ # ar doesn't like it when the file exists beforehand.
+ os.unlink(output.name)
+ libs = [output.name]
+ parent = os.path.dirname(output.name)
+ libs.extend(os.path.join(parent, l) for l in other_libs)
+ for lib in libs:
+ result = subprocess.run(
+ [substs["AR"]] + [f.replace("$@", lib) for f in substs["AR_FLAGS"]]
+ )
+ if result.returncode != 0:
+ return result.returncode
+ return 0
diff --git a/build/win32/moz.build b/build/win32/moz.build
new file mode 100644
index 0000000000..d8d61a22db
--- /dev/null
+++ b/build/win32/moz.build
@@ -0,0 +1,32 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+TEST_DIRS += ["crashinjectdll"]
+
+if CONFIG["ENABLE_TESTS"]:
+ Program("crashinject")
+ SOURCES += [
+ "crashinject.cpp",
+ ]
+ USE_STATIC_LIBS = True
+
+NO_PGO = True
+
+# See comment about *-windows-gnu targets in config/makefiles/rust.mk
+if CONFIG["CC_TYPE"] == "clang":
+ GeneratedFile(
+ "libgcc.a",
+ "libgcc_eh.a",
+ "libpthread.a",
+ script="dummy_libs.py",
+ flags=["libgcc_eh.a", "libpthread.a"],
+ )
+
+
+if CONFIG["WIN32_REDIST_DIR"] and CONFIG["COMPILE_ENVIRONMENT"]:
+ for f in ["MSVC_C_RUNTIME_DLL", "MSVC_C_RUNTIME_1_DLL", "MSVC_CXX_RUNTIME_DLL"]:
+ if CONFIG[f]:
+ FINAL_TARGET_FILES += ["%%%s/%s" % (CONFIG["WIN32_REDIST_DIR"], CONFIG[f])]
diff --git a/build/win32/mozconfig.vs-latest b/build/win32/mozconfig.vs-latest
new file mode 100644
index 0000000000..1d5b73148d
--- /dev/null
+++ b/build/win32/mozconfig.vs-latest
@@ -0,0 +1,3 @@
+. $topsrcdir/build/win32/mozconfig.vs2019
+. "$topsrcdir/build/mozconfig.clang-cl"
+. "$topsrcdir/build/mozconfig.lld-link"
diff --git a/build/win32/mozconfig.vs2019 b/build/win32/mozconfig.vs2019
new file mode 100644
index 0000000000..5dc7574744
--- /dev/null
+++ b/build/win32/mozconfig.vs2019
@@ -0,0 +1,10 @@
+if [ -z "${VSPATH}" ]; then
+ VSPATH="$(cd ${MOZ_FETCHES_DIR} && pwd)/vs"
+fi
+
+if [ -d "${VSPATH}" ]; then
+ export WIN32_REDIST_DIR="${VSPATH}/VC/Redist/MSVC/14.29.30133/x86/Microsoft.VC142.CRT"
+ export WINSYSROOT="${VSPATH}"
+fi
+
+ac_add_options --target=i686-pc-windows-msvc
diff --git a/build/win32/nsis-no-insert-timestamp.patch b/build/win32/nsis-no-insert-timestamp.patch
new file mode 100644
index 0000000000..8053b820c6
--- /dev/null
+++ b/build/win32/nsis-no-insert-timestamp.patch
@@ -0,0 +1,27 @@
+diff -ur nsis-3.03-src/SCons/Config/gnu nsis-3.03-src.n/SCons/Config/gnu
+--- nsis-3.03-src/SCons/Config/gnu 2017-10-06 15:30:20.000000000 -0400
++++ nsis-3.03-src.n/SCons/Config/gnu 2018-06-17 13:26:05.945495151 -0400
+@@ -102,6 +102,7 @@
+ stub_env.Append(LINKFLAGS = ['$NODEFLIBS_FLAG']) # no standard libraries
+ stub_env.Append(LINKFLAGS = ['$ALIGN_FLAG']) # 512 bytes align
+ stub_env.Append(LINKFLAGS = ['$MAP_FLAG']) # generate map file
++stub_env.Append(LINKFLAGS = ['-Wl,--no-insert-timestamp']) # remove timestamps for reproducible builds
+
+ stub_uenv = stub_env.Clone()
+ stub_uenv.Append(CPPDEFINES = ['_UNICODE', 'UNICODE'])
+@@ -142,6 +143,7 @@
+ plugin_env.Append(LINKFLAGS = ['$MAP_FLAG']) # generate map file
+ plugin_env.Append(LINKFLAGS = ['-static-libgcc']) # remove libgcc*.dll dependency
+ plugin_env.Append(LINKFLAGS = ['-static-libstdc++']) # remove libstdc++*.dll dependency
++plugin_env.Append(LINKFLAGS = ['-Wl,--no-insert-timestamp']) # remove timestamps for reproducible builds
+
+ plugin_uenv = plugin_env.Clone()
+ plugin_uenv.Append(CPPDEFINES = ['_UNICODE', 'UNICODE'])
+@@ -181,6 +183,7 @@
+
+ util_env.Append(LINKFLAGS = ['-mwindows']) # build windows executables
+ util_env.Append(LINKFLAGS = ['$ALIGN_FLAG']) # 512 bytes align
++util_env.Append(LINKFLAGS = ['-Wl,--no-insert-timestamp']) # remove timestamps for reproducible builds
+
+
+ conf = FlagsConfigure(util_env)
diff --git a/build/win32/nsis-no-underscore.patch b/build/win32/nsis-no-underscore.patch
new file mode 100644
index 0000000000..79cff1d4b3
--- /dev/null
+++ b/build/win32/nsis-no-underscore.patch
@@ -0,0 +1,34 @@
+The `_` environment variable is a variable that is set by bash and some other
+shells to point to the executable they use when executing a command. That is,
+when executing `foo` from the command line, the shell sets `_` to
+`/usr/bin/foo` (assuming that's where foo is).
+
+However, nothing else does the same, so when e.g. a python program uses
+`subprocess.Popen` to run another program, it doesn't set `_`. Worse, if that
+python program itself was invoked from a shell, `_` would be set to e.g.
+`/usr/bin/python3`.
+
+So when nsis is invoked from a program that is not a shell, but the process
+ancestry has a process that was a shell, `_` may be set to the first
+intermediary program rather than nsis, which defeats nsis's assumption that `_`
+would contain the nsis path. Ironically, nsis also has more reliable fallbacks
+(using e.g. /proc/self/exe), but somehow prefers `_`.
+
+We remove the reliance of `_` entirely, for simplicity's sake.
+
+
+diff -ruN nsis-3.07-src.orig/Source/util.cpp nsis-3.07-src/Source/util.cpp
+--- nsis-3.07-src.orig/Source/util.cpp 2021-09-02 09:25:48.489016918 +0900
++++ nsis-3.07-src/Source/util.cpp 2021-09-02 09:26:21.158814484 +0900
+@@ -810,10 +810,7 @@
+ assert(rc == 0);
+ return tstring(CtoTString(temp_buf));
+ #else /* Linux/BSD/POSIX/etc */
+- const TCHAR *envpath = _tgetenv(_T("_"));
+- if (envpath)
+- return get_full_path(envpath);
+- else {
++ {
+ char *path = NULL, *pathtmp;
+ size_t len = 100;
+ int nchars;
diff --git a/build/win32/nsis-scons.patch b/build/win32/nsis-scons.patch
new file mode 100644
index 0000000000..d372ea99ea
--- /dev/null
+++ b/build/win32/nsis-scons.patch
@@ -0,0 +1,23 @@
+Patch from https://sourceforge.net/p/nsis/code/7291/
+
+diff -ruN nsis-3.07-src/Contrib/ExDLL/SConscript nsis-3.08-src/Contrib/ExDLL/SConscript
+--- nsis-3.07-src/Contrib/ExDLL/SConscript 2015-06-22 01:13:45.000000000 +0900
++++ nsis-3.08-src/Contrib/ExDLL/SConscript 2021-08-05 05:15:13.000000000 +0900
+@@ -47,7 +47,7 @@
+ env.DistributeExamples(api_files, path='Plugin/nsis')
+ env.DistributeExamples(example, path='Plugin')
+ if env['PLATFORM'] != 'win32':
+- if env.has_key('PREFIX_PLUGINAPI_INC'):
++ if 'PREFIX_PLUGINAPI_INC' in env:
+ env.Distribute(api_files, None, 'pluginapi_inc', '', 'nsis', 'pluginapi', 'pluginapi')
+
+
+@@ -56,7 +56,7 @@
+ else:
+ example += lib_files
+
+- if env.has_key('PREFIX_PLUGINAPI_LIB'):
++ if 'PREFIX_PLUGINAPI_LIB' in env:
+ env.Distribute(lib, None, 'pluginapi_lib', '', 'nsis', 'pluginapi', 'pluginapi')
+
+