Perl ソースコードを用いて suidperl を構築する

SETUP


suidperl

Qmail-Scanner というプログラムをインストールしていたときのこと、UID の切り替えに対応した suidperl が必要になりました。

ディストリビューションによっては追加インストール可能になっている場合もあるようでしたけど、Slackware 10.2 では、提供されていないような感じです。C-wrapper があればなくても良いような記載もありましたけど、その C-wrapper の情報も、なかなか見つかりませんでした。

そんな中、Perl をソースコードからコンパイルすれば、UID の切り替えに対応させることができるような情報が見つかりましたので、その方法で suidperl を作成してみることにしました。

 

suidperl を構築する

suidperl を構築するに当たって、まずは http://www.cpan.org/src/README.html から、Perl のソースコードを取得します。

現時点での最新版である Perl 5.8.9 のソースコード (perl-5.8.9.tar.gz) を /usr/local/src ディレクトリへダウンロードしたら、展開し、コンパイルの準備を進めます。

tar xvzf perl-5.8.9.tar.gz

cd perl-5.8.9

次のコマンドを実行すると、Perl の構築に必要な事項の確認を行うことになります。

./Configure

確認される内容については、ほとんどが既定値のままで良いのですけど、一部だけ、特別な設定を行います。

具体的には suidperl として振舞うために "Do you want to do setuid/setgid emulation?" に "y" と回答することと、既存のバージョンの Perl を残しておくために "What shall I put after the #! to start up perl ("none" to not use #!)?" に対して "/usr/local/bin/suidperl" と答える感じです。

質問内容 既定値 設定値
Which of these apply, if any? linux 既定値の通り
Operating system name? linux 既定値の通り
Operating system version? 2.4.31 既定値の通り
Installation prefix to use? (~name ok) /usr/local 既定値の通り
What installation prefix should I use for installing files? (~name ok) /usr/local 既定値の通り
Build Perl for SOCKS? n 既定値の通り
Use the PerlIO abstraction layer? y 既定値の通り
Build a threading Perl? n 既定値の通り
Build Perl for multiplicity? n 既定値の通り
Use which C compiler? cc 既定値の通り
Directories to use for library searches? /usr/local/lib /lib /usr/lib 既定値の通り
What is the file extension used for shared libraries? so 既定値の通り
Try to use long doubles if available? n 既定値の通り
What libraries to use? -lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lc 既定値の通り
What optimizer/debugger flag should be used? -O2 既定値の通り
Any additional cc flags? -fno-scrict-aliasing -pipe -I/usr/local/include 既定値の通り
Any additional ld flags (NOT including libraries)? -L/usr/local/lib 既定値の通り
Try to use 64-bit integers, if available? n 既定値の通り
Try to use maximal 64-bit support, if available? n 既定値の通り
What is your architecture name i686-linux 既定値の通り
Pathname where the public executables will reside? (~name ok) /usr/local/bin 既定値の通り
Use relocatable @INC? n 既定値の通り
Pathname where the private library files will reside? (~name ok) /usr/local/lib/perl5/5.8.9 既定値の通り
Where do you want to put the public architecture-dependent libraries? (~name ok) /usr/local/lib/perl5/5.8.9/i686-linux 既定値の通り
Other username to test security of setuid scripts with? none 既定値の通り
Does your kernel have *secure* setuid scripts? n 既定値の通り
Do you want to do setuid/setgid emulation? n y
Installation prefix to use for add-on modules and utilities? (~name ok) /usr/local 既定値の通り
Pathname for the site-specific library files? (~name ok) /usr/local/lib/perl5/site_perl/5.8.9 既定値の通り
List of earlier versions to include in @INC? none 既定値の通り
Do you wish to wrap malloc calls to protect against potential overflows? y 既定値の通り
Do you wish to attempt to use the malloc that comes with perl5? n 既定値の通り
Pathname for the site-specific architecture-dependent library files? (~name ok) /usr/local/lib/perl5/site_perl/5.8.9/i686-linux 既定値の通り
Do you want to configure vendor-specific add-on directories? n 既定値の通り
Colon-separated list of additional directories for perl to search? none 既定値の通り
Install any extra modules (y or n)? n 既定値の通り
Directory for the main Perl5 html pages? (~name ok) none 既定値の通り
Directory for the Perl5 module html pages? (~name ok) none 既定値の通り
Do you want to install perl as /usr/bin/perl? n 既定値の通り
Shall I use /usr/bin/nm to extract C symbols from the libraries? n 既定値の通り
Do you wish to use dynamic loading? y 既定値の通り
Source file to use for dynamic loading ext/DynaLoader/dl_dlopen.xs 既定値の通り
Any special flags to pass to cc -c to compile shared library modules? -fPIC 既定値の通り
What command should be used to create dynamic libraries? cc 既定値の通り
Any special flags to pass to cc to create a dynamically loaded library? -shared -O2 -L/usr/local/lib 既定値の通り
Any special flags to pass to cc to use dynamic linking? -Wl,-E 既定値の通り
Build a shared libperl.so (y/n) n 既定値の通り
Where do the main Perl5 manual pages (source) go? (~name ok) /usr/local/share/man/man1 既定値の通り
What suffix should be used for the main Perl5 man pages? 1 既定値の通り
Where do the perl5 library man pages (source) go? (~name ok) /usr/local/share/man/man3 既定値の通り
What suffix should be used for the perl5 library man pages? 3 既定値の通り
Your host name appears to be "********". Right? y 既定値の通り
What is your domain name? *****.***.JP 既定値の通り
What is your e-mail address? ***@****.***.JP 既定値の通り
Perl administrator e-mail address ***@****.***.JP 既定値の通り
Do you want to install only the version-specific parts of perl? n 既定値の通り
What shall I put after the #! to start up perl ("none" to not use #!)? /usr/local/bin/perl /usr/local/bin/suidperl
Where do you keep publicly executable scripts? (~name ok) /usr/local/bin 既定値の通り
Pathname where the add-on public executables should be installed? (~name ok) /usr/local/bin 既定値の通り
Pathname where the site-specific html pages should be installed? (~name ok) none 既定値の通り
Pathname where the site-specific library html pages should be installed? (~name ok) none 既定値の通り
Pathname where the site-specific manual pages should be installed? (~name ok) /usr/local/share/man/man1 既定値の通り
Pathname where the site-specific library manual pages should be installed? (~name ok) /usr/local/share/man/man3 既定値の通り
Pathname where add-on public executable scripts should be installed? (~name ok) /usr/local/bin 既定値の通り
Use the "fast stdio" if available? y 既定値の通り
Try to understand large files, if available? y 既定値の通り
What is the extension of dynamically loaded modules so 既定値の通り
Shall I ignore gethostname() from now on? n 既定値の通り
Shall I ignore gethostname() from now on? n 既定値の通り
Do you still want to use vfork()? n 既定値の通り
Doubles must be aligned on a how-many-byte boundary? 4 既定値の通り
Use which function to generate random numbers? drand48 既定値の通り
What type pointer is the second argument to getgroups() and setgroups()? gid_t 既定値の通り
What pager is used on your system? /usr/bin/less 既定値の通り
Which compiler compiler (byacc or yacc or bison -y) shall I use? /usr/bin/byacc 既定値の通り
What extensions do you wish to load dynamically? B ByteLoader Cwd ... threads/shared 既定値の通り
What extensions do you wish to load statically? none 既定値の通り
Press return or use a shell escape to edit config.sh:   既定値の通り
Run make depend now? y 既定値の通り

なお、注意点として、既存のバージョンを残すようにしたとしても、インストール時に /usr/local/bin/perl のバイナリも併せて更新するようです。

既存の Perl は旧バージョンの処理系が維持されるようなのですけど、バイナリが更新されるせいなのか、旧バージョンでも UID の切り替えが可能でした。

コンパイル前に念のため、既にインストールされている Perl のバックアップを取っておくと安心かもしれません。

 

ともあれこれで、コンパイルのための準備は完了です。

具体的には、config.sh 内の d_dosuid の値が 'define' となっていれば大丈夫です。

 

後は次のようにして、Perl のコンパイルを行います。

make

make test

 

make install

これで、/usr/local/bin/suidperl として、Perl がインストールされました。

 

最後に、インストールされた suidperl に対して、s ビットを付加すれば完成です。

chmod +s /usr/local/bin/suidperl

 

suidperl の動作を確認する

suidperl は、Perl スクリプトに設定されている s フラグとそのファイルの所有者情報を元に、実行時の UID を切り替えるようになっています。

正しく動作しているかを確認する方法としては、まず、次のような Perl スクリプトを作成します。

#!/usr/local/bin/suidperl

print `whoami`;

このスクリプトを、たとえば "test.pl" というファイル名で保存したとします。

これに次のようにして、ファイルの所有者を "user1" に変更し、パーミッションとして s ビットを付加します。"user1" というところには、Linux に登録されているユーザ名を指定する必要がありますので、登録済みのユーザ名に置き換えてください。

chown user1 test.pl

chmod +s test.pl

これで準備完了です。

次のようにしてスクリプトを実行すれば、実行時のユーザー名として、ファイルに設定した所有者名が取得されるのを確認できると思います。

./test.pl