Linux – SELinux file path context not working with regex

linuxregexselinux

I've reformatted for readability based on suggestions in the comments.

I have a RADIUS server that uses google authenticator, and SELinux is blocking RADIUS from accessing the .google_authenticator files in the user home directories (these are also winbind users, with home dirs in /home/API). I tried to give it access by building the following policy files:

$ cat ./google-authenticator.fc 
/home/API(/.*)?/\.google_authenticator      gen_context(system_u:object_r:radiusd_google_authenticator_t,s0)
$ cat ./google-authenticator.te
policy_module(radiusd_google_authenticator, 0.0.10)

require {
  type radiusd_t;
  type user_home_dir_t;
  type admin_home_t;
}

type radiusd_google_authenticator_t;

role object_r types radiusd_google_authenticator_t;

allow radiusd_t radiusd_google_authenticator_t:file { rename create unlink rw_file_perms };

files_type(radiusd_google_authenticator_t)
filetrans_pattern(radiusd_t, user_home_dir_t, radiusd_google_authenticator_t, file, ".google_authenticator")
filetrans_pattern(radiusd_t, admin_home_t, radiusd_google_authenticator_t, file, ".google_authenticator")

Installing these shows the path in semanage fcontext -l, but it doesn't work:

 $ sudo semanage fcontext -l | grep google_authenticator
 /home/API(/.*)?/\.google_authenticator             all files          system_u:object_r:radiusd_google_authenticator_t:s0 
 $ matchpathcon /home/API/tcr/.google_authenticator
 /home/API/tcr/.google_authenticator    unconfined_u:object_r:user_home_t:s0

Weirdly enough, when I change it so that the path matches exactly (even with the escaped period), it works:

$ sudo semanage fcontext -l | grep google_authenticator
/home/API/tcr/\.google_authenticator               all files          system_u:object_r:radiusd_google_authenticator_t:s0 
$ matchpathcon /home/API/tcr/.google_authenticator
/home/API/tcr/.google_authenticator system_u:object_r:radiusd_google_authenticator_t:s0

Even weirder, the regex works when, as suggested in Iain's answer, I add the path directly with semanage instead of the policy files (removing the policy path first so there is no conflict):

$ sudo semanage fcontext -l | grep google_authenticator
$ matchpathcon /home/API/tcr/.google_authenticator
/home/API/tcr/.google_authenticator unconfined_u:object_r:user_home_t:s0
$ sudo semanage fcontext -a -t radiusd_google_authenticator_t '/home/API(/.*)?/\.google_authenticator'
$ sudo semanage fcontext -l | grep google_authenticator
/home/API(/.*)?/\.google_authenticator             all files          system_u:object_r:radiusd_google_authenticator_t:s0 
$ matchpathcon /home/API/tcr/.google_authenticator
/home/API/tcr/.google_authenticator system_u:object_r:radiusd_google_authenticator_t:s0

I've also tried various setups using HOME_DIR, but had no luck there either.

Best Answer

Try using

HOME_DIR/\.google_authenticator -- gen_context(system_u:object_r:radiusd_google_authenticator_t,s0)

Instead. Home directories aren't necessarily in /home and this acts as a macro when you rebuild policy.

EDIT

So I checked the source code and it provides the following text which probably indicates whats going on here.

label_file.c
680     /*
681      * Check for matching specifications in reverse order, so that
682      * the last matching specification is used.
683      */

Regex that match last, win. The SELinux library is using the following order of file lookups to match:

/etc/selinux/targeted/contexts/files/file_contexts.subs_dist
/etc/selinux/targeted/contexts/files/file_contexts.subs
/etc/selinux/targeted/contexts/files/file_contexts
/etc/selinux/targeted/contexts/files/file_contexts.homedirs
/etc/selinux/targeted/contexts/files/file_contexts.local

The matching regex that wins in your case is this one:

grep user_home_t /etc/selinux/targeted/contexts/files/file_contexts.homedirs
/home/[^/]+/.+  user_u:object_r:user_home_t:s0

By adding the entry as a local context, it is fetched from this file instead: /etc/selinux/targeted/contexts/files/file_contexts.local which appears after the file that matches at the moment.

So, in order to fix this (which is basically a little bit of a hack) you can add the entry as a local override.

Alternatively I tried adding this as a HOME_DIR override (like I originally suggested, but using audio_home_t to test the principal) doing the following:

HOME_DIR/(tcr)?/\.google_authenticator          --      gen_context(system_u:object_r:audio_home_t)

This worked for me, given it added the entry to the later files and the 'last regex won' when I did that.

It actually changed the regex to this in the file:

grep tcr /etc/selinux/targeted/contexts/files/*
/etc/selinux/targeted/contexts/files/file_contexts.homedirs:/home/[^/]+/(tcr)?/\.google_authenticator   --  user_u:object_r:audio_home_t:s0

I would suggest trying the HOME_DIR option first (which is the actual way in policy you should implement it) or alternatively use a local override.