diff options
Diffstat (limited to 'debug/tst-sprintf-fortify-rdonly.c')
-rw-r--r-- | debug/tst-sprintf-fortify-rdonly.c | 158 |
1 files changed, 140 insertions, 18 deletions
diff --git a/debug/tst-sprintf-fortify-rdonly.c b/debug/tst-sprintf-fortify-rdonly.c index ba5a791..fafc834 100644 --- a/debug/tst-sprintf-fortify-rdonly.c +++ b/debug/tst-sprintf-fortify-rdonly.c @@ -27,16 +27,64 @@ #include <support/check.h> #include <support/support.h> #include <support/temp_file.h> +#include <support/xdlfcn.h> -jmp_buf chk_fail_buf; -bool chk_fail_ok; +static sigjmp_buf chk_fail_buf; +static volatile int ret; +static bool chk_fail_ok; -const char *str2 = "F"; -char buf2[10] = "%s"; +static void +handler (int sig) +{ + if (chk_fail_ok) + { + chk_fail_ok = false; + longjmp (chk_fail_buf, 1); + } + else + _exit (127); +} + +#define FORTIFY_FAIL \ + do { printf ("Failure on line %d\n", __LINE__); ret = 1; } while (0) +#define CHK_FAIL_START \ + chk_fail_ok = true; \ + if (! sigsetjmp (chk_fail_buf, 1)) \ + { +#define CHK_FAIL_END \ + chk_fail_ok = false; \ + FORTIFY_FAIL; \ + } + +static const char *str2 = "F"; +static char writeable_format[10] = "%s"; +static char relro_format[10] __attribute__ ((section (".data.rel.ro"))) = + "%s%n%s%n"; + +extern void init_writable (void); +extern int sprintf_writable (int *, int *); +extern int sprintf_relro (int *, int *); +extern int sprintf_writable_malloc (int *, int *); + +#define str(__x) # __x +void (*init_writable_dlopen)(void); +int (*sprintf_writable_dlopen)(int *, int *); +int (*sprintf_rdonly_dlopen)(int *, int *); +int (*sprintf_writable_malloc_dlopen)(int *, int *); static int do_test (void) { + set_fortify_handler (handler); + + { + void *h = xdlopen ("tst-sprintf-fortify-rdonly-dlopen.so", RTLD_NOW); + init_writable_dlopen = xdlsym (h, str(init_writable)); + sprintf_writable_dlopen = xdlsym (h, str(sprintf_writable)); + sprintf_rdonly_dlopen = xdlsym (h, str(sprintf_relro)); + sprintf_writable_malloc_dlopen = xdlsym (h, str(sprintf_writable_malloc)); + } + struct rlimit rl; int max_fd = 24; @@ -63,20 +111,94 @@ do_test (void) } TEST_VERIFY_EXIT (nfiles != 0); - /* When the format string is writable and contains %n, - with -D_FORTIFY_SOURCE=2 it causes __chk_fail. However, if libc can not - open procfs to check if the input format string in within a writable - memory segment, the fortify version can not perform the check. */ - char buf[128]; - int n1; - int n2; - - strcpy (buf2 + 2, "%n%s%n"); - if (sprintf (buf, buf2, str2, &n1, str2, &n2) != 2 - || n1 != 1 || n2 != 2) - FAIL_EXIT1 ("sprintf failed: %s %d %d", buf, n1, n2); - - return 0; + strcpy (writeable_format + 2, "%n%s%n"); + init_writable (); + init_writable_dlopen (); + + /* writeable_format is at a writable part of .bss segment, so libc should be + able to check it without resorting to procfs. */ + { + char buf[128]; + int n1; + int n2; + CHK_FAIL_START + sprintf (buf, writeable_format, str2, &n1, str2, &n2); + CHK_FAIL_END + } + + /* Same as before, but from an library. */ + { + int n1; + int n2; + CHK_FAIL_START + sprintf_writable (&n1, &n2); + CHK_FAIL_END + } + + { + int n1; + int n2; + CHK_FAIL_START + sprintf_writable_dlopen (&n1, &n2); + CHK_FAIL_END + } + + /* relro_format is at a readonly part of .bss segment, so '%n' in format input + should not trigger a fortify failure. */ + { + char buf[128]; + int n1; + int n2; + if (sprintf (buf, relro_format, str2, &n1, str2, &n2) != 2 + || n1 != 1 || n2 != 2) + FAIL_EXIT1 ("sprintf failed: %s %d %d", buf, n1, n2); + } + + /* Same as before, but from an library. */ + { + int n1; + int n2; + if (sprintf_relro (&n1, &n2) != 2 || n1 != 1 || n2 != 2) + FAIL_EXIT1 ("sprintf failed: %d %d", n1, n2); + } + + { + int n1; + int n2; + if (sprintf_rdonly_dlopen (&n1, &n2) != 2 || n1 != 1 || n2 != 2) + FAIL_EXIT1 ("sprintf failed: %d %d", n1, n2); + } + + /* However if the format string is placed on a writable memory not covered + by ELF segments, libc needs to resort to procfs. */ + { + char buf[128]; + int n1; + int n2; + char *buf2_malloc = xstrdup (writeable_format); + CHK_FAIL_START + sprintf (buf, buf2_malloc, str2, &n1, str2, &n2); + CHK_FAIL_END + } + + /* Same as before, but from an library. */ + { + int n1; + int n2; + CHK_FAIL_START + sprintf_writable_malloc (&n1, &n2); + CHK_FAIL_END + } + + { + int n1; + int n2; + CHK_FAIL_START + sprintf_writable_malloc_dlopen (&n1, &n2); + CHK_FAIL_END + } + + return ret; } #include <support/test-driver.c> |