私は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.HudBncQ4Ni
rdi
rsi
strace
システムコールを呼び出すと、プロセスにシグナル(一時停止など)を注入できますが、strace -e inject=unlink,unlinkat,rmdir:signal=STOP
AFAICTは常にそうです。後ろにファイルが削除されると、システムコールが返されます。
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
ここでは意味)したふりをします。許可が拒否されました)実際に電話せずに。
gdb
strace
すでに実行中のプロセスにそれぞれ使用/接続できます。また、フォークと実行を追跡し、子項目を追跡して親項目に接続し、子項目の切断を監視またはハイジャックするように指示することもできます(およびの設定を参照)。--pid <the-process-id>
-p <the-process-id>
-f
strace
follow-*
gdb
答え2
私が望むことを正確に行うinotify-toolsを使ってこのシェルスクリプトを見つけました(著者:https://unix.stackexchange.com/a/265995/536771):
#!/bin/sh
TMP_DIR=/tmp
CLONE_DIR=/tmp/clone
mkdir -p $CLONE_DIR
wait_dir() {
inotifywait -mr --format='%w%f' -e create "$1" 2>/dev/null | while read file; do
echo $file
DIR=`dirname "$file"`
mkdir -p "${CLONE_DIR}/${DIR#$TMP_DIR/}"
cp -rl "$file" "${CLONE_DIR}/${file#$TMP_DIR/}"
done
}
trap "trap - TERM && kill -- -$$" INT TERM EXIT
inotifywait -m --format='%w%f' -e create "$TMP_DIR" | while read file; do
if ! [ -d "$file" ]; then
continue
fi
echo "setting up wait for $file"
wait_dir "$file" &
done
私にとっては、単純な解決策はスクリプトよりはるかに優れています。
chattr +a /tmp
これは、バイナリがフォルダの代わりに/ tmpの下に単一のファイルを生成するとスクリプトが失敗するためです。バイナリが/ tmpの下に複数のフォルダを作成しても失敗します。
編集:機能するより簡単な解決策は、次のことを実行することです。
cp -rp /source /clone
chattrが私が確認する内容を妨げます。最初のスクリプトは、/ tmpの下に作成されたディレクトリには機能しますが、/ tmpの下に生成されたファイルには機能しません。
答え3
私は過去にも同様の状況に直面していました。chattr -R -a /tmp
本質的にちょうど追加された同様のものを実行したことを曖昧に覚えています/tmp
。プロセスはファイル/ディレクトリを作成できますが、削除することはできません。コマンドを実行する前に慎重に確認し、できるだけ早く属性をキャンセルしてください。
答え4
私がさまざまな機能(リスニング)に使用した解決策は、興味のある機能(unlinkやfopenなど)をオーバーライドする単純な動的ライブラリを作成することです。
コンパイルしてリンクして-fPIC
動的ライブラリを作成し、バイナリに挿入します。
LD_PRELOAD=/path/to/mylib.so ./binary