mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-24 22:10:13 +00:00
Avoid backtrace from __stack_chk_fail [BZ #12189]
__stack_chk_fail is called on corrupted stack. Stack backtrace is very unreliable against corrupted stack. __libc_message is changed to accept enum __libc_message_action and call BEFORE_ABORT only if action includes do_backtrace. __fortify_fail_abort is added to avoid backtrace from __stack_chk_fail. [BZ #12189] * debug/Makefile (CFLAGS-tst-ssp-1.c): New. (tests): Add tst-ssp-1 if -fstack-protector works. * debug/fortify_fail.c: Include <stdbool.h>. (_fortify_fail_abort): New function. (__fortify_fail): Call _fortify_fail_abort. (__fortify_fail_abort): Add a hidden definition. * debug/stack_chk_fail.c: Include <stdbool.h>. (__stack_chk_fail): Call __fortify_fail_abort, instead of __fortify_fail. * debug/tst-ssp-1.c: New file. * include/stdio.h (__libc_message_action): New enum. (__libc_message): Replace int with enum __libc_message_action. (__fortify_fail_abort): New hidden prototype. * malloc/malloc.c (malloc_printerr): Update __libc_message calls. * sysdeps/posix/libc_fatal.c (__libc_message): Replace int with enum __libc_message_action. Call BEFORE_ABORT only if action includes do_backtrace. (__libc_fatal): Update __libc_message call.
This commit is contained in:
parent
94070f86c0
commit
ed421fca42
22
ChangeLog
22
ChangeLog
@ -1,3 +1,25 @@
|
||||
2017-07-11 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
[BZ #12189]
|
||||
* debug/Makefile (CFLAGS-tst-ssp-1.c): New.
|
||||
(tests): Add tst-ssp-1 if -fstack-protector works.
|
||||
* debug/fortify_fail.c: Include <stdbool.h>.
|
||||
(_fortify_fail_abort): New function.
|
||||
(__fortify_fail): Call _fortify_fail_abort.
|
||||
(__fortify_fail_abort): Add a hidden definition.
|
||||
* debug/stack_chk_fail.c: Include <stdbool.h>.
|
||||
(__stack_chk_fail): Call __fortify_fail_abort, instead of
|
||||
__fortify_fail.
|
||||
* debug/tst-ssp-1.c: New file.
|
||||
* include/stdio.h (__libc_message_action): New enum.
|
||||
(__libc_message): Replace int with enum __libc_message_action.
|
||||
(__fortify_fail_abort): New hidden prototype.
|
||||
* malloc/malloc.c (malloc_printerr): Update __libc_message calls.
|
||||
* sysdeps/posix/libc_fatal.c (__libc_message): Replace int
|
||||
with enum __libc_message_action. Call BEFORE_ABORT only if
|
||||
action includes do_backtrace.
|
||||
(__libc_fatal): Update __libc_message call.
|
||||
|
||||
2017-07-11 Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
[BZ #21738]
|
||||
|
@ -139,12 +139,18 @@ LDFLAGS-tst-backtrace4 = -rdynamic
|
||||
LDFLAGS-tst-backtrace5 = -rdynamic
|
||||
LDFLAGS-tst-backtrace6 = -rdynamic
|
||||
|
||||
CFLAGS-tst-ssp-1.c = -fstack-protector
|
||||
|
||||
tests = backtrace-tst tst-longjmp_chk tst-chk1 tst-chk2 tst-chk3 \
|
||||
tst-lfschk1 tst-lfschk2 tst-lfschk3 test-strcpy_chk test-stpcpy_chk \
|
||||
tst-chk4 tst-chk5 tst-chk6 tst-lfschk4 tst-lfschk5 tst-lfschk6 \
|
||||
tst-longjmp_chk2 tst-backtrace2 tst-backtrace3 tst-backtrace4 \
|
||||
tst-backtrace5 tst-backtrace6
|
||||
|
||||
ifeq ($(have-ssp),yes)
|
||||
tests += tst-ssp-1
|
||||
endif
|
||||
|
||||
ifeq (,$(CXX))
|
||||
tests-unsupported = tst-chk4 tst-chk5 tst-chk6 \
|
||||
tst-lfschk4 tst-lfschk5 tst-lfschk6
|
||||
|
@ -17,17 +17,28 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
extern char **__libc_argv attribute_hidden;
|
||||
|
||||
void
|
||||
__attribute__ ((noreturn)) internal_function
|
||||
__fortify_fail (const char *msg)
|
||||
__fortify_fail_abort (_Bool do_backtrace, const char *msg)
|
||||
{
|
||||
/* The loop is added only to keep gcc happy. */
|
||||
while (1)
|
||||
__libc_message (2, "*** %s ***: %s terminated\n",
|
||||
__libc_message (do_backtrace ? (do_abort | do_backtrace) : do_abort,
|
||||
"*** %s ***: %s terminated\n",
|
||||
msg, __libc_argv[0] ?: "<unknown>");
|
||||
}
|
||||
|
||||
void
|
||||
__attribute__ ((noreturn)) internal_function
|
||||
__fortify_fail (const char *msg)
|
||||
{
|
||||
__fortify_fail_abort (true, msg);
|
||||
}
|
||||
|
||||
libc_hidden_def (__fortify_fail)
|
||||
libc_hidden_def (__fortify_fail_abort)
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
extern char **__libc_argv attribute_hidden;
|
||||
@ -25,7 +26,7 @@ void
|
||||
__attribute__ ((noreturn))
|
||||
__stack_chk_fail (void)
|
||||
{
|
||||
__fortify_fail ("stack smashing detected");
|
||||
__fortify_fail_abort (false, "stack smashing detected");
|
||||
}
|
||||
|
||||
strong_alias (__stack_chk_fail, __stack_chk_fail_local)
|
||||
|
45
debug/tst-ssp-1.c
Normal file
45
debug/tst-ssp-1.c
Normal file
@ -0,0 +1,45 @@
|
||||
/* Verify that __stack_chk_fail won't segfault.
|
||||
Copyright (C) 2017 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
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Based on gcc.dg/ssp-1.c from GCC testsuite. */
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
static void
|
||||
__attribute__ ((noinline, noclone))
|
||||
test (char *foo)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* smash stack */
|
||||
for (i = 0; i <= 400; i++)
|
||||
foo[i] = 42;
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
char foo[30];
|
||||
|
||||
test (foo);
|
||||
|
||||
return 1; /* fail */
|
||||
}
|
||||
|
||||
#define EXPECTED_SIGNAL SIGABRT
|
||||
#include <support/test-driver.c>
|
@ -86,13 +86,24 @@ extern int __gen_tempname (char *__tmpl, int __suffixlen, int __flags,
|
||||
# define __GT_DIR 1 /* create a directory */
|
||||
# define __GT_NOCREATE 2 /* just find a name not currently in use */
|
||||
|
||||
enum __libc_message_action
|
||||
{
|
||||
do_message = 0, /* Print message. */
|
||||
do_abort = 1 << 0, /* Abort. */
|
||||
do_backtrace = 1 << 1 /* Backtrace. */
|
||||
};
|
||||
|
||||
/* Print out MESSAGE on the error output and abort. */
|
||||
extern void __libc_fatal (const char *__message)
|
||||
__attribute__ ((__noreturn__));
|
||||
extern void __libc_message (int do_abort, const char *__fnt, ...);
|
||||
extern void __libc_message (enum __libc_message_action action,
|
||||
const char *__fnt, ...);
|
||||
extern void __fortify_fail (const char *msg)
|
||||
__attribute__ ((__noreturn__)) internal_function;
|
||||
extern void __fortify_fail_abort (_Bool, const char *msg)
|
||||
__attribute__ ((__noreturn__)) internal_function;
|
||||
libc_hidden_proto (__fortify_fail)
|
||||
libc_hidden_proto (__fortify_fail_abort)
|
||||
|
||||
/* Acquire ownership of STREAM. */
|
||||
extern void __flockfile (FILE *__stream);
|
||||
|
@ -5397,7 +5397,8 @@ malloc_printerr (int action, const char *str, void *ptr, mstate ar_ptr)
|
||||
set_arena_corrupt (ar_ptr);
|
||||
|
||||
if ((action & 5) == 5)
|
||||
__libc_message (action & 2, "%s\n", str);
|
||||
__libc_message ((action & 2) ? (do_abort | do_backtrace) : do_message,
|
||||
"%s\n", str);
|
||||
else if (action & 1)
|
||||
{
|
||||
char buf[2 * sizeof (uintptr_t) + 1];
|
||||
@ -5407,7 +5408,8 @@ malloc_printerr (int action, const char *str, void *ptr, mstate ar_ptr)
|
||||
while (cp > buf)
|
||||
*--cp = '0';
|
||||
|
||||
__libc_message (action & 2, "*** Error in `%s': %s: 0x%s ***\n",
|
||||
__libc_message ((action & 2) ? (do_abort | do_backtrace) : do_message,
|
||||
"*** Error in `%s': %s: 0x%s ***\n",
|
||||
__libc_argv[0] ? : "<unknown>", str, cp);
|
||||
}
|
||||
else if (action & 2)
|
||||
|
@ -64,7 +64,7 @@ struct str_list
|
||||
|
||||
/* Abort with an error message. */
|
||||
void
|
||||
__libc_message (int do_abort, const char *fmt, ...)
|
||||
__libc_message (enum __libc_message_action action, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int fd = -1;
|
||||
@ -140,7 +140,7 @@ __libc_message (int do_abort, const char *fmt, ...)
|
||||
|
||||
written = WRITEV_FOR_FATAL (fd, iov, nlist, total);
|
||||
|
||||
if (do_abort)
|
||||
if ((action & do_abort))
|
||||
{
|
||||
total = ((total + 1 + GLRO(dl_pagesize) - 1)
|
||||
& ~(GLRO(dl_pagesize) - 1));
|
||||
@ -167,8 +167,9 @@ __libc_message (int do_abort, const char *fmt, ...)
|
||||
|
||||
va_end (ap);
|
||||
|
||||
if (do_abort)
|
||||
if ((action & do_abort))
|
||||
{
|
||||
if ((action & do_backtrace))
|
||||
BEFORE_ABORT (do_abort, written, fd);
|
||||
|
||||
/* Kill the application. */
|
||||
@ -182,6 +183,6 @@ __libc_fatal (const char *message)
|
||||
{
|
||||
/* The loop is added only to keep gcc happy. */
|
||||
while (1)
|
||||
__libc_message (1, "%s", message);
|
||||
__libc_message (do_abort | do_backtrace, "%s", message);
|
||||
}
|
||||
libc_hidden_def (__libc_fatal)
|
||||
|
Loading…
Reference in New Issue
Block a user