/ proc /ファイルを解析しても安全ですか?


152

解析したいのです/proc/net/tcp/が、安全ですか?

/proc/他のプロセス(またはOS自体)が同時にファイルを変更することを恐れずに、ファイルを開いて読み取る方法を教えてください。


29
+1。それはいまいましい良い質問です。答えがあればいいのにと思っていますが、そのようなことをかなり以前にやったことがあるので、見つけられることを楽しみにしています。
paxdiablo

1
読んだだけで、接続のリストに加えて、接続を開いたときと同じように、各接続を所有するUIDが表示されると確信ています。文書化されていないので、ここではコメントにします。
Tim Post

3
ファイルではないので、単純な答えは明らかにイエスです-それを読むことは常に安全でなければなりません。回答を読んだ後は、回答が一貫しない場合がありますが、安全です。
ロリー・アルソップ

そのため、代わりにsysctlを使用する必要があります。(また、syscallが少ない)
Good Person

@GoodPerson- たとえばsysctl、これはどのように/proc/net/tcp/ファイルを解析するのに役立ちますか?
キリルキーロフ

回答:


111

一般的には違います。(したがって、ここでの答えのほとんどは間違っています。)必要なプロパティによっては、安全である可能性があります。ただし、内のファイルの一貫性について過度に想定すると、コードにバグが生じやすくなります/proc。たとえば、それ/proc/mountsが一貫したスナップショットであると想定したことから発生したこのバグを参照してください。

例えば:

  • /proc/uptime誰かが別の回答で述べたように、完全にアトミックです-しかし、Linux 2.6.30以降、それは2年未満です。したがって、この小さくてささいなファイルでさえ、それまでは競合状態の影響を受け、ほとんどのエンタープライズカーネルに残っています。fs/proc/uptime.c現在のソース、またはそれをアトミックにしたコミットを参照してください。2.6.30より前のカーネルでopenread、少しファイルをファイルに入れることができます。その後、何度も戻ってくるreadと、最初に取得したものと一致しなくなります。(私はこれをデモンストレーションしました-楽しんでください)

  • /proc/mounts単一のreadシステムコール内アトミックです。したがって、readファイル全体を一度に処理すると、システム上のマウントポイントの単一の一貫したスナップショットが得られます。ただし、複数のreadシステムコールを使用する場合(ファイルが大きい場合)、通常のI / Oライブラリを使用し、この問題に特別な注意を払わないと、これが発生します。競合が発生します。状態。一貫性のあるスナップショットが得られないだけでなく、開始前に存在し、存在を停止しなかったマウントポイントが、表示されているものから失われる可能性があります。それが1 read()に対してアトミックであることを確認するには、m_start()fs/namespace.cを見て、マウントポイントのリストをガードするセマフォを取得m_stop()します。read()終わらせる。何が問題になるかを確認するには、昨年のバグ(上記でリンクしたものと同じ)を参照してください/proc/mounts

  • /proc/net/tcpあなたが実際に求めているのは、それよりも一貫性が低いことです。それはですだけテーブルの各行内アトミック。これを確認するには、同じファイルlistening_get_next()net/ipv4/tcp_ipv4.cestablished_get_next()そのすぐ下を見て、各エントリに対してロックが順番に取得するロックを確認します。行ごとの一貫性の欠如を示すのに便利な再現コードはありませんが、一貫性を保つためのロック(またはその他)はありません。考えてみると、これは理にかなっています。ネットワーキングはシステムの非常にビジーな部分であることが多いため、この診断ツールで一貫したビューを提示することは、オーバーヘッドに値しません。

続けて他の作品/proc/net/tcp各行内の原子の中にバッファリングされseq_read()、あなたが読むことができる、fs/seq_file.c。これにより、1 read()つの行の一部になると、行全体のテキストがバッファーに保持され、次のread()行が新しい行を開始する前にその行の残りを取得できるようになります。同じメカニズムが/proc/mounts複数のread()呼び出しを行った場合でも各行をアトミックに保つために使用されます。これは、/proc/uptime新しいカーネルでアトミックを維持するために使用されるメカニズムでもあります。カーネルはメモリの使用に注意を払っているので、そのメカニズムはファイル全体をバッファリングしませ

ほとんどのファイルは同じ抽象化を使用しているため、のほとんどのファイルは/procと同じくらい一貫性があり/proc/net/tcp、各行には、提供する情報の1つのエントリの一貫した画像がありますseq_file/proc/uptime例が示すように、しかし、いくつかのファイルがまだ使用して、移行されていたseq_file2009年として、最近、古いメカニズムを使用していて、そのレベルの原子性すら持っていないものはまだあると思います。これらの警告はめったに文書化されていません。特定のファイルについて、唯一の保証はソースを読み取ることです。

の場合は/proc/net/tcp、それを読んで、恐れずに各行を解析できます。しかし、一度に複数の行から何らかの結論を導き出そうとすると、注意してください。他のプロセスとカーネルあなたがそれを読んでいる間にそれを変更しており、おそらくバグを作成しています。


1
readdirの原子性はどうですか?/ proc / self / fdを読むような?安全ですか?
socketpair 2014年

ではない、それはあなたがどのように使用できるか、稼働時間を確認することについて追加して質問に答えるが、それclock_gettime(2)CLOCK_MONOTONIC(多分専門性があるが、私はここを知らないが、私は個人的にのみ起動の時以来でそれを見てきました)。Linuxの場合、オプションもありますsysinfo(2)
プリフタン

44

内のファイルが/procユーザ空間での通常のファイルとして表示され、彼らは本当にファイルではなく、ユーザ空間から標準のファイル操作をサポートするエンティティ(ではありませんopenreadclose)。これは、カーネルによって変更されているディスク上の通常のファイルを持っていることとはかなり異なることに注意してください。

カーネルが行うことは、内部の状態をsprintf-like関数を使用して独自のメモリに出力することだけであり、read(2)システムコールを発行するたびに、そのメモリがユーザー空間にコピーされます。

カーネルはこれらの呼び出しを通常のファイルの場合とはまったく異なる方法で処理します。つまり、読み取るデータのスナップショット全体がその時点で準備されている可能性があるopen(2)一方で、カーネルは同時呼び出しが一貫してアトミックであることを確認します。私はそれをどこでも読んだことはありませんが、それ以外の場合は意味がありません。

私のアドバイスは、特定のUnixフレーバーでのprocファイルの実装を確認することです。これは実際には、標準によって管理されていない実装の問題(出力の形式と内容と同様)です。

最も単純な例はuptime、Linux でのprocファイルの実装です。に提供されるコールバック関数でバッファ全体がどのように生成されるかに注意してくださいsingle_open


3
@Ignacio:私はOPをこの方向に向けているだけです。なぜなら、procファイルはカーネルによって書き込み用に開かれた通常のファイルであると彼が思ったからです。
Blagovest Buyukliev

4
特定のファイルの実装を見るためのアドバイスは良いです。残念ながら、すべてのスナップショットが作成されているという推測open()は、多くのファイル、特に/proc/net/tcpOPが関係しているについては間違っています。これらのセマンティクスを提供するコストを考えると、これは理にかなっています-これらのすべてのTCP接続を記録する内部データ構造をロックするなどの処理を行う必要があります。データをスキャンしてバッファにフォーマットするのに十分です。実際に起こることの詳細については私の答えを参照してください。
グレッグ価格

16

/ procは仮想ファイルシステムです。実際、カーネル内部の便利なビューを提供します。それを読むことは間違いなく安全です(それがここにある理由です)が、これらの仮想ファイルの内部は新しいバージョンのカーネルで進化する可能性があるため、長期的には危険です。

編集

Linuxカーネルdocのprocドキュメントで利用可能な詳細情報、1.4章ネットワーキング情報が時間とともにどのように進化するかについての情報を見つけることができません。私はそれがオープンで凍結されたと思ったが、明確な答えを得ることができない。

EDIT2

Sco docによると(linuxではありませんが、* nixのすべてのフレーバーがそのように動作すると確信しています)

プロセスの状態とその結果として/ procファイルの内容は瞬間的に変化する可能性がありますが、/ procファイルの単一のread(2)は、状態の「正しい」表現を返すことが保証されています。つまり、読み取りはプロセスの状態のアトミックスナップショット。このような保証は、実行中のプロセスの/ procファイルに適用される連続した読み取りには適用されません。さらに、as(address-space)ファイルに適用されるI / Oの原子性は特に保証されません。プロセスのアドレス空間の内容は、そのプロセスのLWPまたはシステム内の他のプロセスによって同時に変更される可能性があります。


3
"おもう" ?決定的な答えがあったらいいですね:)
static_rtti '19

カーネルに/ procを実装すると、これはLinuxにも当てはまります。1回の読み取り呼び出しでprocfsファイルを読み取る場合、一貫性があります。もちろん、読み取るprocファイルがカーネルサイドで正しく実装されていると仮定します。
エリック

8
私はあなたがSCOよりも悪い情報源を思いつくことはないと思いますし、proc異なるカーネル間で同様の振る舞いをしているように扱うことを試みます(あるいは、それが存在すると仮定しても-Unixシステムでは必要ありません) )はあなたに傷ついた世界をもたらすでしょう。
ニコラスナイト

1
@Nicholas:まあ、カーネルのドキュメントで決定的な答えを見つけることができませんでした。知っていれば、遠慮なく指摘してください。
Bruce

2
SCOのドキュメントがそう言っているのは興味深い。残念ながら、これはLinuxでは必ずしも当てはまりません。特に/proc/net/tcp、OPの主な関心事であるについては当てはまりません。むしろ、出力の個々の行のみがアトミックです。詳細については私の回答を参照してください。
グレッグ価格

14

Linuxカーネルのprocfs APIは、読み取りが一貫したデータを返すことを確認するためのインターフェースを提供します。のコメントを読んでください__proc_file_read。大きなコメントブロックの項目1)は、このインターフェイスについて説明しています。

そうは言っても、返されたデータの整合性を確保するためにこのインターフェイスを正しく使用するかどうかは、特定のprocファイルの実装次第です。したがって、あなたの質問に答えるために:いいえ、カーネルは読み取り中のprocファイルの一貫性を保証しませんが、それらのファイルの実装に一貫性を提供する手段を提供します。


4
残念ながら、の多くのファイルは/proc実際には一貫性を提供していません。詳細については私の回答を参照してください。
グレッグ価格

3
また、__proc_file_read()非推奨ですseq_file。長いブロックコメントのすぐ上に、やや苛立たしいコメント(Linusによる)を表示します。
グレッグ価格

6

現在、組み込みARMターゲットでドライバー開発を行っているので、Linux 2.6.27.8のソースが手元にあります。

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));

出力する

[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
...

関数内でraw_sock_seq_show()の階層の一部であるprocfsの機能を扱います。procfs読み取りは情報を更新するよりもはるかに一般的ではないため、テキストはファイルに対してread()要求が行われるまで生成されません。これは/proc/net/tcp合理的なメカニズムです。

一部のドライバー(mineなど)は、単一のでproc_read関数を実装しsprintf()ます。コアドライバーの実装でさらに複雑になるのは、1回の読み取り中に中間のカーネルスペースバッファーに収まらない可能性がある非常に長い出力を処理することです。

64Kの読み取りバッファーを使用するプログラムでテストしましたが、proc_readがデータを返すために、システムでカーネルスペースバッファーが3072バイトになります。返されるテキストよりも多くのテキストを取得するには、前進ポインタを使用した複数の呼び出しが必要です。複数のI / Oが必要な場合に、返されるデータの整合性を保つための適切な方法がわかりません。確かにの各エントリ/proc/net/tcpは自己矛盾がありません。横に並んだ線が異なる時間にスナップショットになる可能性があります。


本当にすみませんでした。では、を使用ifstreamすると安全ではなくなりますが、使用readすると安全になりますか?またはifstream内部で使用しreadますか?そして、あなたは何を提案しますか?
キリルキーロフ

@キリル:混乱してごめんなさい。これは、のデータがどのように/proc/net/tcpフォーマットされるかを説明するものであり、誰がそれを読み取るかとは完全に独立しています。
wallyk

1
うん!そして、あなたの推測では、(の/proc/net/tcp)異なる行は同じスナップショットからのものではありません。説明については、私の回答を参照してください。
グレッグ価格

3

未知のバグがない限り、/proc破損したデータや古いデータと新しいデータの混合の読み取りにつながる競合状態はありません。この意味で、それは安全です。ただし、読み取ったデータの多くは、/proc生成されてすぐに、さらには読み取り/処理に到達するまでに古くなっているという競合状態が依然として存在します。たとえば、プロセスはいつでも停止する可能性があり、新しいプロセスに同じpidを割り当てることができます。競合状態なしで使用できる唯一のプロセスIDは、自分の子プロセスです。ネットワーク情報(開いているポートなど)とのほとんどの情報についても同様/procです。のデータに依存することは悪い危険な習慣だと思います/procあなた自身のプロセスと潜在的にその子プロセスに関するデータを除いて、正確であること。もちろん、その他の情報を/procユーザー/管理者に提供して、有益な情報やログ情報などを提供することも役立ちます。目的。


私はこれを行って、自分のプロセスの情報を取得して使用しています(PIDの場合はを使用getpid())。それで、それは安全でなければなりません。
キリルキーロフ

1
はい、それは完全に安全だと思います。
R .. GitHub ICE HELPING ICEを停止する'19

子プロセスが他のプロセスよりも適切に動作することには同意しません。限り/procインタフェースが関係している、それらはすべて同じ弱点と強みを持っています。とにかく、OPはプロセスではなく、デバイスドライバー関連の情報について尋ねます。
ウォリック2011

1
pid Nが子プロセスのN場合は、wait-family関数を呼び出すまで、pid が同じ(おそらく終了した)プロセスを参照していることを確認できます。これにより、人種がなくなります。
R .. GitHub ICE HELPING ICEの停止2011

-1の洪水とは何で、説明はありませんか?
R .. GitHub STOP HELPING ICE

2

/ procファイルから読み取るとき、カーネルはそのprocファイルの「読み取り」関数として事前に登録されている関数を呼び出しています。__proc_file_readfs / proc / generic.c の関数を参照してください。

したがって、proc読み取りの安全性は、カーネルが読み取り要求を満たすために呼び出す関数と同じくらい安全です。その関数がタッチしてすべてのデータを適切にロックし、バッファーに戻ったら、その関数を使用して読み取ることは完全に安全です。/ proc / net / tcpへの読み取り要求を満たすために使用されるようなprocファイルはしばらく前から存在し、綿密なレビューを受けているため、要求されたのと同じくらい安全です。実際、多くの一般的なLinuxユーティリティは、procファイルシステムからの読み取りと、出力のフォーマット方法に依存しています。(頭の上から、「ps」と「netstat」がこれを行うと思います)。

いつものように、あなたはそれを私の言葉で言う必要はありません。恐れを和らげるために源を見ることができます。proc_net_tcp.txtの次のドキュメントは、/ proc / net / tcpの「読み取り」機能がどこにあるかを示しているので、そのprocファイルから読み取ったときに実行される実際のコードを見て、そのファイルがないことを確認できます。ロックの危険。

このドキュメントでは、インターフェイス/ 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()によってそれぞれ実装されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.