diff -Nuar rebase-2.4.4-1-orig/Changes rebase-2.4.4-1/Changes --- rebase-2.4.4-1-orig/Changes 2005-07-28 09:29:49.000000000 -0400 +++ rebase-2.4.4-1/Changes 2009-02-27 16:13:32.156301300 -0500 @@ -1,5 +1,24 @@ $Id: Changes,v 1.3 2005/07/28 13:29:44 jt Exp $ + * New aslr utility allows to manipulate the following + flags in DLLs: + -a 1 --> Enable Address Space Layout Randomization + -a 0 --> Disable Address Space Layout Randomization + -n 1 --> Indicate that DLL is compatible with DEP (NX: no execute) + -n 0 --> Don't indicate compatibility with DEP + -t 1 --> Indicate that DLL is 'terminal-services aware' + -t 0 --> Don't indicate 'terminal-services' awareness + By default, cygwin DLLs have 0 for all three flags. Using + -n1/-t1 is untested, but -a1 may be useful on Windows Vista + and above. This is highly experimental; USE AT YOUR OWN RISK! + + Run the utility without any arguments to see the current + flag settings for a given DLL or list of DLLs. + +The following are the changes to rebaseall: + * Exclude cyglsa64.dll from rebase list + * Optionally run 'aslr -a 1' on each file after rebasing + 2.4: === The following are the changes to rebaseall: diff -Nuar rebase-2.4.4-1-orig/Makefile rebase-2.4.4-1/Makefile --- rebase-2.4.4-1-orig/Makefile 2008-06-07 16:40:49.000000000 -0400 +++ rebase-2.4.4-1/Makefile 2009-02-27 16:11:48.339101300 -0500 @@ -18,7 +18,7 @@ INSTALL = install CFLAGS = -O2 -I imagehelper -all: rebase +all: rebase aslr .PHONY: imagehelper @@ -30,12 +30,20 @@ -DLIB_VERSION='"$(LibVersion)"' \ -c -o $@ $< +aslr: aslr.o + $(CC) $(LDFLAGS) -o $@ aslr.o + +aslr.o: aslr.c Makefile + $(CC) $(CFLAGS) -DVERSION='"$(Version)"' \ + -c -o $@ $< + imagehelper: $(MAKE) -C imagehelper imagehelper install: all $(INSTALL) -d $(DESTDIR)$(BINDIR) $(INSTALL) -m 755 rebase $(DESTDIR)$(BINDIR) + $(INSTALL) -m 755 aslr $(DESTDIR)$(BINDIR) $(INSTALL) -m 755 rebaseall $(DESTDIR)$(BINDIR) $(INSTALL) -d $(DESTDIR)$(DOCDIR) $(INSTALL) -m 644 README $(DESTDIR)$(DOCDIR)/rebase-$(Version).README diff -Nuar rebase-2.4.4-1-orig/README rebase-2.4.4-1/README --- rebase-2.4.4-1-orig/README 2008-06-07 16:50:49.000000000 -0400 +++ rebase-2.4.4-1/README 2009-02-27 16:10:30.070501300 -0500 @@ -49,6 +49,30 @@ functionality will be added to Cygwin's setup.exe, so that rebasing will happen automatically. +On Vista and newer, it is possible to employ the Address Space Layout +Randomization facitility to help solve the image load address clashing +problem: + + Since Windows relies on relocations instead of position + independent code, a DLL must be loaded at the same address + in each process that uses it to allow the physical memory + used by the DLL to be shared. To facilitate this behaviour, + a global bitmap called _MiImageBitMap is used to represent + the address space from 0x50000000 to 0x78000000. The bitmap + is 0x2800 bits in length with each bit representing 64KB + of memory. As each DLL is loaded, its position is recorded + by setting the appropriate bits in the bitmap to mark the + memory where the DLL is being mapped. When the same DLL + is loaded in another process, its section object is reused + and it is mapped at the same virtual addresses. + http://taossa.com.nyud.net:8080/archive/bh08sotirovdowd.pdf + +Thus, IF all cygwin dlls (except cygwin1.dll) -- or, at least the +ones for which you often get the *** unable to remap *** error -- +are marked ASLR-compatible, then the Windows runtime loader can be +coerced into ensuring that the DLLs are loaded at the same memory +location for all concurrent processes. + Requirements: The following packages or later are required to build and/or execute @@ -81,10 +105,12 @@ The following is the rebaseall command line syntax: - rebaseall [-b BaseAddress] [-o Offset] [-T FileList | -] [-v] + rebaseall [-a] [-A AslrOpts] [-b BaseAddress] [-o Offset] [-T FileList | -] [-v] where: + -a => also run aslr utility on each DLL after rebasing + -A => specify explicit options for aslr (default: -a 1) -b => base address used by rebase (default: 0x70000000) -o => offset between each DLL rebased (default: 0x10000) -s => specify DLL suffix, use multiple if necessary (default: dll, so) @@ -104,6 +130,25 @@ -V => display version and exit -v => verbose (default: off) +The following is the aslr command line syntax: + + aslr [-a BOOL] [-n BOOL] [-t BOOL] [-Vv] [-T FileList | -] Files... + +where: + + -a => modify Address Space Layout Randomization flag + -n => modify NX Compatibility flag + -t => modify Terminal Server Aware flag + -T => specify filelist (or stdin) to list additional files + -V => display version and exit + -v => verbose (default: off) + + BOOL may be 0, false, no, f or n: explicitly marks the associated + facility disabled. BOOL may also be a non-zero integer, true, yes, + t, or y: explicitly marks the associated facility enabled. If aslr + is executed with none of -a/-n/-t, then it will simply display the + current status of those flags for each DLL. + Source: Cygwin rebase builds OOTB under Cygwin. With minor Makefile tweaking, @@ -131,6 +176,9 @@ 4. rebase skips read-only DLLs. +Issues #1, #2, and #4 also apply to the aslr utility. + + Homepage: The primary rebase web site is: diff -Nuar rebase-2.4.4-1-orig/aslr.c rebase-2.4.4-1/aslr.c --- rebase-2.4.4-1-orig/aslr.c 1969-12-31 19:00:00.000000000 -0500 +++ rebase-2.4.4-1/aslr.c 2009-02-27 15:26:30.379901300 -0500 @@ -0,0 +1,499 @@ +/* + * Copyright (c) 2009 Charles Wilson + * Based on rebase.c by Jason Tishler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifndef IMAGE_DLLCHARACTERISTICS_NX_COMPAT +#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100 +#endif + +BOOL do_mark (const char *pathname); +void parse_args (int argc, char *argv[]); +BOOL string_to_bool (const char *string, BOOL *value); +BOOL string_to_ulong (const char *string, unsigned long *value); +void usage (); +BOOL get_characteristics(const char *pathname, + BOOL* has_reloc_info, + WORD* pe_dll_characteristics); +BOOL set_characteristics(const char *pathname, + WORD pe_dll_characteristics); +const char * dll_chars_to_string (WORD pe_dll_characteristics, + WORD flag, + const char * pstr, + const char * nstr); +static BOOL pe_get16 (int fd, off_t offset, unsigned short* value); +static BOOL pe_get32 (int fd, off_t offset, unsigned long* value); +static BOOL pe_set16 (int fd, off_t offset, unsigned short value); +FILE *file_list_fopen (const char *file_list); +char *file_list_fgets (char *buf, int size, FILE *file); +int file_list_fclose (FILE *file); +void version (); + +int mark_aslr = 0; /* 0: do nothing; 1: mark; -1: unmark */ +int mark_nx = 0; /* 0: do nothing; 1: mark; -1: unmark */ +int mark_ts = 0; /* 0: do nothing; 1: mark; -1: unmark */ +int args_index = 0; +int verbose = 0; +const char *file_list = 0; +const char *stdin_file_list = "-"; + +int +main (int argc, char *argv[]) +{ + int i = 0; + + parse_args (argc, argv); + + /* Operate on files in file list, if specified. */ + if (file_list) + { + BOOL status = TRUE; + char filename[MAX_PATH + 2]; + FILE *file = file_list_fopen (file_list); + if (!file) + exit (2); + + while (file_list_fgets (filename, MAX_PATH + 2, file)) + { + status = do_mark (filename); + if (!status) + break; + } + + file_list_fclose (file); + if (!status) + exit (2); + } + + /* Operate on files listed as command line arguments. */ + for (i = args_index; i < argc; i++) + { + const char *filename = argv[i]; + BOOL status = do_mark (filename); + if (!status) + exit (2); + } + + exit (0); +} + +BOOL +do_mark (const char *pathname) +{ + BOOL mark_any = (mark_aslr != 0 || mark_nx != 0 || mark_ts != 0); + BOOL status, status2; + BOOL has_reloc_info; + WORD old_dll_characteristics; + WORD new_dll_characteristics; + + /* Skip if file does not exist */ + if (access (pathname, F_OK) == -1) + { + fprintf (stderr, "%s: skipped because nonexistent\n", pathname); + return TRUE; + } + + if (!mark_any) + { + /* Skip if not writable. */ + if (access (pathname, W_OK) == -1) + { + fprintf (stderr, "%s: skipped because not writable\n", pathname); + return TRUE; + } + } + + if (!get_characteristics (pathname, + &has_reloc_info, + &old_dll_characteristics)) + { + fprintf (stderr, + "%s: skipped because could not read file characteristics\n", + pathname); + return TRUE; + } + new_dll_characteristics = old_dll_characteristics; + + if (mark_any) + { + if (has_reloc_info) + { + if (mark_aslr > 0) + new_dll_characteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE; + else if (mark_aslr < 0) + new_dll_characteristics &= ~IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE; + + if (mark_nx > 0) + new_dll_characteristics |= IMAGE_DLLCHARACTERISTICS_NX_COMPAT; + else if (mark_nx < 0) + new_dll_characteristics &= ~IMAGE_DLLCHARACTERISTICS_NX_COMPAT; + + if (mark_ts > 0) + new_dll_characteristics |= IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE; + else if (mark_ts < 0) + new_dll_characteristics &= ~IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE; + + if (!set_characteristics (pathname, + new_dll_characteristics)) + { + fprintf (stderr, + "%s: could not update characteristics\n", + pathname); + return FALSE; + } + } + else + { + if (verbose) + fprintf (stderr, + "%s: skipped because does not contain relocation info\n", + pathname); + return TRUE; + } + } + + /* Display image characteristics. */ + if (verbose || !mark_any) + { + printf ("%s: old = 0x%04x %s%s%s, new = 0x%04x %s%s%s\n", pathname, + old_dll_characteristics, + dll_chars_to_string (old_dll_characteristics, + IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, + "[+aslr]","[-aslr]"), + dll_chars_to_string (old_dll_characteristics, + IMAGE_DLLCHARACTERISTICS_NX_COMPAT, + "[+nx]","[-nx]"), + dll_chars_to_string (old_dll_characteristics, + IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE, + "[+ts_aware]","[-ts_aware]"), + new_dll_characteristics, + dll_chars_to_string (new_dll_characteristics, + IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, + "[+aslr]","[-aslr]"), + dll_chars_to_string (new_dll_characteristics, + IMAGE_DLLCHARACTERISTICS_NX_COMPAT, + "[+nx]","[-nx]"), + dll_chars_to_string (new_dll_characteristics, + IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE, + "[+ts_aware]","[-ts_aware]")); + } + + return TRUE; +} + +const char * +dll_chars_to_string (WORD pe_dll_characteristics, + WORD flag, + const char * pstr, + const char * nstr) +{ + if ((pe_dll_characteristics & flag) == flag) + return pstr; + return nstr; +} +void +parse_args (int argc, char *argv[]) +{ + const char *anOptions = ":a:n:t:T:vV"; + int anOption = 0; + BOOL bool_value; + + for (anOption; (anOption = getopt (argc, argv, anOptions)) != -1;) + { + switch (anOption) + { + case 'a': + if (!string_to_bool (optarg, &bool_value)) + { + fprintf (stderr, "Invalid argument for -a: %s\n", optarg); + usage (); + exit (1); + } + mark_aslr = (bool_value ? 1 : -1); + break; + case 'n': + if (!string_to_bool (optarg, &bool_value)) + { + fprintf (stderr, "Invalid argument for -n: %s\n", optarg); + usage (); + exit (1); + } + mark_nx = (bool_value ? 1 : -1); + break; + case 't': + if (!string_to_bool (optarg, &bool_value)) + { + fprintf (stderr, "Invalid argument for -t: %s\n", optarg); + usage (); + exit (1); + } + mark_ts = (bool_value ? 1 : -1); + break; + case 'T': + file_list = optarg; + break; + case 'v': + verbose = TRUE; + break; + case 'V': + version (); + exit (1); + break; + default: + usage (); + exit (1); + break; + } + } + + args_index = optind; +} + +BOOL +string_to_bool (const char *string, BOOL *value) +{ + unsigned long number = 0; + if (!string || !*string) + return FALSE; + + if (!string_to_ulong (string, &number)) + { + size_t len = strlen (string); + if ( (len == 4 && strcasecmp (string, "true") == 0) + ||(len == 3 && strcasecmp (string, "yes") == 0) + ||(len == 1 && strcasecmp (string, "t") == 0) + ||(len == 1 && strcasecmp (string, "y") == 0)) + { + *value = TRUE; + } + else if ( (len == 5 && strcasecmp (string, "false") == 0) + ||(len == 2 && strcasecmp (string, "no") == 0) + ||(len == 1 && strcasecmp (string, "f") == 0) + ||(len == 1 && strcasecmp (string, "n") == 0)) + { + *value = FALSE; + } + else + { + return FALSE; + } + } + else + { + *value = (number != 0); + } + return TRUE; +} + +BOOL +string_to_ulong (const char *string, unsigned long *value) +{ + unsigned long number = 0; + char * endp; + errno = 0; + + /* null or empty input */ + if (!string || !*string) + return FALSE; + + number = strtoul (string, &endp, 0); + + /* out of range */ + if (ERANGE == errno) + return FALSE; + + /* no valid numeric input */ + if (endp == string) + return FALSE; + + /* non-numeric trailing characters */ + if (*endp != '\0') + return FALSE; + + *value = number; + return TRUE; +} + +void +usage () +{ + fprintf (stderr, + "usage: aslr [-a BOOL] [-n BOOL] [-t BOOL] [-Vv] " + "[-T FileList | -] Files...\n"); +} + +BOOL +get_characteristics(const char *pathname, + BOOL* has_reloc_info, + WORD* pe_dll_characteristics) +{ + unsigned long pe_header_offset, opthdr_ofs; + BOOL status = FALSE; + int fd, size; + DWORD pe_sig; + WORD pe_char; + + fd = open (pathname, O_RDONLY|O_BINARY); + if (fd == -1) + goto done; + + if (!pe_get32 (fd, 0x3c, &pe_header_offset)) + goto done; + opthdr_ofs = pe_header_offset + 4 + 20; + + pe_sig = 0; + if (!pe_get32 (fd, pe_header_offset, &pe_sig)) + goto done; + if (pe_sig != IMAGE_NT_SIGNATURE) + goto done; + + if (!pe_get16 (fd, pe_header_offset + 4 + 18, &pe_char)) + goto done; + + *has_reloc_info = ((pe_char & IMAGE_FILE_RELOCS_STRIPPED) == 0) + ? TRUE : FALSE; + + if (!pe_get16 (fd, opthdr_ofs + 70, pe_dll_characteristics)) + goto done; + + status = TRUE; + +done: + close (fd); + return status; +} + +BOOL +set_characteristics(const char *pathname, + WORD pe_dll_characteristics) +{ + unsigned long pe_header_offset, opthdr_ofs; + BOOL status = FALSE; + int fd, size; + + /* no extra checking of file's contents below, because + get_characteristics already did that */ + fd = open (pathname, O_RDWR|O_BINARY); + if (fd == -1) + goto done; + + if (!pe_get32 (fd, 0x3c, &pe_header_offset)) + goto done; + opthdr_ofs = pe_header_offset + 4 + 20; + + if (!pe_set16 (fd, opthdr_ofs + 70, pe_dll_characteristics)) + { + fprintf (stderr, + "CATASTROPIC ERROR: attempt to write to file failed! %s could be corrupted; HALTING.\n", + pathname); + close (fd); + exit(2); + } + + status = TRUE; + +done: + close (fd); + return status; + return TRUE; +} + +static BOOL +pe_get16 (int fd, off_t offset, unsigned short* value) +{ + unsigned char b[2]; + if (lseek (fd, offset, SEEK_SET) == -1) + return FALSE; + if (read (fd, b, 2) != 2) + return FALSE; + *value = b[0] + (b[1]<<8); + return TRUE; +} + +static BOOL +pe_get32 (int fd, off_t offset, unsigned long* value) +{ + unsigned char b[4]; + if (lseek (fd, offset, SEEK_SET) == -1) + return FALSE; + if (read (fd, b, 4) != 4) + return FALSE; + *value = b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); + return TRUE; +} + +static BOOL +pe_set16 (int fd, off_t offset, unsigned short value) +{ + unsigned char b[2]; + b[0] = (unsigned char) (value & 0x00ff); + b[1] = (unsigned char) ((value>>8) & 0x00ff); + if (lseek (fd, offset, SEEK_SET) == -1) + return FALSE; + if (write (fd, b, 2) != 2) + return FALSE; + return TRUE; +} + +FILE * +file_list_fopen (const char *file_list) +{ + FILE *file = stdin; + if (strcmp(file_list, stdin_file_list) != 0) + { + file = fopen (file_list, "r"); + if (!file) + fprintf (stderr, "cannot read %s\n", file_list); + } + return file; +} + +char * +file_list_fgets (char *buf, int size, FILE *file) +{ + char *status = fgets (buf, size, file); + if (status) + { + size_t length = strlen (buf); + if (buf[length - 1] == '\n') + buf[length - 1] = '\0'; + } + return status; +} + +int +file_list_fclose (FILE *file) +{ + int status = 0; + if (strcmp(file_list, stdin_file_list) != 0) + status = fclose (file); + return status; +} + +void +version () +{ + fprintf (stderr, "aslr version %s\n", VERSION); + fprintf (stderr, "Copyright (c) 2009 Charles Wilson\n"); +} diff -Nuar rebase-2.4.4-1-orig/rebaseall rebase-2.4.4-1/rebaseall --- rebase-2.4.4-1-orig/rebaseall 2008-06-07 17:48:36.000000000 -0400 +++ rebase-2.4.4-1/rebaseall 2009-02-27 16:16:57.305301300 -0500 @@ -19,17 +19,19 @@ # Define constants PATH=/bin ProgramName=`basename $0` -ProgramOptions='b:o:s:T:v' +ProgramOptions='aA:b:o:s:T:v' DefaultBaseAddress=0x70000000 DefaultOffset=0x10000 DefaultVerbose= DefaultFileList= DefaultSuffixes='dll|so' +DefaultAslrOpts="-a 1" +DefaultDoAslr= # Define functions usage() { - echo "usage: $ProgramName [-b BaseAddress] [-o Offset] [-s DllSuffix] [-T FileList | -] [-v]" + echo "usage: $ProgramName [-a] [-A aslr_opts] [-b BaseAddress] [-o Offset] [-s DllSuffix] [-T FileList | -] [-v]" exit 1 } @@ -48,6 +50,8 @@ Verbose=$DefaultVerbose FileList=$DefaultFileList Suffixes=$DefaultSuffixes +AslrOptions=$DefaultAslrOpts +DoAslr=$DefaultDoAslr # Verify only ash processes are running grep -E -q -i -v '/ash(.exe)?$' /proc/[0-9]*/exename @@ -64,6 +68,10 @@ while getopts $ProgramOptions Option "$@" do case $Option in + a) + DoAslr=yes;; + A) + AslrOpts="$OPTARG";; b) BaseAddress=$OPTARG;; o) @@ -107,7 +115,7 @@ # Create rebase list find /etc/setup -name '*.lst.gz' | xargs gzip -d -c | grep -E "\.($Suffixes)\$" | - sed -e '/cygwin1.dll$/d' -e 's/^/\//' >"$TmpFile" + sed -e '/cygwin1.dll$/d' -e '/cyglsa64.dll$/d' -e 's/^/\//' >"$TmpFile" # Append user supplied file list, if any if [ -n "$FileList" ] @@ -118,6 +126,10 @@ # Rebase files rebase $Verbose -d -b $BaseAddress -o $Offset -T "$TmpFile" ExitCode=$? +if test "x$ExitCode" = "x0" && test -n "$DoAslr" + aslr $Verbose $AslrOpts -T "$TmpFile" + ExitCode=$? +fi # Clean up cleanup