The so-called uncertainty principle says that for two related physical variables, the more precisely you require variable A, the worse the precision of variable B becomes. Conversely, if you demand B more precisely, variable A becomes harder to measure accurately. Security follows the same shitty rhythm: the more secure something is, the more troublesome it tends to be; conversely, if you want to make things simple, security often turns to shit.

SELinux is a decent privilege-management system. For machines exposed to the public internet, just to avoid getting casually hacked and messed with, I’m forced to spend a little care configuring it.

SELinux documentation isn’t hard to find. I followed this and this, the two documents, and fumbled through the configuration a couple of times; it looks like it works now.

A very handy tool is audit2allow. It can analyze the /var/log/audit/audit.log file (see this), and produce a pair of *.te and *.pp files that define the permissions for a given service.

In practice, you sometimes tragically find that SELinux blocks too much. To use a service normally, you have to enable quite a few features. If you rely on audit2allow’s analysis, you have to trigger every event that would cause a permission denied first.

Another method is to edit the *.te file, then package and apply it.

For example, here is svnserve_user.te: we edit the file to define what our svnserve program is allowed to do. (For concrete methods and attributes, refer to the references above.)

module svnserve_user 1.0;

require {
        type user_home_dir_t;
        type svnserve_t;
        type user_home_t;
        type proc_t;
        class capability { dac_read_search dac_override };
        class dir {read add_name create lock open rename setattr unlink remove_name getattr write search append rmdir};
        class file {read create lock open rename setattr unlink getattr write append};
}

#============= svnserve_t ==============
allow svnserve_t proc_t:file  {read create lock open rename setattr unlink getattr write append};

#!!!! This avc is allowed in the current policy
allow svnserve_t self:capability { dac_read_search dac_override };

#!!!! This avc is allowed in the current policy
#allow svnserve_t user_home_dir_t:dir search;

#!!!! This avc is allowed in the current policy
allow svnserve_t user_home_t:dir  {read add_name create lock open rename setattr unlink remove_name getattr write search append rmdir};

#!!!! This avc is allowed in the current policy
allow svnserve_t user_home_t:file   {read create lock open rename setattr unlink getattr write append};

After configuration, we need to compile it into a .pp file before SELinux can recognize it. The method is as follows:

$ checkmodule -M -m -o svnserve_user.mod svnserve_user.te
checkmodule:  loading policy configuration from svnserve_user.te
checkmodule:  policy configuration loaded
checkmodule:  writing binary representation (version 17) to svnserve_user.mod
$ semodule_package -o svnserve_user.pp -m svnserve_user.mod
# semodule -i svnserve_user.pp

After applying it, you’ll find that many permissions originally denied are finally allowed.