[Bug 48417] All Wine 32-bit PE builtin dlls created by llvm-mingw use the same fixed imagebase, preventing non-relocatable native executables from being loaded (dynamicbase/ASLR should be default)

WineHQ Bugzilla wine-bugs at winehq.org
Sun Jan 5 07:29:43 CST 2020


https://bugs.winehq.org/show_bug.cgi?id=48417

Anastasius Focht <focht at gmx.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
            Summary|Wine 32-bit builtins in PE  |All Wine 32-bit PE builtin
                   |format occupy low address   |dlls created by llvm-mingw
                   |space range, preventing     |use the same fixed
                   |non-relocatable native      |imagebase, preventing
                   |executables from being      |non-relocatable native
                   |loaded                      |executables from being
                   |                            |loaded (dynamicbase/ASLR
                   |                            |should be default)

--- Comment #4 from Anastasius Focht <focht at gmx.net> ---
Hello Alexandre,

--- quote ---
Note that this is specific to llvm-mingw, standard mingw uses
--enable-auto-image-base by default. llvm-mingw should probably do the same.
--- quote ---

the distro MinGW-w64 (gcc) indeed has 'enable-auto-image-base' by default:

--- snip ---
$ i686-w64-mingw32-gcc -v
Using built-in specs.
COLLECT_GCC=/usr/bin/i686-w64-mingw32-gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/i686-w64-mingw32/7.3.0/lto-wrapper
Target: i686-w64-mingw32
Configured with: ../configure --prefix=/usr --bindir=/usr/bin
--includedir=/usr/include --mandir=/usr/share/man --infodir=/usr/share/info
--datadir=/usr/share --build=x86_64-redhat-linux-gnu
--host=x86_64-redhat-linux-gnu --with-gnu-as --with-gnu-ld --verbose
--without-newlib --disable-multilib --disable-plugin --with-system-zlib
--disable-nls --without-included-gettext --disable-win32-registry
--enable-languages=c,c++,objc,obj-c++,fortran
--with-bugurl=http://bugzilla.redhat.com/bugzilla --with-cloog
--enable-threads=posix --enable-libgomp --target=i686-w64-mingw32
--with-sysroot=/usr/i686-w64-mingw32/sys-root
--with-gxx-include-dir=/usr/i686-w64-mingw32/sys-root/mingw/include/c++
Thread model: posix
gcc version 7.3.0 20180125 (Fedora MinGW 7.3.0-1.fc28) (GCC) 

$ i686-w64-mingw32-gcc -dumpspecs | grep enable-auto-image-base
%{m64:-m i386pep} %{!m64:-m i386pe} %{mwindows:--subsystem windows}  
%{mconsole:--subsystem console}   %{shared: %{mdll: %eshared and mdll are not
compatible}}   %{shared: --shared} %{mdll:--dll}   %{static:-Bstatic}
%{!static:-Bdynamic}   %{shared|mdll: %{m64:-e DllMainCRTStartup} %{!m64:-e
_DllMainCRTStartup at 12} --enable-auto-image-base}   %(shared_libgcc_undefs)
--- snip ---

The problem: LLVM's LLD doesn't seem to support this ;-(

https://github.com/llvm/llvm-project/blob/master/lld/MinGW/Options.td#L92

--- snip ---
// Ignored options
def: Joined<["-"], "O">;
def: F<"build-id">;
def: F<"disable-auto-image-base">;
def: F<"enable-auto-image-base">;
def: F<"enable-auto-import">, HelpText<"Ignored; listed for libtool
compatibility">;
def: F<"end-group">;
def: Flag<["--"], "full-shutdown">;
def: F<"high-entropy-va">;
def: S<"major-image-version">;
def: S<"minor-image-version">;
def: F<"no-seh">;
def: F<"nxcompat">;
def: F<"pic-executable">;
...
--- snip ---

The closest functionality I could find is LLD option '--dynamicbase' which is
used for ASLR.

https://github.com/llvm/llvm-project/blob/b11386f9be9b2dc7276a758d64f66833da10bdea/lld/COFF/Writer.cpp#L1359

--- snip ---
  if (config->dynamicBase)
pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE;
--- snip ---

I've injected '-Wl,--dynamicbase' into 'CROSSLDFLAGS'.

--- snip ---
$ winedump $(winepath -u "c:\windows\syswow64\kernelbase.dll")
Contents of /home/focht/.wine/dosdevices/c:/windows/syswow64/kernelbase.dll:
1802240 bytes

*** This is a Wine builtin DLL ***

File Header
  Machine:                      014C (i386)
  Number of Sections:           13
  TimeDateStamp:                5E11DCBC (Sun Jan  5 13:55:24 2020) offset 128
  PointerToSymbolTable:         001B7E00
  NumberOfSymbols:              00000000
  SizeOfOptionalHeader:         00E0
  Characteristics:              2102
    EXECUTABLE_IMAGE
    32BIT_MACHINE
    DLL

Optional Header (32bit)
  Magic                              0x10B          267
  linker version                     14.00
  size of code                       0x46800        288768
  size of initialized data           0x171200       1511936
  size of uninitialized data         0x0            0
  entrypoint RVA                     0x20850        133200
  base of code                       0x1000         4096
  base of data                       0x0            0
  image base                         0x10000000     268435456
  section align                      0x1000         4096
  file align                         0x200          512
  required OS version                6.00
  image version                      0.00
  subsystem version                  6.00
  Win32 Version                      0x0            0
  size of image                      0x1c1000       1839104
  size of headers                    0x400          1024
  checksum                           0x0            0
  Subsystem                          0x2 (Windows GUI)
  DLL characteristics:               0x140
    DYNAMIC_BASE
    NX_COMPAT
  stack reserve size                 0x100000       1048576
  stack commit size                  0x1000         4096
  heap reserve size                  0x100000       1048576
  heap commit size                   0x1000         4096
  loader flags                       0x0            0
  RVAs & sizes                       0x10           16

Data Directory
  EXPORT       rva: 0x72468     size: 0xa8e3    
  IMPORT       rva: 0x7cd4b     size: 0x28      
  RESOURCE     rva: 0x0         size: 0x0       
  EXCEPTION    rva: 0x0         size: 0x0       
  SECURITY     rva: 0x0         size: 0x0       
  BASERELOC    rva: 0x85000     size: 0x4158    
  DEBUG        rva: 0x80000     size: 0x1c      
  ARCHITECTURE rva: 0x0         size: 0x0       
  GLOBALPTR    rva: 0x0         size: 0x0       
  TLS          rva: 0x0         size: 0x0       
  LOAD_CONFIG  rva: 0x0         size: 0x0       
  Bound IAT    rva: 0x0         size: 0x0       
  IAT          rva: 0x7d324     size: 0x5b0     
  Delay IAT    rva: 0x0         size: 0x0       
  CLR Header   rva: 0x0         size: 0x0       
               rva: 0x0         size: 0x0       

Done dumping /home/focht/.wine/dosdevices/c:/windows/syswow64/kernelbase.dll
--- snip ---

'DLL characteristics' -> 'DYNAMIC_BASE'

Dlls will still have the default image base set though:

https://github.com/llvm/llvm-project/blob/d3fec7fb456138c83b84e38ce785ea6bfa59c30b/lld/COFF/Driver.cpp#L599

--- snip ---
static uint64_t getDefaultImageBase() {
  if (config->is64())
    return config->dll ? 0x180000000 : 0x140000000;
  return config->dll ? 0x10000000 : 0x400000;
}
--- snip ---

https://github.com/llvm/llvm-project/blob/d3fec7fb456138c83b84e38ce785ea6bfa59c30b/lld/COFF/Driver.cpp#L1788

--- snip ---
  // Set default image base if /base is not given.
  if (config->imageBase == uint64_t(-1))
config->imageBase = getDefaultImageBase();
--- snip ---

The problem: ASLR isn't supported in Wine loader yet.

--- snip ---
$ grep -Hrn DYNAMIC_BASE

dlls/kernel32/tests/loader.c:462:    if
(!(nt_header->OptionalHeader.DllCharacteristics &
IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE))
dlls/kernel32/tests/loader.c:1123:   
nt_header.OptionalHeader.DllCharacteristics =
IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
dlls/kernel32/tests/loader.c:1297:       
nt64.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
dlls/kernel32/tests/loader.c:1408:       
nt32.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;

dlls/fusion/tests/asmcache.c:328:           
IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE |

tools/winedump/pe.c:218:    X(IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE,         
"DYNAMIC_BASE");

server/mapping.c:651:        if ((nt.opt.hdr32.DllCharacteristics &
IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) &&
server/mapping.c:691:        if ((nt.opt.hdr64.DllCharacteristics &
IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) &&

include/winnt.h:2986:#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE         
0x0040
--- snip ---

--- snip ---
$ grep -Hrni DynamicallyRelocated

dlls/kernel32/tests/loader.c:387:        (S(U(image)).ImageDynamicallyRelocated
&& LOWORD(image.TransferAddress) == LOWORD(entry_point)),
dlls/kernel32/tests/loader.c:463:        ok(
!S(U(image)).ImageDynamicallyRelocated || broken( S(U(image)).ComPlusILOnly ),
/* <= win7 */
dlls/kernel32/tests/loader.c:464:            "%u: wrong
ImageDynamicallyRelocated flags %02x\n", id, U(image).ImageFlags );
dlls/kernel32/tests/loader.c:466:        ok(
S(U(image)).ImageDynamicallyRelocated || broken(is_winxp),
dlls/kernel32/tests/loader.c:467:            "%u: wrong
ImageDynamicallyRelocated flags %02x\n", id, U(image).ImageFlags );
dlls/kernel32/tests/loader.c:469:        ok(
!S(U(image)).ImageDynamicallyRelocated || broken(TRUE), /* <= win8 */
dlls/kernel32/tests/loader.c:470:            "%u: wrong
ImageDynamicallyRelocated flags %02x\n", id, U(image).ImageFlags );

server/protocol.def:767:#define IMAGE_FLAGS_ImageDynamicallyRelocated 0x04

server/mapping.c:653:            mapping->image.image_flags |=
IMAGE_FLAGS_ImageDynamicallyRelocated;
server/mapping.c:693:            mapping->image.image_flags |=
IMAGE_FLAGS_ImageDynamicallyRelocated;

include/winternl.h:2028:          UCHAR ImageDynamicallyRelocated : 1;

include/wine/server_protocol.h:751:#define
IMAGE_FLAGS_ImageDynamicallyRelocated 0x04
--- snip ---

I'm not sure if upstream LLVM project is keen to implement
'enable-auto-image-base' since there is already 'dynamicbase'. Actually
'auto-image-base' would be contradictory when 'dynamicbase' is provided. Why
would the linker need to generate a random image load address when the OS
loader does a better job at runtime (has the knowledge of the address space
layout).

I think supporting ASLR in Wine loader is more preferable as it would bring the
PE binaries created with mingw cross-toolchain in line with what's produced by
Microsoft's toolchains by default ->
https://web.archive.org/web/20200105131452/https://devblogs.microsoft.com/cppblog/dynamicbase-and-nxcompat/

If upstream doesn't want 'auto-image-base' for above stated reasons, we could
make this bug report about defaulting to 'dynamicbase' in llvm-mingw (still
upstream?) and create another bug about supporting ASLR in Wine loader.

Regards

-- 
Do not reply to this email, post in Bugzilla using the
above URL to reply.
You are receiving this mail because:
You are watching all bug changes.



More information about the wine-bugs mailing list