Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@ 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.

2025-07-10:

- Fixed a file descriptor leak introduced in 93u+ 2012-07-27 that occurred
when forking nested subshells.

- Fixed a bug that could cause cd(1) to fail with the wrong error message
if the underlying close(2) calls failed after cd failed to change the
directory with fchdir(2).

- Fixed a file descriptor leak that could occur on systems lacking a
useable implementation of arc4random(3).

2025-06-14:

- Fixed a bug occurring on systems with posix_spawn(3), spawnve(2), and
Expand Down
12 changes: 6 additions & 6 deletions src/cmd/builtin/pty.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ mkpty(int* master, int* minion)
return -1;
if (grantpt(*master) || unlockpt(*master) || !(sname = ptsname(*master)) || (*minion = open(sname, O_RDWR|O_cloexec)) < 0)
{
close(*master);
ast_close(*master);
return -1;
}
#else
Expand All @@ -325,8 +325,8 @@ mkpty(int* master, int* minion)
struct termios tst;
if (tcgetattr(*minion, &tst) < 0 && (ioctl(*minion, I_PUSH, "ptem") < 0 || ioctl(*minion, I_PUSH, "ldterm") < 0))
{
close(*minion);
close(*master);
ast_close(*minion);
ast_close(*master);
return -1;
}
}
Expand Down Expand Up @@ -1121,7 +1121,7 @@ b_pty(int argc, char** argv, Shbltin_t* context)
error(ERROR_system(1), "unable run %s", argv[0]);
UNREACHABLE();
}
close(minion);
ast_close(minion);
if (messages)
{
drop = 1;
Expand All @@ -1136,10 +1136,10 @@ b_pty(int argc, char** argv, Shbltin_t* context)
error(ERROR_system(1), "%s: cannot redirect messages", messages);
UNREACHABLE();
}
close(2);
ast_close(2);
dup(fd);
if (drop)
close(fd);
ast_close(fd);
}
minion = (*fun)(mp, lp, delay, timeout);
master = procclose(proc);
Expand Down
15 changes: 10 additions & 5 deletions src/cmd/ksh93/bltins/cd_pwd.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ int sh_diropenat(int dir, const char *path)
}
if(fd < 10)
{
/* Duplicate the fd and register it with the shell */
int shfd = sh_fcntl(fd, F_dupfd_cloexec, 10);
close(fd);
/* Duplicate the fd */
int shfd = fcntl(fd, F_dupfd_cloexec, 10);
ast_close(fd);
if(shfd < 0)
return shfd;
if(F_dupfd_cloexec == F_DUPFD)
Expand All @@ -81,7 +81,8 @@ int sh_diropenat(int dir, const char *path)
else if(O_cloexec == 0)
needs_cloexec = 1;
if(needs_cloexec)
sh_fcntl(fd,F_SETFD,FD_CLOEXEC);
fcntl(fd,F_SETFD,FD_CLOEXEC);
sh.fdstatus[fd] = (IOREAD|IOCLEX);
return fd;
}
#endif /* _lib_openat */
Expand All @@ -92,7 +93,7 @@ int b_cd(int argc, char *argv[],Shbltin_t *context)
Pathcomp_t *cdpath = 0;
const char *dp;
int saverrno=0;
int rval,pflag=0,eflag=0,ret=1;
int rval,pflag=0,eflag=0,ret=1,saverr;
char *oldpwd, *cp;
Namval_t *opwdnod, *pwdnod;
#if _lib_openat
Expand Down Expand Up @@ -240,7 +241,9 @@ int b_cd(int argc, char *argv[],Shbltin_t *context)
sh_pwdupdate(newdirfd);
goto success;
}
saverr = errno;
sh_close(newdirfd);
errno = saverr;
}
#if !O_SEARCH
else if((rval=chdir(cp)) >= 0)
Expand Down Expand Up @@ -268,7 +271,9 @@ int b_cd(int argc, char *argv[],Shbltin_t *context)
sh_pwdupdate(newdirfd);
goto success;
}
saverr = errno;
sh_close(newdirfd);
errno = saverr;
}
#if !O_SEARCH
else if((rval=chdir(dir)) >= 0)
Expand Down
10 changes: 5 additions & 5 deletions src/cmd/ksh93/bltins/mkservice.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ static void process_stream(Sfio_t* iop)
r = (*sp->actionf)(sp, fd, 0);
service_list[fd] = sp;
if(r<0)
close(fd);
ast_close(fd);
}
}

Expand Down Expand Up @@ -284,7 +284,7 @@ static int Accept(Service_t *sp, int accept_fd)
fd = fcntl(accept_fd, F_DUPFD, 10);
if (fd >= 0)
{
close(accept_fd);
ast_close(accept_fd);
if (nq)
{
char* av[3];
Expand All @@ -295,7 +295,7 @@ static int Accept(Service_t *sp, int accept_fd)
sfsprintf(buff, sizeof(buff), "%d", fd);
if (sh_fun(nq, sp->node, av))
{
close(fd);
ast_close(fd);
return -1;
}
}
Expand Down Expand Up @@ -382,7 +382,7 @@ static void putval(Namval_t* np, const char* val, int flag, Namfun_t* fp)
{
if(service_list[i]==sp)
{
close(i);
ast_close(i);
if(--sp->refcount<=0)
break;
}
Expand Down Expand Up @@ -447,7 +447,7 @@ int b_mkservice(int argc, char** argv, Shbltin_t *context)
UNREACHABLE();
}
if((sp->fd = fcntl(fd, F_DUPFD, 10))>=10)
close(fd);
ast_close(fd);
else
sp->fd = fd;
np = nv_open(var,sh.var_tree,NV_ARRAY|NV_VARNAME);
Expand Down
9 changes: 6 additions & 3 deletions src/cmd/ksh93/bltins/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,7 @@ static int test_mode(const char *file)
}

/*
* do an fstat() for /dev/fd/n, otherwise stat()
* do an fstat() for /dev/fd/n or PWD's fd for better performance, otherwise stat()
*/
static int test_stat(const char *name,struct stat *buff)
{
Expand All @@ -715,8 +715,11 @@ static int test_stat(const char *name,struct stat *buff)
errno = ENOENT;
return -1;
}
#if _lib_openat
if(sh.pwdfd > -1 && strcmp(name,e_dot)==0)
return fstat(sh.pwdfd,buff);
#endif
if(sh_isdevfd(name))
return fstat((int)strtol(name+8, NULL, 10),buff);
else
return stat(name,buff);
return stat(name,buff);
}
1 change: 0 additions & 1 deletion src/cmd/ksh93/data/msg.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@

#include "shopt.h"
#include <ast.h>
#include <errno.h>
#include "defs.h"
#include "path.h"
#include "io.h"
Expand Down
1 change: 0 additions & 1 deletion src/cmd/ksh93/edit/edit.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@

#include "shopt.h"
#include <ast.h>
#include <errno.h>
#include <fault.h>
#include "FEATURE/time"
#if _hdr_utime
Expand Down
1 change: 0 additions & 1 deletion src/cmd/ksh93/features/fchdir
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ tst fchdir_osearch_compat note{ can fchdir(2) use file descriptors obtained usin
tst openat_enotdir note{ does openat set ENOTDIR when it fails because the file isn't a directory }end output{
#include <ast.h>
#include <stdio.h>
#include <errno.h>
#if !_lib_openat
#error openat(2) doesn't exist, so this test is pointless
#endif
Expand Down
24 changes: 12 additions & 12 deletions src/cmd/ksh93/features/poll
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ tst pipe_socketpair note{ use socketpair() for peekable pipe() }end execute{
char buf[256];
pid_t pid;
static char msg[] = "hello world\n";
close(0);
ast_close(0);
if (pipe(pfd) < 0 ||
socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) < 0 ||
shutdown(sfd[1], SHUT_RD) < 0 ||
Expand All @@ -39,29 +39,29 @@ tst pipe_socketpair note{ use socketpair() for peekable pipe() }end execute{
return 1;
if (pid)
{
close(pfd[1]);
close(sfd[1]);
ast_close(pfd[1]);
ast_close(sfd[1]);
wait(&n);
if (sfpkrd(pfd[0], buf, sizeof(buf), '\n', -1, 1) >= 0 ||
sfpkrd(sfd[0], buf, sizeof(buf), '\n', -1, 1) < 0)
return 1;
}
else
{
close(pfd[0]);
close(sfd[0]);
ast_close(pfd[0]);
ast_close(sfd[0]);
write(pfd[1], msg, sizeof(msg) - 1);
write(sfd[1], msg, sizeof(msg) - 1);
return 0;
}
close(pfd[0]);
close(sfd[0]);
ast_close(pfd[0]);
ast_close(sfd[0]);
signal(SIGPIPE, handler);
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) < 0 ||
shutdown(sfd[1], SHUT_RD) < 0 ||
shutdown(sfd[0], SHUT_WR) < 0)
return 1;
close(sfd[0]);
ast_close(sfd[0]);
write(sfd[1], msg, sizeof(msg) - 1);
return 1;
}
Expand All @@ -75,18 +75,18 @@ tst socketpair_devfd note{ /dev/fd/N handles socketpair() }end execute{
int devfd;
int n;
int sfd[2];
close(0);
ast_close(0);
open("/dev/null", O_RDONLY);
if ((n = open("/dev/fd/0", O_RDONLY)) < 0)
return 1;
close(n);
ast_close(n);
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) < 0 ||
shutdown(sfd[0], 1) < 0 ||
shutdown(sfd[1], 0) < 0)
return 1;
close(0);
ast_close(0);
dup(sfd[0]);
close(sfd[0]);
ast_close(sfd[0]);
if ((n = open("/dev/fd/0", O_RDONLY)) < 0)
return 1;
return 0;
Expand Down
1 change: 1 addition & 0 deletions src/cmd/ksh93/include/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ extern int sh_trace(char*[],int);
extern void sh_trim(char*);
extern int sh_type(const char*);
extern void sh_unscope(void);
extern void sh_clear_subshell_pwdfd(void);
#if _lib_openat
extern int sh_diropenat(int,const char *);
extern void sh_pwdupdate(int);
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/ksh93/include/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#include <ast_release.h>
#include "git.h"

#define SH_RELEASE_DATE "2025-06-22" /* must be in this format for $((.sh.version)) */
#define SH_RELEASE_DATE "2025-07-10" /* must be in this format for $((.sh.version)) */
/*
* This comment keeps SH_RELEASE_DATE a few lines away from SH_RELEASE_SVER to avoid
* merge conflicts when cherry-picking dev branch commits onto a release branch.
Expand Down
4 changes: 0 additions & 4 deletions src/cmd/ksh93/sh/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -685,10 +685,6 @@ noreturn void sh_done(int sig)
if(sh_isoption(SH_NOEXEC))
kiaclose((Lex_t*)sh.lex_context);
#endif /* SHOPT_KIA */
#if _lib_openat
if(sh.pwdfd > 0)
close(sh.pwdfd);
#endif /* _lib_openat */
/* Exit with portable 8-bit status (128 + signum) if last child process exits due to signal */
if(sh.chldexitsig)
savxit = savxit & ~SH_EXITSIG | 0200;
Expand Down
13 changes: 7 additions & 6 deletions src/cmd/ksh93/sh/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ inetopen(const char* path, int flags)
{
if (server && !bind(fd, p->ai_addr, p->ai_addrlen) && !listen(fd, 5) || !server && !connect(fd, p->ai_addr, p->ai_addrlen))
goto done;
close(fd);
ast_close(fd);
fd = -1;
if (errno != EINTR)
break;
Expand Down Expand Up @@ -714,11 +714,12 @@ int sh_close(int fd)
sh_iovalidfd(fd);
if(!(sp=sh.sftable[fd]) || sfclose(sp) < 0)
{
int err=errno;
if(fdnotify)
(*fdnotify)(fd,SH_FDCLOSE);
while((r=close(fd)) < 0 && errno==EINTR)
errno = err;
errno = 0;
ast_close(fd);
if(errno)
r = -1;
}
if(fd>2)
sh.sftable[fd] = 0;
Expand Down Expand Up @@ -913,7 +914,7 @@ int sh_iomovefd(int fdold)
if((sh.fdstatus[fdold]&IOCLEX) && F_dupfd_cloexec == F_DUPFD)
fcntl(fdnew,F_SETFD,FD_CLOEXEC);
sh.fdstatus[fdnew] = sh.fdstatus[fdold];
close(fdold);
ast_close(fdold);
sh.fdstatus[fdold] = IOCLOSE;
return fdnew;
}
Expand Down Expand Up @@ -1075,7 +1076,7 @@ static char *io_usename(char *name, int *perm, int fno, int mode)
if((fd = sh_open(name,O_RDONLY,0)) >= 0)
{
r = fstat(fd,&statb);
close(fd);
sh_close(fd);
if(r)
return 0;
if(!S_ISREG(statb.st_mode))
Expand Down
3 changes: 1 addition & 2 deletions src/cmd/ksh93/sh/jobs.c
Original file line number Diff line number Diff line change
Expand Up @@ -517,8 +517,7 @@ void job_init(void)
char *ttynam;
if(job.mypgid<0 || !(ttynam=ttyname(JOBTTY)))
return;
while(close(JOBTTY)<0 && errno==EINTR)
;
ast_close(JOBTTY);
if((fd = open(ttynam,O_RDWR)) <0)
return;
if(fd!=JOBTTY)
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/ksh93/sh/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ noreturn void sh_main(int ac, char *av[], Shinit_f userinit)
int isdir = 0;
if((fdin=sh_open(name,O_RDONLY,0))>=0 &&(fstat(fdin,&statb)<0 || S_ISDIR(statb.st_mode)))
{
close(fdin);
sh_close(fdin);
isdir = 1;
fdin = -1;
}
Expand Down
6 changes: 3 additions & 3 deletions src/cmd/ksh93/sh/path.c
Original file line number Diff line number Diff line change
Expand Up @@ -1417,7 +1417,7 @@ static noreturn void exscript(char *path,char *argv[])
sabuf.ac_etime = compress( (time_t)(after-before));
fd = open( SHACCT , O_WRONLY | O_APPEND | O_CREAT,RW_ALL);
write(fd, (const char*)&sabuf, sizeof( sabuf ));
close( fd);
ast_close(fd);
}
}
/*
Expand Down Expand Up @@ -1517,7 +1517,7 @@ static int checkdotpaths(Pathcomp_t *first, Pathcomp_t* old,Pathcomp_t *pp, int
if(!S_ISREG(statb.st_mode))
{
/* .paths cannot be a directory */
close(fd);
ast_close(fd);
return 0;
}
n = statb.st_size;
Expand All @@ -1526,7 +1526,7 @@ static int checkdotpaths(Pathcomp_t *first, Pathcomp_t* old,Pathcomp_t *pp, int
*sp++ = '/';
n=read(fd,cp=sp,n);
sp[n] = 0;
close(fd);
ast_close(fd);
for(ep=0; n--; cp++)
{
if(*cp=='=')
Expand Down
Loading