summaryrefslogtreecommitdiffstats
path: root/bin/sh/eval.c
diff options
context:
space:
mode:
authorjilles <jilles@FreeBSD.org>2010-12-30 22:33:55 +0000
committerjilles <jilles@FreeBSD.org>2010-12-30 22:33:55 +0000
commitca3118f4cab5348e98fb6283d42fca219b5ba6cf (patch)
treeb19941413f90ce2a9c354cf3bdd679a5f201afe2 /bin/sh/eval.c
parent12d4883ccf51c51d512fc50f38d6fba359e78fd3 (diff)
downloadFreeBSD-src-ca3118f4cab5348e98fb6283d42fca219b5ba6cf.zip
FreeBSD-src-ca3118f4cab5348e98fb6283d42fca219b5ba6cf.tar.gz
sh: Avoid side effects from builtins in optimized command substitution.
Change the criterion for builtins to be safe to execute in the same process in optimized command substitution from a blacklist of only cd, . and eval to a whitelist. This avoids clobbering the main shell environment such as by $(exit 4) and $(set -x). The builtins jobid, jobs, times and trap can still show information not available in a child process; this is deliberately permitted. (Changing traps is not.) For some builtins, whether they are safe depends on the arguments passed to them. Some of these are always considered unsafe to keep things simple; this only harms efficiency a little in the rare case they are used alone in a command substitution.
Diffstat (limited to 'bin/sh/eval.c')
-rw-r--r--bin/sh/eval.c32
1 files changed, 27 insertions, 5 deletions
diff --git a/bin/sh/eval.c b/bin/sh/eval.c
index 903f783..25c3fcf 100644
--- a/bin/sh/eval.c
+++ b/bin/sh/eval.c
@@ -643,7 +643,31 @@ out:
result->fd, result->buf, result->nleft, result->jp));
}
-
+/*
+ * Check if a builtin can safely be executed in the same process,
+ * even though it should be in a subshell (command substitution).
+ * Note that jobid, jobs, times and trap can show information not
+ * available in a child process; this is deliberate.
+ * The arguments should already have been expanded.
+ */
+static int
+safe_builtin(int idx, int argc, char **argv)
+{
+ if (idx == BLTINCMD || idx == COMMANDCMD || idx == ECHOCMD ||
+ idx == FALSECMD || idx == JOBIDCMD || idx == JOBSCMD ||
+ idx == KILLCMD || idx == PRINTFCMD || idx == PWDCMD ||
+ idx == TESTCMD || idx == TIMESCMD || idx == TRUECMD ||
+ idx == TYPECMD)
+ return (1);
+ if (idx == EXPORTCMD || idx == TRAPCMD || idx == ULIMITCMD ||
+ idx == UMASKCMD)
+ return (argc <= 1 || (argc == 2 && argv[1][0] == '-'));
+ if (idx == SETCMD)
+ return (argc <= 1 || (argc == 2 && (argv[1][0] == '-' ||
+ argv[1][0] == '+') && argv[1][1] == 'o' &&
+ argv[1][2] == '\0'));
+ return (0);
+}
/*
* Execute a simple command.
@@ -861,10 +885,8 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
|| ((cmdentry.cmdtype == CMDNORMAL || cmdentry.cmdtype == CMDUNKNOWN)
&& ((flags & EV_EXIT) == 0 || have_traps()))
|| ((flags & EV_BACKCMD) != 0
- && (cmdentry.cmdtype != CMDBUILTIN
- || cmdentry.u.index == CDCMD
- || cmdentry.u.index == DOTCMD
- || cmdentry.u.index == EVALCMD))) {
+ && (cmdentry.cmdtype != CMDBUILTIN ||
+ !safe_builtin(cmdentry.u.index, argc, argv)))) {
jp = makejob(cmd, 1);
mode = cmd->ncmd.backgnd;
if (flags & EV_BACKCMD) {
OpenPOWER on IntegriCloud