Compare commits
No commits in common. "c8" and "c8-beta" have entirely different histories.
@ -1,321 +0,0 @@
|
||||
From aa75399b030dfb0efc39be6d07c627aedbc2d2c1 Mon Sep 17 00:00:00 2001
|
||||
From: Johnothan King <johnothanking@protonmail.com>
|
||||
Date: Thu, 29 Jan 2026 16:23:45 -0800
|
||||
Subject: [PATCH] Fix /dev/fd/1 memory fault and $0 for /dev/fd scripts
|
||||
|
||||
Changes:
|
||||
|
||||
- sh_init(): Don't set $0 to the path to ksh. The correct behavior
|
||||
is to always use the script name, even when it's a /dev/fd file.
|
||||
The behavior of ksh93 should match that of bash and other shells.
|
||||
Please read:
|
||||
https://github.com/ksh93/ksh/pull/866#issuecomment-2968762167
|
||||
https://github.com/ksh93/ksh/issues/874#issuecomment-2977615731
|
||||
|
||||
- sh_main(): Do not attempt to optimize away sh_open() for the
|
||||
stdio fds (0, 1, 2) because that can cause buggy behavior. Ksh's
|
||||
handling of /dev/fd/1 and /dev/stdin should not differ. See:
|
||||
https://github.com/ksh93/ksh/pull/879#issuecomment-2989729921
|
||||
|
||||
- exfile(): Don't dup or close fds for /dev/fd scripts with a file
|
||||
descriptor > 2. Those should be left open pursuant to the $0 name
|
||||
of the script. (This cannot be done safely for fds 1 and 2, so
|
||||
the stdio fds are all dup'ed, but not closed.)
|
||||
|
||||
- sh_main(): If the fd obtained for the script by sh_open() is
|
||||
<= 2, that means the shell was opened with one of the stdio fds
|
||||
closed, so for correct behavior use sh_iomovefd() to keep the
|
||||
stdio fd closed.
|
||||
|
||||
- sh_iomovefd(): As an optimization, move the fd to a number that's
|
||||
either >= 3 or >= 10, depending on what is most appropriate. This
|
||||
avoids a possible inefficient scenario of dup'ing an fd from
|
||||
0 -> 3 -> 10 (less syscalls is better for performance).
|
||||
|
||||
- sh_main(): Use O_CLOEXEC in advance for the fd (which is
|
||||
guaranteed to get close-on-exec via a later fcntl call; if we
|
||||
don't end up calling fcntl for whatever reason O_CLOEXEC will
|
||||
help avoid an extra syscall).
|
||||
|
||||
- basic.sh: Add regression tests for $0 and its associated fd. For
|
||||
the time being I've omitted a /dev/fd/1 regression test because I
|
||||
can't get one to work correctly with the pty tool.
|
||||
|
||||
Resolves: https://github.com/ksh93/ksh/issues/874
|
||||
Resolves: https://github.com/ksh93/ksh/issues/877
|
||||
Resolves: https://github.com/ksh93/ksh/pull/879
|
||||
---
|
||||
diff --git a/src/cmd/ksh93/include/io.h b/src/cmd/ksh93/include/io.h
|
||||
index a128393..0c295dd 100644
|
||||
--- a/src/cmd/ksh93/include/io.h
|
||||
+++ b/src/cmd/ksh93/include/io.h
|
||||
@@ -67,7 +67,7 @@
|
||||
|
||||
extern int sh_iocheckfd(Shell_t*,int);
|
||||
extern void sh_ioinit(Shell_t*);
|
||||
-extern int sh_iomovefd(int);
|
||||
+extern int sh_iomovefd(int,int);
|
||||
extern int sh_iorenumber(Shell_t*,int,int);
|
||||
extern void sh_pclose(int[]);
|
||||
extern int sh_rpipe(int[]);
|
||||
diff --git a/src/cmd/ksh93/sh/init.c b/src/cmd/ksh93/sh/init.c
|
||||
index 4131666..7a933a2 100644
|
||||
--- a/src/cmd/ksh93/sh/init.c
|
||||
+++ b/src/cmd/ksh93/sh/init.c
|
||||
@@ -1509,10 +1509,7 @@ Shell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit)
|
||||
else
|
||||
sh_offoption(SH_PRIVILEGED);
|
||||
/* shname for $0 in profiles and . scripts */
|
||||
- if(sh_isdevfd(argv[1]))
|
||||
- shp->shname = strdup(argv[0]);
|
||||
- else
|
||||
- shp->shname = strdup(shp->st.dolv[0]);
|
||||
+ shp->shname = strdup(shp->st.dolv[0]);
|
||||
/*
|
||||
* return here for shell script execution
|
||||
* but not for parenthesis subshells
|
||||
diff --git a/src/cmd/ksh93/sh/io.c b/src/cmd/ksh93/sh/io.c
|
||||
index 8beb60b..9f326bb 100644
|
||||
--- a/src/cmd/ksh93/sh/io.c
|
||||
+++ b/src/cmd/ksh93/sh/io.c
|
||||
@@ -877,17 +877,17 @@ int sh_chkopen(register const char *name)
|
||||
}
|
||||
|
||||
/*
|
||||
- * move open file descriptor to a number > 2
|
||||
+ * move open file descriptor to a number >= minfd
|
||||
*/
|
||||
-int sh_iomovefd(register int fdold)
|
||||
+int sh_iomovefd(register int fdold, int minfd)
|
||||
{
|
||||
Shell_t *shp = sh_getinterp();
|
||||
register int fdnew;
|
||||
if(fdold >= shp->gd->lim.open_max)
|
||||
sh_iovalidfd(shp,fdold);
|
||||
- if(fdold<0 || fdold>2)
|
||||
+ if(fdold<0 || fdold>=minfd)
|
||||
return(fdold);
|
||||
- fdnew = sh_iomovefd(dup(fdold));
|
||||
+ fdnew = sh_iomovefd(dup(fdold),minfd);
|
||||
shp->fdstatus[fdnew] = (shp->fdstatus[fdold]&~IOCLEX);
|
||||
close(fdold);
|
||||
shp->fdstatus[fdold] = IOCLOSE;
|
||||
@@ -903,8 +903,8 @@ int sh_pipe(register int pv[])
|
||||
int fd[2];
|
||||
if(pipe(fd)<0 || (pv[0]=fd[0])<0 || (pv[1]=fd[1])<0)
|
||||
errormsg(SH_DICT,ERROR_system(1),e_pipe);
|
||||
- pv[0] = sh_iomovefd(pv[0]);
|
||||
- pv[1] = sh_iomovefd(pv[1]);
|
||||
+ pv[0] = sh_iomovefd(pv[0],3);
|
||||
+ pv[1] = sh_iomovefd(pv[1],3);
|
||||
shp->fdstatus[pv[0]] = IONOSEEK|IOREAD;
|
||||
shp->fdstatus[pv[1]] = IONOSEEK|IOWRITE;
|
||||
sh_subsavefd(pv[0]);
|
||||
@@ -926,8 +926,8 @@ int sh_pipe(register int pv[])
|
||||
int fd[2];
|
||||
if(pipe(fd)<0 || (pv[0]=fd[0])<0 || (pv[1]=fd[1])<0)
|
||||
errormsg(SH_DICT,ERROR_system(1),e_pipe);
|
||||
- pv[0] = sh_iomovefd(pv[0]);
|
||||
- pv[1] = sh_iomovefd(pv[1]);
|
||||
+ pv[0] = sh_iomovefd(pv[0],3);
|
||||
+ pv[1] = sh_iomovefd(pv[1],3);
|
||||
shp->fdstatus[pv[0]] = IONOSEEK|IOREAD;
|
||||
shp->fdstatus[pv[1]] = IONOSEEK|IOWRITE;
|
||||
sh_subsavefd(pv[0]);
|
||||
@@ -947,7 +947,7 @@ int sh_pipe(register int pv[])
|
||||
if((pv[out]=sh_fcntl(fd,F_DUPFD,10)) >=10)
|
||||
sh_close(fd);
|
||||
else
|
||||
- pv[out] = sh_iomovefd(fd);
|
||||
+ pv[out] = sh_iomovefd(fd,3);
|
||||
if(fcntl(pv[out],F_SETFD,FD_CLOEXEC) >=0)
|
||||
shp->fdstatus[pv[out]] |= IOCLEX;
|
||||
shp->fdstatus[pv[out]] = (out?IOWRITE:IOREAD);
|
||||
@@ -1338,7 +1338,7 @@ int sh_redirect(Shell_t *shp,struct ionod *iop, int flag)
|
||||
if(flag==SH_SHOWME)
|
||||
goto traceit;
|
||||
fd=sh_chkopen(fname);
|
||||
- fd=sh_iomovefd(fd);
|
||||
+ fd=sh_iomovefd(fd,3);
|
||||
}
|
||||
else if(sh_isoption(SH_RESTRICTED))
|
||||
errormsg(SH_DICT,ERROR_exit(1),e_restricted,fname);
|
||||
@@ -1540,7 +1540,7 @@ int sh_redirect(Shell_t *shp,struct ionod *iop, int flag)
|
||||
}
|
||||
else
|
||||
{
|
||||
- fd = sh_iorenumber(shp,sh_iomovefd(fd),fn);
|
||||
+ fd = sh_iorenumber(shp,sh_iomovefd(fd,3),fn);
|
||||
if(fn>2 && fn<10)
|
||||
shp->inuse_bits |= (1<<fn);
|
||||
}
|
||||
diff --git a/src/cmd/ksh93/sh/main.c b/src/cmd/ksh93/sh/main.c
|
||||
index 00a048b..079c2fd 100644
|
||||
--- a/src/cmd/ksh93/sh/main.c
|
||||
+++ b/src/cmd/ksh93/sh/main.c
|
||||
@@ -67,6 +67,9 @@ static void chkmail(Shell_t *shp, char*);
|
||||
static struct stat lastmail;
|
||||
static time_t mailtime;
|
||||
static char beenhere = 0;
|
||||
+#if SHOPT_DEVFD
|
||||
+#define GOT_DEVFD 2
|
||||
+#endif
|
||||
|
||||
#ifdef _lib_sigvec
|
||||
void clearsigmask(register int sig)
|
||||
@@ -160,8 +163,9 @@ int sh_main(int ac, char *av[], Shinit_f userinit)
|
||||
#if SHOPT_BRACEPAT
|
||||
sh_onoption(SH_BRACEEXPAND);
|
||||
#endif
|
||||
- if((beenhere++)==0)
|
||||
+ if(!beenhere)
|
||||
{
|
||||
+ beenhere = 1;
|
||||
sh_onstate(SH_PROFILE);
|
||||
((Lex_t*)shp->lex_context)->nonstandard = 0;
|
||||
if(shp->gd->ppid==1)
|
||||
@@ -257,21 +261,23 @@ int sh_main(int ac, char *av[], Shinit_f userinit)
|
||||
fdin = 0;
|
||||
else
|
||||
{
|
||||
- char *sp;
|
||||
+#if SHOPT_DEVFD
|
||||
/* open stream should have been passed into shell */
|
||||
- if(strmatch(name,e_devfdNN))
|
||||
+ if(strmatch(name,e_devfdNN) && (fdin=(int)strtol(name+8, NULL, 10)) > 2)
|
||||
{
|
||||
- fdin = (int)strtol(name+8, (char**)0, 10);
|
||||
if(fstat(fdin,&statb)<0)
|
||||
errormsg(SH_DICT,ERROR_system(1),e_open,name);
|
||||
name = av[0];
|
||||
sh_offoption(SH_VERBOSE);
|
||||
sh_offoption(SH_XTRACE);
|
||||
+ beenhere = GOT_DEVFD;
|
||||
}
|
||||
else
|
||||
+#endif /* SHOPT_DEVFD */
|
||||
{
|
||||
+ char *sp;
|
||||
int isdir = 0;
|
||||
- if((fdin=sh_open(name,O_RDONLY,0))>=0 &&(fstat(fdin,&statb)<0 || S_ISDIR(statb.st_mode)))
|
||||
+ if((fdin=sh_open(name,O_RDONLY|O_cloexec,0))>=0 &&(fstat(fdin,&statb)<0 || S_ISDIR(statb.st_mode)))
|
||||
{
|
||||
close(fdin);
|
||||
isdir = 1;
|
||||
@@ -290,7 +296,7 @@ int sh_main(int ac, char *av[], Shinit_f userinit)
|
||||
#endif
|
||||
if(sp)
|
||||
{
|
||||
- if((fdin=sh_open(sp,O_RDONLY,0))>=0)
|
||||
+ if((fdin=sh_open(sp,O_RDONLY|O_cloexec,0))>=0)
|
||||
shp->st.filename = path_fullname(shp,sp);
|
||||
}
|
||||
}
|
||||
@@ -309,8 +315,14 @@ int sh_main(int ac, char *av[], Shinit_f userinit)
|
||||
strcopy(name," \"$@\"");
|
||||
goto shell_c;
|
||||
}
|
||||
- if(fdin==0)
|
||||
- fdin = sh_iomovefd(fdin);
|
||||
+ /*
|
||||
+ * Note: fdin could wind up being zero or some such if the
|
||||
+ * shell was opened with stdin/stdout/stderr closed
|
||||
+ * (i.e. 0>&-), so we move the fd in such a case to
|
||||
+ * keep that file descriptor closed.
|
||||
+ */
|
||||
+ if(fdin<=2)
|
||||
+ fdin = sh_iomovefd(fdin,10);
|
||||
}
|
||||
shp->readscript = shp->shname;
|
||||
}
|
||||
@@ -356,15 +368,27 @@ static void exfile(register Shell_t *shp, register Sfio_t *iop,register int fno)
|
||||
{
|
||||
if(fno > 0)
|
||||
{
|
||||
- int r;
|
||||
- if(fno < 10 && ((r=sh_fcntl(fno,F_DUPFD,10))>=10))
|
||||
+#if SHOPT_DEVFD
|
||||
+ if(beenhere == GOT_DEVFD)
|
||||
+ ; /* leave the inherited /dev/fd as is */
|
||||
+ else
|
||||
+#endif
|
||||
{
|
||||
- shp->fdstatus[r] = shp->fdstatus[fno];
|
||||
- sh_close(fno);
|
||||
- fno = r;
|
||||
+ if(fno < 10)
|
||||
+ {
|
||||
+ int r = sh_fcntl(fno,F_DUPFD,10);
|
||||
+ if(r >= 10)
|
||||
+ {
|
||||
+ shp->fdstatus[r] = shp->fdstatus[fno];
|
||||
+ /* leave std* fds open when they're not explicitly closed */
|
||||
+ if(fno > 2)
|
||||
+ sh_close(fno);
|
||||
+ fno = r;
|
||||
+ }
|
||||
}
|
||||
fcntl(fno,F_SETFD,FD_CLOEXEC);
|
||||
shp->fdstatus[fno] |= IOCLEX;
|
||||
+ }
|
||||
iop = sh_iostream((void*)shp,fno);
|
||||
}
|
||||
else
|
||||
@@ -372,6 +396,7 @@ static void exfile(register Shell_t *shp, register Sfio_t *iop,register int fno)
|
||||
}
|
||||
else
|
||||
fno = -1;
|
||||
+ beenhere = 1;
|
||||
shp->infd = fno;
|
||||
if(sh_isstate(SH_INTERACTIVE))
|
||||
{
|
||||
diff --git a/src/cmd/ksh93/sh/path.c b/src/cmd/ksh93/sh/path.c
|
||||
index 993bdfd..05cd956 100644
|
||||
--- a/src/cmd/ksh93/sh/path.c
|
||||
+++ b/src/cmd/ksh93/sh/path.c
|
||||
@@ -525,7 +525,7 @@ static int path_opentype(Shell_t *shp,const char *name, register Pathcomp_t *pp,
|
||||
}
|
||||
}
|
||||
while( fd<0 && pp);
|
||||
- if(fd>=0 && (fd = sh_iomovefd(fd)) > 0)
|
||||
+ if(fd>=0 && (fd = sh_iomovefd(fd,10)) > 0)
|
||||
{
|
||||
fcntl(fd,F_SETFD,FD_CLOEXEC);
|
||||
shp->fdstatus[fd] |= IOCLEX;
|
||||
@@ -1280,7 +1280,7 @@ static void exscript(Shell_t *shp,register char *path,register char *argv[],char
|
||||
if((n=sh_open(path,O_RDONLY,0)) >= 0)
|
||||
{
|
||||
/* move <n> if n=0,1,2 */
|
||||
- n = sh_iomovefd(n);
|
||||
+ n = sh_iomovefd(n,10);
|
||||
if(fstat(n,&statb)>=0 && !(statb.st_mode&(S_ISUID|S_ISGID)))
|
||||
goto openok;
|
||||
sh_close(n);
|
||||
@@ -1321,7 +1321,7 @@ static void exscript(Shell_t *shp,register char *path,register char *argv[],char
|
||||
if((shp->infd = sh_open(path,O_RDONLY,0)) < 0)
|
||||
errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,path);
|
||||
#endif
|
||||
- shp->infd = sh_iomovefd(shp->infd);
|
||||
+ shp->infd = sh_iomovefd(shp->infd,10);
|
||||
#if SHOPT_ACCT
|
||||
sh_accbegin(path) ; /* reset accounting */
|
||||
#endif /* SHOPT_ACCT */
|
||||
diff --git a/src/cmd/ksh93/tests/basic.sh b/src/cmd/ksh93/tests/basic.sh
|
||||
index 1cab8e0..d09ede2 100755
|
||||
--- a/src/cmd/ksh93/tests/basic.sh
|
||||
+++ b/src/cmd/ksh93/tests/basic.sh
|
||||
@@ -514,4 +514,14 @@ $SHELL -xc '$(LD_LIBRARY_PATH=$LD_LIBRARY_PATH exec $SHELL -c :)' > /dev/null 2>
|
||||
|
||||
$SHELL 2> /dev/null -c $'for i;\ndo :;done' || err_exit 'for i ; <newline> not vaid'
|
||||
|
||||
+# ======
|
||||
+# $0 should be the /dev/fd path for scripts executed from a /dev/fd file
|
||||
+# https://github.com/ksh93/ksh/issues/874
|
||||
+# https://github.com/ksh93/ksh/pull/879
|
||||
+if ((SHOPT_DEVFD))
|
||||
+then got=$("$SHELL" <(echo 'echo $0'))
|
||||
+ [[ ${got:0:7} != '/dev/fd' ]] && err_exit '$0 is wrong for process substitution scripts' \\
|
||||
+ "(expected a /dev/fd file name, got $(printf %q "$got"))"
|
||||
+fi
|
||||
+
|
||||
exit $((Errors<125?Errors:125))
|
||||
@ -1,145 +0,0 @@
|
||||
From 4886463bb6d3df2b827d784a97e13c7765d57178 Mon Sep 17 00:00:00 2001
|
||||
From: Martijn Dekker <martijn@inlv.org>
|
||||
Date: Sat, 12 Feb 2022 21:27:36 +0000
|
||||
Subject: [PATCH] Disable broken KEYBD trap for multibyte characters
|
||||
|
||||
In UTF-8 locales, ksh breaks when a KEYBD trap is active, even a
|
||||
dummy no-op one like 'trap : KEYBD'. Entering multi-byte characters
|
||||
fails (the input is interrupted and a new prompt is displayed) and
|
||||
pasting content with multi-byte characters produces corrupted
|
||||
results.
|
||||
|
||||
The cause is that the KEYBD trap code is not multibyte-ready.
|
||||
Unfortunately nobody yet understands the edit.c code well enough
|
||||
to implement a proper fix. Pending that, this commit implements
|
||||
a workaround that at least avoids breaking the shell.
|
||||
|
||||
src/cmd/ksh93/edit/edit.c: ed_getchar():
|
||||
- When a multi-byte locale is active, do not trigger the the KEYBD
|
||||
trap except for ASCII characters (1-127).
|
||||
|
||||
Resolves: https://github.com/ksh93/ksh/issues/307
|
||||
|
||||
(cherry-picked from 4886463bb6d3df2b827d784a97e13c7765d57178)
|
||||
---
|
||||
src/cmd/ksh93/edit/edit.c | 5 ++++-
|
||||
src/cmd/ksh93/sh.1 | 4 ++++
|
||||
2 files changed, 8 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/cmd/ksh93/edit/edit.c b/src/cmd/ksh93/edit/edit.c
|
||||
index d9933b63bb6a..371f5a9ec8fb 100644
|
||||
--- a/src/cmd/ksh93/edit/edit.c
|
||||
+++ b/src/cmd/ksh93/edit/edit.c
|
||||
@@ -1122,7 +1122,10 @@ int ed_getchar(register Edit_t *ep,int mode)
|
||||
killpg(getpgrp(),SIGINT);
|
||||
siglongjmp(ep->e_env, UINTR);
|
||||
}
|
||||
- if(mode<=0 && ep->sh->st.trap[SH_KEYTRAP])
|
||||
+ if(mode<=0 && ep->sh->st.trap[SH_KEYTRAP]
|
||||
+ /* workaround for <https://github.com/ksh93/ksh/issues/307>:
|
||||
+ * do not trigger KEYBD for non-ASCII in multibyte locale */
|
||||
+ && (CC_NATIVE!=CC_ASCII || !mbwide() || c > -128))
|
||||
{
|
||||
ep->e_keytrap = 1;
|
||||
n=1;
|
||||
diff --git a/src/cmd/ksh93/sh.1 b/src/cmd/ksh93/sh.1
|
||||
index 841c28a43bb8..61f71c2d1698 100644
|
||||
--- a/src/cmd/ksh93/sh.1
|
||||
+++ b/src/cmd/ksh93/sh.1
|
||||
@@ -9062,6 +9062,10 @@ Thus, a trap on
|
||||
.B CHLD
|
||||
won't be executed until the foreground job terminates.
|
||||
.PP
|
||||
+In locales that use a multibyte character set such as UTF-8, the
|
||||
+.B KEYBD
|
||||
+trap is only triggered for ASCII characters (1-127).
|
||||
+.PP
|
||||
It is a good idea to leave a space after the comma operator in
|
||||
arithmetic expressions to prevent the comma from being interpreted
|
||||
as the decimal point character in certain locales.
|
||||
|
||||
From 96d73c08a2786806f3def1fda66641b81e0af988 Mon Sep 17 00:00:00 2001
|
||||
From: SHIMIZU Akifumi <shimizu.akifumi@fujitsu.com>
|
||||
Date: Mon, 7 Apr 2025 19:47:16 +0900
|
||||
Subject: [PATCH] Fix long multibyte characters paste issue via ssh (#840)
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
When I paste long multibyte characters(over 80 byte) to ksh via
|
||||
SSH, the characters are not displayed correctly. For example, the
|
||||
following input demonstrates the issue. ja_JP.UTF-8 encoding is
|
||||
used.
|
||||
|
||||
Expected command line display:
|
||||
$ echo "長い文字列を入れるとkshで文字列が乱れる場合があるようです"
|
||||
|
||||
Actual command line display:
|
||||
$ です"echo "長い文字列を入れるとkshで文字列が乱れる場合がある
|
||||
...with the cursor over the 'e' in 'echo'.
|
||||
|
||||
This issue appears to be caused by the ed_read() function splitting
|
||||
a multibyte character sequence when reading into an 80-byte buffer.
|
||||
This leads to incorrect character interpretation and display.
|
||||
|
||||
Therefore, we edited the code to handle the case where the buffer
|
||||
size is full in the middle of a multi-byte character.
|
||||
|
||||
src/cmd/ksh93/sh/edit.c:
|
||||
- putstack():
|
||||
- Before retrying to interpret a multibyte character in case of a
|
||||
split due to end of buffer, restore the start position 'p'.
|
||||
- Fix zeroing out errno = EILSEQ.
|
||||
- ed_getchar(): Avoid a potential buffer overflow in 'readin';
|
||||
allow for an extra multibyte character, not merely an extra byte.
|
||||
|
||||
Co-authored-by: Martijn Dekker <martijn@inlv.org>
|
||||
---
|
||||
src/cmd/ksh93/edit/edit.c | 12 +++++++-----
|
||||
1 files changed, 7 insertions(+), 5 deletions(-)
|
||||
diff --git a/src/cmd/ksh93/edit/edit.c b/src/cmd/ksh93/edit/edit.c
|
||||
index b0a8de5..d827331 100644
|
||||
--- a/src/cmd/ksh93/edit/edit.c
|
||||
+++ b/src/cmd/ksh93/edit/edit.c
|
||||
@@ -973,6 +973,7 @@ static int putstack(Edit_t *ep,char string[], register int nbyte, int type)
|
||||
}
|
||||
else
|
||||
{
|
||||
+ char *prevp = p;
|
||||
again:
|
||||
if((c=mbchar(p)) >=0)
|
||||
{
|
||||
@@ -980,19 +981,20 @@ static int putstack(Edit_t *ep,char string[], register int nbyte, int type)
|
||||
if(type)
|
||||
c = -c;
|
||||
}
|
||||
-#ifdef EILSEQ
|
||||
- else if(errno == EILSEQ)
|
||||
- errno = 0;
|
||||
-#endif
|
||||
else if((endp-p) < mbmax())
|
||||
{
|
||||
+ if(errno == EILSEQ)
|
||||
+ errno = 0;
|
||||
if ((c=ed_read(ep,ep->e_fd,endp, 1,0)) == 1)
|
||||
{
|
||||
+ p = prevp;
|
||||
*++endp = 0;
|
||||
goto again;
|
||||
}
|
||||
return(c);
|
||||
}
|
||||
+ else if(errno == EILSEQ)
|
||||
+ errno = 0;
|
||||
else
|
||||
{
|
||||
ed_ringbell();
|
||||
@@ -1044,7 +1046,7 @@ static int putstack(Edit_t *ep,char string[], register int nbyte, int type)
|
||||
int ed_getchar(register Edit_t *ep,int mode)
|
||||
{
|
||||
register int n, c;
|
||||
- char readin[LOOKAHEAD+1];
|
||||
+ char *readin = fmtbuf(LOOKAHEAD + mbmax());
|
||||
if(!ep->e_lookahead)
|
||||
{
|
||||
ed_flush(ep);
|
||||
@ -1,657 +0,0 @@
|
||||
From 502bf4d41e343d8365bb5a6f21d2c4cb18cc3bdc Mon Sep 17 00:00:00 2001
|
||||
From: Vincent Mihalkovic <vmihalko@redhat.com>
|
||||
Date: Mon, 21 Jul 2025 22:45:37 +0200
|
||||
Subject: [PATCH] From 970812e39c236ff385e440ac6d458d196c237667 Mon Sep 17
|
||||
00:00:00 2001 From: Johnothan King <johnothanking@protonmail.com> Date: Fri,
|
||||
13 Jun 2025 16:29:15 -0700 Subject: [PATCH] Fix arbitrary command
|
||||
execution/code injection bugs (#866)
|
||||
|
||||
* Security patch part 1
|
||||
|
||||
Never use $SHELL or sh.shpath when executing shebang-less scripts
|
||||
|
||||
- sh_ntfork(): Removed a misguided optimization that causes ksh to
|
||||
run scripts without a shebang using the binary pointed to by
|
||||
either $SHELL or sh.shpath. This has a few problems:
|
||||
- The shell in sh.shpath or more disastrously in $SHELL has
|
||||
no guarantee of being identical to the currently running
|
||||
copy of ksh93 or even existing at all, so using either is
|
||||
not only bogus, but potentially dangerous.
|
||||
- The optimization has no ability to pass down the current
|
||||
POSIX mode status to the script.
|
||||
- It's only activated for virtual subshells, resulting in
|
||||
arbitrarily different behavior depending on whether or
|
||||
not we're in a virtual subshell.
|
||||
- It does some weird stuff with /dev/fd that seems superfluous,
|
||||
and also lacks any SHOPT_DEVFD if directive. (Additionally,
|
||||
if it did have one, that stat(2) would likely become mere
|
||||
dead code and a waste of context switches.)
|
||||
|
||||
The optimization was probably intended to be used for running a
|
||||
shebang-less script via posix_spawn, which is ostensibly faster
|
||||
than fork. But this simply isn't possible without risking running
|
||||
the shebang-less script in a shell environment different from
|
||||
the current one. (If ksh were updated by the package manager
|
||||
while ksh is still running, this optimization would cause the
|
||||
script to run via the new version, rather than the currently
|
||||
running older version.) The optimization is unfixable by design,
|
||||
and as such must be removed to ensure correct behavior.
|
||||
|
||||
* Security patch part 2 (re: bae02c39)
|
||||
|
||||
rm setuid script code leading to arbitrary command execution
|
||||
|
||||
Changes:
|
||||
- Delete code for setuid scripts on "Solaris 2.5+" because it
|
||||
allows for arbitrary command execution. One millisecond you think
|
||||
you're launching ksh, the next you're at the mercy of a hijacker.
|
||||
Example:
|
||||
SHELL=/bin/ppmflash /bin/ksh -l /dev/fd/0 < <(true)
|
||||
MANPATH: usage: MANPATH flashfactor [ppmfile]
|
||||
flashfactor: 0.0 = original picture, 1.0 = total whiteout
|
||||
The pathshell() code doesn't *seem* to be vulnerable to privilege
|
||||
escalation, but who knows (cf. CVE-2019-14868; this might need its
|
||||
own CVE 2025. Maybe pathshell() should be scrapped entirely???)
|
||||
- Add fickle but functional regression test (you may need to pass
|
||||
KSH=/bin/ksh or some such to get it to fail against vulnerable
|
||||
versions of ksh). The test uses a login shell via the -l option,
|
||||
but the bug *does not* need a login shell. See:
|
||||
https://github.com/ksh93/ksh/issues/874#issue-3128739066
|
||||
Modify the execveat reproducer to pass along environ (which
|
||||
could include a hijacked SHELL), and you're in for a BAD time.
|
||||
|
||||
Maybe the deleted code (introduced sometime within the period of 1995
|
||||
and 1999) was relevant to some Solaris-specific use case or something.
|
||||
Maybe the erasure even causes an incompatibility. But that code must
|
||||
go; it's far too dangerous to execv whatever the hell pathshell gives
|
||||
us during **init**. (Need I bring CVE-2019-14868 back to remembrance
|
||||
again? This bug has similarities to that one.)
|
||||
|
||||
FWIW, all of the regression tests in the ksh and modernish suites pass
|
||||
with this patch applied.
|
||||
|
||||
* Security patch part 3
|
||||
|
||||
Delete pathshell() and replace uses of it with safer equivalents
|
||||
|
||||
This function is a dangerous attack vector that ought not remain
|
||||
in the code base. The value returned by astconf() is doubtless
|
||||
safer than what is returned by pathshell().
|
||||
|
||||
* Other changes
|
||||
|
||||
The libast pathprog function and prog feature test are now unused,
|
||||
and are removed.
|
||||
---
|
||||
src/cmd/ksh93/sh/init.c | 37 ---------
|
||||
src/cmd/ksh93/sh/main.c | 19 -----
|
||||
src/cmd/ksh93/sh/path.c | 2 -
|
||||
src/cmd/ksh93/sh/xec.c | 20 -----
|
||||
src/lib/libast/Mamfile | 28 +------
|
||||
src/lib/libast/comp/omitted.c | 2 +-
|
||||
src/lib/libast/features/prog | 12 ---
|
||||
src/lib/libast/include/ast.h | 2 -
|
||||
src/lib/libast/man/path.3 | 13 ----
|
||||
src/lib/libast/man/proc.3 | 5 +-
|
||||
src/lib/libast/misc/cmdarg.c | 2 +-
|
||||
src/lib/libast/misc/procopen.c | 2 +-
|
||||
src/lib/libast/path/pathprog.c | 128 --------------------------------
|
||||
src/lib/libast/path/pathshell.c | 112 ----------------------------
|
||||
14 files changed, 7 insertions(+), 377 deletions(-)
|
||||
delete mode 100644 src/lib/libast/features/prog
|
||||
delete mode 100644 src/lib/libast/path/pathprog.c
|
||||
delete mode 100644 src/lib/libast/path/pathshell.c
|
||||
|
||||
diff --git a/src/cmd/ksh93/sh/init.c b/src/cmd/ksh93/sh/init.c
|
||||
index 4adf9b0..4131666 100644
|
||||
--- a/src/cmd/ksh93/sh/init.c
|
||||
+++ b/src/cmd/ksh93/sh/init.c
|
||||
@@ -1400,43 +1400,6 @@ Shell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit)
|
||||
}
|
||||
*SHLVL->nvalue.ip +=1;
|
||||
nv_offattr(SHLVL,NV_IMPORT);
|
||||
-#if SHOPT_SPAWN
|
||||
- {
|
||||
- /*
|
||||
- * try to find the pathname for this interpreter
|
||||
- * try using environment variable _ or argv[0]
|
||||
- */
|
||||
- char *cp=nv_getval(L_ARGNOD);
|
||||
- char buff[PATH_MAX+1];
|
||||
- shp->gd->shpath = 0;
|
||||
-#if _AST_VERSION >= 20090202L
|
||||
- if((n = pathprog(NiL, buff, sizeof(buff))) > 0 && n <= sizeof(buff))
|
||||
- shp->gd->shpath = strdup(buff);
|
||||
-#else
|
||||
- sfprintf(shp->strbuf,"/proc/%d/exe",getpid());
|
||||
- if((n=readlink(sfstruse(shp->strbuf),buff,sizeof(buff)-1))>0)
|
||||
- {
|
||||
- buff[n] = 0;
|
||||
- shp->gd->shpath = strdup(buff);
|
||||
- }
|
||||
-#endif
|
||||
- else if((cp && (sh_type(cp)&SH_TYPE_SH)) || (argc>0 && strchr(cp= *argv,'/')))
|
||||
- {
|
||||
- if(*cp=='/')
|
||||
- shp->gd->shpath = strdup(cp);
|
||||
- else if(cp = nv_getval(PWDNOD))
|
||||
- {
|
||||
- int offset = staktell();
|
||||
- stakputs(cp);
|
||||
- stakputc('/');
|
||||
- stakputs(argv[0]);
|
||||
- pathcanon(stakptr(offset),PATH_DOTDOT);
|
||||
- shp->gd->shpath = strdup(stakptr(offset));
|
||||
- stakseek(offset);
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-#endif
|
||||
nv_putval(IFSNOD,(char*)e_sptbnl,NV_RDONLY);
|
||||
#if SHOPT_FS_3D
|
||||
nv_stack(VPATHNOD, &VPATH_init);
|
||||
diff --git a/src/cmd/ksh93/sh/main.c b/src/cmd/ksh93/sh/main.c
|
||||
index a9d8694..00a048b 100644
|
||||
--- a/src/cmd/ksh93/sh/main.c
|
||||
+++ b/src/cmd/ksh93/sh/main.c
|
||||
@@ -261,28 +261,9 @@ int sh_main(int ac, char *av[], Shinit_f userinit)
|
||||
/* open stream should have been passed into shell */
|
||||
if(strmatch(name,e_devfdNN))
|
||||
{
|
||||
-#if !_WINIX
|
||||
- char *cp;
|
||||
- int type;
|
||||
-#endif
|
||||
fdin = (int)strtol(name+8, (char**)0, 10);
|
||||
if(fstat(fdin,&statb)<0)
|
||||
errormsg(SH_DICT,ERROR_system(1),e_open,name);
|
||||
-#if !_WINIX
|
||||
- /*
|
||||
- * try to undo effect of solaris 2.5+
|
||||
- * change for argv for setuid scripts
|
||||
- */
|
||||
- if(((type = sh_type(cp = av[0])) & SH_TYPE_SH) && (!(name = nv_getval(L_ARGNOD)) || !((type = sh_type(cp = name)) & SH_TYPE_SH)))
|
||||
- {
|
||||
- av[0] = (type & SH_TYPE_LOGIN) ? cp : path_basename(cp);
|
||||
- /* exec to change $0 for ps */
|
||||
- execv(pathshell(),av);
|
||||
- /* exec fails */
|
||||
- shp->st.dolv[0] = av[0];
|
||||
- fixargs(shp->st.dolv,1);
|
||||
- }
|
||||
-#endif
|
||||
name = av[0];
|
||||
sh_offoption(SH_VERBOSE);
|
||||
sh_offoption(SH_XTRACE);
|
||||
diff --git a/src/cmd/ksh93/sh/path.c b/src/cmd/ksh93/sh/path.c
|
||||
index 98b7972..993bdfd 100644
|
||||
--- a/src/cmd/ksh93/sh/path.c
|
||||
+++ b/src/cmd/ksh93/sh/path.c
|
||||
@@ -1186,8 +1186,6 @@ retry:
|
||||
if(spawn)
|
||||
{
|
||||
#ifdef _lib_fork
|
||||
- if(shp->subshell)
|
||||
- return(-1);
|
||||
do
|
||||
{
|
||||
if((pid=fork())>0)
|
||||
diff --git a/src/cmd/ksh93/sh/xec.c b/src/cmd/ksh93/sh/xec.c
|
||||
index 928e6b1..21c9002 100644
|
||||
--- a/src/cmd/ksh93/sh/xec.c
|
||||
+++ b/src/cmd/ksh93/sh/xec.c
|
||||
@@ -4042,26 +4042,6 @@ static pid_t sh_ntfork(Shell_t *shp,const Shnode_t *t,char *argv[],int *jobid,in
|
||||
job_fork(-1);
|
||||
jobfork = 1;
|
||||
spawnpid = path_spawn(shp,path,argv,arge,pp,(grp<<1)|1);
|
||||
- if(spawnpid < 0 && errno==ENOEXEC)
|
||||
- {
|
||||
- char *devfd;
|
||||
- int fd = open(path,O_RDONLY);
|
||||
- argv[-1] = argv[0];
|
||||
- argv[0] = path;
|
||||
- if(fd>=0)
|
||||
- {
|
||||
- struct stat statb;
|
||||
- sfprintf(shp->strbuf,"/dev/fd/%d",fd);
|
||||
- if(stat(devfd=sfstruse(shp->strbuf),&statb)>=0)
|
||||
- argv[0] = devfd;
|
||||
- }
|
||||
- if(!shp->gd->shpath)
|
||||
- shp->gd->shpath = pathshell();
|
||||
- spawnpid = path_spawn(shp,shp->gd->shpath,&argv[-1],arge,pp,(grp<<1)|1);
|
||||
- if(fd>=0)
|
||||
- close(fd);
|
||||
- argv[0] = argv[-1];
|
||||
- }
|
||||
fail:
|
||||
if(jobfork && spawnpid<0)
|
||||
job_fork(0);
|
||||
diff --git a/src/lib/libast/Mamfile b/src/lib/libast/Mamfile
|
||||
index 77aed1b..8a8bcea 100644
|
||||
--- a/src/lib/libast/Mamfile
|
||||
+++ b/src/lib/libast/Mamfile
|
||||
@@ -1176,14 +1176,6 @@ meta pathbin.o %.c>%.o path/pathbin.c pathbin
|
||||
prev path/pathbin.c
|
||||
exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -Icomp -Iinclude -Istd -D_PACKAGE_ast -c path/pathbin.c
|
||||
done pathbin.o generated
|
||||
-make pathshell.o
|
||||
-make path/pathshell.c
|
||||
-prev include/ast.h implicit
|
||||
-done path/pathshell.c
|
||||
-meta pathshell.o %.c>%.o path/pathshell.c pathshell
|
||||
-prev path/pathshell.c
|
||||
-exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -Icomp -Iinclude -Istd -D_PACKAGE_ast -c path/pathshell.c
|
||||
-done pathshell.o generated
|
||||
make pathcd.o
|
||||
make path/pathcd.c
|
||||
make include/stk.h implicit
|
||||
@@ -1196,24 +1188,6 @@ meta pathcd.o %.c>%.o path/pathcd.c pathcd
|
||||
prev path/pathcd.c
|
||||
exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -Icomp -Iinclude -Istd -D_PACKAGE_ast -c path/pathcd.c
|
||||
done pathcd.o generated
|
||||
-make pathprog.o
|
||||
-make path/pathprog.c
|
||||
-make FEATURE/prog implicit
|
||||
-meta FEATURE/prog features/%>FEATURE/% features/prog prog
|
||||
-make features/prog
|
||||
-done features/prog
|
||||
-exec - iffe -v -X ast -X std -c '${CC} ${mam_cc_FLAGS} ${CCFLAGS} ${LDFLAGS} ' run features/prog
|
||||
-done FEATURE/prog generated
|
||||
-make include/ast_windows.h implicit
|
||||
-make windows.h implicit
|
||||
-done windows.h dontcare virtual
|
||||
-done include/ast_windows.h dontcare
|
||||
-prev include/ast.h implicit
|
||||
-done path/pathprog.c
|
||||
-meta pathprog.o %.c>%.o path/pathprog.c pathprog
|
||||
-prev path/pathprog.c
|
||||
-exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -Icomp -Iinclude -Istd -D_PACKAGE_ast -c path/pathprog.c
|
||||
-done pathprog.o generated
|
||||
make fs3d.o
|
||||
make misc/fs3d.c
|
||||
prev include/fs3d.h implicit
|
||||
@@ -6098,7 +6072,7 @@ prev obsolete/spawn.c
|
||||
exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -Icomp -Iinclude -Istd -D_PACKAGE_ast -c obsolete/spawn.c
|
||||
done spawn.o generated
|
||||
exec - ${AR} rc libast.a state.o transition.o opendir.o readdir.o rewinddir.o seekdir.o telldir.o getcwd.o fastfind.o hashalloc.o hashdump.o hashfree.o hashlast.o hashlook.o hashscan.o hashsize.o hashview.o hashwalk.o memhash.o memsum.o strhash.o strkey.o strsum.o stracmp.o strnacmp.o ccmap.o ccmapid.o ccnative.o chresc.o chrtoi.o
|
||||
-exec - ${AR} rc libast.a streval.o strexpr.o strmatch.o strcopy.o modei.o modex.o strmode.o strlcat.o strlcpy.o strlook.o strncopy.o strsearch.o strpsearch.o stresc.o stropt.o strtape.o strpcmp.o strnpcmp.o strvcmp.o strnvcmp.o tok.o tokline.o tokscan.o pathaccess.o pathcat.o pathcanon.o pathcheck.o pathpath.o pathexists.o pathfind.o pathkey.o pathprobe.o pathrepl.o pathnative.o pathposix.o pathtemp.o pathtmp.o pathstat.o pathgetlink.o pathsetlink.o pathbin.o pathshell.o pathcd.o pathprog.o fs3d.o ftwalk.o ftwflags.o fts.o astintercept.o conformance.o getenv.o setenviron.o optget.o optjoin.o optesc.o optctx.o strsort.o struniq.o magic.o mime.o mimetype.o signal.o sigflag.o systrace.o error.o errorf.o errormsg.o errorx.o localeconv.o setlocale.o translate.o catopen.o iconv.o lc.o lctab.o mc.o base64.o recfmt.o recstr.o reclen.o fmtrec.o fmtbase.o fmtbuf.o fmtclock.o fmtdev.o fmtelapsed.o fmterror.o fmtesc.o fmtfmt.o fmtfs.o fmtident.o fmtint.o fmtip4.o fmtip6.o fmtls.o fmtmatch.o fmtmode.o fmtnum.o fmtperm.o fmtre.o fmttime.o
|
||||
+exec - ${AR} rc libast.a streval.o strexpr.o strmatch.o strcopy.o modei.o modex.o strmode.o strlcat.o strlcpy.o strlook.o strncopy.o strsearch.o strpsearch.o stresc.o stropt.o strtape.o strpcmp.o strnpcmp.o strvcmp.o strnvcmp.o tok.o tokline.o tokscan.o pathaccess.o pathcat.o pathcanon.o pathcheck.o pathpath.o pathexists.o pathfind.o pathkey.o pathprobe.o pathrepl.o pathnative.o pathposix.o pathtemp.o pathtmp.o pathstat.o pathgetlink.o pathsetlink.o pathbin.o pathcd.o fs3d.o ftwalk.o ftwflags.o fts.o astintercept.o conformance.o getenv.o setenviron.o optget.o optjoin.o optesc.o optctx.o strsort.o struniq.o magic.o mime.o mimetype.o signal.o sigflag.o systrace.o error.o errorf.o errormsg.o errorx.o localeconv.o setlocale.o translate.o catopen.o iconv.o lc.o lctab.o mc.o base64.o recfmt.o recstr.o reclen.o fmtrec.o fmtbase.o fmtbuf.o fmtclock.o fmtdev.o fmtelapsed.o fmterror.o fmtesc.o fmtfmt.o fmtfs.o fmtident.o fmtint.o fmtip4.o fmtip6.o fmtls.o fmtmatch.o fmtmode.o fmtnum.o fmtperm.o fmtre.o fmttime.o
|
||||
exec - ${AR} rc libast.a fmtuid.o fmtgid.o fmtsignal.o fmtscale.o fmttmx.o fmttv.o fmtversion.o strelapsed.o strperm.o struid.o strgid.o strtoip4.o strtoip6.o stack.o stk.o swapget.o swapmem.o swapop.o swapput.o sigdata.o sigcrit.o sigunblock.o procopen.o procclose.o procrun.o procfree.o tmdate.o tmequiv.o tmfix.o tmfmt.o tmform.o tmgoff.o tminit.o tmleap.o tmlex.o tmlocale.o tmmake.o tmpoff.o tmscan.o tmsleep.o tmtime.o tmtype.o tmweek.o tmword.o tmzone.o tmxdate.o tmxduration.o tmxfmt.o tmxgettime.o tmxleap.o tmxmake.o tmxscan.o tmxsettime.o tmxsleep.o tmxtime.o tmxtouch.o tvcmp.o tvgettime.o tvsettime.o tvsleep.o tvtouch.o cmdarg.o vecargs.o vecfile.o vecfree.o vecload.o vecstring.o univdata.o touch.o mnt.o debug.o memccpy.o memchr.o memcmp.o memcpy.o memdup.o memmove.o memset.o mkdir.o mkfifo.o mknod.o rmdir.o remove.o rename.o link.o unlink.o strdup.o strchr.o strrchr.o strstr.o strtod.o strtold.o strtol.o strtoll.o strtoul.o strtoull.o strton.o strtonll.o strntod.o strntold.o strnton.o
|
||||
exec - ${AR} rc libast.a strntonll.o strntol.o strntoll.o strntoul.o strntoull.o strcasecmp.o strncasecmp.o strerror.o mktemp.o tmpnam.o fsync.o execlp.o execve.o execvp.o execvpe.o spawnveg.o vfork.o killpg.o hsearch.o tsearch.o getlogin.o putenv.o setenv.o unsetenv.o lstat.o statvfs.o eaccess.o gross.o omitted.o readlink.o symlink.o getpgrp.o setpgid.o setsid.o waitpid.o creat64.o fcntl.o open.o atexit.o getdents.o getwd.o dup2.o errno.o getpreroot.o ispreroot.o realopen.o setpreroot.o getgroups.o mount.o system.o iblocks.o modedata.o tmdata.o memfatal.o sfkeyprintf.o sfdcdio.o sfdcdos.o sfdcfilter.o sfdcseekable.o sfdcslow.o sfdcsubstr.o sfdctee.o sfdcunion.o sfdcmore.o sfdcprefix.o wc.o wc2utf8.o basename.o closelog.o dirname.o fmtmsglib.o fnmatch.o ftw.o getdate.o getsubopt.o glob.o nftw.o openlog.o re_comp.o resolvepath.o realpath.o regcmp.o regexp.o setlogmask.o strftime.o strptime.o swab.o syslog.o tempnam.o wordexp.o mktime.o regalloc.o regclass.o regcoll.o regcomp.o regcache.o regdecomp.o regerror.o regexec.o regfatal.o reginit.o
|
||||
exec - ${AR} rc libast.a regnexec.o regsubcomp.o regsubexec.o regsub.o regrecord.o regrexec.o regstat.o dtclose.o dtdisc.o dthash.o dtlist.o dtmethod.o dtopen.o dtstrhash.o dttree.o dtview.o dtwalk.o dtnew.o dtcomp.o sfclose.o sfclrlock.o sfdisc.o sfdlen.o sfexcept.o sfgetl.o sfgetu.o sfcvt.o sfecvt.o sffcvt.o sfextern.o sffilbuf.o sfflsbuf.o sfprints.o sfgetd.o sfgetr.o sfllen.o sfmode.o sfmove.o sfnew.o sfpkrd.o sfnotify.o sfnputc.o sfopen.o sfpeek.o sfpoll.o sfpool.o sfpopen.o sfprintf.o sfputd.o sfputl.o sfputr.o sfputu.o sfrd.o sfread.o sfreserve.o sfscanf.o sfseek.o sfset.o sfsetbuf.o sfsetfd.o sfsize.o sfsk.o sfstack.o sfstrtod.o sfsync.o sfswap.o sftable.o sftell.o sftmp.o sfungetc.o sfvprintf.o sfvscanf.o sfwr.o sfwrite.o sfpurge.o sfraise.o sfwalk.o sfgetm.o sfmutex.o sfputm.o sfresize.o _sfclrerr.o _sfeof.o _sferror.o _sffileno.o _sfopen.o _sfstacked.o _sfvalue.o _sfgetc.o _sfgetl.o _sfgetl2.o _sfgetu.o _sfgetu2.o _sfdlen.o _sfllen.o _sfslen.o _sfulen.o _sfputc.o _sfputd.o _sfputl.o _sfputm.o
|
||||
diff --git a/src/lib/libast/comp/omitted.c b/src/lib/libast/comp/omitted.c
|
||||
index b517965..0f24dbf 100644
|
||||
--- a/src/lib/libast/comp/omitted.c
|
||||
+++ b/src/lib/libast/comp/omitted.c
|
||||
@@ -514,7 +514,7 @@ runve(int mode, const char* path, char* const* argv, char* const* envv)
|
||||
p = v;
|
||||
*p++ = (char*)path;
|
||||
*p++ = (char*)path;
|
||||
- path = (const char*)pathshell();
|
||||
+ path = "/bin/sh.exe";
|
||||
if (*argv)
|
||||
argv++;
|
||||
while (*p++ = (char*)*argv++);
|
||||
diff --git a/src/lib/libast/features/prog b/src/lib/libast/features/prog
|
||||
deleted file mode 100644
|
||||
index 365ce88..0000000
|
||||
--- a/src/lib/libast/features/prog
|
||||
+++ /dev/null
|
||||
@@ -1,12 +0,0 @@
|
||||
-lib getexecname,_NSGetExecutablePath
|
||||
-
|
||||
-tst run{
|
||||
- for p in /proc/self/exe /proc/self/path/a.out
|
||||
- do if test -e $p
|
||||
- then echo "#define _PROC_PROG \"$p\""
|
||||
- break
|
||||
- fi
|
||||
- done
|
||||
-}end
|
||||
-
|
||||
-_hdr_macho_o_dyld = hdr mach-o/dyld
|
||||
diff --git a/src/lib/libast/include/ast.h b/src/lib/libast/include/ast.h
|
||||
index f4bbe6d..7a5e0a0 100644
|
||||
--- a/src/lib/libast/include/ast.h
|
||||
+++ b/src/lib/libast/include/ast.h
|
||||
@@ -324,11 +324,9 @@ extern char* pathpath_20100601(const char*, const char*, int, char*, size_t);
|
||||
extern size_t pathposix(const char*, char*, size_t);
|
||||
extern char* pathprobe(char*, char*, const char*, const char*, const char*, int);
|
||||
extern char* pathprobe_20100601(const char*, const char*, const char*, int, char*, size_t, char*, size_t);
|
||||
-extern size_t pathprog(const char*, char*, size_t);
|
||||
extern char* pathrepl(char*, const char*, const char*);
|
||||
extern char* pathrepl_20100601(char*, size_t, const char*, const char*);
|
||||
extern int pathsetlink(const char*, const char*);
|
||||
-extern char* pathshell(void);
|
||||
extern char* pathtemp(char*, size_t, const char*, const char*, int*);
|
||||
extern char* pathtmp(char*, const char*, const char*, int*);
|
||||
extern char* setenviron(const char*);
|
||||
diff --git a/src/lib/libast/man/path.3 b/src/lib/libast/man/path.3
|
||||
index 8721888..03a17e5 100644
|
||||
--- a/src/lib/libast/man/path.3
|
||||
+++ b/src/lib/libast/man/path.3
|
||||
@@ -56,7 +56,6 @@ char* pathpath(char* \fIpath\fP, const char* \fIp\fP, const char* \fIa\fP, i
|
||||
char* pathprobe(char* \fIpath\fP, char* \fIattr\fP, const char* \fIlang\fP, const char* \fItool\fP, const char* \fIproc\fP, int \fIop\fP);
|
||||
char* pathrepl(char* \fIpath\fP, const char* \fImatch\fP, const char* \fIreplace\fP);
|
||||
int pathsetlink(const char* \fItext\fP, char* \fIname\fP);
|
||||
-char* pathshell(void);
|
||||
int pathstat(const char* \fIpath\fP, struct stat* \fIst\fP);
|
||||
char* pathtemp(char* \fIpath\fP, const char* \fIdir\fP, const char* \fIpfx\fP);
|
||||
.EE
|
||||
@@ -338,18 +337,6 @@ above for weird
|
||||
.IR universe (1)
|
||||
interactions hidden by this routine.
|
||||
.PP
|
||||
-.L pathshell
|
||||
-returns a pointer to the pathname for the shell for the current process.
|
||||
-The
|
||||
-.L SHELL
|
||||
-environment variable is first consulted, but is rejected under suspicious
|
||||
-ownership/setuid conditions of if it seems to point to
|
||||
-.IR csh (1) ;
|
||||
-otherwise
|
||||
-.L confstr(_CS_SHELL,...)
|
||||
-is used.
|
||||
-A valid string is always returned.
|
||||
-.PP
|
||||
.L pathstat
|
||||
first tries
|
||||
.LI stat( path,st )
|
||||
diff --git a/src/lib/libast/man/proc.3 b/src/lib/libast/man/proc.3
|
||||
index 64c1a6e..21e9bca 100644
|
||||
--- a/src/lib/libast/man/proc.3
|
||||
+++ b/src/lib/libast/man/proc.3
|
||||
@@ -79,8 +79,9 @@ If
|
||||
.I command
|
||||
is
|
||||
.L 0
|
||||
-then the current shell is used (see
|
||||
-.IR pathshell (3)).
|
||||
+then the shell returned by
|
||||
+.IR astconf (3)
|
||||
+is used.
|
||||
If
|
||||
.I envv
|
||||
is not
|
||||
diff --git a/src/lib/libast/misc/cmdarg.c b/src/lib/libast/misc/cmdarg.c
|
||||
index c6b99c8..63cc93b 100644
|
||||
--- a/src/lib/libast/misc/cmdarg.c
|
||||
+++ b/src/lib/libast/misc/cmdarg.c
|
||||
@@ -131,7 +131,7 @@ cmdopen_20120411(char** argv, int argmax, int size, const char* argpat, Cmddisc_
|
||||
x = ARG_MAX;
|
||||
if (size <= 0 || size > x)
|
||||
size = x;
|
||||
- sh = pathshell();
|
||||
+ sh = astconf("SH", NiL, NiL);
|
||||
m = n + (argc + 4) * sizeof(char**) + strlen(sh) + 1;
|
||||
m = roundof(m, sizeof(char**));
|
||||
if (size < m)
|
||||
diff --git a/src/lib/libast/misc/procopen.c b/src/lib/libast/misc/procopen.c
|
||||
index 2af92e7..783f0cc 100644
|
||||
--- a/src/lib/libast/misc/procopen.c
|
||||
+++ b/src/lib/libast/misc/procopen.c
|
||||
@@ -768,7 +768,7 @@ sfsync(sfstderr);
|
||||
*p = path;
|
||||
*--p = "sh";
|
||||
}
|
||||
- strcpy(env + 2, (flags & PROC_PARANOID) ? astconf("SH", NiL, NiL) : pathshell());
|
||||
+ strcpy(env + 2, astconf("SH", NiL, NiL));
|
||||
if (forked || (flags & PROC_OVERLAY))
|
||||
execve(env + 2, p, environ);
|
||||
#if _use_spawnveg
|
||||
diff --git a/src/lib/libast/path/pathprog.c b/src/lib/libast/path/pathprog.c
|
||||
deleted file mode 100644
|
||||
index 62e9653..0000000
|
||||
--- a/src/lib/libast/path/pathprog.c
|
||||
+++ /dev/null
|
||||
@@ -1,128 +0,0 @@
|
||||
-/***********************************************************************
|
||||
-* *
|
||||
-* This software is part of the ast package *
|
||||
-* Copyright (c) 1985-2012 AT&T Intellectual Property *
|
||||
-* and is licensed under the *
|
||||
-* Eclipse Public License, Version 1.0 *
|
||||
-* by AT&T Intellectual Property *
|
||||
-* *
|
||||
-* A copy of the License is available at *
|
||||
-* http://www.eclipse.org/org/documents/epl-v10.html *
|
||||
-* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
|
||||
-* *
|
||||
-* Information and Software Systems Research *
|
||||
-* AT&T Research *
|
||||
-* Florham Park NJ *
|
||||
-* *
|
||||
-* Glenn Fowler <gsf@research.att.com> *
|
||||
-* David Korn <dgk@research.att.com> *
|
||||
-* Phong Vo <kpv@research.att.com> *
|
||||
-* *
|
||||
-***********************************************************************/
|
||||
-#pragma prototyped
|
||||
-/*
|
||||
- * Glenn Fowler
|
||||
- * AT&T Research
|
||||
- *
|
||||
- * return the full path of the current program in path
|
||||
- * command!=0 is used as a default
|
||||
- */
|
||||
-
|
||||
-#include <ast.h>
|
||||
-
|
||||
-#if _WINIX
|
||||
-#include <ast_windows.h>
|
||||
-#include <ctype.h>
|
||||
-#endif
|
||||
-
|
||||
-#include "FEATURE/prog"
|
||||
-
|
||||
-#if _hdr_macho_o_dyld && _lib__NSGetExecutablePath
|
||||
-#include <mach-o/dyld.h>
|
||||
-#else
|
||||
-#undef _lib__NSGetExecutablePath
|
||||
-#endif
|
||||
-
|
||||
-static size_t
|
||||
-prog(const char* command, char* path, size_t size)
|
||||
-{
|
||||
- ssize_t n;
|
||||
- char* s;
|
||||
-#if _WINIX
|
||||
- char* t;
|
||||
- char* e;
|
||||
- int c;
|
||||
- int q;
|
||||
-#endif
|
||||
-#if _lib__NSGetExecutablePath
|
||||
- uint32_t z;
|
||||
-#endif
|
||||
-
|
||||
-#ifdef _PROC_PROG
|
||||
- if ((n = readlink(_PROC_PROG, path, size)) > 0 && *path == '/')
|
||||
- {
|
||||
- if (n < size)
|
||||
- path[n] = 0;
|
||||
- return n;
|
||||
- }
|
||||
-#endif
|
||||
-#if _lib_getexecname
|
||||
- if ((s = (char*)getexecname()) && *s == '/')
|
||||
- goto found;
|
||||
-#endif
|
||||
-#if _lib__NSGetExecutablePath
|
||||
- z = size;
|
||||
- if (!_NSGetExecutablePath(path, &z) && *path == '/')
|
||||
- return strlen(path);
|
||||
-#endif
|
||||
-#if _WINIX
|
||||
- if (s = GetCommandLine())
|
||||
- {
|
||||
- n = 0;
|
||||
- q = 0;
|
||||
- t = path;
|
||||
- e = path + size - 1;
|
||||
- while (c = *s++)
|
||||
- {
|
||||
- if (c == q)
|
||||
- q = 0;
|
||||
- else if (!q && c == '"')
|
||||
- q = c;
|
||||
- else if (!q && isspace(c))
|
||||
- break;
|
||||
- else if (t < e)
|
||||
- *t++ = c == '\\' ? '/' : c;
|
||||
- else
|
||||
- n++;
|
||||
- }
|
||||
- if (t < e)
|
||||
- *t = 0;
|
||||
- return (t - path) + n;
|
||||
- }
|
||||
-#endif
|
||||
- if (command)
|
||||
- {
|
||||
- s = (char*)command;
|
||||
- goto found;
|
||||
- }
|
||||
- return 0;
|
||||
- found:
|
||||
- n = strlen(s);
|
||||
- if (n < size)
|
||||
- memcpy(path, s, n + 1);
|
||||
- return n;
|
||||
-}
|
||||
-
|
||||
-size_t
|
||||
-pathprog(const char* command, char* path, size_t size)
|
||||
-{
|
||||
- char* rel;
|
||||
- ssize_t n;
|
||||
-
|
||||
- if ((n = prog(command, path, size)) > 0 && n < size && *path != '/' && (rel = strdup(path)))
|
||||
- {
|
||||
- n = pathpath(rel, NiL, PATH_REGULAR|PATH_EXECUTE, path, size) ? strlen(path) : 0;
|
||||
- free(rel);
|
||||
- }
|
||||
- return n;
|
||||
-}
|
||||
diff --git a/src/lib/libast/path/pathshell.c b/src/lib/libast/path/pathshell.c
|
||||
deleted file mode 100644
|
||||
index f4b2557..0000000
|
||||
--- a/src/lib/libast/path/pathshell.c
|
||||
+++ /dev/null
|
||||
@@ -1,112 +0,0 @@
|
||||
-/***********************************************************************
|
||||
-* *
|
||||
-* This software is part of the ast package *
|
||||
-* Copyright (c) 1985-2011 AT&T Intellectual Property *
|
||||
-* and is licensed under the *
|
||||
-* Eclipse Public License, Version 1.0 *
|
||||
-* by AT&T Intellectual Property *
|
||||
-* *
|
||||
-* A copy of the License is available at *
|
||||
-* http://www.eclipse.org/org/documents/epl-v10.html *
|
||||
-* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
|
||||
-* *
|
||||
-* Information and Software Systems Research *
|
||||
-* AT&T Research *
|
||||
-* Florham Park NJ *
|
||||
-* *
|
||||
-* Glenn Fowler <gsf@research.att.com> *
|
||||
-* David Korn <dgk@research.att.com> *
|
||||
-* Phong Vo <kpv@research.att.com> *
|
||||
-* *
|
||||
-***********************************************************************/
|
||||
-#pragma prototyped
|
||||
-/*
|
||||
- * G. S. Fowler
|
||||
- * D. G. Korn
|
||||
- * AT&T Bell Laboratories
|
||||
- *
|
||||
- * shell library support
|
||||
- */
|
||||
-
|
||||
-#include <ast.h>
|
||||
-#include <sys/stat.h>
|
||||
-
|
||||
-/*
|
||||
- * return pointer to the full path name of the shell
|
||||
- *
|
||||
- * SHELL is read from the environment and must start with /
|
||||
- *
|
||||
- * if set-uid or set-gid then the executable and its containing
|
||||
- * directory must not be owned by the real user/group
|
||||
- *
|
||||
- * root/administrator has its own test
|
||||
- *
|
||||
- * astconf("SH",NiL,NiL) is returned by default
|
||||
- *
|
||||
- * NOTE: csh is rejected because the bsh/csh differentiation is
|
||||
- * not done for `csh script arg ...'
|
||||
- */
|
||||
-
|
||||
-char*
|
||||
-pathshell(void)
|
||||
-{
|
||||
- register char* sh;
|
||||
- int ru;
|
||||
- int eu;
|
||||
- int rg;
|
||||
- int eg;
|
||||
- struct stat st;
|
||||
-
|
||||
- static char* val;
|
||||
-
|
||||
- if ((sh = getenv("SHELL")) && *sh == '/' && strmatch(sh, "*/(sh|*[!cC]sh)*([[:digit:]])?(-+([.[:alnum:]]))?(.exe)"))
|
||||
- {
|
||||
- if (!(ru = getuid()) || !eaccess("/bin", W_OK))
|
||||
- {
|
||||
- if (stat(sh, &st))
|
||||
- goto defshell;
|
||||
- if (ru != st.st_uid && !strmatch(sh, "?(/usr)?(/local)/?([ls])bin/?([[:lower:]])sh?(.exe)"))
|
||||
- goto defshell;
|
||||
- }
|
||||
- else
|
||||
- {
|
||||
- eu = geteuid();
|
||||
- rg = getgid();
|
||||
- eg = getegid();
|
||||
- if (ru != eu || rg != eg)
|
||||
- {
|
||||
- char* s;
|
||||
- char dir[PATH_MAX];
|
||||
-
|
||||
- s = sh;
|
||||
- for (;;)
|
||||
- {
|
||||
- if (stat(s, &st))
|
||||
- goto defshell;
|
||||
- if (ru != eu && st.st_uid == ru)
|
||||
- goto defshell;
|
||||
- if (rg != eg && st.st_gid == rg)
|
||||
- goto defshell;
|
||||
- if (s != sh)
|
||||
- break;
|
||||
- if (strlen(s) >= sizeof(dir))
|
||||
- goto defshell;
|
||||
- strcpy(dir, s);
|
||||
- if (!(s = strrchr(dir, '/')))
|
||||
- break;
|
||||
- *s = 0;
|
||||
- s = dir;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- return sh;
|
||||
- }
|
||||
- defshell:
|
||||
- if (!(sh = val))
|
||||
- {
|
||||
- if (!*(sh = astconf("SH", NiL, NiL)) || *sh != '/' || eaccess(sh, X_OK) || !(sh = strdup(sh)))
|
||||
- sh = "/bin/sh";
|
||||
- val = sh;
|
||||
- }
|
||||
- return sh;
|
||||
-}
|
||||
--
|
||||
2.50.0
|
||||
|
||||
@ -6,7 +6,7 @@ Summary: The Original ATT Korn Shell
|
||||
URL: http://www.kornshell.com/
|
||||
License: EPL-1.0
|
||||
Version: %{releasedate}
|
||||
Release: 271%{?dist}
|
||||
Release: 267%{?dist}
|
||||
Source0: http://www.research.att.com/~gsf/download/tgz/ast-ksh.%{release_date}.tgz
|
||||
Source1: http://www.research.att.com/~gsf/download/tgz/INIT.%{release_date}.tgz
|
||||
Source2: kshcomp.conf
|
||||
@ -258,19 +258,6 @@ Patch99: %{name}-1.0.7-history-trim.patch
|
||||
# upstream commit: https://github.com/ksh93/ksh/commit/91a7c2e3e9feb8ac1391146ebcda9e6adfcd3cfb
|
||||
Patch100: ksh-20120801-subshell-interrupt-segv.patch
|
||||
|
||||
# RHEL-87334
|
||||
# upstream commit: https://github.com/ksh93/ksh/commit/4886463bb6d3df2b827d784a97e13c7765d57178
|
||||
# upstream commit: https://github.com/ksh93/ksh/commit/96d73c08a2786806f3def1fda66641b81e0af988
|
||||
Patch101: ksh-1.0.11-ssh-multibyte-long-paste.patch
|
||||
|
||||
# RHEL-92629
|
||||
# https://github.com/ksh93/ksh/commit/970812e39c236ff385e440ac6d458d196c237667
|
||||
Patch102: ksh-1.0.12-security.patch
|
||||
|
||||
# upstream commit: https://github.com/ksh93/ksh/commit/c2cfcfc6f4b2d63472b2290debb9d0bb84c932df
|
||||
# Fix $0 reporting /usr/bin/ksh instead of script name for /dev/fd scripts
|
||||
Patch103: ksh-1.0.11-devfd-memory-fault.patch
|
||||
|
||||
Conflicts: pdksh
|
||||
Requires: coreutils, diffutils, chkconfig
|
||||
BuildRequires: bison
|
||||
@ -424,22 +411,6 @@ fi
|
||||
%config(noreplace) %{_sysconfdir}/binfmt.d/kshcomp.conf
|
||||
|
||||
%changelog
|
||||
* Mon Feb 09 2026 Vincent Mihalkovic <vmihalko@redhat.com> - 20120801-271
|
||||
- Fix $0 reporting /usr/bin/ksh instead of script name for /dev/fd scripts
|
||||
Resolves: RHEL-92633
|
||||
|
||||
* Mon Jul 21 2025 Vincent Mihalkovic <vmihalko@redhat.com> - 20120801-270
|
||||
- Fix arbitrary command execution/code injection bugs
|
||||
RHEL-92629
|
||||
|
||||
* Wed Jun 25 2025 Lukáš Zaoral <lzaoral@redhat.com> - 20120801-269
|
||||
- Further fix long multibyte characters paste issue via ssh
|
||||
Resolves: RHEL-87334
|
||||
|
||||
* Tue Apr 22 2025 Vincent Mihalkovic <vmihalko@redhat.com> - 20120801-268
|
||||
- Fix long multibyte characters paste issue via ssh
|
||||
Resolves: RHEL-87334
|
||||
|
||||
* Fri Feb 09 2024 Vincent Mihalkovic <vmihalko@redhat.com> - 20120801-267
|
||||
- Re-fix segfault in strdup
|
||||
Resolves: RHEL-11982
|
||||
|
||||
Loading…
Reference in New Issue
Block a user