[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