Skip to content

Commit

Permalink
Fix out-of-bounds write on Ctrl+C with -H on (#700)
Browse files Browse the repository at this point in the history
On OpenBSD 7.4, ksh crashes when SIGINT is sent with Ctrl+C in the
absence of a foreground job, provided that:

  * The histexpand option is set
  * ksh was built without AST_vmalloc

This happens because slowread in io.c attempts to append \0 to the
buffer before calling hist_expand. In the case of SIGINT, the size
of the buffer (rsize) registers as -1 from ed_emacsread or
ed_viread, resulting in an out-of-bounds write. Because of the
strict malloc of OpenBSD, the shell crashes.

The fix is straightforward: in slowread, check for positive (rather
than non-zero) buffer size before proceeding with history
expansion-related operations.

Although this crash would have first appeared in default builds
when vmalloc was deprecated in December 2021 (f9364b1), the bad
write itself has been present since history expansion was
introduced in June 2003 (ksh93o+).

src/cmd/ksh93/sh/io.c: slowread():
- Check for positive buffer size before preparing to attempt
  history expansion.
  • Loading branch information
pghvlaans authored Jan 5, 2024
1 parent 61e9e09 commit ef4c83c
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 1 deletion.
5 changes: 5 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ This documents significant changes in the dev branch of ksh 93u+m.
For full details, see the git log at: https://github.com/ksh93/ksh
Uppercase BUG_* IDs are shell bug IDs as used by the Modernish shell library.

2024-01-05:

- Fixed a potential crash on pressing Ctrl+C on the command line while
history expansion (the -H or histexpand option) is active.

2023-12-28:

- Fixed intermittent incorrect behaviour (a race condition), introduced on
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/ksh93/sh/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -2014,7 +2014,7 @@ static ssize_t slowread(Sfio_t *iop,void *buff,size_t size,Sfdisc_t *handle)
sh_timerdel(timeout);
timeout=0;
#if SHOPT_HISTEXPAND
if(rsize && *(char*)buff != '\n' && sh.nextprompt==1 && sh_isoption(SH_HISTEXPAND))
if(rsize > 0 && *(char*)buff != '\n' && sh.nextprompt==1 && sh_isoption(SH_HISTEXPAND))
{
int r;
((char*)buff)[rsize] = '\0';
Expand Down

0 comments on commit ef4c83c

Please sign in to comment.