mirror of
https://sourceware.org/git/glibc.git
synced 2025-07-29 11:41:21 +03: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:
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>
|
2017-07-11 Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||||
|
|
||||||
[BZ #21738]
|
[BZ #21738]
|
||||||
|
@ -139,12 +139,18 @@ LDFLAGS-tst-backtrace4 = -rdynamic
|
|||||||
LDFLAGS-tst-backtrace5 = -rdynamic
|
LDFLAGS-tst-backtrace5 = -rdynamic
|
||||||
LDFLAGS-tst-backtrace6 = -rdynamic
|
LDFLAGS-tst-backtrace6 = -rdynamic
|
||||||
|
|
||||||
|
CFLAGS-tst-ssp-1.c = -fstack-protector
|
||||||
|
|
||||||
tests = backtrace-tst tst-longjmp_chk tst-chk1 tst-chk2 tst-chk3 \
|
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-lfschk1 tst-lfschk2 tst-lfschk3 test-strcpy_chk test-stpcpy_chk \
|
||||||
tst-chk4 tst-chk5 tst-chk6 tst-lfschk4 tst-lfschk5 tst-lfschk6 \
|
tst-chk4 tst-chk5 tst-chk6 tst-lfschk4 tst-lfschk5 tst-lfschk6 \
|
||||||
tst-longjmp_chk2 tst-backtrace2 tst-backtrace3 tst-backtrace4 \
|
tst-longjmp_chk2 tst-backtrace2 tst-backtrace3 tst-backtrace4 \
|
||||||
tst-backtrace5 tst-backtrace6
|
tst-backtrace5 tst-backtrace6
|
||||||
|
|
||||||
|
ifeq ($(have-ssp),yes)
|
||||||
|
tests += tst-ssp-1
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq (,$(CXX))
|
ifeq (,$(CXX))
|
||||||
tests-unsupported = tst-chk4 tst-chk5 tst-chk6 \
|
tests-unsupported = tst-chk4 tst-chk5 tst-chk6 \
|
||||||
tst-lfschk4 tst-lfschk5 tst-lfschk6
|
tst-lfschk4 tst-lfschk5 tst-lfschk6
|
||||||
|
@ -17,17 +17,28 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
|
||||||
extern char **__libc_argv attribute_hidden;
|
extern char **__libc_argv attribute_hidden;
|
||||||
|
|
||||||
void
|
void
|
||||||
__attribute__ ((noreturn)) internal_function
|
__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. */
|
/* The loop is added only to keep gcc happy. */
|
||||||
while (1)
|
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>");
|
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)
|
||||||
|
libc_hidden_def (__fortify_fail_abort)
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
|
||||||
extern char **__libc_argv attribute_hidden;
|
extern char **__libc_argv attribute_hidden;
|
||||||
@ -25,7 +26,7 @@ void
|
|||||||
__attribute__ ((noreturn))
|
__attribute__ ((noreturn))
|
||||||
__stack_chk_fail (void)
|
__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)
|
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_DIR 1 /* create a directory */
|
||||||
# define __GT_NOCREATE 2 /* just find a name not currently in use */
|
# 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. */
|
/* Print out MESSAGE on the error output and abort. */
|
||||||
extern void __libc_fatal (const char *__message)
|
extern void __libc_fatal (const char *__message)
|
||||||
__attribute__ ((__noreturn__));
|
__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)
|
extern void __fortify_fail (const char *msg)
|
||||||
__attribute__ ((__noreturn__)) internal_function;
|
__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)
|
||||||
|
libc_hidden_proto (__fortify_fail_abort)
|
||||||
|
|
||||||
/* Acquire ownership of STREAM. */
|
/* Acquire ownership of STREAM. */
|
||||||
extern void __flockfile (FILE *__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);
|
set_arena_corrupt (ar_ptr);
|
||||||
|
|
||||||
if ((action & 5) == 5)
|
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)
|
else if (action & 1)
|
||||||
{
|
{
|
||||||
char buf[2 * sizeof (uintptr_t) + 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)
|
while (cp > buf)
|
||||||
*--cp = '0';
|
*--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);
|
__libc_argv[0] ? : "<unknown>", str, cp);
|
||||||
}
|
}
|
||||||
else if (action & 2)
|
else if (action & 2)
|
||||||
|
@ -64,7 +64,7 @@ struct str_list
|
|||||||
|
|
||||||
/* Abort with an error message. */
|
/* Abort with an error message. */
|
||||||
void
|
void
|
||||||
__libc_message (int do_abort, const char *fmt, ...)
|
__libc_message (enum __libc_message_action action, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
@ -140,7 +140,7 @@ __libc_message (int do_abort, const char *fmt, ...)
|
|||||||
|
|
||||||
written = WRITEV_FOR_FATAL (fd, iov, nlist, total);
|
written = WRITEV_FOR_FATAL (fd, iov, nlist, total);
|
||||||
|
|
||||||
if (do_abort)
|
if ((action & do_abort))
|
||||||
{
|
{
|
||||||
total = ((total + 1 + GLRO(dl_pagesize) - 1)
|
total = ((total + 1 + GLRO(dl_pagesize) - 1)
|
||||||
& ~(GLRO(dl_pagesize) - 1));
|
& ~(GLRO(dl_pagesize) - 1));
|
||||||
@ -167,9 +167,10 @@ __libc_message (int do_abort, const char *fmt, ...)
|
|||||||
|
|
||||||
va_end (ap);
|
va_end (ap);
|
||||||
|
|
||||||
if (do_abort)
|
if ((action & do_abort))
|
||||||
{
|
{
|
||||||
BEFORE_ABORT (do_abort, written, fd);
|
if ((action & do_backtrace))
|
||||||
|
BEFORE_ABORT (do_abort, written, fd);
|
||||||
|
|
||||||
/* Kill the application. */
|
/* Kill the application. */
|
||||||
abort ();
|
abort ();
|
||||||
@ -182,6 +183,6 @@ __libc_fatal (const char *message)
|
|||||||
{
|
{
|
||||||
/* The loop is added only to keep gcc happy. */
|
/* The loop is added only to keep gcc happy. */
|
||||||
while (1)
|
while (1)
|
||||||
__libc_message (1, "%s", message);
|
__libc_message (do_abort | do_backtrace, "%s", message);
|
||||||
}
|
}
|
||||||
libc_hidden_def (__libc_fatal)
|
libc_hidden_def (__libc_fatal)
|
||||||
|
Reference in New Issue
Block a user