めもめも

このブログに記載の内容は個人の見解であり、必ずしも所属組織の立場、戦略、意見を代表するものではありません。

Perl の system() 関数が EUID/EGID を引き継がない件

うーん。なぜでしょう? → 理由が分かりました。記事の下の方を見てください。

[root@client01 ~]# perl -v

This is perl, v5.8.8 built for x86_64-linux-thread-multi

Copyright 1987-2006, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.

[root@client01 ~]# cat /etc/redhat-release
Red Hat Enterprise Linux Server release 5.5 (Tikanga)

[root@client01 ~]# cat hoge.pl
#!/usr/bin/perl

printf ( "GID, EGID = %d, %d\n", $(, $) );
printf ( "UID, EUID = %d, %d\n", $<, $> );

if ( fork() ) {
        open ( OUT, "> /tmp/00nofork" ); print OUT "test\n"; close OUT;
        system ( "date > /tmp/00sysfork" );
} else {
        open ( OUT, "> /tmp/00dofork" ); print OUT "test\n"; close OUT;
        exit 0;
}

$) = 1001;
$> = 1001;
printf ( "GID, EGID = %d, %d\n", $(, $) );
printf ( "UID, EUID = %d, %d\n", $<, $> );

if ( fork() ) {
        open ( OUT, "> /tmp/01nofork" ); print OUT "test\n"; close OUT;
        system ( "date > /tmp/01sysfork" );
} else {
        open ( OUT, "> /tmp/01dofork" ); print OUT "test\n"; close OUT;
        exit 0;
}

$( = 1001;
$< = 1001;
printf ( "GID, EGID = %d, %d\n", $(, $) );
printf ( "UID, EUID = %d, %d\n", $<, $> );

if ( fork() ) {
        open ( OUT, "> /tmp/11nofork" ); print OUT "test\n"; close OUT;
        system ( "date > /tmp/11sysfork" );
} else {
        open ( OUT, "> /tmp/11dofork" ); print OUT "test\n"; close OUT;
        exit 0;
}
[root@client01 ~]#
[root@client01 ~]# ./hoge.pl
GID, EGID = 0, 0
UID, EUID = 0, 0
GID, EGID = 0, 1001
UID, EUID = 0, 1001
GID, EGID = 1001, 1001
UID, EUID = 1001, 1001
[root@client01 ~]#
[root@client01 ~]# ls -l /tmp/*fork*
-rw-r--r-- 1 root   root     5  36 14:14 /tmp/00dofork
-rw-r--r-- 1 root   root     5  36 14:14 /tmp/00nofork
-rw-r--r-- 1 root   root    43  36 14:14 /tmp/00sysfork
-rw-r--r-- 1 user01 group01  5  36 14:14 /tmp/01dofork
-rw-r--r-- 1 user01 group01  5  36 14:14 /tmp/01nofork
-rw-r--r-- 1 root   root    43  36 14:14 /tmp/01sysfork  <---- EUID/EGID が反映されない!
-rw-r--r-- 1 user01 group01  5  36 14:14 /tmp/11dofork
-rw-r--r-- 1 user01 group01  5  36 14:14 /tmp/11nofork
-rw-r--r-- 1 user01 group01 43  36 14:14 /tmp/11sysfork

理由はこれでした。

system(3) の NOTES セクションより

                                                       system() will  not,  in
       fact,  work  properly  from  programs  with set-user-ID or set-group-ID
       privileges on systems on which /bin/sh is bash version 2, since bash  2
       drops  privileges  on startup.  (Debian uses a modified bash which does
       not do this when invoked as sh.)

bash(1) の -p オプションの説明より

       If the shell is started with the effective user (group) id not equal to
       the real user (group) id, and the -p option is not supplied, no startup
       files are read, shell functions are not inherited from the environment,
       the SHELLOPTS variable, if it appears in the environment,  is  ignored,
       and the effective user id is set to the real user id.  If the -p option
       is supplied at invocation, the startup behavior is the  same,  but  the
       effective user id is not reset.

system() は、内部的に sh を呼び出しますが、sh が bash の場合は、bash の仕様で EUID/EGID が無視されます。