SELinux - canonical way of automatically applying a context on file creation

My current understanding is that you have to manually use restorecon to apply the desired context to a newly created file or directory unless you are happy with the context that it inherits from its parent directory.

I am wondering if it is possible to automatically apply a context on creation based on its path without having to run restorecon.

I googled a bit and found this post by Dan Walsh where he mentions restorecond which uses inotify to change context on creation. He also points out the obvious problem with it (race condition). Is this the only way to automatically solve the issue of re-context-ing in case a child should not inherit its context from the parent directory?

One problem is that restorecond does not seem to handle entries the same way as /etc/selinux/targeted/contexts/files/file_contexts, that is, no regexes and it does not work recursively, so /etc/selinux/restorecond.conf cannot contain something like

/var/www(/.*)?/logs(/.*)?

or

/var/www/*

or even

/var/www/*/logs

Is there a way to work around this problem?

EDIT:

As per @Michael's answer this should work OOTB if a respective rule exists, but it doesn't:

# rm -rf /var/www/foo
# semanage fcontext -a -t httpd_log_t '/var/www/foo/logs'
# grep '/var/www.*logs' /etc/selinux/targeted/contexts/files/file_contexts*
/etc/selinux/targeted/contexts/files/file_contexts:/var/www(/.*)?/logs(/.*)?    system_u:object_r:httpd_log_t:s0
/etc/selinux/targeted/contexts/files/file_contexts.local:/var/www/foo/logs    system_u:object_r:httpd_log_t:s0
# matchpathcon /var/www/foo/logs
/var/www/foo/logs       system_u:object_r:httpd_log_t:s0
# mkdir -p /var/www/foo/logs
# touch /var/www/foo/logs/quux
# ls -alZ /var/www/foo/logs*
drwxr-xr-x. root root unconfined_u:object_r:httpd_sys_content_t:s0 .
drwxr-xr-x. root root unconfined_u:object_r:httpd_sys_content_t:s0 ..
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 quux
# restorecon -vR /var/www/foo
restorecon reset /var/www/foo/logs context unconfined_u:object_r:httpd_sys_content_t:s0->unconfined_u:object_r:httpd_log_t:s0
restorecon reset /var/www/foo/logs/quux context unconfined_u:object_r:httpd_sys_content_t:s0->unconfined_u:object_r:httpd_log_t:s0

Solution 1:

The kernel makes the following procedure to determine what the file type of a newly created file will be.

  • There exists in policy a specific file transition rule. So apply this.
  • Make the newly created file acquire the type of the parent directory.

In the vast majority of cases, new files inherit the parent directories type. Sometimes this is not desirable -- so a policy writer can create rules based off the conditions of who is doing the labelling and where in order to transition to another type.

This is controlled in policy with the type_transition statement, although normally a policy writer will call the filetrans_pattern macro instead.

In the kernel, these decisions are not based on paths but types (although a minor exception exists in newer policies).

A rule typically looks like this;

type_transition httpd_t var_log_t:file httpd_var_log_t;

In this example, the rule states that. If the process/user performing the file creation is httpd_t and the directory the object is being created in is var_log_t and the object is classified as a file, then the new file must be labelled as httpd_var_log_t.

This, of course has a number of limitations, a good example of this is the condition when you create .htaccess files in apache (in /var/www/html). In this example the default policy of creating a file type with the same type as its parent directory applies, but in reality the proper type of this file is httpd_sys_htacess_t not the default of httpd_sys_content_t.

This was a known problem for a number of years and was eventually fixed by allowing policy writers to specify the filename that the transition applies to in policy -- unfortunately this features is not available in EL6.

In your specific case -- as you have mentioned there are some workarounds involving restorecond. Other than this you should ideally split your data up with different types by putting them in separate subdirectories where the subdirectory is an adequately labelled type. If this is still not possible, and restorecond is not possible -- the only solution is a post-fix of running restorecon on the file after its creation.

Even the 'newer' named filetrans has problems because ultimately it does not support globbing or regex, which severely limits its functionality to specifically well-named files (like .htaccess).

As it stands at this moment, there exists no in-kernel mechanism as flexible as restorecon and its regexes to properly label files correctly to that degree.

Solution 2:

The problem of correct labeling at file creation was addressed in Fedora 16 with a feature called file name transition (although you can find it also as "named file transitions"), whose definition basically states that:

With File Name Transitions Features, policy writers can write rules that take into account the file name, not the file path. This is the basename of the file path. Since the kernel knows at the time of object creation the label of the containing directory, the label of the process creating the object and the objects Name. we can now write a policy rule that states, if an unconfined_t process creates a file named resolv.conf in a directory labelled etc_t, the file should get labelled resolv.conf.

It is known that the way an object gets labeled at creation time can vary depending on the process creating the object (cp vs. mv is a good example). Also, the default way to label an object would be by inheritance: the object gets the label of the parent directory.

While this is convenient, it is not always correct, and the system administrator must correct the situation manually using (a combination of) restorecon + restorecond + semanage fcontext -a -t.

This is the problem Name File Transitions try to correct, by letting

[...] policy writers have the ability to overwrite this by writing a rule in policy that states, if a process with type a_t creates a object of class "file" in a directory labelled b_t, the object will get created c_t.

Obviously, named file transitions don't exist for custom locations. You could find already existing ones with, for example:

# sesearch -ASCT -s unconfined_t | grep Found
...
Found XX named file transition filename_trans:
...

So, in order to address your problem, you need to know beforehand which user (SELinux user) will create what file/directory and where, and then write a custom policy including a file transition. There are a couple of examples in the Fedora Project wiki page I linked above.