プロセスによって作成され削除された/tmp/ディレクトリをどのようにコピーしますか?

プロセスによって作成され削除された/tmp/ディレクトリをどのようにコピーしますか?

私はOracle Linux 9(XFSファイルシステム)でバイナリの動作を研究しています。プロセスがこのバイナリを呼び出すと、その下にディレクトリが作成され、/tmp一部のファイルがそのディレクトリにコピーされます。このディレクトリは、プロセスが実行されるたびにランダムな名前(キーワード+ GUID)を取得します。

その後、そのディレクトリをすぐに削除します。ディレクトリを削除する前にディレクトリに含まれているファイルにアクセスしたいのですが、コマンドを実行するにはプロセス全体が早すぎます。

ディレクトリを削除する前にディレクトリを「傍受」してコピーする方法はありますか?

ベストアンサー1

いつでも次の場所でアプリケーションを実行できます。

gdb --args /path/to/your/your-program and its args

unlink()unlinkat()次に、、rmdir()関数、またはシステムコールにブレークポイントを追加します。

catch syscall unlink
catch syscall unlinkat
catch syscall rmdir
run

その後、ブレークポイントに達するたびにそのディレクトリのファイルを削除することを確認し、その中のファイルを確認するか、別の場所にコピーします。cont実行を再開するには(次のブレークポイントまで)、gdbに入力してください。

rm -rf:

$ gdb -q --args rm -rf /tmp/tmp.HudBncQ4Ni
Reading symbols from rm...
Reading symbols from /usr/lib/debug/.build-id/f6/7ac1d7304650a51950992d074f98ec88fe2f49.debug...
(gdb) catch syscall unlink
Catchpoint 1 (syscall 'unlink' [87])
(gdb) catch syscall unlinkat
Catchpoint 2 (syscall 'unlinkat' [263])
(gdb) catch syscall rmdir
Catchpoint 3 (syscall 'rmdir' [84])
(gdb) run
Starting program: /bin/rm -rf /tmp/tmp.HudBncQ4Ni

Catchpoint 2 (call to syscall unlinkat), 0x00007ffff7eb6fa7 in __GI_unlinkat () at ../sysdeps/unix/syscall-template.S:120
120     ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb) info registers
rax            0xffffffffffffffda  -38
rbx            0x555555569830      93824992319536
rcx            0x7ffff7eb6fa7      140737352789927
rdx            0x0                 0
rsi            0x555555569938      93824992319800
rdi            0x4                 4
rbp            0x555555568440      0x555555568440
rsp            0x7fffffffda48      0x7fffffffda48
r8             0x3                 3
r9             0x0                 0
r10            0xfffffffffffffa9c  -1380
r11            0x206               518
r12            0x0                 0
r13            0x7fffffffdc30      140737488346160
r14            0x0                 0
r15            0x555555569830      93824992319536
rip            0x7ffff7eb6fa7      0x7ffff7eb6fa7 <__GI_unlinkat+7>
eflags         0x206               [ PF IF ]
cs             0x33                51
ss             0x2b                43
ds             0x0                 0
es             0x0                 0
fs             0x0                 0
gs             0x0                 0
(gdb) x/s $rsi
0x555555569938: "test"
(gdb) info proc
process 7524
cmdline = '/bin/rm -rf /tmp/tmp.HudBncQ4Ni'
cwd = '/export/home/stephane'
exe = '/bin/rm'
(gdb) !readlink /proc/7524/fd/4
/tmp/tmp.HudBncQ4Ni
(gdb) !find /tmp/tmp.HudBncQ4Ni -ls
  1875981      4 drwx------   2 stephane stephane     4096 Aug  8 09:30 /tmp/tmp.HudBncQ4Ni
  1835128      4 -rw-r--r--   1 stephane stephane        5 Aug  8 09:30 /tmp/tmp.HudBncQ4Ni/test

ここで、ブレークポイントはunlinkat()x86_64 Linux システム内部エントリのシステムコールに置かれます。ここで、システムコールの最初の2つのパラメータはおよびレジスタにあります。test/tmp/tmp.HudBncQ4Nirdirsi

straceシステムコールを呼び出すと、プロセスにシグナル(一時停止など)を注入できますが、strace -e inject=unlink,unlinkat,rmdir:signal=STOPAFAICTは常にそうです。後ろにファイルが削除されると、システムコールが返されます。

Ctrlただし、+を使用して手動で一時停止できるように入力を遅らせることができますZ。たとえば、次のようになります。

$ strace -e inject=unlink,unlinkat,rmdir:delay_enter=5s -e unlink,unlinkat,rmdir rm -rf /tmp/tmp.HudBncQ4Ni
unlinkat(4, "test", 0^Z
zsh: suspended  strace -e inject=unlink,unlinkat,rmdir:delay_enter=10s -e  rm -rf

または、@PhilippWendlerが提案したように、次のものを使用できます。

strace -e inject=unlink,unlinkat,rmdir:retval=0 -e unlink,unlinkat,rmdir ...

または:

strace -e inject=unlink,unlinkat,rmdir:error=EACCES -e unlink,unlinkat,rmdir ...

システムコールをハイジャックし、成功(使用retval=0)または失敗(EACCESここでは意味)したふりをします。許可が拒否されました)実際に電話せずに。

gdbstraceすでに実行中のプロセスにそれぞれ使用/接続できます。また、フォークと実行を追跡し、子項目を追跡して親項目に接続し、子項目の切断を監視またはハイジャックするように指示することもできます(およびの設定を参照)。--pid <the-process-id>-p <the-process-id>-fstracefollow-*gdb

おすすめ記事