diff options
| author | Paul Eggert <eggert@cs.ucla.edu> | 2012-10-01 15:12:44 -0700 |
|---|---|---|
| committer | Paul Eggert <eggert@cs.ucla.edu> | 2012-10-01 15:12:44 -0700 |
| commit | aa1ba90e4a95542c83cf636de3bc67e8fb23bad3 (patch) | |
| tree | 1407a999bbc11bf54aaeba40764d6a75565db182 | |
| parent | ace917bddb2ed2448a97ddf279445bb581c5cd32 (diff) | |
| download | emacs-aa1ba90e4a95542c83cf636de3bc67e8fb23bad3.tar.gz | |
Fix a malloc race condition involving strsignal.
A signal can arrive in the middle of a malloc, and Emacs's signal
handler can invoke strsignal, which can invoke malloc, which is
not portable. This race condition bug makes Emacs hang on GNU/Linux.
Fix it by altering the signal handler so that it does not invoke
strsignal.
* emacs.c (shut_down_emacs): Use safe_strsignal, not strsignal.
* process.c (status_message): Use const pointer, in case strsignal
is #defined to safe_strsignal.
* sysdep.c (sys_siglist, init_signals): Always define and
initialize a substitute sys_siglist if the system does not define
one, even if HAVE_STRSIGNAL.
(safe_strsignal): Rename from strsignal. Always define,
using sys_siglist. Return a const pointer.
* syssignal.h (safe_strsignal): New decl.
(strsignal) [!HAVE_STRSIGNAL]: Define in terms of safe_strsignal.
| -rw-r--r-- | src/ChangeLog | 19 | ||||
| -rw-r--r-- | src/emacs.c | 2 | ||||
| -rw-r--r-- | src/process.c | 2 | ||||
| -rw-r--r-- | src/sysdep.c | 29 | ||||
| -rw-r--r-- | src/syssignal.h | 4 |
5 files changed, 36 insertions, 20 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 7061038fdec..3a94af80c30 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,22 @@ +2012-10-01 Paul Eggert <eggert@cs.ucla.edu> + + Fix a malloc race condition involving strsignal. + A signal can arrive in the middle of a malloc, and Emacs's signal + handler can invoke strsignal, which can invoke malloc, which is + not portable. This race condition bug makes Emacs hang on GNU/Linux. + Fix it by altering the signal handler so that it does not invoke + strsignal. + * emacs.c (shut_down_emacs): Use safe_strsignal, not strsignal. + * process.c (status_message): Use const pointer, in case strsignal + is #defined to safe_strsignal. + * sysdep.c (sys_siglist, init_signals): Always define and + initialize a substitute sys_siglist if the system does not define + one, even if HAVE_STRSIGNAL. + (safe_strsignal): Rename from strsignal. Always define, + using sys_siglist. Return a const pointer. + * syssignal.h (safe_strsignal): New decl. + (strsignal) [!HAVE_STRSIGNAL]: Define in terms of safe_strsignal. + 2012-10-01 Eli Zaretskii <eliz@gnu.org> * w32proc.c (timer_loop): Fix code that waits for timer diff --git a/src/emacs.c b/src/emacs.c index a603a56b792..bc54f56b98a 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -1886,7 +1886,7 @@ shut_down_emacs (int sig, Lisp_Object stuff) static char const format[] = "Fatal error %d: "; char buf[sizeof format - 2 + INT_STRLEN_BOUND (int)]; int buflen = sprintf (buf, format, sig); - char const *sig_desc = strsignal (sig); + char const *sig_desc = safe_strsignal (sig); ignore_value (write (STDERR_FILENO, buf, buflen)); ignore_value (write (STDERR_FILENO, sig_desc, strlen (sig_desc))); } diff --git a/src/process.c b/src/process.c index dfc89809fa5..92bea0d3a27 100644 --- a/src/process.c +++ b/src/process.c @@ -570,7 +570,7 @@ status_message (struct Lisp_Process *p) if (EQ (symbol, Qsignal) || EQ (symbol, Qstop)) { - char *signame; + char const *signame; synchronize_system_messages_locale (); signame = strsignal (code); if (signame == 0) diff --git a/src/sysdep.c b/src/sysdep.c index a825145c6dd..74617fcaf0f 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -1543,12 +1543,10 @@ deliver_thread_signal (int sig, signal_handler_t handler) errno = old_errno; } -#if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST -static char *my_sys_siglist[NSIG]; -# ifdef sys_siglist -# undef sys_siglist -# endif +#if !HAVE_DECL_SYS_SIGLIST +# undef sys_siglist # define sys_siglist my_sys_siglist +static char const *sys_siglist[NSIG]; #endif /* Handle bus errors, invalid instruction, etc. */ @@ -1611,7 +1609,7 @@ init_signals (bool dumping) main_thread = pthread_self (); #endif -#if !defined HAVE_STRSIGNAL && !HAVE_DECL_SYS_SIGLIST +#if !HAVE_DECL_SYS_SIGLIST if (! initialized) { sys_siglist[SIGABRT] = "Aborted"; @@ -1759,7 +1757,7 @@ init_signals (bool dumping) sys_siglist[SIGXFSZ] = "File size limit exceeded"; # endif } -#endif /* !defined HAVE_STRSIGNAL && !defined HAVE_DECL_SYS_SIGLIST */ +#endif /* !HAVE_DECL_SYS_SIGLIST */ /* Don't alter signal handlers if dumping. On some machines, changing signal handlers sets static data that would make signals @@ -2280,21 +2278,20 @@ set_file_times (int fd, const char *filename, return fdutimens (fd, filename, timespec); } -#ifndef HAVE_STRSIGNAL -char * -strsignal (int code) +/* Like strsignal, except async-signal-safe, and this function typically + returns a string in the C locale rather than the current locale. */ +char const * +safe_strsignal (int code) { - char *signame = 0; + char const *signame = 0; if (0 <= code && code < NSIG) - { - /* Cast to suppress warning if the table has const char *. */ - signame = (char *) sys_siglist[code]; - } + signame = sys_siglist[code]; + if (! signame) + signame = "Unknown signal"; return signame; } -#endif /* HAVE_STRSIGNAL */ #ifndef DOS_NT /* For make-serial-process */ diff --git a/src/syssignal.h b/src/syssignal.h index ece2515dec9..66538aad100 100644 --- a/src/syssignal.h +++ b/src/syssignal.h @@ -39,6 +39,7 @@ extern sigset_t empty_mask; typedef void (*signal_handler_t) (int); extern void emacs_sigaction_init (struct sigaction *, signal_handler_t); +char const *safe_strsignal (int); #if NSIG < NSIG_MINIMUM # undef NSIG @@ -70,8 +71,7 @@ extern void emacs_sigaction_init (struct sigaction *, signal_handler_t); #endif /* ! defined (SIGCLD) */ #ifndef HAVE_STRSIGNAL -/* strsignal is in sysdep.c */ -char *strsignal (int); +# define strsignal(sig) safe_strsignal (sig) #endif void deliver_process_signal (int, signal_handler_t); |
