Can a bash array be used in place of eval set — “$params”?

Clash Royale CLAN TAG#URR8PPP
I'm taking a look at the optparse library for bash option parsing, specifically this bit in the generated code:
params=""
while [ $# -ne 0 ]; do
param="$1"
shift
case "$param" in
--my-long-flag)
params="$params -m";;
--another-flag)
params="$params -a";;
"-?"|--help)
usage
exit 0;;
*)
if [[ "$param" == --* ]]; then
echo -e "Unrecognized long option: $param"
usage
exit 1
fi
params="$params "$param"";; ##### THIS LINE
esac
done
eval set -- "$params" ##### AND THIS LINE
# then a typical while getopts loop
Would there be any real reason to use eval here? The input to eval seems to be properly sanitized. But wouldn't it work the same to use:
params=()
# ...
--my-long-flag)
params+=("-m");;
--another-flag)
params+=("-a");;
# ...
params+=("$param");;
# ...
set -- "$params[@]"
That seems cleaner to me.
In fact, wouldn't this allow options to be parsed directly out of the params array (without even using set) by using while getopts "ma" option "$params[@]"; do instead of while getopts "ma" option; do?
bash array options parameter getopts
add a comment |
I'm taking a look at the optparse library for bash option parsing, specifically this bit in the generated code:
params=""
while [ $# -ne 0 ]; do
param="$1"
shift
case "$param" in
--my-long-flag)
params="$params -m";;
--another-flag)
params="$params -a";;
"-?"|--help)
usage
exit 0;;
*)
if [[ "$param" == --* ]]; then
echo -e "Unrecognized long option: $param"
usage
exit 1
fi
params="$params "$param"";; ##### THIS LINE
esac
done
eval set -- "$params" ##### AND THIS LINE
# then a typical while getopts loop
Would there be any real reason to use eval here? The input to eval seems to be properly sanitized. But wouldn't it work the same to use:
params=()
# ...
--my-long-flag)
params+=("-m");;
--another-flag)
params+=("-a");;
# ...
params+=("$param");;
# ...
set -- "$params[@]"
That seems cleaner to me.
In fact, wouldn't this allow options to be parsed directly out of the params array (without even using set) by using while getopts "ma" option "$params[@]"; do instead of while getopts "ma" option; do?
bash array options parameter getopts
add a comment |
I'm taking a look at the optparse library for bash option parsing, specifically this bit in the generated code:
params=""
while [ $# -ne 0 ]; do
param="$1"
shift
case "$param" in
--my-long-flag)
params="$params -m";;
--another-flag)
params="$params -a";;
"-?"|--help)
usage
exit 0;;
*)
if [[ "$param" == --* ]]; then
echo -e "Unrecognized long option: $param"
usage
exit 1
fi
params="$params "$param"";; ##### THIS LINE
esac
done
eval set -- "$params" ##### AND THIS LINE
# then a typical while getopts loop
Would there be any real reason to use eval here? The input to eval seems to be properly sanitized. But wouldn't it work the same to use:
params=()
# ...
--my-long-flag)
params+=("-m");;
--another-flag)
params+=("-a");;
# ...
params+=("$param");;
# ...
set -- "$params[@]"
That seems cleaner to me.
In fact, wouldn't this allow options to be parsed directly out of the params array (without even using set) by using while getopts "ma" option "$params[@]"; do instead of while getopts "ma" option; do?
bash array options parameter getopts
I'm taking a look at the optparse library for bash option parsing, specifically this bit in the generated code:
params=""
while [ $# -ne 0 ]; do
param="$1"
shift
case "$param" in
--my-long-flag)
params="$params -m";;
--another-flag)
params="$params -a";;
"-?"|--help)
usage
exit 0;;
*)
if [[ "$param" == --* ]]; then
echo -e "Unrecognized long option: $param"
usage
exit 1
fi
params="$params "$param"";; ##### THIS LINE
esac
done
eval set -- "$params" ##### AND THIS LINE
# then a typical while getopts loop
Would there be any real reason to use eval here? The input to eval seems to be properly sanitized. But wouldn't it work the same to use:
params=()
# ...
--my-long-flag)
params+=("-m");;
--another-flag)
params+=("-a");;
# ...
params+=("$param");;
# ...
set -- "$params[@]"
That seems cleaner to me.
In fact, wouldn't this allow options to be parsed directly out of the params array (without even using set) by using while getopts "ma" option "$params[@]"; do instead of while getopts "ma" option; do?
bash array options parameter getopts
bash array options parameter getopts
edited Jan 6 '16 at 0:06
asked Jan 5 '16 at 20:21
Wildcard
22.6k962164
22.6k962164
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
You don't need to use a bash array here (but do so if it feels better).
Here's how to do it for /bin/sh:
#!/bin/sh
for arg do
shift
case "$arg" in
--my-long-flag)
set -- "$@" -m ;;
--another-flag)
set -- "$@" -a ;;
"-?"|--help)
usage
exit 0 ;;
--*)
printf 'Unrecognised long option: %sn' "$arg" >$2
usage
exit 1 ;;
*)
set -- "$@" "$arg"
esac
done
This is cleaner than the bash array solution (personal opinion) since it doesn't need to introduce another variable. It's also better than the auto-generated code that you show as it retains each command line argument as a separate item in "$@". This is good, because this allows the user to pass arguments containing whitespace characters as long as they are quoted (which the auto-generated code does not do).
Style comments:
The loop above is supposed to translate long options into short options for a loop over
getoptslater. As such, it breaks from that task by actually acting on some options, such as-?and--help. IMHO, these should instead be translated to-h(or some suitable short option).It also does the translation of long options past the point where options should not be accepted. Calling the script as
./script.sh --my-long-flag -- -?should not interpret
-?as an option due to the--(meaning "options ends here"). Likewise,./script.sh filename --my-long-flagshould not interpret
--my-long-optionas an option, as the parsing of options should stop at the first non-option.
Here's a variant that takes the above into account:
#!/bin/sh
parse=YES
for arg do
shift
if [ "$parse" = YES ]; then
case "$arg" in
--my-long-flag)
set -- "$@" -m ;;
--another-flag)
set -- "$@" -a ;;
--help)
set -- "$@" -h ;;
--)
parse=NO
set -- "$@" -- ;;
--*)
printf 'Unrecognised long option: %sn' "$arg" >$2
usage
exit 1 ;;
*)
parse=NO
set -- "$@" "$arg"
esac
else
set -- "$@" "$arg"
fi
done
What this does not allow is long options with separate option arguments, such as --option hello (the hello would be treated as a non-option and the option parsing would end). Something like --option=hello would be fairly easy to handle with a bit of extra tinkering though.
I would love an explanation of how iterating over the positional parameters interacts with changing those positional parameters at the same time.
– Wildcard
Dec 20 '18 at 22:23
1
@Wildcard The standardforloop always iterates over a static list, so once it's started, you can do whatever with$@. The loop range/items is not re-evaluated in each iteration.
– Kusalananda
Dec 20 '18 at 22:58
1
@Wildcard In this instance, you could also dofor dummy do arg=$1; shift; ...; done. This would just iterate as many times as the original$@had elements but thedummyvariable would not be used.
– Kusalananda
Dec 20 '18 at 23:09
add a comment |
The question is "Should a bash array be used in place of eval set — “$params”?", and the answer is yes!.
In your script, the input to eval is clearly not properly sanitized. Try
yourscript '`xterm`'
and you'll see that an xterm is started even though the backticks are properly quoted by single quotes. (Compare with
echo '`xterm`'
which does not start an xterm.)
Fixing the bug while keepting eval is very difficult.
Even changing the line
params="$params "$param"";;
to
params="$params '$param'";;
would not help: Now
yourscript '`xterm`'
no longer starts an xterm, but
yourscript '' `xterm` ''
still does.
Thanks! I'm working on a remote box over ssh, so I don't havextermavailable, but I tested it withmyscript '`touch /tmp/hacked`'(and compared it toecho '`touch /tmp/hacked`'). I didn't even need the double quotes or the spaces, though; is there a different edge case those are hacking around?
– Wildcard
Jan 5 '16 at 23:35
Also, I've never usedbasharrays before—I wrote the "cleaner" version that uses arrays after a brief once-over of the applicable man page section. Did I get it right? Any pitfalls in it that you see?
– Wildcard
Jan 5 '16 at 23:36
Also NB: This is not my script. I linked to the optparse library in my question; that's the source of this code. However, the optparse library is sourced from some other code that I have to maintain, so I want to clean up the vulnerabilities. I've never usedevalin a script and probably never will. ;)
– Wildcard
Jan 5 '16 at 23:40
1
@Wildcard yes, you're right, the double quotes or the spaces are unnecessary, since the script tries to protect$paramwith double quotes, and backticks are evaluated even within double quotes. If$paramwere protected with single quote, one would need a more complicated argument.
– Uwe
Jan 5 '16 at 23:57
2
@AlexejMagura These are literal backticks. They are properly quoted. They are not supposed to be interpreted -- but they are interpreted.
– Uwe
Jan 19 '17 at 21:49
|
show 3 more comments
Your Answer
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "106"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f253481%2fcan-a-bash-array-be-used-in-place-of-eval-set-params%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
You don't need to use a bash array here (but do so if it feels better).
Here's how to do it for /bin/sh:
#!/bin/sh
for arg do
shift
case "$arg" in
--my-long-flag)
set -- "$@" -m ;;
--another-flag)
set -- "$@" -a ;;
"-?"|--help)
usage
exit 0 ;;
--*)
printf 'Unrecognised long option: %sn' "$arg" >$2
usage
exit 1 ;;
*)
set -- "$@" "$arg"
esac
done
This is cleaner than the bash array solution (personal opinion) since it doesn't need to introduce another variable. It's also better than the auto-generated code that you show as it retains each command line argument as a separate item in "$@". This is good, because this allows the user to pass arguments containing whitespace characters as long as they are quoted (which the auto-generated code does not do).
Style comments:
The loop above is supposed to translate long options into short options for a loop over
getoptslater. As such, it breaks from that task by actually acting on some options, such as-?and--help. IMHO, these should instead be translated to-h(or some suitable short option).It also does the translation of long options past the point where options should not be accepted. Calling the script as
./script.sh --my-long-flag -- -?should not interpret
-?as an option due to the--(meaning "options ends here"). Likewise,./script.sh filename --my-long-flagshould not interpret
--my-long-optionas an option, as the parsing of options should stop at the first non-option.
Here's a variant that takes the above into account:
#!/bin/sh
parse=YES
for arg do
shift
if [ "$parse" = YES ]; then
case "$arg" in
--my-long-flag)
set -- "$@" -m ;;
--another-flag)
set -- "$@" -a ;;
--help)
set -- "$@" -h ;;
--)
parse=NO
set -- "$@" -- ;;
--*)
printf 'Unrecognised long option: %sn' "$arg" >$2
usage
exit 1 ;;
*)
parse=NO
set -- "$@" "$arg"
esac
else
set -- "$@" "$arg"
fi
done
What this does not allow is long options with separate option arguments, such as --option hello (the hello would be treated as a non-option and the option parsing would end). Something like --option=hello would be fairly easy to handle with a bit of extra tinkering though.
I would love an explanation of how iterating over the positional parameters interacts with changing those positional parameters at the same time.
– Wildcard
Dec 20 '18 at 22:23
1
@Wildcard The standardforloop always iterates over a static list, so once it's started, you can do whatever with$@. The loop range/items is not re-evaluated in each iteration.
– Kusalananda
Dec 20 '18 at 22:58
1
@Wildcard In this instance, you could also dofor dummy do arg=$1; shift; ...; done. This would just iterate as many times as the original$@had elements but thedummyvariable would not be used.
– Kusalananda
Dec 20 '18 at 23:09
add a comment |
You don't need to use a bash array here (but do so if it feels better).
Here's how to do it for /bin/sh:
#!/bin/sh
for arg do
shift
case "$arg" in
--my-long-flag)
set -- "$@" -m ;;
--another-flag)
set -- "$@" -a ;;
"-?"|--help)
usage
exit 0 ;;
--*)
printf 'Unrecognised long option: %sn' "$arg" >$2
usage
exit 1 ;;
*)
set -- "$@" "$arg"
esac
done
This is cleaner than the bash array solution (personal opinion) since it doesn't need to introduce another variable. It's also better than the auto-generated code that you show as it retains each command line argument as a separate item in "$@". This is good, because this allows the user to pass arguments containing whitespace characters as long as they are quoted (which the auto-generated code does not do).
Style comments:
The loop above is supposed to translate long options into short options for a loop over
getoptslater. As such, it breaks from that task by actually acting on some options, such as-?and--help. IMHO, these should instead be translated to-h(or some suitable short option).It also does the translation of long options past the point where options should not be accepted. Calling the script as
./script.sh --my-long-flag -- -?should not interpret
-?as an option due to the--(meaning "options ends here"). Likewise,./script.sh filename --my-long-flagshould not interpret
--my-long-optionas an option, as the parsing of options should stop at the first non-option.
Here's a variant that takes the above into account:
#!/bin/sh
parse=YES
for arg do
shift
if [ "$parse" = YES ]; then
case "$arg" in
--my-long-flag)
set -- "$@" -m ;;
--another-flag)
set -- "$@" -a ;;
--help)
set -- "$@" -h ;;
--)
parse=NO
set -- "$@" -- ;;
--*)
printf 'Unrecognised long option: %sn' "$arg" >$2
usage
exit 1 ;;
*)
parse=NO
set -- "$@" "$arg"
esac
else
set -- "$@" "$arg"
fi
done
What this does not allow is long options with separate option arguments, such as --option hello (the hello would be treated as a non-option and the option parsing would end). Something like --option=hello would be fairly easy to handle with a bit of extra tinkering though.
I would love an explanation of how iterating over the positional parameters interacts with changing those positional parameters at the same time.
– Wildcard
Dec 20 '18 at 22:23
1
@Wildcard The standardforloop always iterates over a static list, so once it's started, you can do whatever with$@. The loop range/items is not re-evaluated in each iteration.
– Kusalananda
Dec 20 '18 at 22:58
1
@Wildcard In this instance, you could also dofor dummy do arg=$1; shift; ...; done. This would just iterate as many times as the original$@had elements but thedummyvariable would not be used.
– Kusalananda
Dec 20 '18 at 23:09
add a comment |
You don't need to use a bash array here (but do so if it feels better).
Here's how to do it for /bin/sh:
#!/bin/sh
for arg do
shift
case "$arg" in
--my-long-flag)
set -- "$@" -m ;;
--another-flag)
set -- "$@" -a ;;
"-?"|--help)
usage
exit 0 ;;
--*)
printf 'Unrecognised long option: %sn' "$arg" >$2
usage
exit 1 ;;
*)
set -- "$@" "$arg"
esac
done
This is cleaner than the bash array solution (personal opinion) since it doesn't need to introduce another variable. It's also better than the auto-generated code that you show as it retains each command line argument as a separate item in "$@". This is good, because this allows the user to pass arguments containing whitespace characters as long as they are quoted (which the auto-generated code does not do).
Style comments:
The loop above is supposed to translate long options into short options for a loop over
getoptslater. As such, it breaks from that task by actually acting on some options, such as-?and--help. IMHO, these should instead be translated to-h(or some suitable short option).It also does the translation of long options past the point where options should not be accepted. Calling the script as
./script.sh --my-long-flag -- -?should not interpret
-?as an option due to the--(meaning "options ends here"). Likewise,./script.sh filename --my-long-flagshould not interpret
--my-long-optionas an option, as the parsing of options should stop at the first non-option.
Here's a variant that takes the above into account:
#!/bin/sh
parse=YES
for arg do
shift
if [ "$parse" = YES ]; then
case "$arg" in
--my-long-flag)
set -- "$@" -m ;;
--another-flag)
set -- "$@" -a ;;
--help)
set -- "$@" -h ;;
--)
parse=NO
set -- "$@" -- ;;
--*)
printf 'Unrecognised long option: %sn' "$arg" >$2
usage
exit 1 ;;
*)
parse=NO
set -- "$@" "$arg"
esac
else
set -- "$@" "$arg"
fi
done
What this does not allow is long options with separate option arguments, such as --option hello (the hello would be treated as a non-option and the option parsing would end). Something like --option=hello would be fairly easy to handle with a bit of extra tinkering though.
You don't need to use a bash array here (but do so if it feels better).
Here's how to do it for /bin/sh:
#!/bin/sh
for arg do
shift
case "$arg" in
--my-long-flag)
set -- "$@" -m ;;
--another-flag)
set -- "$@" -a ;;
"-?"|--help)
usage
exit 0 ;;
--*)
printf 'Unrecognised long option: %sn' "$arg" >$2
usage
exit 1 ;;
*)
set -- "$@" "$arg"
esac
done
This is cleaner than the bash array solution (personal opinion) since it doesn't need to introduce another variable. It's also better than the auto-generated code that you show as it retains each command line argument as a separate item in "$@". This is good, because this allows the user to pass arguments containing whitespace characters as long as they are quoted (which the auto-generated code does not do).
Style comments:
The loop above is supposed to translate long options into short options for a loop over
getoptslater. As such, it breaks from that task by actually acting on some options, such as-?and--help. IMHO, these should instead be translated to-h(or some suitable short option).It also does the translation of long options past the point where options should not be accepted. Calling the script as
./script.sh --my-long-flag -- -?should not interpret
-?as an option due to the--(meaning "options ends here"). Likewise,./script.sh filename --my-long-flagshould not interpret
--my-long-optionas an option, as the parsing of options should stop at the first non-option.
Here's a variant that takes the above into account:
#!/bin/sh
parse=YES
for arg do
shift
if [ "$parse" = YES ]; then
case "$arg" in
--my-long-flag)
set -- "$@" -m ;;
--another-flag)
set -- "$@" -a ;;
--help)
set -- "$@" -h ;;
--)
parse=NO
set -- "$@" -- ;;
--*)
printf 'Unrecognised long option: %sn' "$arg" >$2
usage
exit 1 ;;
*)
parse=NO
set -- "$@" "$arg"
esac
else
set -- "$@" "$arg"
fi
done
What this does not allow is long options with separate option arguments, such as --option hello (the hello would be treated as a non-option and the option parsing would end). Something like --option=hello would be fairly easy to handle with a bit of extra tinkering though.
edited Dec 20 '18 at 23:38
answered Dec 20 '18 at 21:54
Kusalananda
122k16229374
122k16229374
I would love an explanation of how iterating over the positional parameters interacts with changing those positional parameters at the same time.
– Wildcard
Dec 20 '18 at 22:23
1
@Wildcard The standardforloop always iterates over a static list, so once it's started, you can do whatever with$@. The loop range/items is not re-evaluated in each iteration.
– Kusalananda
Dec 20 '18 at 22:58
1
@Wildcard In this instance, you could also dofor dummy do arg=$1; shift; ...; done. This would just iterate as many times as the original$@had elements but thedummyvariable would not be used.
– Kusalananda
Dec 20 '18 at 23:09
add a comment |
I would love an explanation of how iterating over the positional parameters interacts with changing those positional parameters at the same time.
– Wildcard
Dec 20 '18 at 22:23
1
@Wildcard The standardforloop always iterates over a static list, so once it's started, you can do whatever with$@. The loop range/items is not re-evaluated in each iteration.
– Kusalananda
Dec 20 '18 at 22:58
1
@Wildcard In this instance, you could also dofor dummy do arg=$1; shift; ...; done. This would just iterate as many times as the original$@had elements but thedummyvariable would not be used.
– Kusalananda
Dec 20 '18 at 23:09
I would love an explanation of how iterating over the positional parameters interacts with changing those positional parameters at the same time.
– Wildcard
Dec 20 '18 at 22:23
I would love an explanation of how iterating over the positional parameters interacts with changing those positional parameters at the same time.
– Wildcard
Dec 20 '18 at 22:23
1
1
@Wildcard The standard
for loop always iterates over a static list, so once it's started, you can do whatever with $@. The loop range/items is not re-evaluated in each iteration.– Kusalananda
Dec 20 '18 at 22:58
@Wildcard The standard
for loop always iterates over a static list, so once it's started, you can do whatever with $@. The loop range/items is not re-evaluated in each iteration.– Kusalananda
Dec 20 '18 at 22:58
1
1
@Wildcard In this instance, you could also do
for dummy do arg=$1; shift; ...; done. This would just iterate as many times as the original $@ had elements but the dummy variable would not be used.– Kusalananda
Dec 20 '18 at 23:09
@Wildcard In this instance, you could also do
for dummy do arg=$1; shift; ...; done. This would just iterate as many times as the original $@ had elements but the dummy variable would not be used.– Kusalananda
Dec 20 '18 at 23:09
add a comment |
The question is "Should a bash array be used in place of eval set — “$params”?", and the answer is yes!.
In your script, the input to eval is clearly not properly sanitized. Try
yourscript '`xterm`'
and you'll see that an xterm is started even though the backticks are properly quoted by single quotes. (Compare with
echo '`xterm`'
which does not start an xterm.)
Fixing the bug while keepting eval is very difficult.
Even changing the line
params="$params "$param"";;
to
params="$params '$param'";;
would not help: Now
yourscript '`xterm`'
no longer starts an xterm, but
yourscript '' `xterm` ''
still does.
Thanks! I'm working on a remote box over ssh, so I don't havextermavailable, but I tested it withmyscript '`touch /tmp/hacked`'(and compared it toecho '`touch /tmp/hacked`'). I didn't even need the double quotes or the spaces, though; is there a different edge case those are hacking around?
– Wildcard
Jan 5 '16 at 23:35
Also, I've never usedbasharrays before—I wrote the "cleaner" version that uses arrays after a brief once-over of the applicable man page section. Did I get it right? Any pitfalls in it that you see?
– Wildcard
Jan 5 '16 at 23:36
Also NB: This is not my script. I linked to the optparse library in my question; that's the source of this code. However, the optparse library is sourced from some other code that I have to maintain, so I want to clean up the vulnerabilities. I've never usedevalin a script and probably never will. ;)
– Wildcard
Jan 5 '16 at 23:40
1
@Wildcard yes, you're right, the double quotes or the spaces are unnecessary, since the script tries to protect$paramwith double quotes, and backticks are evaluated even within double quotes. If$paramwere protected with single quote, one would need a more complicated argument.
– Uwe
Jan 5 '16 at 23:57
2
@AlexejMagura These are literal backticks. They are properly quoted. They are not supposed to be interpreted -- but they are interpreted.
– Uwe
Jan 19 '17 at 21:49
|
show 3 more comments
The question is "Should a bash array be used in place of eval set — “$params”?", and the answer is yes!.
In your script, the input to eval is clearly not properly sanitized. Try
yourscript '`xterm`'
and you'll see that an xterm is started even though the backticks are properly quoted by single quotes. (Compare with
echo '`xterm`'
which does not start an xterm.)
Fixing the bug while keepting eval is very difficult.
Even changing the line
params="$params "$param"";;
to
params="$params '$param'";;
would not help: Now
yourscript '`xterm`'
no longer starts an xterm, but
yourscript '' `xterm` ''
still does.
Thanks! I'm working on a remote box over ssh, so I don't havextermavailable, but I tested it withmyscript '`touch /tmp/hacked`'(and compared it toecho '`touch /tmp/hacked`'). I didn't even need the double quotes or the spaces, though; is there a different edge case those are hacking around?
– Wildcard
Jan 5 '16 at 23:35
Also, I've never usedbasharrays before—I wrote the "cleaner" version that uses arrays after a brief once-over of the applicable man page section. Did I get it right? Any pitfalls in it that you see?
– Wildcard
Jan 5 '16 at 23:36
Also NB: This is not my script. I linked to the optparse library in my question; that's the source of this code. However, the optparse library is sourced from some other code that I have to maintain, so I want to clean up the vulnerabilities. I've never usedevalin a script and probably never will. ;)
– Wildcard
Jan 5 '16 at 23:40
1
@Wildcard yes, you're right, the double quotes or the spaces are unnecessary, since the script tries to protect$paramwith double quotes, and backticks are evaluated even within double quotes. If$paramwere protected with single quote, one would need a more complicated argument.
– Uwe
Jan 5 '16 at 23:57
2
@AlexejMagura These are literal backticks. They are properly quoted. They are not supposed to be interpreted -- but they are interpreted.
– Uwe
Jan 19 '17 at 21:49
|
show 3 more comments
The question is "Should a bash array be used in place of eval set — “$params”?", and the answer is yes!.
In your script, the input to eval is clearly not properly sanitized. Try
yourscript '`xterm`'
and you'll see that an xterm is started even though the backticks are properly quoted by single quotes. (Compare with
echo '`xterm`'
which does not start an xterm.)
Fixing the bug while keepting eval is very difficult.
Even changing the line
params="$params "$param"";;
to
params="$params '$param'";;
would not help: Now
yourscript '`xterm`'
no longer starts an xterm, but
yourscript '' `xterm` ''
still does.
The question is "Should a bash array be used in place of eval set — “$params”?", and the answer is yes!.
In your script, the input to eval is clearly not properly sanitized. Try
yourscript '`xterm`'
and you'll see that an xterm is started even though the backticks are properly quoted by single quotes. (Compare with
echo '`xterm`'
which does not start an xterm.)
Fixing the bug while keepting eval is very difficult.
Even changing the line
params="$params "$param"";;
to
params="$params '$param'";;
would not help: Now
yourscript '`xterm`'
no longer starts an xterm, but
yourscript '' `xterm` ''
still does.
edited Jan 6 '16 at 0:19
answered Jan 5 '16 at 23:21
Uwe
3,0171217
3,0171217
Thanks! I'm working on a remote box over ssh, so I don't havextermavailable, but I tested it withmyscript '`touch /tmp/hacked`'(and compared it toecho '`touch /tmp/hacked`'). I didn't even need the double quotes or the spaces, though; is there a different edge case those are hacking around?
– Wildcard
Jan 5 '16 at 23:35
Also, I've never usedbasharrays before—I wrote the "cleaner" version that uses arrays after a brief once-over of the applicable man page section. Did I get it right? Any pitfalls in it that you see?
– Wildcard
Jan 5 '16 at 23:36
Also NB: This is not my script. I linked to the optparse library in my question; that's the source of this code. However, the optparse library is sourced from some other code that I have to maintain, so I want to clean up the vulnerabilities. I've never usedevalin a script and probably never will. ;)
– Wildcard
Jan 5 '16 at 23:40
1
@Wildcard yes, you're right, the double quotes or the spaces are unnecessary, since the script tries to protect$paramwith double quotes, and backticks are evaluated even within double quotes. If$paramwere protected with single quote, one would need a more complicated argument.
– Uwe
Jan 5 '16 at 23:57
2
@AlexejMagura These are literal backticks. They are properly quoted. They are not supposed to be interpreted -- but they are interpreted.
– Uwe
Jan 19 '17 at 21:49
|
show 3 more comments
Thanks! I'm working on a remote box over ssh, so I don't havextermavailable, but I tested it withmyscript '`touch /tmp/hacked`'(and compared it toecho '`touch /tmp/hacked`'). I didn't even need the double quotes or the spaces, though; is there a different edge case those are hacking around?
– Wildcard
Jan 5 '16 at 23:35
Also, I've never usedbasharrays before—I wrote the "cleaner" version that uses arrays after a brief once-over of the applicable man page section. Did I get it right? Any pitfalls in it that you see?
– Wildcard
Jan 5 '16 at 23:36
Also NB: This is not my script. I linked to the optparse library in my question; that's the source of this code. However, the optparse library is sourced from some other code that I have to maintain, so I want to clean up the vulnerabilities. I've never usedevalin a script and probably never will. ;)
– Wildcard
Jan 5 '16 at 23:40
1
@Wildcard yes, you're right, the double quotes or the spaces are unnecessary, since the script tries to protect$paramwith double quotes, and backticks are evaluated even within double quotes. If$paramwere protected with single quote, one would need a more complicated argument.
– Uwe
Jan 5 '16 at 23:57
2
@AlexejMagura These are literal backticks. They are properly quoted. They are not supposed to be interpreted -- but they are interpreted.
– Uwe
Jan 19 '17 at 21:49
Thanks! I'm working on a remote box over ssh, so I don't have
xterm available, but I tested it with myscript '`touch /tmp/hacked`' (and compared it to echo '`touch /tmp/hacked`'). I didn't even need the double quotes or the spaces, though; is there a different edge case those are hacking around?– Wildcard
Jan 5 '16 at 23:35
Thanks! I'm working on a remote box over ssh, so I don't have
xterm available, but I tested it with myscript '`touch /tmp/hacked`' (and compared it to echo '`touch /tmp/hacked`'). I didn't even need the double quotes or the spaces, though; is there a different edge case those are hacking around?– Wildcard
Jan 5 '16 at 23:35
Also, I've never used
bash arrays before—I wrote the "cleaner" version that uses arrays after a brief once-over of the applicable man page section. Did I get it right? Any pitfalls in it that you see?– Wildcard
Jan 5 '16 at 23:36
Also, I've never used
bash arrays before—I wrote the "cleaner" version that uses arrays after a brief once-over of the applicable man page section. Did I get it right? Any pitfalls in it that you see?– Wildcard
Jan 5 '16 at 23:36
Also NB: This is not my script. I linked to the optparse library in my question; that's the source of this code. However, the optparse library is sourced from some other code that I have to maintain, so I want to clean up the vulnerabilities. I've never used
eval in a script and probably never will. ;)– Wildcard
Jan 5 '16 at 23:40
Also NB: This is not my script. I linked to the optparse library in my question; that's the source of this code. However, the optparse library is sourced from some other code that I have to maintain, so I want to clean up the vulnerabilities. I've never used
eval in a script and probably never will. ;)– Wildcard
Jan 5 '16 at 23:40
1
1
@Wildcard yes, you're right, the double quotes or the spaces are unnecessary, since the script tries to protect
$param with double quotes, and backticks are evaluated even within double quotes. If $param were protected with single quote, one would need a more complicated argument.– Uwe
Jan 5 '16 at 23:57
@Wildcard yes, you're right, the double quotes or the spaces are unnecessary, since the script tries to protect
$param with double quotes, and backticks are evaluated even within double quotes. If $param were protected with single quote, one would need a more complicated argument.– Uwe
Jan 5 '16 at 23:57
2
2
@AlexejMagura These are literal backticks. They are properly quoted. They are not supposed to be interpreted -- but they are interpreted.
– Uwe
Jan 19 '17 at 21:49
@AlexejMagura These are literal backticks. They are properly quoted. They are not supposed to be interpreted -- but they are interpreted.
– Uwe
Jan 19 '17 at 21:49
|
show 3 more comments
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f253481%2fcan-a-bash-array-be-used-in-place-of-eval-set-params%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown