summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjilles <jilles@FreeBSD.org>2014-10-26 17:50:33 +0000
committerjilles <jilles@FreeBSD.org>2014-10-26 17:50:33 +0000
commitbc5702addf6a68dc471c6dd3884ca164587b8271 (patch)
tree8484fb30e43bfd82dc96d44ef76a402bd991793c
parent0963d8042b3129788a04f3b99596ffeef457dc3f (diff)
downloadFreeBSD-src-bc5702addf6a68dc471c6dd3884ca164587b8271.zip
FreeBSD-src-bc5702addf6a68dc471c6dd3884ca164587b8271.tar.gz
sh: Make getopts memory-safe if with changing arguments.
POSIX does not permit to continuing a getopts loop with different arguments. For parsing the positional parameters, we handle this case by resetting the getopts state when the positional parameters are changed in any way (and the getopts state is local to a function). However, in the syntax getopts <optstring> <var> <arg...>, changes could lead to invalid memory access. In the syntax getopts <optstring> <var> <arg...>, store a copy of the arguments and continue to use them until getopts is reset.
-rw-r--r--bin/sh/eval.c1
-rw-r--r--bin/sh/options.c31
-rw-r--r--bin/sh/options.h1
-rw-r--r--bin/sh/tests/builtins/getopts9.09
-rw-r--r--bin/sh/tests/builtins/getopts9.0.stdout3
5 files changed, 39 insertions, 6 deletions
diff --git a/bin/sh/eval.c b/bin/sh/eval.c
index 38e227c..c1a9cdb 100644
--- a/bin/sh/eval.c
+++ b/bin/sh/eval.c
@@ -1039,6 +1039,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
shellparam.reset = 1;
shellparam.nparam = argc - 1;
shellparam.p = argv + 1;
+ shellparam.optp = NULL;
shellparam.optnext = NULL;
INTOFF;
savelocalvars = localvars;
diff --git a/bin/sh/options.c b/bin/sh/options.c
index bf00a4e..860cf6c 100644
--- a/bin/sh/options.c
+++ b/bin/sh/options.c
@@ -325,6 +325,7 @@ setparam(char **argv)
shellparam.malloc = 1;
shellparam.nparam = nparam;
shellparam.p = newparam;
+ shellparam.optp = NULL;
shellparam.reset = 1;
shellparam.optnext = NULL;
}
@@ -344,6 +345,11 @@ freeparam(struct shparam *param)
ckfree(*ap);
ckfree(param->p);
}
+ if (param->optp) {
+ for (ap = param->optp ; *ap ; ap++)
+ ckfree(*ap);
+ ckfree(param->optp);
+ }
}
@@ -417,20 +423,33 @@ getoptsreset(const char *value)
int
getoptscmd(int argc, char **argv)
{
- char **optbase = NULL;
+ char **optbase = NULL, **ap;
+ int i;
if (argc < 3)
error("usage: getopts optstring var [arg]");
- else if (argc == 3)
- optbase = shellparam.p;
- else
- optbase = &argv[3];
if (shellparam.reset == 1) {
+ INTOFF;
+ if (shellparam.optp) {
+ for (ap = shellparam.optp ; *ap ; ap++)
+ ckfree(*ap);
+ ckfree(shellparam.optp);
+ shellparam.optp = NULL;
+ }
+ if (argc > 3) {
+ shellparam.optp = ckmalloc((argc - 2) * sizeof *ap);
+ memset(shellparam.optp, '\0', (argc - 2) * sizeof *ap);
+ for (i = 0; i < argc - 3; i++)
+ shellparam.optp[i] = savestr(argv[i + 3]);
+ }
+ INTON;
+ optbase = argc == 3 ? shellparam.p : shellparam.optp;
shellparam.optnext = optbase;
shellparam.optptr = NULL;
shellparam.reset = 0;
- }
+ } else
+ optbase = shellparam.optp ? shellparam.optp : shellparam.p;
return getopts(argv[1], argv[2], optbase, &shellparam.optnext,
&shellparam.optptr);
diff --git a/bin/sh/options.h b/bin/sh/options.h
index acc2a11..0994862 100644
--- a/bin/sh/options.h
+++ b/bin/sh/options.h
@@ -38,6 +38,7 @@ struct shparam {
unsigned char malloc; /* if parameter list dynamically allocated */
unsigned char reset; /* if getopts has been reset */
char **p; /* parameter list */
+ char **optp; /* parameter list for getopts */
char **optnext; /* next parameter to be processed by getopts */
char *optptr; /* used by getopts */
};
diff --git a/bin/sh/tests/builtins/getopts9.0 b/bin/sh/tests/builtins/getopts9.0
new file mode 100644
index 0000000..d23fc43
--- /dev/null
+++ b/bin/sh/tests/builtins/getopts9.0
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+args='-ab'
+getopts ab opt $args
+echo $?:$opt:$OPTARG
+for dummy in dummy1 dummy2; do
+ getopts ab opt $args
+ echo $?:$opt:$OPTARG
+done
diff --git a/bin/sh/tests/builtins/getopts9.0.stdout b/bin/sh/tests/builtins/getopts9.0.stdout
new file mode 100644
index 0000000..4d32063
--- /dev/null
+++ b/bin/sh/tests/builtins/getopts9.0.stdout
@@ -0,0 +1,3 @@
+0:a:
+0:b:
+1:?:
OpenPOWER on IntegriCloud