From f7043f647e84a9642ff03d001062f47e53f631bb Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Fri, 6 Nov 2026 12:00:10 -0500 Subject: [PATCH] fix potential crash with invalid readline key binding command; fix crash caused by signal cleanup after using ^G to abort out of listing possible completions --- CWRU/CWRU.chlog | 24 ++++++++++++++++++++++++ bashhist.h | 4 ++++ lib/readline/bind.c | 7 ++++++- lib/readline/complete.c | 28 +++++++++++++++++++++++++--- lib/readline/rlprivate.h | 2 +- lib/readline/util.c | 6 +++--- 6 files changed, 63 insertions(+), 8 deletions(-) diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 3ab4f7e1..08812fcf 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -13524,3 +13524,27 @@ redir.c with zreadc/zreadcintr/zreadn and invalidate the buffered data if so Report from Edgar MAGDELAINE + + 11/4 + ---- +lib/readline/bind.c + - rl_generic_bind: make sure to cast prevkey to unsigned char because + we use it as an index into a keymap + Report and fix from Can Ozkan + + 11/6 + ---- +lib/readline/complete.c + - _rl_abort_completion: new function, fakes a signal to clean up the + saved match list state, then calls _rl_abort_internal + - get_y_or_n: if we read ^G or get a read error, return -1 and let + the caller handle it instead of calling _rl_abort_internal() + - _rl_internal_pager, display_matches: if get_y_or_n returns -1, call + _rl_abort_completion to clean up the completion state and longjmp + back to reading input + Report from Sergio Herreros + +lib/readline/util.c,lib/readline/rlprivate.h + - _rl_abort_internal: now a void function with noreturn attribute; + changed callers to accommodate + diff --git a/bashhist.h b/bashhist.h index dcdbdff8..b0891c80 100644 --- a/bashhist.h +++ b/bashhist.h @@ -87,4 +87,8 @@ extern void setup_history_ignore (const char *); extern char *last_history_line (void); +#ifdef BASH_SYSLOG_HISTORY +extern void bash_syslog_history (const char *); +#endif + #endif /* _BASHHIST_H_ */ diff --git a/lib/readline/bind.c b/lib/readline/bind.c index e55cbde9..932937d7 100644 --- a/lib/readline/bind.c +++ b/lib/readline/bind.c @@ -410,7 +410,12 @@ rl_generic_bind (int type, const char *keyseq, char *data, Keymap map) } prevmap = map; - prevkey = keys[0]; + prevkey = (unsigned char)keys[0]; + if (prevkey >= KEYMAP_SIZE) + { + xfree (keys); + return -1; + } /* Bind keys, making new keymaps as necessary. */ for (i = 0; i < keys_len; i++) diff --git a/lib/readline/complete.c b/lib/readline/complete.c index 0bb569b2..87c63cca 100644 --- a/lib/readline/complete.c +++ b/lib/readline/complete.c @@ -129,6 +129,7 @@ static int path_isdir (const char *); static char *rl_quote_filename (char *, int, char *); static void _rl_complete_sigcleanup (int, void *); +static void _rl_abort_completion (void) __attribute__((noreturn)); static void set_completion_defaults (int); static int get_y_or_n (int); @@ -540,6 +541,19 @@ _rl_complete_sigcleanup (int sig, void *ptr) } } +static void +_rl_abort_completion () +{ + if (_rl_sigcleanup && _rl_sigcleanup == _rl_complete_sigcleanup) + { + _rl_sigcleanup (SIGINT, _rl_sigcleanarg); + _rl_sigcleanup = 0; + _rl_sigcleanarg = 0; + } + _rl_complete_display_matches_interrupt = 0; + _rl_abort_internal (); +} + /************************************/ /* */ /* Completion utility functions */ @@ -611,7 +625,7 @@ get_y_or_n (int for_pager) if (c == 'n' || c == 'N' || c == RUBOUT) return (0); if (c == ABORT_CHAR || c < 0) - _rl_abort_internal (); + return -1; if (for_pager && (c == NEWLINE || c == RETURN)) return (2); if (for_pager && (c == 'q' || c == 'Q')) @@ -643,6 +657,11 @@ _rl_internal_pager (int lines) n = _rl_screenheight / 2; return (lines > n) ? (lines - n) : -1; } + else if (i < 0) + { + _rl_abort_completion (); + return 0; + } else return 0; } @@ -1812,14 +1831,17 @@ display_matches (char **matches) rl_crlf (); fprintf (rl_outstream, "Display all %d possibilities? (y or n)", len); fflush (rl_outstream); - if ((completion_y_or_n = get_y_or_n (0)) == 0) + if ((completion_y_or_n = get_y_or_n (0)) <= 0) { rl_crlf (); rl_forced_update_display (); rl_display_fixed = 1; - return; + if (completion_y_or_n < 0) + _rl_abort_completion (); + else + return; } } diff --git a/lib/readline/rlprivate.h b/lib/readline/rlprivate.h index 320236b1..13586f13 100644 --- a/lib/readline/rlprivate.h +++ b/lib/readline/rlprivate.h @@ -516,7 +516,7 @@ extern void _rl_audit_tty (char *); extern int _rl_tropen (void); -extern int _rl_abort_internal (void); +extern void _rl_abort_internal (void) __attribute__((noreturn)); extern int _rl_null_function (int, int); extern char *_rl_strindex (const char *, const char *); extern int _rl_strcaseeqn (const char *, const char *, size_t, int); diff --git a/lib/readline/util.c b/lib/readline/util.c index 2b57fb95..e0112a53 100644 --- a/lib/readline/util.c +++ b/lib/readline/util.c @@ -95,7 +95,7 @@ _rl_walphabetic (WCHAR_T wc) #endif /* How to abort things. */ -int +void _rl_abort_internal (void) { if (RL_ISSTATE (RL_STATE_TIMEOUT) == 0) @@ -115,13 +115,13 @@ _rl_abort_internal (void) _rl_command_to_execute = 0; _rl_longjmp (_rl_top_level, 1); - return (0); } int rl_abort (int count, int key) { - return (_rl_abort_internal ()); + _rl_abort_internal (); + return 0; } int