With SELinux MLS on client side, it is important to make sure that SELinux is properly enforced on all Lustre clients. To that extent, we gather SELinux policy info on client side and send it to servers where it is checked against reference info specified in nodemap.
We have several patches to implement this. First we add a new field for nodemap entries, named 'sepol'. The purpose of this field is to store the reference SELinux status information for a set of Lustre clients.
Then we create new functions to retrieve SELinux status information. The SELinux policy info syntax is the following:
- <mode> is a digit telling if SELinux is in Permissive mode (0)
or Enforcing mode (1)
- <name> is the name of the SELinux policy, retrieved from /etc/selinux/config file
- <version> is the version of the SELinux policy
- <sha1> is the computed SHA1 of the binary representation of the
policy, as exported in /etc/selinux/<name>/policy/policy.<version>
Due to the lack of necessary kernel API to get this information, we use a usermode helper called l_getsepol. It could impact performance, so we only call it when we detect SELinux policy has changed. Having to call a usermode helper is not really a security flaw in itself. Of course, if a user can be root on client node, the usermode helper could be hacked to return a value that does not represent the actual SELinux status. But Lustre kernel code can also be modified and recompiled to do the same. So a full security solution is to complement SElinux status checking with authentication (Kerberos or Shared Key) to avoid having a Lustre client where user is root and can do anything.
Userland command l_getsepol can be called by a security administrator to get SELinux status information to store into 'sepol' field of nodemap.
We also modify Lustre code that handles connection and metadata operations like create, open, unlink, rename, getxattr, and setxatt, both on client and server sides. On client side, it uses newly added functions to retrieve SELinux policy info and add it to the requests. On server side, it retrieves info from requests' body and compare it with reference info from nodemap entry. If they do not match, we return Permission Denied.