Tim*_*Tim 4 bash environment-variables function
从Bash 手册:
请注意,具有相同名称的 shell 函数和变量可能会导致环境中多个同名条目传递给 shell 的子项。在这可能会导致问题的情况下,应该小心。
bash 如何区分“shell 函数和同名变量”?
$ func () { return 3; }; func=4; declare -p func; declare -f func;
declare -- func="4"
func ()
{
return 3
}
Run Code Online (Sandbox Code Playgroud)
“传递给 shell 子项的环境中的多个同名条目”何时发生?
遇到什么问题应该“注意”什么?
通常,shell 区分变量和函数,因为它们在不同的上下文中使用。简而言之,如果名称出现在 a 之后$
,或者作为export
(without -f
) 和unset
(without -f
)等内置函数的参数,它就是变量名。名称是如果它显示为(别名扩展之后)的命令或作为一个参数的函数名export -f
,unset -f
等
变量可以导出到环境中。环境变量的名称与shell变量的名称相同(并且值也相同)。
与大多数其他 shell 不同,Bash 还可以将函数导出到环境中。由于环境中没有类型指示,因此无法识别环境中的条目是否为函数,只能通过分析环境变量的名称或值。
较旧版本的 bash 使用函数名作为名称在环境中存储一个函数,并且将看起来像函数定义的东西作为函数值。例如:
bash-4.1$ foobar () { echo foobar; }
bash-4.1$ export -f foobar
bash-4.1$ env |grep -A1 foobar
foobar=() { echo foobar
}
bash-4.1$
Run Code Online (Sandbox Code Playgroud)
请注意,无法区分其代码是{ echo foobar; }
其值是() { echo foobar?}
(where?
是换行符)的变量的函数。结果证明这是一个糟糕的设计决定。
有时,shell 脚本会使用环境变量调用,其值受潜在敌对实体的控制。例如,CGI 脚本。Bash 的函数导出/导入功能允许以这种方式注入函数。例如执行脚本
#!/bin/bash
ls
Run Code Online (Sandbox Code Playgroud)
只要环境不包含具有特定名称(例如PATH
)的变量,来自远程请求就是安全的。但是,如果该请求可以在环境变量设置ls
到() { cat /etc/passwd; }
这时,bash会愉快地执行cat /etc/passwd
,因为那是身体ls
功能。
这个安全漏洞是由Stéphane Chazelas发现的,是Shellshock 漏洞的一个方面。在 bash 的后 Shellshock 版本中,导出的函数由它们的名称而不是它们的内容标识。
bash-4.3$ foobar () { echo foobar; }
bash-4.3$ export -f foobar
bash-4.3$ env |grep -A1 foobar
BASH_FUNC_foobar%%=() { echo foobar
}
Run Code Online (Sandbox Code Playgroud)
现在没有安全问题,因为像这样BASH_FUNC_foobar%%
的名称不常用作命令名称,并且可以被允许传递环境变量的接口过滤掉。在技术上可以%
在环境变量的名称中包含一个字符(这就是现代 bash 的导出函数工作的原因),但通常人们不会这样做,因为 shell 不接受%
变量名称。
bash 手册中的句子指的是旧的(Shellshock 之前的)行为。它应该被更新或删除。对于现代 bash 版本,如果您假设环境变量的名称不以%%
.