在 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 -d
:https://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 测试脚本再次运行。
我在 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 -d
:https://pastebin.com/4NMGD2aR
我对此的解释是,在切换到 cgi-bin 目录后,cgid 在 64 位中被杀死,而在 32 位中执行脚本。 权限是一样的,所以我看不出这里有什么问题。至少它解释了错误日志中的消息——因为脚本没有被执行,所以没有 headers 被打印出来。
无论如何,我有点迷失从这里去哪里。任何有关如何进一步调试的提示都将不胜感激。
您的 32 位和 64 位测试不一样。根据发布的 truss
输出,32 位进程似乎 运行 一个名为 cgi-test.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 测试脚本再次运行。