Installing Moodle with SELinux

Print Friendly, PDF & Email

We followed the instructions for installing Moodle from here:  http://docs.moodle.org/24/en/Installing_Moodle with some small variations:

1. We created a “moodle” user and installed the software as that user:

useradd_faculty moodle
su - moodle
git clone -b MOODLE_24_STABLE git://git.moodle.org/moodle.git 
mv moodle/* public_html/

Since the files are owned by moodle, they won’t be writable by the web server (apache).

2. We created a MySQL user account:

mysql-useradd.sh moodle random moodle_db

3. We created the moodle data directory in the home directory of the moodle account, not in public_html, following their security guidelines:

mkdir ~/data

4. Now, we need that directory to be writable by apache, so, as root, we did the following:

# chgrp apache ~moodle/data
# chmod g+rwx ~moodle/data

5. We then ran their installer:

# chown apache ~moodle/public_html
# cd ~moodle/public_html/admin/cli
# sudo -u apache /usr/bin/php install.php
# chown -R moodle ~moodle/public_html

6. Unfortunately, that asked a lot of questions that we didn’t know the answers to, so we had to do some guessing.  We wish their installation instructions had been a bit more comprehensive.

7. And after all that, failure!  We get the following in our web browser:

Fatal error: /home/moodle/data is not writable, admin has to fix directory permissions! Exiting

8. We double-checked the data directory, and even opened them up to 777, and no go.

9. Could it be SELinux?  Sure could.  Do this and here are the new entries that arrive in /var/log/audit/audit.log:

> type=AVC msg=audit(1360875272.798:582224): avc:  denied  { write } for  pid=3259 comm="httpd" name="data" dev=dm-4 ino=36455789 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=dir
> type=SYSCALL msg=audit(1360875272.798:582224): arch=c000003e syscall=21 success=no exit=-13 a0=7f0dfb551e50 a1=2 a2=0 a3=7f0dfb5c6ce0 items=0 ppid=8066 pid=3259 auid=4678 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=21996 comm="httpd" exe="/usr/sbin/httpd" subj=unconfined_u:system_r:httpd_t:s0 key=(null)
[root@tempest ~]

I got that info by the following script, which looks like a generally useful technique to see what SElinux complaints are caused by a particular operation:

[root@tempest moodle] cat /tmp/new-audits 
#!/bin/bash

before=`mktemp audit.before.XXX`
after=`mktemp audit.after.XXX`

tail -30 /var/log/audit/audit.log > $before
GET http://cs.wellesley.edu/~moodle/
tail -30 /var/log/audit/audit.log > $after
diff $before $after
[root@tempest moodle]

Unfortunately, Moodle’s installation instructions are mute on the subject of SELinux.  Still, there’s some promising information here:

http://beginlinux.com/server_training/web-server/976-apache-and-selinux

https://moodle.org/mod/forum/discuss.php?d=114665

http://wiki.centos.org/TipsAndTricks/SelinuxBooleans

I tried the following command, which lists Selinux booleans and a brief description:

[root@tempest moodle] semanage boolean -l | grep httpd 
httpd_can_network_relay        (off  ,  off)  Allow httpd to act as a relay
httpd_can_network_connect_db   (off  ,  off)  Allow HTTPD scripts and modules to connect to databases over the network.
httpd_use_gpg                  (off  ,  off)  Allow httpd to run gpg in gpg-web domain
httpd_enable_cgi               (on   ,   on)  Allow httpd cgi support
httpd_verify_dns               (off  ,  off)  Allow Apache to query NS records
allow_httpd_mod_auth_pam       (off  ,  off)  Allow Apache to use mod_auth_pam
httpd_run_stickshift           (off  ,  off)  Allow Apache to run in stickshift mode, not transition to passenger
httpd_enable_homedirs          (on   ,   on)  Allow httpd to read home directories
allow_httpd_sys_script_anon_write (off  ,  off)  Allow apache scripts to write to public content.  Directories/Files must be labeled public_rw_content_t.
httpd_dbus_avahi               (on   ,   on)  Allow Apache to communicate with avahi service via dbus
httpd_use_cifs                 (off  ,  off)  Allow httpd to access cifs file systems
httpd_unified                  (on   ,   on)  Unify HTTPD handling of all content files.
httpd_builtin_scripting        (on   ,   on)  Allow httpd to use built in scripting (usually php)
httpd_can_network_connect      (off  ,  off)  Allow HTTPD scripts and modules to connect to the network using TCP.
httpd_tty_comm                 (on   ,   on)  Unify HTTPD to communicate with the terminal. Needed for entering the passphrase for certificates at the terminal.
allow_httpd_anon_write         (off  ,  off)  Allow Apache to modify public files used for public file transfer services. Directories/Files must be labeled public_rw_content_t.
httpd_read_user_content        (on   ,   on)  Allow httpd to read user content
httpd_use_nfs                  (off  ,  off)  Allow httpd to access nfs file systems
httpd_tmp_exec                 (off  ,  off)  Allow Apache to execute tmp content.
httpd_execmem                  (on   ,   on)  Allow httpd scripts and modules execmem/execstack
httpd_manage_ipa               (off  ,  off)  Allow httpd processes to manage IPA content
httpd_can_sendmail             (on   ,   on)  Allow http daemon to send mail
httpd_can_check_spam           (off  ,  off)  Allow http daemon to check spam
allow_httpd_mod_auth_ntlm_winbind (off  ,  off)  Allow Apache to use mod_auth_ntlm_winbind
httpd_can_network_memcache     (off  ,  off)  Allow httpd to connect to memcache server
httpd_can_network_connect_cobbler (off  ,  off)  Allow HTTPD scripts and modules to connect to cobbler over the network.
httpd_ssi_exec                 (on   ,   on)  Allow HTTPD to run SSI executables in the same domain as system CGI scripts.
httpd_use_openstack            (off  ,  off)  Allow httpd to access openstack ports
httpd_enable_ftp_server        (off  ,  off)  Allow httpd to act as a FTP server by listening on the ftp port.
httpd_setrlimit                (off  ,  off)  Allow httpd daemon to change system limits
[root@tempest moodle]

Excellent.  Even more focused is this:

[root@tempest moodle] semanage boolean -l | grep httpd  | grep write
allow_httpd_sys_script_anon_write (off  ,  off)  Allow apache scripts to write to public content.  Directories/Files must be labeled public_rw_content_t.
allow_httpd_anon_write         (off  ,  off)  Allow Apache to modify public files used for public file transfer services. Directories/Files must be labeled public_rw_content_t.
[root@tempest moodle]

Okay, the first of these seems to be worth trying.  Let’s give it a go.

First, let’s use the script above to look at selinux alerts:

[root@tempest moodle] sealert -a  audit.after.tvn
 found 1 alerts in audit.after.tvn
 --------------------------------------------------------------------------------

SELinux is preventing /usr/sbin/httpd from write access on the directory /home/moodle/data

*****  Plugin catchall (100. confidence) suggests  ***************************

If you believe that httpd should be allowed write access on the data directory by default.
 Then you should report this as a bug.
 You can generate a local policy module to allow this access.
 Do
 allow this access for now by executing:
 # grep httpd /var/log/audit/audit.log | audit2allow -M mypol
 # semodule -i mypol.pp

[root@tempest moodle] grep httpd /var/log/audit/audit.log | audit2allow -M mypol
 ******************** IMPORTANT ***********************
 To make this policy package active, execute:

semodule -i mypol.pp

Okay, so I did the first half of that, grepping for httpd complaints and piping to audit2allow.  But I didn’t want to immediately make it active.

[root@tempest moodle] file mypol.*
 mypol.pp: data
 mypol.te: ASCII C++ program text, with very long lines
 [root@tempest moodle] more mypol.te
module mypol 1.0;
require {
 type user_tmp_t;
 type proc_net_t;
 type user_home_dir_t;
 type httpd_t;
 type user_home_t;
 type sysfs_t;
 type httpd_suexec_t;
 type devlog_t;
 type gconf_home_t;
 type httpd_sys_script_t;
 class sock_file write;
 class lnk_file read;
 class file { read execute };
 class dir { write read getattr search };
 }
#============= httpd_suexec_t ==============
 allow httpd_suexec_t user_home_t:file execute;
#============= httpd_sys_script_t ==============
 allow httpd_sys_script_t devlog_t:sock_file write;
 allow httpd_sys_script_t gconf_home_t:dir search;
 allow httpd_sys_script_t proc_net_t:file read;
 allow httpd_sys_script_t sysfs_t:dir search;
 allow httpd_sys_script_t user_home_dir_t:lnk_file read;
 allow httpd_sys_script_t user_tmp_t:dir { read getattr };
#============= httpd_t ==============
 #!!!! The source type 'httpd_t' can write to a 'dir' of the following types:
 # tmp_t, var_t, tmpfs_t, httpd_log_t, dirsrv_config_t, httpd_tmp_t, dirsrvadmin_tmp_t, httpd_cache_t, httpd_tmpfs_t, var_lib_t, var_run_t, httpd_squirrelmail_t,
 var_log_t, httpd_mediawiki_tmp_t, dirsrv_var_log_t, zarafa_var_lib_t, dirsrv_var_run_t, httpd_var_lib_t, httpd_var_run_t, dirsrvadmin_config_t, squirrelmail_sp
 ool_t, var_lock_t, httpd_awstats_ra_content_t, httpd_awstats_rw_content_t, httpd_user_ra_content_t, httpd_user_rw_content_t, httpdcontent, httpd_cobbler_ra_cont
 ent_t, httpd_cobbler_rw_content_t, httpd_munin_ra_content_t, httpd_munin_rw_content_t, httpd_bugzilla_ra_content_t, httpd_bugzilla_rw_content_t, root_t, httpd_c
 vs_ra_content_t, httpd_cvs_rw_content_t, httpd_git_ra_content_t, httpd_git_rw_content_t, httpd_sys_ra_content_t, httpd_sys_rw_content_t, httpd_sys_rw_content_t,
 httpd_nagios_ra_content_t, httpd_nagios_rw_content_t, httpd_nutups_cgi_ra_content_t, httpd_nutups_cgi_rw_content_t, passenger_tmp_t, httpd_apcupsd_cgi_ra_conte
 nt_t, httpd_apcupsd_cgi_rw_content_t, httpd_mediawiki_ra_content_t, httpd_mediawiki_rw_content_t, httpd_sys_content_t, httpd_squid_ra_content_t, httpd_squid_rw_
 content_t, httpd_smokeping_cgi_ra_content_t, httpd_smokeping_cgi_rw_content_t, httpd_prewikka_ra_content_t, httpd_prewikka_rw_content_t, httpd_openshift_ra_cont
 ent_t, httpd_openshift_rw_content_t, httpd_dirsrvadmin_ra_content_t, httpd_dirsrvadmin_rw_content_t, passenger_var_run_t, httpd_w3c_validator_ra_content_t, http
 d_w3c_validator_rw_content_t
allow httpd_t user_home_t:dir write;

Ick, that’s a lot.  Do I really want to do that?  Can I be a bit more focussed?  Let’s try just changing the selinux context of the data directory to the type suggested in the rule summary, above:

[root@tempest moodle] semanage fcontext -a -t httpd_sys_rw_content data/
 libsepol.context_from_record: type httpd_sys_rw_content is not defined (No such file or directory).
 libsepol.context_from_record: could not create context structure (Invalid argument).
 libsemanage.validate_handler: invalid context system_u:object_r:httpd_sys_rw_content:s0 specified for data/ [all files] (Invalid argument).
 libsemanage.dbase_llist_iterate: could not iterate over records (Invalid argument).
 /usr/sbin/semanage: Could not commit semanage transaction

Darn.  So much for following their advice!  Let me try a different context:

 [root@tempest moodle] semanage fcontext -a -t httpd_sys_rw_content_t data/
 [root@tempest moodle] GET http://cs.wellesley.edu/~moodle/
 Remote Addr is 149.130.136.40 Fatal error: /home/moodle/data is not writable, admin has to fix directory permissions! Exiting.
 [root@tempest moodle] ls -ldZ data
 drwxrwsrwx. apache apache unconfined_u:object_r:user_home_t:s0 data
 [root@tempest moodle] restorecon -R data
 [root@tempest moodle] ls -ldZ data
 drwxrwsrwx. apache apache unconfined_u:object_r:user_home_t:s0 data
 [root@tempest moodle] !seman
 semanage fcontext -a -t httpd_sys_rw_content_t data/
 [root@tempest moodle] ls -ldZ data
 drwxrwsrwx. apache apache unconfined_u:object_r:user_home_t:s0 data

Okay, that was a miserable failure.  (I later realized that, I think, the problem was that I neededto use an absolute pathname for the files and directories in the semanage command.)  Meanwhile, I took another tack.  (I’m showing the whole journey because we may have to un-do some of these steps.)

Okay, let’s try that sledgehammer policy file that audit2allow wrote:

[root@tempest moodle] semodule -i mypol.pp
 [root@tempest moodle] GET http://cs.wellesley.edu/~moodle/
Warning: mkdir(): Permission denied in /home/moodle/public_html/lib/setuplib.php on line 1213
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml"  lang="en" xml:lang="en">
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Error</title>
 </head><body><div style="margin-top: 6em; margin-left:auto; margin-right:auto; color:#990000; text-align:center; font-size:large; border-width:1px;
 border-color:black; background-color:#ffffee; border-style:solid; border-radius: 20px; border-collapse: collapse;
 width: 80%; -moz-border-radius: 20px; padding: 15px">
 Unable to save the cache config to file.
 </div></body></html>[root@tempest moodle]

Okay, so that seems to have pretty much worked.  I think.

Later, I realized that I already have a PHP script that is able to write to the filesystem, namely /home/anderson/public_html/cgi-bin/webapps/signup9/database.php.  So, I wrote a little script to test writeability for three locations, /tmp, the moodle data directory and my signup9 directory.  They are all writable by permissions, so the issue must be SELinux contexts.  Here’s what I did:

First, here’s the PHP script:

[root@tempest moodle] cat public_html/testwrite.php 
<?php
function writeable($dir) {
  if( is_writeable($dir) ) {
    print "<p>Directory $dir is writeable\n";
  } else {
    print "<p>Directory $dir is <em>not</em> writeable\n";
  }
  $file = "$dir/sda.tmp";
  if( !$handle = fopen($file,'wb') ) {
    print "but couldn't open a file for writing.\n";
    return;
  }
  if( fwrite($handle,"yes, writeable") === FALSE ) {
    print "but couldn't write any data to it.\n";
    return;
  }
  fflush($handle);
  fclose($handle);
  }

writeable("/tmp");
writeable("/home/moodle/data");
writeable("/home/anderson/public_html/cgi-bin/webapps/signup9");

?>

Let's try it:

[root@tempest moodle] GET http://cs.wellesley.edu/~moodle/testwrite.php
<p>Directory /tmp is writeable
<p>Directory /home/moodle/data is writeable

Warning: fopen(/home/moodle/data/sda.tmp): failed to open stream: Permission denied in /home/moodle/public_html/testwrite.php on line 9
but couldn't open a file for writing.
<p>Directory /home/anderson/public_html/cgi-bin/webapps/signup9 is writeable

Okay so that means the sledgehammer didn't quite work.  

[root@tempest moodle] ls -ldZ /tmp /home/moodle/data /home/anderson/public_html/cgi-bin/webapps/signup9
drwxrwxrwx. anderson faculty system_u:object_r:httpd_user_content_t:s0 /home/anderson/public_html/cgi-bin/webapps/signup9
drwxrwsr-x. apache   apache  unconfined_u:object_r:user_home_t:s0 /home/moodle/data
drwxrwxrwt. root     root    system_u:object_r:tmp_t:s0       /tmp
[root@tempest moodle] semanage fcontext -a -t httpd_user_content_t /home/moodle/data
[root@tempest moodle] ls -ldZ /tmp /home/moodle/data /home/anderson/public_html/cgi-bin/webapps/signup9
drwxrwxrwx. anderson faculty system_u:object_r:httpd_user_content_t:s0 /home/anderson/public_html/cgi-bin/webapps/signup9
drwxrwsr-x. apache   apache  unconfined_u:object_r:user_home_t:s0 /home/moodle/data
drwxrwxrwt. root     root    system_u:object_r:tmp_t:s0       /tmp
[root@tempest moodle] restorecon -v /home/moodle/data
restorecon reset /home/moodle/data context unconfined_u:object_r:user_home_t:s0->unconfined_u:object_r:httpd_user_content_t:s0
[root@tempest moodle] ls -ldZ /tmp /home/moodle/data /home/anderson/public_html/cgi-bin/webapps/signup9
drwxrwxrwx. anderson faculty system_u:object_r:httpd_user_content_t:s0 /home/anderson/public_html/cgi-bin/webapps/signup9
drwxrwsr-x. apache   apache  unconfined_u:object_r:httpd_user_content_t:s0 /home/moodle/data
drwxrwxrwt. root     root    system_u:object_r:tmp_t:s0       /tmp
[root@tempest moodle] GET http://cs.wellesley.edu/~moodle/testwrite.php
<p>Directory /tmp is writeable
<p>Directory /home/moodle/data is writeable
<p>Directory /home/anderson/public_html/cgi-bin/webapps/signup9 is writeable
[root@tempest moodle]

This is looking good!

Note that I learned that changing a file’s selinux context is a two-step proces from this page: https://access.redhat.com/knowledge/docs/en-US/Red_Hat_Enterprise_Linux/6/html/Security-Enhanced_Linux/sect-Security-Enhanced_Linux-SELinux_Contexts_Labeling_Files-Persistent_Changes_semanage_fcontext.html

Let’s try the moodle script:

[root@tempest moodle] GET http://cs.wellesley.edu/~moodle/index.php

Warning: mkdir(): Permission denied in /home/moodle/public_html/lib/setuplib.php on line 1213

Warning: mkdir(): Permission denied in /home/moodle/public_html/lib/setuplib.php on line 1188

Okay, so there’s more to do.  I think this is just an issue of recursively setting the SElinux context:

[root@tempest moodle]  find data -exec echo semanage fcontext -a -t httpd_user_content_t /home/moodle/{} \;
semanage fcontext -a -t httpd_user_content_t /home/moodle/data
semanage fcontext -a -t httpd_user_content_t /home/moodle/data/temp
semanage fcontext -a -t httpd_user_content_t /home/moodle/data/cache
semanage fcontext -a -t httpd_user_content_t /home/moodle/data/muc
semanage fcontext -a -t httpd_user_content_t /home/moodle/data/lang
[root@tempest moodle]  find data -exec semanage fcontext -a -t httpd_user_content_t /home/moodle/{} \;
[root@tempest moodle] restorecon -R -v /home/moodle/data/
restorecon reset /home/moodle/data/temp context unconfined_u:object_r:user_home_t:s0->unconfined_u:object_r:httpd_user_content_t:s0
restorecon reset /home/moodle/data/cache context unconfined_u:object_r:user_home_t:s0->unconfined_u:object_r:httpd_user_content_t:s0
restorecon reset /home/moodle/data/lang context unconfined_u:object_r:user_home_t:s0->unconfined_u:object_r:httpd_user_content_t:s0
[root@tempest moodle] ls -lRZ data/
data/:
drwxrwsrwx. apache apache unconfined_u:object_r:httpd_user_content_t:s0 cache
drwxrwsrwx. apache apache unconfined_u:object_r:httpd_user_content_t:s0 lang
drwxrwsrwx. apache apache unconfined_u:object_r:httpd_user_content_t:s0 muc
drwxrwsrwx. apache apache unconfined_u:object_r:httpd_user_content_t:s0 temp

data/cache:

data/lang:

data/muc:

data/temp:
[root@tempest moodle] GET http://cs.wellesley.edu/~moodle/index.php
<!DOCTYPE html>
<html  dir=”ltr” lang=”en” xml:lang=”en”>
<head>
<title>Installation – Moodle 2.4.1+ (Build: 20130208)</title>
<link rel=”shortcut icon” href=”http://cs.wellesley.edu/~moodle/theme/image.php?theme=standard&amp;component=theme&amp;image=favicon” />
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<meta name=”keywords” content=”moodle, Installation – Moodle 2.4.1+ (Build: 20130208)” />
<meta http-equiv=”pragma” content=”no-cache” />
<meta http-equiv=”expires” content=”0″ />

Yay!

Scott

 

 

 

 

 

About CS SysAdmins

The CS Department System Administrators
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *