aboutsummaryrefslogtreecommitdiff
path: root/debug/tst-sprintf-fortify-rdonly.c
diff options
context:
space:
mode:
Diffstat (limited to 'debug/tst-sprintf-fortify-rdonly.c')
-rw-r--r--debug/tst-sprintf-fortify-rdonly.c158
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>