Answers:
问题在于,如果$x外壳代码可能最终在特权提升上下文中使用(例如,setuid调用的脚本),则其中的内容尚未经过清理并包含可能受到攻击者控制的数据应用程序,sudoers脚本或用于直接或间接处理网络外数据(CGI,DHCP钩子...)。
如果:
x='(PATH=2)'
然后:
x=$((1-$x)))
具有设置PATH为2(相对路径很可能在攻击者的控制之下)的副作用。您可以替换PATH使用LD_LIBRARY_PATH或IFS...这同样与发生x=$((1-x))在bash,zsh中或ksh(不是冲也不佳日只接受变量有数字常量)。
注意:
x=$((1-$x))
对于$x实现了(按POSIX可选)--(减量)运算符的某些shell中的负值,它将不能正常工作(与一样x=-1,这意味着要求shell评估1--1算术表达式)。"$((1-x))"没有这个问题,因为x算术评估的一部分(不早于此)已经扩展了。
在bash,zsh和ksh(不dash或yash)中,如果x是:
x='a[0$(uname>&2)]'
然后扩展$((1-$x))或$((1-x))导致uname执行该命令(对于zsh,a需要是一个数组变量,但是可以使用该变量psvar)。
总之,我们不应该使用未初始化或不消毒的炮弹在算术表达式中的外部数据(注意,算术评估可以这样做$((...))(又名$[...]中bash或zsh),而且还取决于在壳let,[/ test,declare/typeset/export...,return,break,continue,exit,printf,print内建函数,数组索引((..))和[[...]]结构等)。
要检查变量是否包含文字十进制整数,可以使用POSIXly:
case $var in
("" | - | *[!0123456789-]* | ?*-*) echo >&2 not a valid number; exit 1;;
esac
请注意,[0-9]在某些语言环境中,匹配项超过0123456789。[[:digit:]]应该可以,但我不会打赌。
还请记住,在某些情况下,带有前导零的数字被视为八进制(010有时为10,有时为8),并且请注意,上面的检查将使可能大于系统(或您将要使用的任何应用程序)支持的最大整数的数字通过在其中使用该整数;例如bash将18446744073709551616视为0,即2 64)。因此,您可能想要在上述case语句中添加额外的检查,例如:
(0?* | -0?*)
echo >&2 'Only decimal numbers without leading 0 accepted'; exit 1;;
(-??????????* | [!-]?????????*)
echo >&2 'Only numbers from -999999999 to 999999999 supported'; exit 1;;
例子:
$ export 'x=psvar[0$(uname>&2)]'
$ ksh93 -c 'echo "$((x))"'
Linux
ksh93: psvar: parameter not set
$ ksh93 -c '[ x -lt 2 ]'
Linux
ksh93: [: psvar: parameter not set
$ bash -c 'echo "$((x))"'
Linux
0
$ bash -c '[[ $x -lt 2 ]]'
Linux
$ bash -c 'typeset -i a; export a="$x"'
Linux
$ bash -c 'typeset -a a=([x]=1)'
Linux
$ bash -c '[ -v "$x" ]'
Linux
$ mksh -c '[[ $x -lt 2 ]]'
Linux
$ zsh -c 'echo "$((x))"'
Linux
0
$ zsh -c 'printf %d $x'
Linux
0
$ zsh -c 'integer x'
Linux
$ zsh -c 'exit $x'
Linux
更多阅读:
x[0$(...)]我们注意此问题)。bash。
x='P=3'; : $(($x + 5))将设置P为8,但x='P=3'; : $((x + 5))将设置P到3(在zsh,ksh或bash)。“$((x + 1))…… 也发生同样的情况”现在不正确;它将设置PATH为2,与旧版本相同。