在 64 位上通过 cgid 在 solaris 上执行 perl 失败,但在 32 位上工作

Executing perl via cgid on solaris fails in 64 bit, but works in 32 bit

我在 solaris 10 上定制了 apache 的 httpd 2.2 版和 perl 5.22 版。httpd 在 chroot 环境中运行,perl 脚本通过 httpd 的 mod_cgid。到目前为止,一切都在 32 位工作。现在我已经编译了 64 位的所有东西(因为另一个 httpd 模块只作为 64 位二进制文​​件提供),现在我无法通过 cgid 执行 perl 脚本。

http 错误日志包含行

Premature end of script headers.

所以我尝试在没有 cgid 的情况下执行我的测试脚本,只是在 chroot 中使用 perl,除了一些警告之外,它运行良好。这是我的脚本,如果有任何兴趣:

#!/local/perl5/bin/perl
print "Content-type: text/plain\n\n";
opendir(DIRHANDLE, "/");
@filenames = readdir(DIRHANDLE);
foreach $file (@filenames) { print "$file\n"; }
closedir(DIRHANDLE);

(我知道它不是很好 :))

警告是关于未设置语言环境的,所以我通过将 /usr/lib/locale 添加到 chroot 来解决这个问题。这修复了警告,但没有解决原始问题。所以我认为这不是根本原因。更重要的是,当我与 32 位版本进行比较时,我得到了相同的警告,但是脚本可以通过 cgid 正常执行。

接下来我要做的是通过 truss -f -o mylogfile.txt 跟踪系统调用。可以找到完整的输出 on pastebin (32 bit truss)。这是 32 位构建的摘录(pastebin 上的第 4296 行)——请注意,路径与 pastebin 上的路径不完全相同,但观察到的结果是相同的:

28420:  sigaction(SIGCLD, 0xFFBFF6A8, 0xFFBFF748)       = 0
28420:  chdir("/path/to/my/chroot/cgi-bin/") = 0
28420:  execve("/path/to/my/chroot/cgi-bin/test.pl", 0x00183DB8, 0x00183570)  argc = 3
28420:      *** SUID: ruid/euid/suid = 50001 / 50001 / 50001  ***
28420:      *** SGID: rgid/egid/sgid = 50001 / 50001 / 50001  ***
28420:  sysinfo(SI_MACHINE, "sun4u", 257)               = 6

这是 64 位构建的 truss output。以下是摘录(第 4489 行),注意我遗漏了一些行,用 [...]:

表示
28906/21:       open("/dev/urandom", O_RDONLY)                  = 12
[...]
28911:  sigaction(SIGCLD, 0xFFFFFFFF7FFFF150, 0xFFFFFFFF7FFFF250) = 0
28911:  chdir("/path/to/my/chroot/cgi-bin/") = 0
28906/21:       pollsys(0xFFFFFFFF747F7080, 1, 0xFFFFFFFF747F6FA0, 0x00000000) = 1
28906/21:       read(12, 0x10034BB38, 8000)                     = 0
28906/21:       close(12)                                       = 0
[...]
28906/21:       read(10, "[=13=][=13=] pEF", 4)                         = 4
28906/21:       kill(28911, SIGTERM)                            Err#3 ESRCH
28904:  close(4)                                        = 0

正如 Andrew Haenle 所注意到的,我没有在 32 位和 64 位中执行相同的脚本——至少在上面显示的 truss 输出中是这样。所以这是失败的 64 位的 truss 输出,我在其中执行与 32 位相同的脚本:https://pastebin.com/Nz1jBjne

这是 64 位构建的更多 truss 输出,带有附加标志 -a -e -dhttps://pastebin.com/4NMGD2aR

我对此的解释是,在切换到 cgi-bin 目录后,cgid 在 64 位中被杀死,而在 32 位中执行脚本。 权限是一样的,所以我看不出这里有什么问题。至少它解释了错误日志中的消息——因为脚本没有被执行,所以没有 headers 被打印出来。

无论如何,我有点迷失从这里去哪里。任何有关如何进一步调试的提示都将不胜感激。

您的 32 位和 64 位测试不一样。根据发布的 truss 输出,32 位进程似乎 运行 一个名为 cgi-test.cgi:

的 Perl CGI 脚本
28415/25:   stat64("/local/content/apache/myinstance.acme.com/cgi-bin/cgi-test.cgi", 0xFAFFBA18) = 0
28415/25:   lstat64("/local", 0xFAFFBA18)           = 0
28415/25:   lstat64("/local/content", 0xFAFFBA18)       = 0
28415/25:   lstat64("/local/content/apache", 0xFAFFBA18)    = 0
28415/25:   lstat64("/local/content/apache/myinstance.acme.com", 0xFAFFBA18) = 0
28415/25:   lstat64("/local/content/apache/myinstance.acme.com/cgi-bin", 0xFAFFBA18) = 0
28415/25:   lstat64("/local/content/apache/myinstance.acme.com/cgi-bin/cgi-test.cgi", 0xFAFFBA18) = 0
28415/25:   open("/dev/urandom", O_RDONLY)          = 12
28415/25:   read(12, "C3 E DB1 A03 5 kCBA8DF\r".., 64)  = 64
28415/25:   close(12)                   = 0
28415/25:   open("/dev/urandom", O_RDONLY)          = 12
28415/25:   read(12, "E6 L _F3 uBC fA7E18AFC \".., 64)  = 64
28415/25:   close(12)                   = 0
28415/25:   so_socket(PF_UNIX, SOCK_STREAM, 0, "", SOV_DEFAULT) = 12
28415/25:   connect(12, 0xFAFF7AA8, 110, SOV_DEFAULT)  
 ...
28420:  sigaction(SIGCLD, 0xFFBFF6A8, 0xFFBFF748)   = 0
28420:  chdir("/local/content/apache/myinstance.acme.com/cgi-bin/") = 0
28420:  execve("/local/content/apache/myinstance.acme.com/cgi-bin/cgi-test.cgi", 0x00183DB8, 0x00183570)  argc = 3
28420:      *** SUID: ruid/euid/suid = 50001 / 50001 / 50001  ***
28420:      *** SGID: rgid/egid/sgid = 50001 / 50001 / 50001  ***

请注意,CGI 脚本是 运行 的 PID 28420,其中 PID 28415 似乎是 "controlling" 进程。

但是对于64位进程,这是对应的输出,CGI脚本为test.pl:

28906/21:   stat("/local/content/apache/myinstance.acme.com/cgi-bin/test.pl", 0xFFFFFFFF747FB3E0) = 0
28906/21:   lstat("/local", 0xFFFFFFFF747FB3E0)     = 0
28906/21:   lstat("/local/content", 0xFFFFFFFF747FB3E0) = 0
28906/21:   lstat("/local/content/apache", 0xFFFFFFFF747FB3E0) = 0
28906/21:   lstat("/local/content/apache/myinstance.acme.com", 0xFFFFFFFF747FB3E0) = 0
28906/21:   lstat("/local/content/apache/myinstance.acme.com/cgi-bin", 0xFFFFFFFF747FB3E0) = 0
28906/21:   lstat("/local/content/apache/myinstance.acme.com/cgi-bin/test.pl", 0xFFFFFFFF747FB3E0) = 0
28906/21:   open("/dev/urandom", O_RDONLY)          = 12
28906/21:   read(12, "9C `9F9899 uAED9 `1CBE11".., 64)  = 64
28906/21:   close(12)                   = 0
28906/21:   open("/dev/urandom", O_RDONLY)          = 12
28906/21:   read(12, "C2F8FC11C31D = ! V ; O =".., 64)  = 64
28906/21:   close(12)                   = 0
28906/21:   so_socket(PF_UNIX, SOCK_STREAM, 0, "", SOV_DEFAULT) = 12
28906/21:   connect(12, 0xFFFFFFFF747F9560, 110, SOV_DEFAULT) = 0
...
28911:  sigaction(SIGCLD, 0xFFFFFFFF7FFFF150, 0xFFFFFFFF7FFFF250) = 0
28911:  chdir("/local/content/apache/myinstance.acme.com/cgi-bin/") = 0

请注意缺少 execve() 调用。然后 PID 28911 消失,直到:

28906/21:   kill(28911, SIGTERM)                Err#3 ESRCH
28906/21:   kill(28911, SIG#0)              Err#3 ESRCH

不仅没有 execve() 实际执行 Perl 脚本的调用,也没有 PID 28911。

问题似乎是 test.pl 脚本。脚本的权限是什么? user/group 拥有它的是什么?它是否附加了任何 ACL?

首先感谢所有提出意见和建议的朋友

最后发现是权限问题。不在脚本中,而是在库中。我的 chroot 环境的构建方式是它获得在 chroot 中应用的自定义权限。现在该机制尚未适应 64 位。 64 位库位于标准位置的不同子目录中,以实现 32 位向后兼容性。此外,我的 httpd 进程以非 root 用户身份运行。更正权限后,perl 在 64 位中工作得很好。

但对于一般 public 来说更有趣的是我是如何发现这一点的:我将 -X 标志添加到 apache 启动命令中。这为 apache 启用了调试模式,并最终产生了我需要的错误消息:

env.pl: Cannot execute /lib/sparcv9/ld.so.1
cgi-test.cgi: Cannot execute /lib/sparcv9/ld.so.1

执行后 - 当然是在 chroot 中 -

chmod o+x /lib/sparcv9/ld.so.1
chmod o+r /lib/sparcv9/*

我的 perl 测试脚本再次运行。