fstat(2) after open(2) for set -C case when initial stat(2) was !S_ISREG
to fix race condition as suggested by jilles
This commit is contained in:
42
exec.c
42
exec.c
@ -23,7 +23,7 @@
|
||||
|
||||
#include "sh.h"
|
||||
|
||||
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.169 2015/12/31 12:58:43 tg Exp $");
|
||||
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.170 2015/12/31 21:03:47 tg Exp $");
|
||||
|
||||
#ifndef MKSH_DEFAULT_EXECSHELL
|
||||
#define MKSH_DEFAULT_EXECSHELL MKSH_UNIXROOT "/bin/sh"
|
||||
@ -1363,7 +1363,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
|
||||
int u = -1;
|
||||
char *cp = iop->ioname;
|
||||
int iotype = iop->ioflag & IOTYPE;
|
||||
bool do_open = true, do_close = false;
|
||||
bool do_open = true, do_close = false, do_fstat = false;
|
||||
int flags = 0;
|
||||
struct ioword iotmp;
|
||||
struct stat statb;
|
||||
@ -1392,14 +1392,27 @@ iosetup(struct ioword *iop, struct tbl *tp)
|
||||
break;
|
||||
|
||||
case IOWRITE:
|
||||
flags = O_WRONLY | O_CREAT | O_TRUNC;
|
||||
/*
|
||||
* The stat() is here to allow redirections to
|
||||
* things like /dev/null without error.
|
||||
*/
|
||||
if (Flag(FNOCLOBBER) && !(iop->ioflag & IOCLOB) &&
|
||||
(stat(cp, &statb) < 0 || S_ISREG(statb.st_mode)))
|
||||
flags |= O_EXCL;
|
||||
if (Flag(FNOCLOBBER) && !(iop->ioflag & IOCLOB)) {
|
||||
/* >file under set -C */
|
||||
if (stat(cp, &statb)) {
|
||||
/* nonexistent file */
|
||||
flags = O_WRONLY | O_CREAT | O_EXCL;
|
||||
} else if (S_ISREG(statb.st_mode)) {
|
||||
/* regular file, refuse clobbering */
|
||||
goto clobber_refused;
|
||||
} else {
|
||||
/*
|
||||
* allow redirections to things
|
||||
* like /dev/null without error
|
||||
*/
|
||||
flags = O_WRONLY;
|
||||
/* but check again after opening */
|
||||
do_fstat = true;
|
||||
}
|
||||
} else {
|
||||
/* >|file or set +C */
|
||||
flags = O_WRONLY | O_CREAT | O_TRUNC;
|
||||
}
|
||||
break;
|
||||
|
||||
case IORDWR:
|
||||
@ -1444,6 +1457,15 @@ iosetup(struct ioword *iop, struct tbl *tp)
|
||||
return (-1);
|
||||
}
|
||||
u = binopen3(cp, flags, 0666);
|
||||
if (do_fstat && u >= 0) {
|
||||
/* prevent race conditions */
|
||||
if (fstat(u, &statb) || S_ISREG(statb.st_mode)) {
|
||||
close(u);
|
||||
clobber_refused:
|
||||
u = -1;
|
||||
errno = EEXIST;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (u < 0) {
|
||||
/* herein() may already have printed message */
|
||||
|
Reference in New Issue
Block a user