Shell脚本mktemp,创建临时命名管道的最佳方法是什么?


30

我知道最好使用创建临时文件mktemp,但是命名管道呢?

我希望事情尽可能与POSIX兼容,但是仅Linux是可以接受的。正如我在中所写,避免Bashisms是我唯一的困难标准dash

Answers:


41
tmppipe=$(mktemp -u)
mkfifo -m 600 "$tmppipe"

与常规文件创建(容易被现有文件或符号链接劫持)不同,创建名称管道mkfifo基础函数要么在指定位置创建新文件,要么失败。这样的事情: >foo是不安全的,因为如果攻击者可以预测其输出,mktemp则攻击者可以为自己创建目标文件。但是mkfifo foo在这种情况下会失败。

如果您需要完全的POSIX可移植性,mkfifo -m 600 /tmp/myfifo则可以安全地防止劫持,但容易遭到拒绝服务;如果无法访问强随机文件名生成器,则需要管理重试尝试。

如果您不关心临时文件周围的细微安全性问题,可以遵循一个简单的规则:创建一个私有目录,并将所有内容保存在其中。

tmpdir=
cleanup () {
  if [ -n "$tmpdir" ] ; then rm -rf "$tmpdir"; fi
  if [ -n "$1" ]; then kill -$1 $$; fi
}
tmpdir=$(mktemp -d)
trap 'cleanup' EXIT
trap 'cleanup HUP' HUP
trap 'cleanup TERM' TERM
trap 'cleanup INT' INT
mkfifo "$tmpdir/pipe"

昨天早些时候,我实际上已经选择了此解决方案,我在等着看是否有人发布了它,或者是更好的解决方案。就我而言,我也觉得这是要走的路。无论如何...非常感谢您的帮助。
JM Becker 2012年

1
trap命令不应该trap "rm -rf '$tempdir'" EXIT HUP INT TERM吗?陷阱可以做自己的变量扩展吗?
2015年

@Six您的命令将$tempdirtrap评估命令时扩展,而不是在触发陷阱时扩展。在这种情况下,它没有任何区别,只是如果代码的值tempdir包含单引号,则代码将严重中断,而我的代码将始终有效。
吉尔(Gilles)'所以

@Gilles这是一个不错的功能。我尝试了单引号示例,但是没有运气,所以我认为trap无法在运行时评估变量。原来,my $tempdir是在本地声明的,必须全局定义它,陷阱才能对其进行访问。现在说得通...
2015年

1
@Gilles ...只要$tempdir 也不变,这对于所有目的都是可以接受的。请注意不要使用相同的名称来创建多个临时文件/目录...
MestreLion

3

一种更安全的选择是使用mktemp来安全地创建目录,然后将命名管道放入该目录中,然后进行操作以rm -R $dir最终将其删除。


我选择在mktemp目录中创建FIFO ,因为它确实是唯一可接受的答案,以防万一您没有注意到,@ Gilles已经对此答案进行了深入介绍。
JM Becker

2

使用“空运行”选项:

mkfifo $(mktemp -ut pipe.XXX)

1
根据手册页,-u“不鼓励” 使用选项。
dogbane 2012年

@dogbane的用法也是如此-t,但是只要它可靠地工作,我就会同意的。
polemon 2012年

抱歉,在哪说不-t建议这样做?
dogbane 2012年

2
@dogbane如果有任何关键意义,我将制作一个微型C应用程序,调用该mkstemp()函数(linux.die.net/man/3/mkstemp)。该-t开关没有气馁,它是-p,是我不好。
polemon 2012年

1

您可以mktemp用来创建一个临时文件,然后将其删除并创建一个具有相同名称的命名管道。

例如:

TMPPIPE=$(mktemp -t pipe.XXX) && {
    rm -f $TMPPIPE
    mkfifo $TMPPIPE
}

删除$TMPPIPE之前是否mkfifo可以避免发生“不安全”问题TMPPIPE=`mktemp -u` ; mkfifo $TMPPIPE
JM Becker 2012年

1
@TechZilla mkfifo实际上是安全的,与通常从shell创建常规文件不同。如果不是这样,创建文件然后删除它根本没有帮助(实际上,通过使攻击者不需要猜测文件名,这将极大地促进了攻击者的工作)。因此,dogbane的答案有效,但是中间文件的创建是无用的麻烦。
吉尔斯(Gilles)'所以

1
@Gilles,您知道mktemp手册页中称为-u“不安全”选项的方面吗?
JM Becker 2012年

@dogbane,我对您的回答投了赞成票,我认为您的评论很可靠。虽然,我已经在昨天完成了此操作。.我只是在等待有人发布我的解决方案或希望有更好的解决方案。因此,即使我使用了mktemp -d您,仍然可以为您提供一些建议。感谢您的所有帮助,我非常感谢!
JM Becker 2012年

1
@TechZilla mktemp -u在创建常规文件时是不安全的,因为它提供了防止拒绝服务的保护(如果它生成的名称足够不可预测),但不会阻止攻击者在程序的鼻子下创建文件。创建fifo而非常规文件是手册页无法解决的罕见用例。
吉尔斯(Gilles)'“ SO-不要邪恶”

0

在Unix中使用mkfifo或,mknod在Unix中,两个单独的进程可以按名称访问管道-一个进程可以将其作为读取器打开,而另一个进程可以作为写入器打开。

mkfifo my_pipe
gzip -9 -c < my_pipe > out.gz
cat file > my_pipe

可以像删除任何文件一样删除命名管道:

rm my_pipe

mkfifo --mode=0666 /tmp/namedPipe
gzip --stdout -d file.gz > /tmp/namedPipe

NamedPipe可以用作常规文件,只能读取一次。

http://www.linuxjournal.com/article/2156


2
我完全了解命名管道和mkfifo。除了解决创建临时目录外,它没有解决我有关临时命名管道的问题mkdir
JM Becker 2012年

2
如何mktemp解决安全创建命名管道所要解决的问题?
camh 2012年

1
哦,好的,最好是在/ tmp下创建它们,根据定义它们是临时文件,并且在系统重启后将被清除。或者更好的是,具有一个shell函数,该函数将根据mktemp结果本身创建命名管道(当然,首先删除temp文件,然后mkfifo在该文件上运行)。 mktemp也可以用于创建临时目录,请尝试使用-t -dswitch。
Nikhil Mulley 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.