camel

さすがにこの目的のためだけにXS Hackというのは、ハエ退治にパトリオットミサイル撃つようなものなので、キンチョールも紹介しておきたく。

PL_check hack - daily dayflower
ゴール
#!/usr/bin/perl
eval 'print "Hello ' . $ARGV[0] . '!\n"';
とか危険ですよねー*1。こんな機能があるなんてけしからん。ですので,eval の実行を抑制するモジュールを書いてみました。

そのためには、Safeモジュールを使います。Perl 5.02からCOREに入っている由緒あるモジュールです。Malcolm Beattie がBのフレームワークを作った理由の一つが、これを可能にすることでした。今はpumpkingの Rafaël Garcia-Suarez がメンテしています。

で、何をするモジュールかというと、opcodeの一つ一つをオンにしたりオフにしたり出来るモジュールです。

まずはこういうファイルを用意しましょう。
#!perl
use strict;
use warnings;
use Safe;

$ARGV[0] ||= 'world'; # for codepad

my $safe = Safe->new;
# $safe->permit(qw/print entereval/);
$safe->reval(qq{
    print "Hello ", $ARGV[0], "!\n";
    eval 'print "Hello ", $ARGV[0], "!\n"';
});
die $@ if $@;

実行してみます。

[run via codepad]
eval "string" trapped by operation mask at (eval 2) line 5.

今度は、# $safe->permit(qw/print entereval/)をuncommentして実行してみましょう。

[run via codepad]
Hello world!
Hello world!

今度はうまく行きました。

それでは次に、qq{ ... }q{ ... }にしてみましょう。

[run via codepad]
Hello !
Hello !

はまちちゃんになっちゃいました。じゃなくて、@ARGVがSafe環境と共有されていないことがわかりました。

で、具体的にevalだけ殺してみましょう。$safe->permit(qw/print entereval/)からenterevalを取り除いてみて下さい。

[run via codepad]
eval "string" trapped by operation mask at (eval 2) line 3.

evaレないことが確認できます。

それではファイルを最初のバージョンに戻して、コマンドラインからこう打ってみて下さい。codepadの禁則事項なので、各自お願いします。

% /usr/bin/perl safe.pl 'qx(date)'

こうなったはずです。

'quoted execution (``, qx)' trapped by operation mask at (eval 2) line 2.

Safeを使うと、Taint Modeでは不可能なきめ細かいコントロールが出来ます。Taint Modeが使えない、mod_perlで使うことが出来る点もぐーです。

続きは

で!

Dan the Safe Perl Monger