首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >解析/proc/文件安全吗?

解析/proc/文件安全吗?
EN

Stack Overflow用户
提问于 2011-04-19 16:12:45
回答 7查看 15.5K关注 0票数 155

我想解析/proc/net/tcp/,但是它安全吗?

我应该如何从/proc/打开和读取文件,而不是害怕其他进程(或操作系统本身)会在同一时间更改它?

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2011-05-04 16:15:34

通常不是。(所以这里的大多数答案都是错误的。)它可能是安全的,这取决于您想要的属性。但是,如果您过多地假设/proc中文件的一致性,那么很容易在代码中出现bug。例如,请参见this bug which came from assuming that /proc/mounts was a consistent snapshot

例如:

正如有人在另一个答案中提到的那样,

  • /proc/uptime完全的原子 --但只是在Linux2.6.30之后,它才成立不到两年。因此,即使是这个微小的、微不足道的文件,在此之前也会受到竞争条件的影响,并且仍然存在于大多数企业内核中。请参见当前源代码或the commit that made it atomicfs/proc/uptime.c。在2.6.30之前的内核中,你可以open文件,read它的一小部分,然后如果你回来并再次read,你得到的部分将与第一部分不一致。(我刚刚演示了这一点--您可以自己尝试一下,因为fun.)
  • /proc/mounts在单个read 系统调用中是原子的。因此,如果您一次read整个文件,就会得到系统上挂载点的单个一致快照。但是,如果您使用多个read系统调用--如果文件很大,如果您使用普通的I/O库而不特别注意这个问题,就会发生这种情况--您将受到竞争条件的影响。您不仅不会获得一致的快照,而且在您开始之前已经存在并且从未停止存在的挂载点可能会在您看到的内容中丢失。要查看它是否针对一个read()是原子的,请查看m_start() in fs/namespace.c,并查看它获取一个信号量,该信号量保护挂载点列表,该信号量一直保留到m_stop()为止,read()完成时将调用该信号量。要查看可能会出错的地方,请查看其他高质量软件中的this bug from last year (我在上面链接过的那个),它轻松地读取您实际询问的/proc/mounts.
  • /proc/net/tcp,,甚至比这更不一致。它只在表的每一行中是原子的。要查看这一点,请查看下面同一文件中的listening_get_next() in net/ipv4/tcp_ipv4.cestablished_get_next(),并依次查看它们对每个条目的锁定。我手头没有repro代码来证明行与行之间缺乏一致性,但没有锁(或其他任何东西)来使其保持一致性。这是有道理的--网络通常是系统中非常繁忙的一部分,所以不值得在这个诊断工具中呈现一致的视图。

在每一行中保持/proc/net/tcp原子性的另一个部分是seq_read()中的缓冲,您可以将其读取为in fs/seq_file.c。这确保了一旦read()一行的一部分,整个行的文本就会保存在缓冲区中,这样下一个read()就会在开始新行之前获取该行的其余部分。在/proc/mounts中使用了相同的机制来保持每一行的原子性,即使您进行了多个read()调用,这也是较新内核中的/proc/uptime用来保持原子性的机制。这种机制不会缓冲整个文件,因为内核对内存使用非常谨慎。

/proc中的大多数文件至少与/proc/net/tcp一样一致,无论它们提供什么信息,每一行都有一个一致的条目,因为它们中的大多数都使用相同的seq_file抽象。然而,正如/proc/uptime示例所说明的,直到2009年,仍有一些文件被迁移到使用seq_file;我敢打赌,仍然有一些文件使用较旧的机制,甚至没有这种原子性级别。这些警告很少被记录在案。对于给定的文件,您唯一的保证就是读取源代码。

在使用/proc/net/tcp的情况下,您可以毫无畏惧地读取并解析每一行。但是,如果您试图一次从多行代码中得出任何结论--请注意,当您读取它时,其他进程和内核正在更改它,并且您可能正在创建一个bug。

票数 113
EN

Stack Overflow用户

发布于 2011-04-19 16:32:31

尽管/proc中的文件看起来像用户空间中的常规文件,但它们并不是真正的文件,而是支持用户空间(openreadclose)标准文件操作的实体。请注意,这与在磁盘上存放由内核更改的普通文件有很大不同。

内核所做的就是使用sprintf-like函数将其内部状态打印到自己的内存中,每当您发出read(2)系统调用时,该内存就会被复制到用户空间中。

内核处理这些调用的方式与处理常规文件的方式完全不同,这可能意味着您将读取的数据的整个快照在您对其执行open(2)操作时已经准备就绪,而内核则确保并发调用是一致的和原子的。我在任何地方都没有读过这篇文章,但如果不是这样的话,这真的没有什么意义。

我的建议是看看你的Unix风格的proc文件是如何实现的。这实际上是一个不受标准约束的实现问题(输出的格式和内容也是如此)。

最简单的例子就是在Linux中实现uptime proc文件。注意整个缓冲区是如何在提供给single_open的回调函数中生成的。

票数 44
EN

Stack Overflow用户

发布于 2011-04-19 16:22:26

/proc是一个虚拟文件系统:实际上,它只是提供了一个方便的内核内部视图。读取它绝对是安全的(这就是为什么它在这里),但从长远来看,这是有风险的,因为这些虚拟文件的内部可能会随着更新版本的内核而演变。

编辑

proc documentation in Linux kernel doc的1.4章网络中提供了更多信息,我找不到信息是如何随着时间的推移演变的。我认为它是冻结在开放,但不能有一个明确的答案。

EDIT2

根据Sco doc (不是linux,但我非常确定*nix的所有版本都是这样的)

虽然进程状态和/proc文件的内容可以随时更改,但/proc文件的单次读取(2)肯定会返回状态的状态表示,也就是说,读取将是进程状态的原子快照。对于正在运行的进程,对应用于/proc文件的连续读取没有这样的保证。此外,对于应用于as (地址空间)文件的任何I/O,原子性都不能得到特别保证;任何进程的地址空间的内容都可能被该进程或系统中任何其他进程的LWP同时修改。

票数 16
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5713451

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档