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:
tg 2015-12-31 21:03:47 +00:00
parent c56d848a10
commit 4059e105a2
3 changed files with 37 additions and 15 deletions

View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.716 2015/12/12 23:31:15 tg Exp $ # $MirOS: src/bin/mksh/check.t,v 1.717 2015/12/31 21:03:44 tg Exp $
# -*- mode: sh -*- # -*- mode: sh -*-
#- #-
# Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@ -30,7 +30,7 @@
# (2013/12/02 20:39:44) http://openbsd.cs.toronto.edu/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date # (2013/12/02 20:39:44) http://openbsd.cs.toronto.edu/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date
expected-stdout: expected-stdout:
@(#)MIRBSD KSH R52 2015/12/12 @(#)MIRBSD KSH R52 2015/12/31
description: description:
Check version of shell. Check version of shell.
stdin: stdin:
@ -39,7 +39,7 @@ name: KSH_VERSION
category: shell:legacy-no category: shell:legacy-no
--- ---
expected-stdout: expected-stdout:
@(#)LEGACY KSH R52 2015/12/12 @(#)LEGACY KSH R52 2015/12/31
description: description:
Check version of legacy shell. Check version of legacy shell.
stdin: stdin:

42
exec.c
View File

@ -23,7 +23,7 @@
#include "sh.h" #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 #ifndef MKSH_DEFAULT_EXECSHELL
#define MKSH_DEFAULT_EXECSHELL MKSH_UNIXROOT "/bin/sh" #define MKSH_DEFAULT_EXECSHELL MKSH_UNIXROOT "/bin/sh"
@ -1363,7 +1363,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
int u = -1; int u = -1;
char *cp = iop->ioname; char *cp = iop->ioname;
int iotype = iop->ioflag & IOTYPE; 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; int flags = 0;
struct ioword iotmp; struct ioword iotmp;
struct stat statb; struct stat statb;
@ -1392,14 +1392,27 @@ iosetup(struct ioword *iop, struct tbl *tp)
break; break;
case IOWRITE: case IOWRITE:
flags = O_WRONLY | O_CREAT | O_TRUNC; if (Flag(FNOCLOBBER) && !(iop->ioflag & IOCLOB)) {
/* /* >file under set -C */
* The stat() is here to allow redirections to if (stat(cp, &statb)) {
* things like /dev/null without error. /* nonexistent file */
*/ flags = O_WRONLY | O_CREAT | O_EXCL;
if (Flag(FNOCLOBBER) && !(iop->ioflag & IOCLOB) && } else if (S_ISREG(statb.st_mode)) {
(stat(cp, &statb) < 0 || S_ISREG(statb.st_mode))) /* regular file, refuse clobbering */
flags |= O_EXCL; 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; break;
case IORDWR: case IORDWR:
@ -1444,6 +1457,15 @@ iosetup(struct ioword *iop, struct tbl *tp)
return (-1); return (-1);
} }
u = binopen3(cp, flags, 0666); 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) { if (u < 0) {
/* herein() may already have printed message */ /* herein() may already have printed message */

4
sh.h
View File

@ -175,9 +175,9 @@
#endif #endif
#ifdef EXTERN #ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.751 2015/12/12 22:25:15 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/sh.h,v 1.752 2015/12/31 21:03:47 tg Exp $");
#endif #endif
#define MKSH_VERSION "R52 2015/12/12" #define MKSH_VERSION "R52 2015/12/31"
/* arithmetic types: C implementation */ /* arithmetic types: C implementation */
#if !HAVE_CAN_INTTYPES #if !HAVE_CAN_INTTYPES