shell命令列表中的竞争条件

时间:2012-03-03 19:49:54

标签: security bash shell symlink race-condition

shell(或bash)中的命令列表在竞争条件下的安全性如何?

if [ -h "$dir" ]; then
  echo 'Directory exists and is a symlink'
  exit 1
fi
cd "$dir"

上面的代码显然容易出现竞争条件:攻击者可以在检查后创建一个符号链接,但仍然可以在将目录更改为它之前。

这同样适用于||命令列表吗?换句话说:以下命令是否对竞争条件免疫,或者上述规则是否仍然适用?

[ -h "$dir" ] || cd "$dir"

显示错误消息:

[ -h "$dir" ]
  && { echo 'Directory exists and is a symlink'; exit 1; }
  || cd "$dir"

4 个答案:

答案 0 :(得分:3)

这是一个很好的教育问题,但在实践中你正在解决错误的问题。 Linux安全模型不依赖于脚本并发问题,而是依赖于文件系统权限。

如果您担心攻击者可能会改变执行程序下的工作环境,那么您应该保护环境:确保只有您对将要运行的脚本和二进制文件具有写入权限,并创建文件和目录仅限于您只能写入的位置。

对于二进制可执行文件,请查看使用setuid位,它允许普通用户使用提升的权限执行它们,但要注意,必须仔细调试并检查以此方式运行的任何进程是否存在安全问题。但是,大多数Linux发行版都不允许脚本以这种方式运行。

值得一提的是,获得您(或根)密码的攻击者可以轻易地击败这个和其他安全措施,但在这种情况下,您遇到了更大的问题。 : - )

祝你好运!

答案 1 :(得分:3)

只有两种安全且相对便携的方法可以在不遵循符号链接的情况下更改目录。在shell脚本中都不容易实现。

为了讨论起见,假设我们试图安全地进入“foo”。第一种方法是将当前目录保存在一个打开的文件描述符中,其open(".", O_RDONLY)lstat()为“foo”目录,记录产生的st_devst_ino值,调用chdir(“foo”)然后stat()“。”。比较得到的st_devst_ino值。如果他们是相同的,你赢得了比赛。如果没有,请使用您保存的fd发回错误消息fchdir(),然后中止或重试。

第二种不太便于使用的方式是使用fd = open("foo", O_RDONLY|O_NOFOLLOW)然后使用fchdir(fd)。您也可以在此处使用openat代替open。可移植性问题是并非所有系统都有O_NOFOLLOW而某些旧内核不能正确解释该标志(而是忽略它,这是一个安全问题)。

有关更多信息,请查看GNU find的源代码,其中我使用与上述方法非常相似的方法来避免此类问题。

至于在shell脚本中解决这个问题:

如果您的系统有stat(1)命令或Perl之类的命令,您可以使用它们来执行stat操作;您可以将结果记录在shell变量中。这意味着您可以或多或少地在shell脚本中实现第一个方法,但需要使用fchdir来恢复。如果可以在shell脚本丢失竞争时立即中止,那么您当然可以调整第一种方法在shell中使用。但最终在shell中编写安全代码非常非常困难。

答案 2 :(得分:0)

我认为没有理由使用||不会受到相同竞争条件的影响。实际上,因为它不容易受到攻击,所以需要使用

来实现
  • 某种原子stat-and-chdir文件系统操作(我很确定不存在),或者

  • cd之后进行某种双重检查,以确保目录仍然指向与以前相同的位置。

我不是bash guru,但我很确定这两种情况都不是。

答案 3 :(得分:0)

一般来说,您无法避免shell脚本中的竞争条件。您需要使用C,并使用TOCTTOU安全接口,例如openatfchdir等。避免TOCTTOU(种族)漏洞并非易事,需要仔细研究。