这样做的最佳方式是什么?
这是我的想法:
fd = open("/tmp/some-benchmark-data.txt", O_APPEND | O_CREAT | O_NOFOLLOW | O_WRONLY, 0644);
fstat(fd, &st);
if (st.st_nlink != 1) {
HARD LINK ATTACK!
}
问题:有人可以将文件链接到我的一些短期文件,因此/tmp/some-benchmark-data.txt与我的另一个脚本正在使用的/ tmp / tmpfileXXXXXX相同(和使用O_EXCL和所有这些正确打开。然后我的基准数据被附加到这个/ tmp / tmpfileXXXXXX文件,当它仍然被使用时。
如果我的其他脚本碰巧打开了它的临时文件,那么删除它,然后使用它;然后我的基准数据会破坏该文件的内容。然后,这个其他脚本必须在上面代码的open()和fstat()之间删除它的文件。
换句话说:
This script Dr.Evil My other script or program
open(fn2, O_EXCL | O_CREAT | O_RDWR)
link(fn1,fn2)
open(fn1, ...)
unlink(fn2)
fstat(..)=>link is 1
write(...)
close(...)
write(...)
seek(0, ...)
read(...) => (maybe) WRONG DATA!
因此上述解决方案不起作用。很可能还有其他攻击。
什么是正确的方法?除了不使用世界可写目录。
修改: 为了防止恶意用户使用他/她的所有权和权限创建文件的结果,或者只是错误的权限(通过硬链接文件然后删除原始文件,或者硬连接你的短文件)我可以检查nlink检查后的所有权和权限位。
不存在任何安全问题,但也可以避免意外。最糟糕的情况是,我从我的其他文件复制的文件开头得到了一些我自己的数据(来自另一个文件)。
编辑2 : 我认为几乎不可能防止某人将名称硬链接到打开,删除然后使用的文件。例如EXE打包程序,有时甚至可以通过/ proc / pid / fd-num执行删除的文件。与此竞争会导致打包程序的执行失败。 lsof可能会发现是否有其他人打开了inode,但它似乎比它的价值更麻烦。
答案 0 :(得分:2)
无论你做什么,你通常会遇到竞争条件,其他人创建一个链接,然后在你的fstat()系统调用执行时删除它。
你没有准确说出你想要阻止的东西。肯定有内核补丁可以防止在世界可写目录(或粘性目录)中创建您不拥有的文件(硬或符号)链接。
将它放在一个非世界可写的目录中似乎是正确的做法。
SELinux,它似乎是标准的增强型安全性Linux,可能能够配置策略禁止用户做坏事而破坏你的应用程序。
通常,如果您以root用户身份运行,请不要在/ tmp中创建文件。另一种可能性是使用setfsuid()将文件系统uid设置为其他人,然后如果该文件不能被该用户写入,则操作将失败。
答案 1 :(得分:1)
除了你刚刚说明的内容之外,我尝试过的唯一另一件事最终几乎同样具有竞争性且更昂贵,在/ tmp 之前创建inotify手表来创建文件,这样可以捕获在某些情况下发生硬链接。
然而,它仍然非常具有竞争性和低效率,因为您还需要完成广度优先搜索/ tmp,至少达到您要创建文件的级别。
据我所知,除了不使用单词可写目录之外,没有“确定”方法可以避免这种竞争。有人通过硬链接拦截你的i / o会有什么后果......他们会得到什么有用的东西,或者只是让你的应用程序表现出不明确的行为?