2015-11-20

Mac OS Xで削除がとても難しいファイルを作成する方法

2013年の記事だが、Mac OS XとそのHFS+はこの上なくクソなので何があっても驚きはしないが、Mac OS Xで削除しにくいシンボリックリンクファイルを作成する方法があるらしい

OS X and the Unremovable File - galvanist

HFS+上で、削除しにくいシンボリックリンクを作成できる。

# be root, for example with: sudo -i
str1=$(python -c "print '1' * 255")
str2=$(python -c "print '2' * 255")
str3=$(python -c "print '3' * 255")
str4=$(python -c "print '4' * 253")
mkdir -p  $str1/$str2/$str3/$str4
ln -s ftw $str1/$str2/$str3/$str4/L

さて、このように作った以上、OS X v10.9では以下のコマンドでは削除できない。


# still as root...
unlink 1*/2*/3*/4*/L
unlink $str1/$str2/$str3/$str4/L
rm -rf 1*
rm -rf $str1
rm -rf $str1/$str2/$str3/$str4
rm -rf $str1/$str2/$str3/$str4/L
(cd $str1/$str2/$str3/$str4; unlink L)
(cd $str1/$str2/$str3/$str4; rm -rf L)

すべて、以下のようなエラーとなる。(読みやすさのために[...]で省略)

root# pwd
/private/tmp/111[ ... ]111/222[ ... ]222/333[ ... ]333/444[ ... ]444
root# ls
L
root# rm -f L
rm: L: No space left on device
root# df -H
Filesystem      Size   Used  Avail Capacity   iused     ifree %iused  Mounted on
/dev/disk1      250G   108G   142G    44%  26385563  34601956   43%   /
[...]

念の為、システムコールを直接呼び出すコードを書いてみる。/tmp/fixit.cにおいてあるとする。

#include <unistd.h>
#include <stdio.h>
#include <errno.h>

int main(int argc, char* argv[]) {
    printf("Unlink returned %i\n", unlink("L"));
    perror("Error was");
    return 0;
}

実行してみるが、

root# pwd
/private/tmp/111[ ... ]111/222[ ... ]222/333[ ... ]333/444[ ... ]444
root# gcc -o /tmp/fixit /tmp/fixit.c 
root# /tmp/fixit 
Unlink returned -1
Error was: No space left on device

ENOSPCだと。unlink(2) Mac OS X Developer Tools Manual Pageに返すとは書かれていないエラーだぞ。

状況は複雑だ。

  • 一般ユーザーが作ったのならば、一般ユーザーは、rm -rfで消すことができる
  • 一般ユーザーが作ったのならば、rootは消すことができない。おかしい
  • rootが作ったのならば、rootは消すことができない
  • rootが作ったのならば、通常通りの権限により、一般ユーザーは削除が行えない
  • rootが作ったものであっても、chmod -hとchown -hで権限を変えれば、一般ユーザーにも消せるはずである
  • rootが作ったものを、chmod -hとchown -hしようとすると、ENOSPCが返る。
  • rootが作ったものに対し、"mkdir -p some/containing/paths; mv 1111* some/containing/paths/"は動くが、その後、"rm -rf some"しても動かない。

Workaround

なぜか、パスはシンボリックリンクを作るには短いが、削除するには長すぎるようだ。パスを短縮すれば消せる。

root# pwd
/private/tmp/111[ ... ]111/222[ ... ]222/333[ ... ]333/444[ ... ]444
root# ls
L
root# mv /private/tmp/1* /private/tmp/one
root# pwd
/private/tmp/one/222[ ... ]222/333[ ... ]333/444[ ... ]444
root# rm L
root# ls
root# rm -rf /tmp/one
root# 

workaroundは十分なのか。

そういうわけで、一応workaroundはあるのだが、しかし疑問がある。

  • アンチウイルスソフトウェアはマルウェアがこのような方法で保存されていた場合、ちゃんと消せるよう作られているのか? アンチウイルスソフトウェアはすでにchflags(2)の問題に対処しなければならないが、こういうパスと複数のchflagsで構成されていた場合はどうか
  • マルウェアや悪意ある人物がディスクをこのようなもので埋め尽くした時に、rm -rfの代替品となるツールは存在するのか?

ちなみに、これは2013年の記事だが、Yosemiteまでは同じ問題があるそうだ。El Capitainだと、ファイルパスが長すぎて作成できないエラーが返るらしい。そもそも、Mac OS XのカーネルであるXNUのファイルパスの上限が2024文字なのに2025文字のファイルパスを作成できてしまうのがおかしいようだ。

No comments: