Apache: Permission denied: exec of ‘/var/www/html/cgi-test/first.pl’ failed

apache-2.4cgiperl

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:

$ semanage fcontext --list | grep cgi-bin 
 (...)
/var/www/[^/]*/cgi-bin(/.*)?                       all files          system_u:object_r:httpd_sys_script_exec_t:s0
/var/www/html/[^/]*/cgi-bin(/.*)?                  all files          system_u:object_r:httpd_sys_script_exec_t:s0
 (...)

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 the cgi-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:

$ chcon -t httpd_sys_script_exec_t /var/www/html/cgi-test/first.pl

Check the file's SELinux attributes with ls -laZ:

$ ls -laZ /var/www/html/cgi-test/first.pl
-rwxr-xr-x. root root system_u:object_r:httpd_sys_script_exec_t:s0 /var/www/html/cgi-test/first.pl

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 the policycoreutils-python RPM package):

$ semanage fcontext -a -t httpd_sys_script_exec_t "/var/www/html/cgi-test(/.*)?"

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:

$ restorecon -R -v /var/www/html/cgi-test

You can check your newly-added rule with:

$ semanage fcontext --list | grep cgi-test
Related Topic