Don't acquire __environ_lock around exec*() calls; nothing requires

that these calls be thread-safe with respect to the environment, and it
causes serious problems for threaded applications which call vfork() and
exec*() (including indirectly, via popen() or system()).

Acquire and release __environ_lock in the parent in popen() and system() to
play safe and provide the child with a stable environment.

__environ_lock should also have an atfork() handler; still under development.
This commit is contained in:
nathanw 2003-03-04 19:44:09 +00:00
parent 2ea5d53fe3
commit f60f35f3ab
5 changed files with 26 additions and 30 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: execl.c,v 1.9 2003/01/18 11:23:53 thorpej Exp $ */ /* $NetBSD: execl.c,v 1.10 2003/03/04 19:44:09 nathanw Exp $ */
/*- /*-
* Copyright (c) 1991, 1993 * Copyright (c) 1991, 1993
@ -38,7 +38,7 @@
#if 0 #if 0
static char sccsid[] = "@(#)exec.c 8.1 (Berkeley) 6/4/93"; static char sccsid[] = "@(#)exec.c 8.1 (Berkeley) 6/4/93";
#else #else
__RCSID("$NetBSD: execl.c,v 1.9 2003/01/18 11:23:53 thorpej Exp $"); __RCSID("$NetBSD: execl.c,v 1.10 2003/03/04 19:44:09 nathanw Exp $");
#endif #endif
#endif /* LIBC_SCCS and not lint */ #endif /* LIBC_SCCS and not lint */
@ -54,18 +54,13 @@ __weak_alias(execl,_execl)
extern char **environ; extern char **environ;
#ifdef _REENTRANT
extern rwlock_t __environ_lock;
#endif
int int
execl(const char *name, const char *arg, ...) execl(const char *name, const char *arg, ...)
{ {
int r; int r;
#if defined(__i386__) || defined(__m68k__) || defined(__ns32k__) #if defined(__i386__) || defined(__m68k__) || defined(__ns32k__)
rwlock_rdlock(&__environ_lock);
r = execve(name, (char **) &arg, environ); r = execve(name, (char **) &arg, environ);
rwlock_unlock(&__environ_lock);
return (r); return (r);
#else #else
va_list ap; va_list ap;
@ -85,9 +80,7 @@ execl(const char *name, const char *arg, ...)
; ;
va_end(ap); va_end(ap);
rwlock_rdlock(&__environ_lock);
r = execve(name, argv, environ); r = execve(name, argv, environ);
rwlock_unlock(&__environ_lock);
return (r); return (r);
#endif #endif
} }

View File

@ -1,4 +1,4 @@
/* $NetBSD: execv.c,v 1.6 2003/01/18 11:23:53 thorpej Exp $ */ /* $NetBSD: execv.c,v 1.7 2003/03/04 19:44:09 nathanw Exp $ */
/*- /*-
* Copyright (c) 1991, 1993 * Copyright (c) 1991, 1993
@ -38,7 +38,7 @@
#if 0 #if 0
static char sccsid[] = "@(#)exec.c 8.1 (Berkeley) 6/4/93"; static char sccsid[] = "@(#)exec.c 8.1 (Berkeley) 6/4/93";
#else #else
__RCSID("$NetBSD: execv.c,v 1.6 2003/01/18 11:23:53 thorpej Exp $"); __RCSID("$NetBSD: execv.c,v 1.7 2003/03/04 19:44:09 nathanw Exp $");
#endif #endif
#endif /* LIBC_SCCS and not lint */ #endif /* LIBC_SCCS and not lint */
@ -51,9 +51,6 @@ __weak_alias(execv,_execv)
#endif #endif
extern char **environ; extern char **environ;
#ifdef _REENTRANT
extern rwlock_t __environ_lock;
#endif
int int
execv(name, argv) execv(name, argv)
@ -62,8 +59,6 @@ execv(name, argv)
{ {
int r; int r;
rwlock_rdlock(&__environ_lock);
r = execve(name, argv, environ); r = execve(name, argv, environ);
rwlock_unlock(&__environ_lock);
return (r); return (r);
} }

View File

@ -1,4 +1,4 @@
/* $NetBSD: execvp.c,v 1.21 2003/01/18 11:23:53 thorpej Exp $ */ /* $NetBSD: execvp.c,v 1.22 2003/03/04 19:44:10 nathanw Exp $ */
/*- /*-
* Copyright (c) 1991, 1993 * Copyright (c) 1991, 1993
@ -38,7 +38,7 @@
#if 0 #if 0
static char sccsid[] = "@(#)exec.c 8.1 (Berkeley) 6/4/93"; static char sccsid[] = "@(#)exec.c 8.1 (Berkeley) 6/4/93";
#else #else
__RCSID("$NetBSD: execvp.c,v 1.21 2003/01/18 11:23:53 thorpej Exp $"); __RCSID("$NetBSD: execvp.c,v 1.22 2003/03/04 19:44:10 nathanw Exp $");
#endif #endif
#endif /* LIBC_SCCS and not lint */ #endif /* LIBC_SCCS and not lint */
@ -58,9 +58,6 @@ __weak_alias(execvp,_execvp)
#endif #endif
extern char **environ; extern char **environ;
#ifdef _REENTRANT
extern rwlock_t __environ_lock;
#endif
int int
execvp(const char *name, char * const *argv) execvp(const char *name, char * const *argv)
@ -123,9 +120,7 @@ execvp(const char *name, char * const *argv)
memcpy(buf + lp + 1, name, ln); memcpy(buf + lp + 1, name, ln);
buf[lp + ln + 1] = '\0'; buf[lp + ln + 1] = '\0';
retry: rwlock_rdlock(&__environ_lock); retry: (void)execve(bp, argv, environ);
(void)execve(bp, argv, environ);
rwlock_unlock(&__environ_lock);
switch (errno) { switch (errno) {
case EACCES: case EACCES:
eacces = 1; eacces = 1;
@ -140,10 +135,8 @@ retry: rwlock_rdlock(&__environ_lock);
memp[0] = _PATH_BSHELL; memp[0] = _PATH_BSHELL;
memp[1] = bp; memp[1] = bp;
(void)memcpy(&memp[2], &argv[1], cnt * sizeof(*memp)); (void)memcpy(&memp[2], &argv[1], cnt * sizeof(*memp));
rwlock_rdlock(&__environ_lock);
(void)execve(_PATH_BSHELL, (char * const *)memp, (void)execve(_PATH_BSHELL, (char * const *)memp,
environ); environ);
rwlock_unlock(&__environ_lock);
goto done; goto done;
case ETXTBSY: case ETXTBSY:
if (etxtbsy < 3) if (etxtbsy < 3)

View File

@ -1,4 +1,4 @@
/* $NetBSD: popen.c,v 1.25 2000/01/22 22:19:11 mycroft Exp $ */ /* $NetBSD: popen.c,v 1.26 2003/03/04 19:44:10 nathanw Exp $ */
/* /*
* Copyright (c) 1988, 1993 * Copyright (c) 1988, 1993
@ -41,7 +41,7 @@
#if 0 #if 0
static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 5/3/95"; static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 5/3/95";
#else #else
__RCSID("$NetBSD: popen.c,v 1.25 2000/01/22 22:19:11 mycroft Exp $"); __RCSID("$NetBSD: popen.c,v 1.26 2003/03/04 19:44:10 nathanw Exp $");
#endif #endif
#endif /* LIBC_SCCS and not lint */ #endif /* LIBC_SCCS and not lint */
@ -58,12 +58,17 @@ __RCSID("$NetBSD: popen.c,v 1.25 2000/01/22 22:19:11 mycroft Exp $");
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include "reentrant.h"
#ifdef __weak_alias #ifdef __weak_alias
__weak_alias(popen,_popen) __weak_alias(popen,_popen)
__weak_alias(pclose,_pclose) __weak_alias(pclose,_pclose)
#endif #endif
#ifdef _REENTRANT
extern rwlock_t __environ_lock;
#endif
static struct pid { static struct pid {
struct pid *next; struct pid *next;
FILE *fp; FILE *fp;
@ -107,9 +112,11 @@ popen(command, type)
return (NULL); return (NULL);
} }
rwlock_rdlock(&__environ_lock);
switch (pid = vfork()) { switch (pid = vfork()) {
case -1: /* Error. */ case -1: /* Error. */
serrno = errno; serrno = errno;
rwlock_unlock(&__environ_lock);
free(cur); free(cur);
(void)close(pdes[0]); (void)close(pdes[0]);
(void)close(pdes[1]); (void)close(pdes[1]);
@ -143,6 +150,7 @@ popen(command, type)
_exit(127); _exit(127);
/* NOTREACHED */ /* NOTREACHED */
} }
rwlock_unlock(&__environ_lock);
/* Parent; assume fdopen can't fail. */ /* Parent; assume fdopen can't fail. */
if (*type == 'r') { if (*type == 'r') {

View File

@ -1,4 +1,4 @@
/* $NetBSD: system.c,v 1.17 2001/10/31 13:31:26 kleink Exp $ */ /* $NetBSD: system.c,v 1.18 2003/03/04 19:44:10 nathanw Exp $ */
/* /*
* Copyright (c) 1988, 1993 * Copyright (c) 1988, 1993
@ -38,7 +38,7 @@
#if 0 #if 0
static char sccsid[] = "@(#)system.c 8.1 (Berkeley) 6/4/93"; static char sccsid[] = "@(#)system.c 8.1 (Berkeley) 6/4/93";
#else #else
__RCSID("$NetBSD: system.c,v 1.17 2001/10/31 13:31:26 kleink Exp $"); __RCSID("$NetBSD: system.c,v 1.18 2003/03/04 19:44:10 nathanw Exp $");
#endif #endif
#endif /* LIBC_SCCS and not lint */ #endif /* LIBC_SCCS and not lint */
@ -50,7 +50,11 @@ __RCSID("$NetBSD: system.c,v 1.17 2001/10/31 13:31:26 kleink Exp $");
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <paths.h> #include <paths.h>
#include "reentrant.h"
#ifdef _REENTRANT
extern rwlock_t __environ_lock;
#endif
extern char **environ; extern char **environ;
int int
@ -80,8 +84,10 @@ system(command)
if (sigprocmask(SIG_BLOCK, &nmask, &omask) == -1) if (sigprocmask(SIG_BLOCK, &nmask, &omask) == -1)
return -1; return -1;
rwlock_rdlock(&__environ_lock);
switch(pid = vfork()) { switch(pid = vfork()) {
case -1: /* error */ case -1: /* error */
rwlock_unlock(&__environ_lock);
sigaction(SIGINT, &intsa, NULL); sigaction(SIGINT, &intsa, NULL);
sigaction(SIGQUIT, &quitsa, NULL); sigaction(SIGQUIT, &quitsa, NULL);
(void)sigprocmask(SIG_SETMASK, &omask, NULL); (void)sigprocmask(SIG_SETMASK, &omask, NULL);
@ -93,6 +99,7 @@ system(command)
execve(_PATH_BSHELL, argp, environ); execve(_PATH_BSHELL, argp, environ);
_exit(127); _exit(127);
} }
rwlock_unlock(&__environ_lock);
while (waitpid(pid, &pstat, 0) == -1) { while (waitpid(pid, &pstat, 0) == -1) {
if (errno != EINTR) { if (errno != EINTR) {