So, I'm new to CGI / Perl, I'm trying to move a perl-based web app to a new server.
My new server is CentOS 7, which runs Apache HTTPD 2.4.6.
I'm trying to get a basic Perl CGI working from an HTTP request.
The web request is returning "500 Internal Server Error"
The error log is showing "permission denied":
[Tue May 12 16:56:44.604660 2015] [cgi:error] [pid 12302] [client 10.0.2.2:56693] AH01215: (13)Permission denied: exec of '/var/www/html/cgi-test/first.pl' failed
[Tue May 12 16:56:44.604708 2015] [cgi:error] [pid 12302] [client 10.0.2.2:56693] End of script output before headers: first.pl
My CGI script is in /var/www/html/cgi-test/first.pl
It looks like this:
#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "Hello, World.";
In the cgi-test directory the permissions look like this:
drwxr-xr-x. 2 root root 21 May 12 16:48 .
drwxr-xr-x. 4 root root 32 May 12 16:48 ..
-r-xr-xr-x. 1 root root 76 May 12 16:48 first.pl
Perl is in the normal place and has I think normal permissions
[root@localhost cgi-test]# ls -al /usr/bin/perl
-rwxr-xr-x. 2 root root 11400 Mar 6 05:07 /usr/bin/perl
My httpd.conf is the default. I've just added the following section in order to allow cgi in my cgi-test directory:
<Directory "/var/www/html/cgi-test">
Options +ExecCGI
AddHandler cgi-script .cgi .pl
</Directory>
To eliminate the possibility of suexec being the cause of this issue I've moved it from /usr/sbin/suexec to another file name.
Httpd is running as user "apache" which is in group "apache"
[root@localhost cgi-test]# ps -Af | grep httpd
root 12298 1 0 16:56 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
apache 12299 12298 0 16:56 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
apache 12300 12298 0 16:56 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
apache 12301 12298 0 16:56 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
apache 12302 12298 0 16:56 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
apache 12303 12298 0 16:56 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
root 12342 12260 0 17:20 pts/0 00:00:00 grep --color=auto httpd
[root@localhost cgi-test]# groups apache
apache : apache
I have tried running the script as apache, it works without any problem.
[root@localhost cgi-test]# su -s /bin/bash apache
bash-4.2$ perl /var/www/html/cgi-test/first.pl
Content-type: text/html
Hello, World.bash-4.2$
Presumably I'm hitting some security precaution of Apache. Lots of conflicting advice about what this might be. Any help much appreciated.
Best Answer
I see from your own answer that it was a SELinux permissions issue due to trying to run CGI scripts from within apache in a non-standard directory.
The proper way to solve the permissions issue while maintaining SELinux in 'enforcing' mode, and thus improving your server's security is to apply the proper context to the files in your custom CGI script directory. If it is to be a permanent directory, you should change the selinux policy to automatically create new files with the proper permissions.
You can check the selinux policy for the cgi-bin directory with the command:
This means that every file created inside the standard cgi-bin directories for apache will be automatically given the SELinux type
httpd_sys_script_exec_t
and be executable by httpd, so this is what your files in thecgi-test
directory should have as well.NOTE: the examples shown below are based on CentOS/RHEL6, it should work just the same for RHEL7 with the eventual tweak.
Temporary solution
You can simply change your perl script's SELinux context with:
Check the file's SELinux attributes with
ls -laZ
:However, if there's a SELinux relabel operation on this filesystem, the attributes will be reverted to the defaults and it will stop working again. It will also have to be done every time a new CGI script is added.
Definite solution
You can change the SELinux policy by adding a rule for your custom CGI directory and all contained subdirectories and files.
This is done via the
semanage
command (available in thepolicycoreutils-python
RPM package):This will take a while to run. After changing the policy any new files created in your custom directory will have the new context. For the ones already there, you can apply the policy manually with:
You can check your newly-added rule with: