假设foo
在当前 shell 会话中定义了某个 shell 函数。然后命令
typeset -f foo
打印出该函数的源代码。这意味着,至少在原则上,人们可以通过ssh
如下所示在远程主机上执行此功能:
ssh <REMOTE-HOST> "$(typeset -f foo); foo"
(出于本问题的目的,假设 中提到的所有命令和文件系统路径foo
都可用<REMOTE-HOST>
。此外,假设bash
两端都是 shell。)
我的直觉是,盲目地获取一些像这样自动生成的源代码将是非常脆弱的,但我无法提出foo
这个习惯用法失败的函数的示例。
我的问题是:这个习语有多安全?如果它不安全,有人可以给我一个具体的例子来说明它是如何失败的吗? (安全问题包括以下内容:是否bash
保证这种使用typeset -f
是安全的?)
注意:在这篇文章中,我并不是在寻找替代方案;而是在寻找替代方案。我只是想了解这个特定习语的属性。
编辑:澄清这bash
是两端的外壳。
答案1
如果代码没有在与生成它的语言环境相同的语言环境中解释(或者如果语言环境姓名是相同的,但 ssh 客户端主机和服务器主机之间的区域设置的定义不同)。
blank
特别重要的是、alpha
和类别中的字符编码和字符成员资格alnum
。
例如,α
BIG5 字符集中的字符(希腊字母小写 alpha)被编码为 0xa3 0x5c,0x5c\
在 ASCII 中(以及包括 BIG5 在内的所有字符集)。
因此,如果您foo
在该字符集中定义了一个函数:
foo() {
echo α
}
typeset -f
会这样输出,但如果在不同的语言环境(如 C)中解释,则 0xa3 0x5c 不会被视为 a,α
而是被视为未知的 0xa3 字符,后跟反斜杠。可以这样利用:
$ env LC_ALL=zh_TW.big5 $'BASH_FUNC_foo%%=() { echo \xa3\\\\;}; echo gotcha; }' bash -c 'typeset -f foo' | bash
gotcha
bash: line 5: syntax error near unexpected token `}'
bash: line 5: `}'
当在不同的语言环境中解释时,就foo() { echo α\;}; echo gotcha; }
变成了。foo() { echo <0xa3>\\; }; echo gotcha; }
其他问题:
UTF-8 中的字符à
编码为 0xc3 0xa0。在iso8859-1和其他几个iso8859
字符集中,0xa0 是不间断空格字符。在某些系统上,该字符包含在空白的字符类,因此 bash 在其语法中将其作为标记分隔符。
Solaris 就是这样一个系统,其中 U+00A0 被视为空白:
$ env $'BASH_FUNC_foo%%=() { nawk -v x=àBEGIN\'{system("echo gotcha")}\' 1;}' bash -c 'typeset -f foo; echo foo' | ssh solaris LC_ALL=en_GB.ISO8859-1 bash
gotcha
看看如何:
nawk -v x=àBEGIN... 1
被解释为:
nawk -v x=<0xc3> 'BEGIN{system("...")}' 1
请注意,如果该函数是在 0xa0 不是空白或 0xa3 0x5c 是 alpha 的语言环境中定义的,typeset -f
即使在它是空白的语言环境中调用,仍会输出相同的结果(解释时产生不同的输出)
$ LC_ALL=zh_TW.big5 bash -c $'f() { echo \xa3\x5c$(uname); }; export LC_ALL=C; typeset -f f | bash'
bash: line 3: syntax error near unexpected token `('
bash: line 3: ` echo �\$(uname)'
更一般地说,输出typeset
, alias
, export -p
, set
,locale
都是意思是适合重新输入到 shell,但除了这些区域设置问题之外,已知各种实现也存在几个问题,如果还有更多问题,我也不会感到惊讶。
所以,是的,我同意你认为它是危险的,这是一个好主意,并且最好只在你知道输出数据来自哪里的上下文中使用它们。例如,在 的情况下typeset -f foo
,仅将其用于foo
,仅在满足以下条件的函数你已定义(并避免在其中使用非 ASCII 字符)。