Linux 解析 /proc/ 文件是否安全?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5713451/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it safe to parse a /proc/ file?
提问by Kiril Kirov
I want to parse /proc/net/tcp/
, but is it safe?
我想解析/proc/net/tcp/
,但它安全吗?
How should I open and read files from /proc/
and not be afraid, that some other process (or the OS itself) will be changing it in the same time?
我应该如何打开和读取文件/proc/
而不害怕其他进程(或操作系统本身)会同时更改它?
采纳答案by Greg Price
In general, no.(So most of the answers here are wrong.) It mightbe safe, depending on what property you want. But it's easy to end up with bugs in your code if you assume too much about the consistency of a file in /proc
. For example, see this bug which came from assuming that /proc/mounts
was a consistent snapshot.
一般来说,没有。(所以这里的大多数答案都是错误的。)这可能是安全的,这取决于您想要什么属性。但是,如果您对/proc
. 例如,请参阅这个错误,它来自假设/proc/mounts
是一致的快照。
For example:
例如:
/proc/uptime
is totally atomic, as someone mentioned in another answer -- but only since Linux 2.6.30, which is less than two years old. So even this tiny, trivial file was subject to a race condition until then, and still is in most enterprise kernels. Seefs/proc/uptime.c
for the current source, or the commit that made it atomic. On a pre-2.6.30 kernel, you canopen
the file,read
a bit of it, then if you later come back andread
again, the piece you get will be inconsistent with the first piece. (I just demonstrated this -- try it yourself for fun.)/proc/mounts
is atomic within a singleread
system call.So if youread
the whole file all at once, you get a single consistent snapshot of the mount points on the system. However, if you use severalread
system calls -- and if the file is big, this is exactly what will happen if you use normal I/O libraries and don't pay special attention to this issue -- you will be subject to a race condition. Not only will you not get a consistent snapshot, but mount points which were present before you started and never stopped being present might go missing in what you see. To see that it's atomic for oneread()
, look atm_start()
infs/namespace.c
and see it grab a semaphore that guards the list of mountpoints, which it keeps untilm_stop()
, which is called when theread()
is done. To see what can go wrong, see this bug from last year(same one I linked above) in otherwise high-quality software that blithely read/proc/mounts
./proc/net/tcp
, which is the one you're actually asking about, is even less consistent than that. It's atomic only within each row of the table. To see this, look atlistening_get_next()
innet/ipv4/tcp_ipv4.c
andestablished_get_next()
just below in the same file, and see the locks they take out on each entry in turn. I don't have repro code handy to demonstrate the lack of consistency from row to row, but there are no locks there (or anything else) that would make it consistent. Which makes sense if you think about it -- networking is often a super-busy part of the system, so it's not worth the overhead to present a consistent view in this diagnostic tool.
/proc/uptime
完全是原子的,正如有人在另一个答案中提到的那样——但仅从不到两年的Linux 2.6.30 开始。因此,即使是这个微小的、琐碎的文件在此之前也受到竞争条件的影响,并且仍然存在于大多数企业内核中。查看fs/proc/uptime.c
当前来源,或使其成为 atomic 的提交。在 2.6.30 之前的内核上,您可以open
将文件,其中的read
一小部分,然后如果您以后再回来,read
您得到的部分将与第一部分不一致。(我刚刚演示了这一点——为了好玩,自己尝试一下。)/proc/mounts
在单个read
系统调用中是原子的。因此,如果您read
一次性查看整个文件,您将获得系统上挂载点的单一一致快照。然而,如果你使用多个read
系统调用——如果文件很大,这正是你使用普通 I/O 库并且不特别注意这个问题时会发生的情况——你将受到竞争健康)状况。您不仅不会获得一致的快照,而且在您开始之前存在且从未停止存在的挂载点可能会在您看到的内容中丢失。要查看它是原子的read()
,请查看m_start()
infs/namespace.c
并看到它获取一个信号量,该信号量保护挂载点列表,它一直保持到m_stop()
,当read()
已经完成了。要了解可能会出现什么问题,请查看去年的这个错误(我在上面链接的那个错误)在其他高质量的软件中可以轻松阅读/proc/mounts
./proc/net/tcp
,这是您实际询问的那个,甚至比这更不一致。它仅在 table 的每一行内是原子的。要看到这一点,请查看同一文件中的listening_get_next()
innet/ipv4/tcp_ipv4.c
和established_get_next()
下方,并依次查看它们对每个条目取出的锁。我没有方便的重现代码来证明行与行之间缺乏一致性,但是那里没有锁(或其他任何东西)可以使它保持一致。如果您考虑一下,这是有道理的 - 网络通常是系统中非常繁忙的部分,因此在此诊断工具中呈现一致的视图是不值得的。
The other piece that keeps /proc/net/tcp
atomic within each row is the buffering in seq_read()
, which you can read in fs/seq_file.c
. This ensures that once you read()
part of one row, the text of the whole row is kept in a buffer so that the next read()
will get the rest of that row before starting a new one. The same mechanism is used in /proc/mounts
to keep each row atomic even if you do multiple read()
calls, and it's also the mechanism that /proc/uptime
in newer kernels uses to stay atomic. That mechanism does notbuffer the whole file, because the kernel is cautious about memory use.
/proc/net/tcp
在每一行中保持原子性的另一部分是缓冲 in seq_read()
,您可以读入fs/seq_file.c
。这可确保一旦您read()
成为一行的一部分,整行的文本将保存在缓冲区中,以便下一read()
行在开始新行之前获得该行的其余部分。/proc/mounts
即使您进行多次read()
调用,也使用相同的机制来保持每一行的原子性,这也是/proc/uptime
新内核中用来保持原子性的机制。这种机制也没有缓冲整个文件,因为内核是谨慎的内存使用。
Most files in /proc
will be at least as consistent as /proc/net/tcp
, with each row a consistent picture of one entry in whatever information they're providing, because most of them use the same seq_file
abstraction. As the /proc/uptime
example illustrates, though, some files were still being migrated to use seq_file
as recently as 2009; I bet there are still some that use older mechanisms and don't have even that level of atomicity. These caveats are rarely documented. For a given file, your only guarantee is to read the source.
中的大多数文件/proc
至少与 一样一致/proc/net/tcp
,每一行在它们提供的任何信息中都有一个条目的一致图片,因为它们中的大多数使用相同的seq_file
抽象。/proc/uptime
但是,正如示例所示,直到seq_file
2009 年,某些文件仍在迁移以使用;我敢打赌,仍然有一些使用旧机制,甚至没有那种原子性级别。这些警告很少被记录在案。对于给定的文件,您唯一的保证是阅读源代码。
In the case of /proc/net/tcp
, you can read it and parse each line without fear. But if you try to draw any conclusions from multiple lines at once -- beware, other processes and the kernel arechanging it while you read it, and you are probably creating a bug.
在 的情况下/proc/net/tcp
,您可以毫无畏惧地阅读并解析每一行。但是,如果您试图一次从多行中得出任何结论——请注意,其他进程和内核在您阅读时正在更改它,您可能正在创建一个错误。
回答by Bruce
/proc is a virtual file system : in fact, it just gives a convenient view of the kernel internals. It's definitely safe to read it (that's why it's here) but it's risky on the long term, as the internal of these virtual files may evolve with newer version of kernel.
/proc 是一个虚拟文件系统:事实上,它只是提供了内核内部结构的方便视图。阅读它绝对是安全的(这就是它在这里的原因)但从长远来看这是有风险的,因为这些虚拟文件的内部可能会随着更新版本的内核而发展。
EDIT
编辑
More information available in proc documentation in Linux kernel doc, chapter 1.4 Networking I can't find if the information how the information evolve over time. I thought it was frozen on open, but can't have a definite answer.
Linux kernel doc中的proc 文档中提供了更多信息,第 1.4 章网络我无法找到信息如何随时间演变的信息。我以为它在打开时被冻结了,但不能有明确的答案。
EDIT2
编辑2
According to Sco doc(not linux, but I'm pretty sure all flavours of *nix behave like that)
根据Sco doc(不是 linux,但我很确定 *nix 的所有风格都是这样的)
Although process state and consequently the contents of /proc files can change from instant to instant, a single read(2) of a /proc file is guaranteed to return a ``sane'' representation of state, that is, the read will be an atomic snapshot of the state of the process. No such guarantee applies to successive reads applied to a /proc file for a running process. In addition, atomicity is specifically not guaranteed for any I/O applied to the as (address-space) file; the contents of any process's address space might be concurrently modified by an LWP of that process or any other process in the system.
尽管进程状态以及 /proc 文件的内容可能会从瞬间变为瞬间,但 /proc 文件的单个 read(2) 保证返回状态的“理智”表示,即读取将是进程状态的原子快照。此类保证不适用于应用于正在运行的进程的 /proc 文件的连续读取。此外,对于应用于 as(地址空间)文件的任何 I/O,都不特别保证原子性;任何进程的地址空间的内容可能会被该进程的 LWP 或系统中的任何其他进程同时修改。
回答by Blagovest Buyukliev
Although the files in /proc
appear as regular files in userspace, they are not really files but rather entities that support the standard file operations from userspace (open
, read
, close
). Note that this is quite different than having an ordinary file on disk that is being changed by the kernel.
尽管 中的文件在/proc
用户空间中显示为常规文件,但它们并不是真正的文件,而是支持来自用户空间的标准文件操作的实体 ( open
, read
, close
)。请注意,这与内核正在更改的磁盘上的普通文件完全不同。
All the kernel does is print its internal state into its own memory using a sprintf
-like function, and that memory is copied into userspace whenever you issue a read(2)
system call.
内核所做的就是使用类似sprintf
函数将其内部状态打印到自己的内存中,并且每当您发出read(2)
系统调用时,该内存就会被复制到用户空间中。
The kernel handles these calls in an entirely different way than for regular files, which could mean that the entire snapshot of the data you will read could be ready at the time you open(2)
it, while the kernel makes sure that concurrent calls are consistent and atomic. I haven't read that anywhere, but it doesn't really make sense to be otherwise.
内核以与常规文件完全不同的方式处理这些调用,这可能意味着您将读取的数据的整个快照在您读取时已经准备就绪open(2)
,而内核确保并发调用是一致的和原子的。我没有在任何地方读过,但如果不是这样,那真的没有意义。
My advice is to take a look at the implementation of a proc file in your particular Unix flavour. This is really an implementation issue (as is the format and the contents of the output) that is not governed by a standard.
我的建议是在您的特定 Unix 风格中查看 proc 文件的实现。这实际上是一个不受标准约束的实现问题(输出的格式和内容也是如此)。
The simplest example would be the implementation of the uptime
proc file in Linux. Note how the entire buffer is produced in the callback function supplied to single_open
.
最简单的例子是uptime
在 Linux 中实现proc 文件。请注意整个缓冲区是如何在提供给 的回调函数中生成的single_open
。
回答by Job
The procfs API in the Linux kernel provides an interface to make sure that reads return consistent data. Read the comments in __proc_file_read
. Item 1) in the big comment block explains this interface.
Linux 内核中的 procfs API 提供了一个接口来确保读取返回一致的数据。阅读 中的评论__proc_file_read
。大注释块中的第 1) 项解释了此接口。
That being said, it is of course up to the implementation of a specific proc file to use this interface correctly to make sure its returned data is consistent. So, to answer your question: no, the kernel does not guarantee consistency of the proc files during a read but it provides the means for the implementations of those files to provide consistency.
话虽如此,当然要正确使用此接口以确保其返回的数据一致,这取决于特定 proc 文件的实现。所以,回答你的问题:不,内核不保证读取过程中 proc 文件的一致性,但它为这些文件的实现提供了提供一致性的方法。
回答by R.. GitHub STOP HELPING ICE
Short of unknown bugs, there are no race conditions in /proc
that would lead to reading corrupted data or a mix of old and new data. In this sense, it's safe. However there's still the race condition that much of the data you read from /proc
is potentially-outdated as soon as it's generated, and even moreso by the time you get to reading/processing it. For instance processes can die at any time and a new process can be assigned the same pid; the only process ids you can ever use without race conditions are your own child processes'. Same goes for network information (open ports, etc.) and really most of the information in /proc
. I would consider it bad and dangerous practice to rely on any data in /proc
being accurate, except data about your own process and potentially its child processes. Of course it may still be useful to present other information from /proc
to the user/admin for informative/logging/etc. purposes.
除了未知的错误,没有竞争条件/proc
会导致读取损坏的数据或新旧数据的混合。从这个意义上说,它是安全的。但是,仍然存在竞争条件,即您从中读取的大部分数据/proc
一旦生成就可能已过时,甚至在您开始阅读/处理它时更是如此。例如,进程可以随时终止,并且可以为新进程分配相同的 pid;您可以在没有竞争条件的情况下使用的唯一进程 ID 是您自己的子进程。网络信息(开放端口等)和/proc
. 我认为依赖任何数据是不好和危险的做法/proc
是准确的,除了有关您自己的流程及其可能的子流程的数据。当然,/proc
向用户/管理员提供其他信息以提供信息/日志记录等可能仍然有用。目的。
回答by wallyk
I have the source for Linux 2.6.27.8 handy since I'm doing driver development at the moment on an embedded ARM target.
我手边有 Linux 2.6.27.8 的源代码,因为我目前正在嵌入式 ARM 目标上进行驱动程序开发。
The file ...linux-2.6.27.8-lpc32xx/net/ipv4/raw.c
at line 934 contains, for example
文件 ...linux-2.6.27.8-lpc32xx/net/ipv4/raw.c
在第 934 行包含,例如
seq_printf(seq, "%4d: %08X:%04X %08X:%04X"
" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n",
i, src, srcp, dest, destp, sp->sk_state,
atomic_read(&sp->sk_wmem_alloc),
atomic_read(&sp->sk_rmem_alloc),
0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));
which outputs
哪个输出
[wally@zenetfedora ~]$ cat /proc/net/tcp
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 017AA8C0:0035 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 15160 1 f552de00 299
1: 00000000:C775 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 13237 1 f552ca00 299
...
in function raw_sock_seq_show()
which is part of a hierarchy of procfshandling functions. The text is not generated until a read()
request is made of the /proc/net/tcp
file, a reasonable mechanism since procfsreads are surely much less common than updating the information.
in 函数raw_sock_seq_show()
,它是procfs处理函数层次结构的一部分。在read()
对/proc/net/tcp
文件发出请求之前不会生成文本,这是一种合理的机制,因为procfs读取肯定比更新信息少得多。
Some drivers (such as mine) implement the proc_read function with a single sprintf()
. The extra complication in the core drivers implementation is to handle potentially very long output which may not fit in the intermediate, kernel-space buffer during a single read.
一些驱动程序(例如我的)使用单个sprintf()
. 核心驱动程序实现中的额外复杂性是在单次读取期间处理可能不适合中间内核空间缓冲区的潜在非常长的输出。
I tested that with a program using a 64K read buffer but it results in a kernel space buffer of 3072 bytes in my system for proc_read to return data. Multiple calls with advancing pointers are needed to get more than that much text returned. I don't know what the right way to make the returned data consistent when more than one i/o is needed. Certainly each entry in /proc/net/tcp
is self-consistent. There is some likelihood that lines side-by-side are snapshot at different times.
我用一个使用 64K 读取缓冲区的程序进行了测试,但它会在我的系统中产生 3072 字节的内核空间缓冲区,以便 proc_read 返回数据。需要使用前进指针进行多次调用才能获得比返回的更多文本。当需要多个 i/o 时,我不知道使返回的数据保持一致的正确方法是什么。当然,每个条目/proc/net/tcp
都是自洽的。并排的线条可能是不同时间的快照。
回答by heath
When you read from a /proc file, the kernel is calling a function which has been registered in advance to be the "read" function for that proc file. See the __proc_file_read
function in fs/proc/generic.c .
当您从 /proc 文件中读取时,内核正在调用一个预先注册为该 proc 文件的“读取”函数的函数。查看__proc_file_read
fs/proc/generic.c 中的函数。
Therefore, the safety of the proc read is only as safe as the function the kernel calls to satisfy the read request. If that function properly locks all data it touches and returns to you in a buffer, then it is completely safe to read using that function. Since proc files like the one used for satisfying read requests to /proc/net/tcp have been around for a while and have undergone scrupulous review, they are about as safe as you could ask for. In fact, many common Linux utilities rely on reading from the proc filesystem and formatting the output in a different way. (Off the top of my head, I think 'ps' and 'netstat' do this).
因此,proc read 的安全性仅与内核调用以满足读取请求的函数一样安全。如果该函数正确地锁定了它接触到的所有数据并在缓冲区中返回给您,那么使用该函数读取是完全安全的。由于像用于满足对 /proc/net/tcp 的读取请求的 proc 文件已经存在了一段时间并且经过了严格的,因此它们与您要求的一样安全。事实上,许多常见的 Linux 实用程序依赖于从 proc 文件系统读取并以不同的方式格式化输出。(在我的脑海中,我认为 'ps' 和 'netstat' 可以做到这一点)。
As always, you don't have to take my word for it; you can look at the source to calm your fears. The following documentation from proc_net_tcp.txt tells you where the "read" functions for /proc/net/tcp live, so you can look at the actual code that is run when you read from that proc file and verify for yourself that there are no locking hazards.
和往常一样,你不必相信我的话。你可以查看源头来平息你的恐惧。proc_net_tcp.txt 中的以下文档告诉您 /proc/net/tcp 的“读取”函数在哪里,因此您可以查看从该 proc 文件读取时运行的实际代码,并自行验证是否存在锁定危险。
This document describes the interfaces /proc/net/tcp and /proc/net/tcp6.
Note that these interfaces are deprecated in favor of tcp_diag. These /proc interfaces provide information about currently active TCP connections, and are implemented by tcp4_seq_show() in net/ipv4/tcp_ipv4.c and tcp6_seq_show() in net/ipv6/tcp_ipv6.c, respectively.
本文档描述了接口 /proc/net/tcp 和 /proc/net/tcp6。
请注意,这些接口已被弃用,以支持 tcp_diag。这些 /proc 接口提供有关当前活动 TCP 连接的信息,分别由 net/ipv4/tcp_ipv4.c 中的 tcp4_seq_show() 和 net/ipv6/tcp_ipv6.c 中的 tcp6_seq_show() 实现。