I have a custom build of apache’s httpd
version 2.2 together with perl
version 5.22 on solaris 10. The httpd runs in a chroot environment, and the perl script is executed via httpd’s mod_cgid
. So far all was in 32 bit things worked. Now I have compiled everything in 64 bit (because another httpd module is only provided as a 64 bit binary), and now I cannot get the perl script to be executed via cgid.
The http error log contains the line
Premature end of script headers.
So I tried to execute my test script without cgid, just using perl inside the chroot, and besides some warnings it just worked fine. Here is my script, if its of any interest:
#!/local/perl5/bin/perl
print "Content-type: text/plainnn";
opendir(DIRHANDLE, "/");
@filenames = readdir(DIRHANDLE);
foreach $file (@filenames) { print "$filen"; }
closedir(DIRHANDLE);
(I know its not a great one :))
The warnings were about the locale not being set, so I fixed that by adding /usr/lib/locale
to the chroot. This fixed the warnings, but did not fix the original problem. So I assume this was not the root cause. Even more so, when I compared to the 32 bit build, I got the same warnings, however the script would execute fine via cgid.
Next thing I did was to trace the systemcalls via truss -f -o mylogfile.txt
. The full output can be found on pastebin (32 bit truss). Here is an excerpt for the 32 bit build (line 4296 on pastebin) – note that paths are not exactly the same as on pastebin, but the observed result is the same:
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
And here is the truss output for the 64 bit build. The following is an excerpt (line 4489), note I left out some lines, denoted by [...]
:
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, " pEF", 4) = 4
28906/21: kill(28911, SIGTERM) Err#3 ESRCH
28904: close(4) = 0
As Andrew Haenle noticed, I did not execute the same scripts in 32 bit vs 64 bit – at least in the truss output shown above. So here is the truss output for the failing 64 bit, where I execute the same script as in 32 bit: https://pastebin.com/Nz1jBjne
Here is some more truss output from the 64 bit build, with the additional flags -a -e -d
: https://pastebin.com/4NMGD2aR
The way I interpret this is that after changing to the cgi-bin directory, cgid gets killed in 64 bit, vs. executing the script in 32 bit.
Permissions are the same, so I do not see what is the problem here. At least it explains the message from the error log – since the script is not executed, no headers are ever printed.
Anyway, I am a bit lost where to go from here. Any hints how to debug this further would be highly appreciated.
2
Answers
First of all thank you to all who have made comments and suggestions.
Finally it turns out that it was a permissions problem. Not in the script, but in the libraries. The way my chroot environment is built is that it gets is custom permissions applied inside the chroot. Now that mechanism was not yet adapted to 64 bit. 64 bit libraries live in different subdirectories of the standard locations for 32 bit backwards compatibility. Also, my httpd process runs as a non-root user. After correcting the permissions perl worked like a charm in 64 bit.
But maybe more interesting for the general public is how I found this out: I added the
-X
flag to the apache startup command. That enables debug mode for apache, and finally produced the error message I needed:After executing - inside the chroot of course -
my perl test scripts worked again.
Your 32- and 64-bit tests are not the same. Per the posted
truss
output, the 32-bit process appears to run a Perl CGI script calledcgi-test.cgi
:Note that the CGI script is run by PID 28420, where PID 28415 appears to be the “controlling” process.
But for the 64-bit process, this is the corresponding output, with the CGI script being
test.pl
:Note the lack of an
execve()
call. And then PID 28911 disappears until this:There’s not only no
execve()
call that actually executes the Perl script, there’s no PID 28911 any more.The problem appears to be the
test.pl
script. What are the permissions on the script? What user/group owns it? Does it have any ACLs attached?