diff --git a/ksh-1.0.11-segfault-sigwinch.patch b/ksh-1.0.11-segfault-sigwinch.patch new file mode 100644 index 0000000..a342475 --- /dev/null +++ b/ksh-1.0.11-segfault-sigwinch.patch @@ -0,0 +1,264 @@ +From b533bc2feb9a1b58b9cdb3a9f5bc94f4ff060a84 Mon Sep 17 00:00:00 2001 +From: Martijn Dekker +Date: Fri, 28 Mar 2025 02:59:46 +0000 +Subject: [PATCH] Fix segfault upon SIGWINCH after 'stty -echo' (re: 83630f9d) + +After disabling terminal echo (stty -echo), ksh either crashes or +writes garbage to the terminal upon resizing the terminal window. +This also affects the use of ksh for 'M-x shell' in emacs. + +Analysis: The ed_viread and ed_emacsread functions declare buffers +as local (automatic) variables that are destroyed when the function +exits, but other functions then access then using globally declared +pointers in structs of type Edit_t, Emacs_t and Vi_t. + +However, upon 'stty -echo', the terminal cannot be set to raw mode, +so the tty_raw call fails in these two functions. At this point, +they fall back to ed_read and return, never initialising those +pointers. But the SIGWINCH handling routine in edit.c calls redraw +routines that depend on those pointers being valid -- and crash. + +src/cmd/ksh93/edit/emacs.c: ed_emacsread(): +- Attempt to set raw mode before doing or initialising anything + else: move the tty_raw call and ed_read fallback to the start. + This avoids superfluous init and makes more sense. +- Before returning, reset all global pointers that point to this + function call's local variables to NULL. (To aid with this, use a + 'done' goto label and an 'r' variable for the return code.) This + ensures these pointers will be either valid or NULL, making + debugging easier, as well as allowing the code to check for this. + +src/cmd/ksh93/edit/vi.c: ed_viread(): +- Same changes as for emacs. + +src/cmd/ksh93/edit/edit.c: ed_read(): +- If e_prompt is NULL, that is now an indication that ed_emacsread + or ed_viread are not being used because the tty_raw call failed; + therefore, skip SIGWINCH handling, except for flushing the notify + buffer (see 667034ff). This fixes the crash. + +Thanks to @nickpapadonis for the report. +Resolves: https://github.com/ksh93/ksh/issues/827 +--- + src/cmd/ksh93/edit/edit.c | 22 ++++++++++++++++++---- + src/cmd/ksh93/edit/emacs.c | 27 ++++++++++++++++----------- + src/cmd/ksh93/edit/vi.c | 38 +++++++++++++++----------------------- + 3 files changed, 49 insertions(+), 38 deletions(-) + +diff --git a/src/cmd/ksh93/edit/edit.c b/src/cmd/ksh93/edit/edit.c +index 1dcef1b..846c0d8 100644 +--- a/src/cmd/ksh93/edit/edit.c ++++ b/src/cmd/ksh93/edit/edit.c +@@ -690,6 +690,16 @@ static void ed_nputchar(Edit_t *ep, int n, int c) + } + #endif /* SHOPT_ESH || SHOPT_VSH */ + ++/* ++ * Show any buffered 'set -b' job notification(s) ++ */ ++static void flush_notifybuf(void) ++{ ++ char *cp; ++ if(sh.notifybuf && (cp = sfstruse(sh.notifybuf)) && *cp) ++ sfputr(sfstderr, cp, -1); ++} ++ + /* + * Do read, restart on interrupt unless SH_SIGSET or SH_SIGTRAP is set + * Use select(2) (via sfpkrd()) to wait for input if possible +@@ -729,7 +739,12 @@ int ed_read(void *context, int fd, char *buff, int size, int reedit) + if(sh.winch && sh_editor_active() && sh_isstate(SH_INTERACTIVE)) + { + int n, newsize; +- char *cp; ++ if(!ep->e_prompt) ++ { ++ /* ed_emacsread or ed_viread was unable to put the tty in raw mode */ ++ flush_notifybuf(); ++ goto skipwinch; ++ } + sh_winsize(NULL,&newsize); + ed_putchar(ep,'\r'); + /* +@@ -751,9 +766,7 @@ int ed_read(void *context, int fd, char *buff, int size, int reedit) + ed_putchar(ep,'\r'); + } + ed_flush(ep); +- /* show any buffered 'set -b' job notification(s) */ +- if(sh.notifybuf && (cp = sfstruse(sh.notifybuf)) && *cp) +- sfputr(sfstderr, cp, -1); ++ flush_notifybuf(); + /* update window size */ + ep->e_winsz = newsize-1; + if(ep->e_winsz < MINWINDOW) +@@ -777,6 +790,7 @@ int ed_read(void *context, int fd, char *buff, int size, int reedit) + emacs_redraw(ep->e_emacs); + #endif /* SHOPT_ESH && SHOPT_VSH */ + } ++ skipwinch: + #endif /* SHOPT_ESH || SHOPT_VSH */ + sh.winch = 0; + /* an interrupt that should be ignored */ +diff --git a/src/cmd/ksh93/edit/emacs.c b/src/cmd/ksh93/edit/emacs.c +index 1dd6023..128e592 100644 +--- a/src/cmd/ksh93/edit/emacs.c ++++ b/src/cmd/ksh93/edit/emacs.c +@@ -185,6 +185,7 @@ int ed_emacsread(void *context, int fd,char *buff,int scend, int reedit) + Edit_t *ed = (Edit_t*)context; + int c; + int i; ++ int r = -1; /* return code */ + genchar *out; + int count; + Emacs_t *ep = ed->e_emacs; +@@ -194,6 +195,10 @@ int ed_emacsread(void *context, int fd,char *buff,int scend, int reedit) + genchar *kptr; + char prompt[PRSIZE]; + genchar Screen[MAXLINE]; ++ /* Set raw mode */ ++ if(tty_raw(ERRIO,0) < 0) ++ return reedit ? reedit : ed_read(context, fd, buff, scend, 0); ++ /* Initialize some things */ + memset(Screen,0,sizeof(Screen)); + if(!ep) + { +@@ -206,10 +211,6 @@ int ed_emacsread(void *context, int fd,char *buff,int scend, int reedit) + ep->screen = Screen; + ep->lastdraw = FINAL; + ep->ehist = 0; +- if(tty_raw(ERRIO,0) < 0) +- { +- return reedit ? reedit : ed_read(context,fd,buff,scend,0); +- } + raw = 1; + /* This mess in case the read system call fails */ + ed_setup(ep->ed,fd,reedit); +@@ -240,6 +241,7 @@ int ed_emacsread(void *context, int fd,char *buff,int scend, int reedit) + } + ep->in_mult = hloff; /* save pos in last command */ + #endif /* ESH_NFIRST */ ++ /* Handle user interrupt, user quit, or EOF */ + i = sigsetjmp(env,0); + if (i !=0) + { +@@ -251,10 +253,8 @@ int ed_emacsread(void *context, int fd,char *buff,int scend, int reedit) + } + tty_cooked(ERRIO); + if (i == UEOF) +- { +- return 0; /* EOF */ +- } +- return -1; /* some other error */ ++ r = 0; /* EOF */ ++ goto done; + } + out[reedit] = 0; + if(scend+plen > (MAXLINE-2)) +@@ -349,7 +349,8 @@ int ed_emacsread(void *context, int fd,char *buff,int scend, int reedit) + case EOFCHAR: + ed_flush(ep->ed); + tty_cooked(ERRIO); +- return 0; ++ r = 0; ++ goto done; + #ifdef u370 + case cntl('S') : + case cntl('Q') : +@@ -754,8 +755,12 @@ process: + #endif /* SHOPT_MULTIBYTE */ + i = (int)strlen(buff); + if (i) +- return i; +- return -1; ++ r = i; ++done: ++ /* avoid leaving invalid pointers to destroyed automatic variables */ ++ Prompt = NULL; ++ drawbuff = ep->screen = ep->cursor = NULL; ++ return r; + } + + static void show_info(Emacs_t *ep,const char *str) +diff --git a/src/cmd/ksh93/edit/vi.c b/src/cmd/ksh93/edit/vi.c +index 0e878df..fac40ee 100644 +--- a/src/cmd/ksh93/edit/vi.c ++++ b/src/cmd/ksh93/edit/vi.c +@@ -208,6 +208,7 @@ int ed_viread(void *context, int fd, char *shbuf, int nchar, int reedit) + { + Edit_t *ed = (Edit_t*)context; + int i; /* general variable */ ++ int r = -1; /* return value */ + int term_char=0; /* read() termination character */ + Vi_t *vp = ed->e_vi; + char prompt[PRSIZE+2]; /* prompt */ +@@ -218,6 +219,10 @@ int ed_viread(void *context, int fd, char *shbuf, int nchar, int reedit) + int Globals[9]; /* local global variables */ + int esc_or_hang=0; /* or hangup */ + char cntl_char=0; /* TRUE if control character present */ ++ ++ if( tty_raw(ERRIO,0) < 0 ) ++ return reedit ? reedit : ed_read(context, fd, shbuf, nchar, 0); ++ + if(!vp) + { + ed->e_vi = vp = sh_newof(0,Vi_t,1,0); +@@ -232,16 +237,9 @@ int ed_viread(void *context, int fd, char *shbuf, int nchar, int reedit) + ed_setup(vp->ed,fd, reedit); + shbuf[reedit] = 0; + +- { +- /*** Set raw mode ***/ +- +- if(tty_raw(ERRIO,0) < 0 ) +- return reedit ? reedit : ed_read(context, fd, shbuf, nchar,0); +- i = last_virt-1; +- } +- + /*** Initialize some things ***/ + ++ i = last_virt-1; + virtual = (genchar*)shbuf; + #if SHOPT_MULTIBYTE + virtual = (genchar*)roundof((char*)virtual-(char*)0,sizeof(genchar)); +@@ -307,18 +305,9 @@ int ed_viread(void *context, int fd, char *shbuf, int nchar, int reedit) + } + virtual[0] = '\0'; + tty_cooked(ERRIO); +- +- switch(i) +- { +- case UEOF: +- /*** EOF ***/ +- return 0; +- +- case UINTR: +- /** interrupt **/ +- return -1; +- } +- return -1; ++ if (i == UEOF) ++ r = 0; /* EOF */ ++ goto done; + } + + /*** Get a line from the terminal ***/ +@@ -363,10 +352,13 @@ int ed_viread(void *context, int fd, char *shbuf, int nchar, int reedit) + if(vp->ed->nhlist) + ed_histlist(vp->ed,0); + #endif /* SHOPT_EDPREDICT */ +- return last_virt; ++ r = last_virt; + } +- else +- return -1; ++done: ++ /* avoid leaving invalid pointers to destroyed automatic variables */ ++ Prompt = NULL; ++ virtual = physical = window = vp->U_space = vp->u_space = NULL; ++ return r; + } + + +-- +2.49.0 + diff --git a/ksh.spec b/ksh.spec index 52ba3df..cd835ea 100644 --- a/ksh.spec +++ b/ksh.spec @@ -4,7 +4,7 @@ URL: http://www.kornshell.com/ License: EPL-1.0 Epoch: 3 Version: 1.0.6 -Release: 10%{?dist} +Release: 11%{?dist} Source0: https://github.com/ksh93/%{name}/archive/v%{version}/%{name}-%{version}.tar.gz Source1: kshcomp.conf Source2: kshrc.rhs @@ -48,6 +48,9 @@ Patch10: ksh-1.0.11-stty-noecho.patch # upstream commit: https://github.com/ksh93/ksh/commit/96d73c08a2786806f3def1fda66641b81e0af988 Patch11: ksh-1.0.11-ssh-multibyte-long-paste.patch +# upstream commit: https://github.com/ksh93/ksh/commit/9f03b3bdb577ce74be3122d533c02830e3038e54 +Patch12: ksh-1.0.11-segfault-sigwinch.patch + Conflicts: pdksh Requires: coreutils, diffutils BuildRequires: gcc @@ -169,6 +172,9 @@ fi %config(noreplace) %{_sysconfdir}/binfmt.d/kshcomp.conf %changelog +* Mon May 19 2025 Vincent Mihalkovic - 3:1.0.6-11 +- Fix segfault upon SIGWINCH after 'stty -echo' Resolves: RHEL-91097 + * Wed Apr 16 2025 Vincent Mihalkovic - 3:1.0.6-10 - Fix long multibyte characters paste issue via ssh Resolves: RHEL-87561