Re: [Mingw-w64-public] [PATCH v2] crt: Add support for Control Flow Guard

2022-09-21 Thread Martin Storsjö

On Tue, 20 Sep 2022, Alvin Wong via Mingw-w64-public wrote:


This adds support to enable building mingw-w64-crt and user code with
Control Flow Guard using Clang, with the option `--enable-cfguard`. In
addition to adding the Clang 16 compiler option `-mguard=cf` to CFLAGS,
it also add two new objects to `libmingwex.a`:

- `mingw_cfguard_support.c` contains the guard check and dispatch
 function pointers and their backward compatible no-op.
- `mingw_cfguard_loadcfg.S` contains the definition of a load config
 directory structure with the symbol name `_load_config_used`.


By reading the paragraph above and this, I get the feeling that these are 
added to the library only if --enable-cfguard is set, but we settled on 
always including mingw_cfguard_support.c in any case, right? Is there a 
way to reword it to make this aspect clearer?


Other than that, I think this patch looks good - I didn't spot anything 
else I'd like to have changed. So if there's no objections from others, we 
can probably consider merging it soon!


// Martin



___
Mingw-w64-public mailing list
Mingw-w64-public@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public


[Mingw-w64-public] [PATCH v2] crt: Add support for Control Flow Guard

2022-09-20 Thread Alvin Wong via Mingw-w64-public
This adds support to enable building mingw-w64-crt and user code with
Control Flow Guard using Clang, with the option `--enable-cfguard`. In
addition to adding the Clang 16 compiler option `-mguard=cf` to CFLAGS,
it also add two new objects to `libmingwex.a`:

- `mingw_cfguard_support.c` contains the guard check and dispatch
  function pointers and their backward compatible no-op.
- `mingw_cfguard_loadcfg.S` contains the definition of a load config
  directory structure with the symbol name `_load_config_used`.

This change alone is not enough to fully enable CFGuard in user-built
binaries. All other libraries shipped with the toolchain will also need
to be built with `-mguard=cf` to include CFGuard checks. Same goes for
building user code. If the user builds and links an executable without
`-mguard=cf`, it will still run normally but without any of the CFGuard
checks being operational.

(An exception is the sanitizer libraries -- their API hooking mechanisms
may result in indirect calls that fails CFGuard checks.)

User code may use the function attribute `__declspec(guard(nocf))`
(supported by Clang 16) to stop CFGuard checks from being added to
indirect calls within one function.

===

CFGuard works by having the compiler insert a check before performing
any indirect calls (which terminates the process if the call target is
invalid). The compiler also has to keep track of all the address-taken
functions, which the linker will then use to assemble a
`GuardCFFunctionTable` to list all valid indirect call target addresses.

To maintain backward compatibile, the guard check function is referenced
via a function pointer which points to a no-op by default. On systems
supporting CFGuard, the image loader replaces the function pointer with
the address of the actual guard check function.

For this to work, the metadata is stored in the load config directory
struct. MSVC supplies this struct in vcruntime as a symbol with the name
`_load_config_used`, which the linker takes as the load config
directory. In addition, the linker generates synthetic symbols to be
included in the load config struct. This also works with LLD since it
has implemented this feature.

The load config directory can be inspected using `llvm-readobj
--coff-load-config file.exe` or `dumpbin.exe /loadconfig file.exe`
(dumpbin.exe is included in MSVC build tools.)

Further reading:
- Control Flow Guard: 
https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard
- Load config structure: 
https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#the-load-configuration-structure-image-only
- Control Flow Guard metadata: 
https://docs.microsoft.com/en-us/windows/win32/secbp/pe-metadata
- My personal notes on CFGuard: 
https://gist.github.com/alvinhochun/a65e4177e2b34d551d7ecb02b55a4b0a

Signed-off-by: Alvin Wong 
---
 mingw-w64-crt/Makefile.am |  10 +-
 mingw-w64-crt/cfguard/mingw_cfguard_loadcfg.S | 124 ++
 mingw-w64-crt/cfguard/mingw_cfguard_support.c |  58 
 mingw-w64-crt/configure.ac|  16 +++
 4 files changed, 207 insertions(+), 1 deletion(-)
 create mode 100644 mingw-w64-crt/cfguard/mingw_cfguard_loadcfg.S
 create mode 100644 mingw-w64-crt/cfguard/mingw_cfguard_support.c

diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am
index 23b1ab9f..c8a510c0 100644
--- a/mingw-w64-crt/Makefile.am
+++ b/mingw-w64-crt/Makefile.am
@@ -20,7 +20,7 @@ else
 endif
 
 AM_CPPFLAGS=$(sysincludes)
-AM_CFLAGS=-pipe -std=gnu99 -D_CRTBLD -D_WIN32_WINNT=0x0f00 
-D__MSVCRT_VERSION__=0x700 -D__USE_MINGW_ANSI_STDIO=0 @ADD_C_CXX_WARNING_FLAGS@ 
@ADD_C_ONLY_WARNING_FLAGS@
+AM_CFLAGS=-pipe -std=gnu99 -D_CRTBLD -D_WIN32_WINNT=0x0f00 
-D__MSVCRT_VERSION__=0x700 -D__USE_MINGW_ANSI_STDIO=0 @CFGUARD_CFLAGS@ 
@ADD_C_CXX_WARNING_FLAGS@ @ADD_C_ONLY_WARNING_FLAGS@
 AM_CXXFLAGS=@ADD_C_CXX_WARNING_FLAGS@ @ADD_CXX_ONLY_WARNING_FLAGS@
 CPPFLAGSARM32=-mfpu=vfpv3
 CPPFLAGS32=-m32
@@ -490,6 +490,8 @@ src_msvcr120_app=\
 
 # These mingwex sources are target independent:
 src_libmingwex=\
+  cfguard/mingw_cfguard_support.c \
+  \
   crt/dllentry.ccrt/dllmain.c \
   \
   complex/_cabs.ccomplex/cabs.c   complex/cabsf.c   complex/cabsl.c   
complex/cacos.c   complex/cacosf.c   \
@@ -582,6 +584,12 @@ src_libmingwex=\
   stdio/vscanf.c   stdio/vsnprintf.c stdio/vsnwprintf.c
stdio/vsscanf.c \
   stdio/vswscanf.c stdio/vwscanf.c   stdio/wtoll.c
stdio/mingw_asprintf.cstdio/mingw_vasprintf.c
 
+# Include the default load config struct only for Control Flow Guard support.
+if CFGUARD
+src_libmingwex+=\
+  cfguard/mingw_cfguard_loadcfg.S
+endif
+
 # these go into both 32 and 64 bit x86 versions:
 src_libmingwex_x86=\
   math/x86/_chgsignl.S  math/x86/acosf.c  math/x86/acosh.c 
 math/x86/acosl.c  math/x86/acosh.def.h  \
diff --git a/mingw-w64-crt/cfguard/mingw_cfguard_loadcfg.S