どの「ファイル記述子」が同じ「オープンファイル記述」を共有しているかを調べる


17

私が(Bourneのようなシェルで)する場合:

exec 3> file 4>&3 5> file 6>> file

ファイル記述子3と4は、4がdup()3から編集されたため、同じ開いているファイルの説明を共有します(同じプロパティ、ファイル内の同じオフセット...)。そのプロセスのファイル記述子5と6は、異なるオープンファイル記述上にあります(たとえば、それぞれファイル内に独自のポインターがあります)。

これで、lsof出力で表示されるのは次のとおりです。

zsh     21519 stephane    3w   REG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    4w   REG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    5w   REG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    6w   REG  254,2        0 10505865 /home/stephane/file

それは少し良いですlsof +fg

zsh     21519 stephane    3w   REG          W,LG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    4w   REG          W,LG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    5w   REG          W,LG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    6w   REG       W,AP,LG  254,2        0 10505865 /home/stephane/file

(ここではLinux 3.16)fd 6には異なるフラグが表示されるため、fd 3、4、または5にあるものとは異なるオープンファイル記述でなければなりませんが、fd 5が異なるオープンファイル記述。で-o、オフセットも見ることができましたが、同じオフセットは同じオープンファイル記述であることを保証しません。

それを見つけるための非侵入的な1つの方法はありますか?外部的に、またはプロセス自身のファイル記述子のために?


1。ヒューリスティックなアプローチの1つは、1つのfdのフラグを変更fcntl()し、その結果フラグが更新される他のファイル記述子を確認することですが、それは明らかに理想的でも愚かでもありません


このアプローチは、原則として機能し、ほとんどのシナリオで破壊的ではないはずです。最初に子をフォークします(外部から行う場合はptraceを使用)。次に、子で、他のプロセスに影響を与えないファイル記述子で何かをします。Linuxでは、そのためのリースが機能するはずです。
ジル「SO-停止されて悪」

@Gilles、ありがとう。しかし、それは多かれ少なかれ、すでに質問で提案しているアプローチです。リース(F_SETLEASE fcntlを意味すると仮定します。BTWについて知ってくれてありがとう)は、同じファイルに別の「書き込み」オープンファイル記述がある場合(EBUSY)にではなく、所有している通常のファイルに対してのみ機能します。-侵入的。
ステファンシャゼラス

この質問を放棄しましたか?SystemTapがあなたが望むことをどのように行うことができるかに関するいくつかの情報を投稿しましたが、あなたは答えを完了としてマークしていません...?
アズレイ

回答:


2

Linux 3.5以降では、これはkcmp(3)で実現できます。

KCMP_FILE

  • ファイル記述子かどうかを確認IDX1プロセスにおいてPID1は同じオープンファイル記述を参照する(参照オープン(2)のようなファイル記述子)IDX2プロセスでPID2を。同じオープンファイル記述を参照する2つのファイル記述子の存在は、dup(2)(および同様の)fork(2)の結果、またはドメインソケットを介してファイル記述子を渡すことで発生する可能性があります(unix(7)を参照)。

マニュアルページは、OPが要求したユースケース専用の例を提供します。このsyscallでは、カーネルをCONFIG_CHECKPOINT_RESTOREset でコンパイルする必要があることに注意してください。


ありがとう。まさに私が探していたもの。あなたのしているスーパーがない限り、それはあなたの二つのプロセスも(とはsetuid / setgidを...ではない)していることに注意してください(当然)
ステファンChazelas

@StéphaneChazelasまさに。何らかの理由でCPIUサポートがカーネルに組み込まれておらず、再構築したくない場合は、struct file *ポインターを比較できるユーザーランドインターフェイスをエクスポートするカーネルモジュールをいつでも作成できると思います。
minmaxavg

3

比較しようとしているのはstruct file、ファイル記述子が指すポインターです。(Insideは、カーネルが1つのであるtask_structことが呼ばれる別の構造体へのポインタが含まれています。各スレッドのデータ構造files_struct。そして、その構造は、ポインタの配列、にそれぞれ1が含まれていますstruct file。それはだstruct fileオフセット求めて、オープンフラグ、およびAを保持します他のいくつかのフィールド。)

files_structいくつかの侵入ツールを使用する以外に、ユーザーが目に見える方法でポインターを見る方法を知りません。たとえば、SystemTapにPIDを指定し、対応するものを見つけtask_structてポインターをたどることができます。パッシブを探している場合でも、それはそれだと思います。デルは、ツール解放長いライブカーネルメモリへのスプレッドシートのようなインターフェースを与えた時間前にKME(カーネルメモリエディタ)と呼ばれるが、それはあなたがやりたいことができ、それは、64ビットに移植されていませんでした。(私は試してみましたが、完全に機能することはありませんでした。理由はわかりませんでした。)

役に立たない理由の1つlsofは、これらのポインターも表示されないことです(ただし+f、非Linuxシステムのオプションを見てください)。内のすべてのフィールドを理論的に比較しstruct file、2つの構造は同じであると考えることができますが、それでも別々のopen(2)呼び出しからのものである可能性があります。

アイデアについては、pfiles SystemTapスクリプトをご覧ください。のアドレスを印刷するように変更した場合struct file、解決策があります。また、チェックかもしれないopened_file_by_pid.stp歩くことで機能がありますので、files_structすなわち、。ファイル記述子テーブル、struct fileオブジェクトを見て...

あなたが何を達成しようとしているのか聞いてみませんか?


私はそれを必要としたまさにそのケースを思い出すことができないことを認めなければなりません。デバッグやフォレンジックのタスクは間違いありません。
ステファンシャゼル

PoC systemtapコードを楽しみにしています:
StéphaneChazelas 15年

質問を投稿する前に、systemtapまたは/ proc / kcoreのアプローチを確認しました。難しいのは、すべてのタスクのすべてのfd 情報を取得することでした。私が見つけた最も有望なアプローチは、/ proc / * / task / fdディレクトリのコンテンツを生成する関数にフックすることでしたが、ソースファイルの特定の行番号にフックすることに関連する唯一の実行可能なものあるカーネルバージョンから次のバージョンへの移植性。systemtapでタスクリストを実際にループすることはできません。/ proc / kcore経由で可能かもしれませんが、手間がかかりすぎて、おそらく信頼性が低いでしょう。
ステファンシャゼル

これまでで最高の反応をありがとう。あなたの指針を見ていきます。
ステファンシャゼル

もちろんできます!probe beginブロックを設定し、for_each_processスクリプトに埋め込まれたCコードのブロックでマクロを使用するようにします(Cコードを埋め込むには、「グル」モードのSystemTapを使用する必要があります)。実際、これを面白くするために(!)、SystemTapの連想配列の1つを使用できます。files_structキーとしてアドレスを使用し、値としてPID / TIDのリストを使用します。これで、開いているすべてのファイルと、それらを共有しているタスクのリストが表示されます(親/子間で共有できます)。SystemTapについて話し合う場合は、もう一度返信してください。
アズレイ

0

Linux固有のソリューションを次に示します。/ proc / self / fdは、現在のプロセスで開いているファイルハンドルのシンボリックリンクのディレクトリです。リンク値を比較するだけです。子プロセスは、pidに依存するシンボリックリンクであるため、子は異なる/ proc / selfを持つため、子プロセスを使用する場合はより複雑になります。この問題を回避するには、/ proc / $$ / fdを使用します($$は目的のpidです)。


ありがとう。しかし、それは私が求めていることではありません。Linuxでは、lsofは実際に/ proc / pid / fdを使用して各ファイル記述子のパスを取得し、フラグの/ proc / pid / fdinfoを使用します。しかし、私が望むのは、同じオープンファイル記述を指しているか、2つのファイル記述子が独立してオープンされているかにかかわらず、同じファイルへの2つのfds についてです。
ステファンシャゼル

わかりました。同じファイル名で開かれているファイル記述子のペアを見つけたら、両方でテルを実行し、結果が異なる場合は別々に比較します。同じ場合は、1つのファイル記述子をシークして繰り返します。一致する場合は同じです。
hildred

まあ、それは私が質問で言及するヒューリスティックなアプローチのより邪魔な変種であり、通常のファイル(ソケット、デバイス(ターミナルなど)、パイプではない...)に対してのみ機能します。
ステファンシャゼル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.