jar*_*rno 3 security bash zsh sh dash-shell
我的意思是我想使用unset它本身不是shell函数.如果我能做到这一点,我可以command通过跑步来确保它是纯粹的
#!/bin/sh
{ \unset -f unalias command [; \unalias unset command [ } 2>/dev/null;
# make zsh find *builtins* with `command` too:
[ -n "$ZSH_VERSION" ] && options[POSIX_BUILTINS]=on
Run Code Online (Sandbox Code Playgroud)
如果我使用的是Debian Almquist shell(破折号),我认为我可以依赖它\unset是纯粹的.至少我不能定义一个名为shell函数unset在dash.而在我bash或之中zsh我可以定义unset() { echo fake unset; },然后我无法取消该功能:\unset -f unset输出"假未设置".
与此相关,在bash脚本中,可以导出函数,export -f <function name>以便可以在bash脚本调用的脚本中使用它.但是,这在dash脚本中不起作用.我想知道,如果我不得不担心一个命令被定义为我写的脚本文件外的shell函数,如果我正在使用dash?其他POSIX兼容的shell怎么样?
注:以下内容适用于所有主要的POSIX兼容的炮弹,除非另有说明:bash,dash,ksh,和zsh.(dash,Debian Almquist Shell,是sh基于Debian的Linux发行版(如Ubuntu)的默认shell()).
unset具有其原始含义 - 一个可以通过其选项取消定义shell 函数的内置函数-f - 是确保任何其他shell关键字,命令或内置函数具有其原始含义的关键.
unset,您可以确保未修改shopt和/或command,它们可以一起用于绕过或取消定义可能影响shell关键字,内置函数和外部实用程序的任何别名或shell函数.command可以用来绕过它们,包括那些可能已经通过环境在代码之外定义的函数; bash支撑件,仅是一个这些机制; 不同的壳有不同的壳,可能支持几个 - 见下文.只有dash,ksh和bash 当POSIX兼容模式下保证unset不重新定义:
dash并且ksh是安全的,因为它们不允许定义一个名为的函数unset,正如您所发现的那样,并且可以通过调用as来绕过任何别名形式\unset.
bash,当处于POSIX兼容模式时,允许您定义一个名为的函数unset,但在调用时忽略它unset,并始终执行内置函数,如您稍后发现的那样.
unset 功能.遗憾的是,据我所知,在zsh- 以及在bash默认模式下 - 没有办法保证它unset本身没有被重新定义,并且可能有其他类似POSIX的shell表现相似.
\unset(引用名称的任何部分)将绕过别名重定义,但不会重新定义函数 - 并撤消您需要原始unset本身:catch 22.因此,与在执行环境无法控制,你可以不写是完全不受篡改shell脚本,除非你知道你的代码会被执行dash,ksh或者bash(在地方解决方法).
如果您愿意假设unset没有被篡改,最强大的方法是:
使用\unset -f以确保unalias和command未修改(而不是由一个shell函数阴影:\unset -f unalias command)
typeset -f工程bash,ksh和zsh,但dash似乎没有任何机制可言),使取消定义的所有功能,是并非总是可行.使用\unalias -a删除所有别名.
然后调用一切有command [-p],除了功能,您已经定义.在调用外部实用程序时,尽可能使用显式路径,和/或在标准实用程序的情况下使用command -p,它使用$PATH限制在标准位置的最小定义(运行command -p getconf PATH以查看该定义).
附加信息:
每个POSIX,引用命令名称的任何部分(例如\unset),用该名称绕过任何别名形式或关键字形式(POSIX和用语中的保留字zsh) - 但不是 shell 函数.
按POSIX,unalias -a取消定义所有别名.没有等效的POSIX兼容命令来取消定义所有功能.
zsh版本不支持-a; v5.0.8但至少,他们确实如此.内建command可用于绕过关键字,别名,函数中bash,dash和ksh-换句话说:command只执行内建和外部公用事业.相比之下,zsh默认情况下也会绕过内置组件 ; 要zsh使用内置函数,请使用options[POSIX_BUILTINS]=on.
以下内容可用于在所有shell中执行仅命名的外部实用程序<name>:
"$(command which <name>)" ...
请注意,虽然which它不是POSIX实用程序,但它在现代类Unix平台上广泛使用.
命令形式的优先顺序:
bash,zsh:别名> shell关键字> shell函数>内置>外部实用程序ksh,dash:shell关键字>别名> shell函数>内置>外部实用程序bash和zsh别名可以覆盖shell关键字,而in ksh和dash它不能.bash,ksh和zsh- 但不是dash- 都允许非标准函数签名function <name> { ...,作为POSIX兼容<name>() { ...表单的替代.
function语法是先决条件:
<name>它本身不受别名扩展的影响.<name>也是一个shell 关键字 ; \while.ksh,使用function语法还意味着typeset语句创建局部变量.)dash,ksh和bash 当在POSIX模式附加地防止命名功能特殊内置命令(例如,unset,break,set,shift); POSIX定义的特殊内置列表可以在这里找到; 双方dash并ksh添加更多一些不能被重新定义(例如,local在dash; typeset而unalias在ksh),但两个壳具有附加的,非特殊的是内建可被重新定义(如type).ksh上述规则的情况下,无论是否使用function语法,都适用.代码范围内的环境shell函数的潜在来源:
注意:谨防这些最简单的方法是使用(未修改)command内置(在zsh用options[POSIX_BUILTINS]=on,以防止建宏旁路为好),只要你想调用一个内置或外部工具.
POSIX任务,通过在环境变量的绝对路径指定的脚本ENV来采购的互动壳(有一些限制-见规范); ksh并且dash总是尊重这一点,而bash只有sh在v4.2 +中调用时才会这样做--posix; 相比之下,zsh从不尊重这个变量.
sh -i强制交互式实例.bash有2种机制:
export -fdeclare -fxBASH_ENV.ksh支持自动装载的功能通过可选的FPATH环境变量:含有位于指定的任何目录函数定义文件FPATH是隐式和自动加载.
zsh支持FPATH,但自动加载函数需要一个显式 autoload <name>语句,因此除非您特别要求给定名称的函数自动加载,否则不会向shell添加任何函数.)zsh支持采购脚本任何 zsh情况下(无论是交互式或不能)通过其/etc/zshenv与~/.zhsenv初始化文件.
(dash似乎不支持通过环境定义函数的任何机制.)
bash:确保unset具有其原始含义:如果您知道bash将执行您的脚本,这种解决方法是安全的,遗憾的是,这本身不能保证.
此外,因为它修改了shell环境(删除了别名和函数),所以它不适合设计为源代码的脚本.
如上所述,通常不希望在Bash的POSIX兼容模式下运行代码,但您可以暂时激活它以确保unset不被函数遮蔽:
#!/bin/bash
# *Temporarily* force Bash into POSIX compatibility mode, where `unset` cannot
# be shadowed, which allows us to undefine any `unset` *function* as well
# as other functions that may shadow crucial commands.
# Note: Fortunately, POSIXLY_CORRECT= works even without `export`, because
# use of `export` is not safe at this point.
# By contrast, a simple assignment cannot be tampered with.
POSIXLY_CORRECT=
# If defined, unset unset() and other functions that may shadow crucial commands.
# Note the \ prefix to ensure that aliases are bypassed.
\unset -f unset unalias read declare
# Remove all aliases.
# (Note that while alias expansion is off by default in scripts, it may
# have been turned on explicitly in a tampered-with environment.)
\unalias -a # Note: After this, \ to bypass aliases is no longer needed.
# Now it is safe to turn POSIX mode back off, so as to reenable all Bash
# features.
unset POSIXLY_CORRECT
# Now UNDEFINE ALL REMAINING FUNCTIONS:
# Note that we do this AFTER switching back from POSIX mode, because
# Bash in its default mode allows defining functions with nonstandard names
# such as `[` or `z?`, and such functions can also only be *unset* while
# in default mode.
# Also note that we needn't worry about keywords `while`, `do` and `done`
# being shadowed by functions, because the only way to invoke such functions
# (which you can only define with the nonstandard `function` keyword) would
# be with `\` (e.g., `\while`).
while read _ _ n; do unset -f "$n"; done < <(declare -F)
# IN THE REST OF THE SCRIPT:
# - It is now safe to call *builtins* as-is.
# - *External utilities* should be invoked:
# - by full path, if feasible
# - and/or, in the case of *standard utilities*, with
# command -p, which uses a minimal $PATH definition that only
# comprises the locations of standard utilities.
# - alternatively, as @jarno suggests, you can redefine your $PATH
# to contain standard locations only, after which you can invoke
# standard utilities by name only, as usual:
# PATH=$(command -p getconf PATH)
# Example command:
# Verify that `unset` now refers to the *builtin*:
type unset
Run Code Online (Sandbox Code Playgroud)
测试命令:
假设上面的代码已保存到script当前目录中的文件中.
下面的命令模拟篡改,与环境中,unset由两个别名和功能,以及文件阴影script的来源,使其看到的功能和交互来源时,过于扩大别名:
$ (unset() { echo hi; }; alias unset='echo here'; . ./script)
unset is a shell builtin
Run Code Online (Sandbox Code Playgroud)
type unset输出unset is a shell builtin是证明影响内置函数的函数和别名unset都被取消激活的证明.
有趣的是,你已经说了内置名称——command
$ var="FOO"
$ unset() { echo nope; }
$ echo "${var}"
FOO
$ unset var
nope
$ echo "${var}"
FOO
$ command unset var
$ echo "${var}"
<nothing!>
Run Code Online (Sandbox Code Playgroud)
如果您处于某人创建了command() { :; }函数的敌对环境中,这并没有帮助。但如果你处于敌对的环境中,你就已经失败了;)。
当涉及到将函数导出到环境中时,这是特定于 bash 的扩展,您不应该真正依赖它。POSIX shell(如 dash)在设计上不支持这一点。
| 归档时间: |
|
| 查看次数: |
684 次 |
| 最近记录: |