有一个类似的问题处理“包装”场景,例如您想要替换cd
为调用内置cd
.
然而,鉴于 shellshock 等人并知道 bash 从环境导入函数,我做了一些测试,但找不到cd
从脚本中安全调用内置函数的方法。
考虑一下这个
cd() { echo "muahaha"; }
export -f cd
在此环境中使用使用调用的任何脚本cd
都将中断(考虑类似的效果cd dir && rm -rf .
)。
有检查命令类型的命令(方便地称为type
)和用于执行内置版本而不是函数的命令(builtin
和command
)。但是,你瞧,这些也可以使用函数来覆盖
builtin() { "$@"; }
command() { "$@"; }
type() { echo "$1 is a shell builtin"; }
将产生以下结果:
$ type cd
cd is a shell builtin
$ cd x
muahaha
$ builtin cd x
muahaha
$ command cd x
muahaha
有没有什么方法可以安全地强制 bash 使用内置命令,或者至少检测到命令不是内置命令,而无需清除整个环境?
我意识到,如果有人控制你的环境,你可能会被搞砸,但至少对于别名,你可以选择通过在别名\
之前插入 a 来不调用别名。
答案1
奥利维尔·D·几乎正确,但必须POSIXLY_CORRECT
在运行之前设置unset
。 POSIX 有一个概念特殊内置, 和bash 支持这个。unset
就是这样一个内置的。在 bash 源中搜索SPECIAL_BUILTIN
inbuiltins/*.c
查找列表,其中包括set
、unset
、export
和eval
。source
$ unset() { echo muahaha-unset; }
$ unset unset
muahaha-unset
$ POSIXLY_CORRECT=1
$ unset unset
流氓unset
现在已从环境中删除,如果您取消设置command
, type
,builtin
那么您应该能够继续,但unset POSIXLY_CORRECT
如果您稍后依赖非 POSIX 行为或高级 bash 功能。
这才不是但地址别名,所以你必须使用\unset
(或使用某种形式的引用/转义在这个词上)以确保它在交互式 shell 中工作(或者总是,以防万一expand_aliases
有效)。
对于偏执狂来说,这应该解决一切问题,我认为:
POSIXLY_CORRECT=1
\unset -f help read unset
\unset POSIXLY_CORRECT
re='^([a-z:.\[]+):' # =~ is troublesome to escape
while \read cmd; do
[[ "$cmd" =~ $re ]] && \unset -f ${BASH_REMATCH[1]};
done < <( \help -s "*" )
(while
、do
、done
和[[
是保留字,不需要预防措施。不能=
在别名或函数名中使用,因此设置时不需要预防措施POSIXLY_CORRECT
。)请注意,我们使用unset -f
来确保取消设置函数,尽管变量和函数共享同一个命名空间,两者可以同时存在(感谢 Etan Reisner),在这种情况下取消设置两次也可以解决问题。你能将函数标记为只读,bash 不会阻止您取消设置 bash-4.2 及之前版本的只读函数,bash-4.3 确实会阻止您,但在POSIXLY_CORRECT
设置时它仍然尊重特殊的内置函数。
只读POSIXLY_CORRECT
不是真正的问题,这不是布尔值或标志在场启用 POSIX 模式,因此如果它作为只读存在,您可以依赖 POSIX 功能,即使该值为空或 0。您只需要以与上面不同的方式取消设置有问题的函数,也许需要进行一些剪切和粘贴:
\help -s "*" | while IFS=": " read cmd junk; do echo \\unset -f $cmd; done
(并忽略任何错误)或从事其他一些事情脚本学。
其他注意事项:
function
是保留字,可以使用别名但不能用函数覆盖。 (别名function
有点麻烦,因为\function
不是作为绕过它的一种方式是可以接受的)[[
,]]
是保留字,它们可以使用别名(将被忽略),但不能用函数覆盖(尽管函数可以如此命名)((
不是函数的有效名称,也不是别名
感谢下面评论者的额外建议。
答案2
我意识到如果有人控制了你的环境你可能就完蛋了
对,就那个。如果您在未知环境中运行脚本,则各种情况都可能出错,首先是LD_PRELOAD
导致 shell 进程在读取脚本之前执行任意代码。尝试从脚本内部防范敌对环境是徒劳的。
十多年来,Sudo 一直通过删除任何看起来像 bash 函数定义的内容来净化环境。自从炮弹休克,在不完全受信任的环境中运行 shell 脚本的其他环境也纷纷效仿。
您无法在不受信任的实体设置的环境中安全地运行脚本。因此担心函数定义是没有成效的。清理你的环境,并在这样做时 bash 会将变量解释为函数定义。
答案3
您可以使用该命令unset -f
删除函数builtin
、command
和type
。