| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- /* Testcase for BZ 30932.
- Copyright (C) 2023-2026 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <https://www.gnu.org/licenses/>. */
- #include <errno.h>
- #include <setjmp.h>
- #include <stdbool.h>
- #include <stdio.h>
- #include <string.h>
- #include <sys/resource.h>
- #include <unistd.h>
- #include <support/check.h>
- #include <support/support.h>
- #include <support/temp_file.h>
- #include <support/xdlfcn.h>
- static sigjmp_buf chk_fail_buf;
- static volatile int ret;
- static bool chk_fail_ok;
- 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;
- if (getrlimit (RLIMIT_NOFILE, &rl) == -1)
- FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m");
- max_fd = (rl.rlim_cur < max_fd ? rl.rlim_cur : max_fd);
- rl.rlim_cur = max_fd;
- if (setrlimit (RLIMIT_NOFILE, &rl) == -1)
- FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m");
- /* Exhaust the file descriptor limit with temporary files. */
- int nfiles = 0;
- for (; nfiles < max_fd; nfiles++)
- {
- int fd = create_temp_file ("tst-sprintf-fortify-rdonly-.", NULL);
- if (fd == -1)
- {
- if (errno != EMFILE)
- FAIL_EXIT1 ("create_temp_file: %m");
- break;
- }
- }
- TEST_VERIFY_EXIT (nfiles != 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>
|