Archives

Categories

SE Linux File Context Precedence

In my previous post I expressed a desire to use regular expressions for files that may appear in multiple places in the tree due to bind mounts for /run and /var/run etc [1]. However there is a problem with this idea.

The SE Linux file labeling program restorecon reads the file /etc/selinux/$SELINUXTYPE/contexts/files/file_contexts which contains a set of regular expressions to assign labels to files. That file is ordered and the last entry which matches is the one that counts. When the file_contexts file is created the order is based on how many characters at the start of the file specification aren’t regular expression meta-characters. For example the entry “/.*” is at the top of the file (and therefore has the lowest precedence), which makes it the catch-all entry for files that have no other match. So an entry for “/var/run/REGEX” will have a higher precedence than one for “/var/REGEX”, this means however that when I replaced the “/var/run” part with a regular expression then it had a lower precedence and it didn’t work properly.

I should have remembered this as I did a lot of work on setfiles (which became restorecon) in the early days. I have now developed a new way of solving this and this time I’m testing it before blogging about it.

I have written the following PERL program to fix the file contexts, this adds multiple lines and uses a distro_debian conditional on them so that they don’t slip into upstream use – and so that if I lose track of where each patch came from I’ll know that I can delete them in future because it only matters to Debian.

#!/usr/bin/perl
use warnings;
use strict;

open(LIST, "find . -name \"*.fc\"|xargs egrep \"^/(var.*run)|(var/lock)|(dev/shm)\"|cut -f1 -d:|uniq|") or die "Can't get file list\n";
while(<LIST>)
{
  my $filename = $_;
  chomp $filename;
  open(my $infile, "<", $filename) or die "Can't open file $filename";
  open(my $outfile, ">", $filename . ".new") or die "Can't open file ". $filename . ".new";
  while(<$infile>)
  {
    print $outfile $_;
    my $newline;
    if($_ =~ /^\/var\/run/)
    {
      print $outfile "ifdef(`distro_debian', `\n";
      $newline = $_;
      $newline =~ s/^\/var//;
      print $outfile $newline;
      print $outfile "')\n";
    }
    if($_ =~ /^\/var\/lock/)
    {
      print $outfile "ifdef(`distro_debian', `\n";
      $newline = $_;
      $newline =~ s/^\/var/\/var\/run/;
      print $outfile $newline;
      $newline =~ s/^\/var//;
      print $outfile $newline;
      print $outfile "')\n";
    }
    if($_ =~ /^\/dev\/shm/)
    {
      print $outfile "ifdef(`distro_debian', `\n";
      $newline = $_;
      $newline =~ s/^\/dev/\/run/;
      print $outfile $newline;
      print $outfile "/var" . $newline;
      print $outfile "')\n";
    }
  }
  close($infile);
  close($outfile);
  rename $filename . ".new", $filename or die "Can't rename " . $filename . ".new to " . $filename;
}

The next policy thing that I have to work on is systemd. From a quick test it seems that systemd policy changes will be more invasive than is suitable for Squeeze. This means that someone who wants to upgrade from Squeeze to Wheezy+systemd will have to upgrade to Wheeze policy before installing systemd. I think that I will make 0.2.20100524-10 the last version in Unstable based on the 2010 release, I will now start work on packaging the latest upstream policy for Unstable.

PS I’m not much of a PERL programmer, so if anyone has suggestions for how to improve the above PERL code then please let me know. Please note however that I’m not interested in making my code look like line-noise.

3 comments to SE Linux File Context Precedence

  • In response to the PS:

    Firstly there is no acronym “PERL”, but there is Perl the language or perl the interpreter.

    There are lots of different ways your script could be written in Perl, but there a couple of ways to improve it without bringing in modules or using features only available the newer versions:

    1. Avoid using $_ unless it is one of the few (eg grep or map) situations where you have to. This could mean using the regexps on it automatically, or for better maintainability assign to a named variable.

    For the while loops:
    while ( my $filename = )
    while ( my $oldfile = )

    2. Always use lexical filehandles. This means that LIST is replaced by $list. Only applies to the first open, as the inner two are already doing this.

    3. As the regexps are dealing with paths, then changing the regexp delimiter to something else (curly braces preferred) makes them much easier to maintain:

    From: /^\/var\/run/
    To: m{^/var/run}

    From: s/^\/var/\/var\/run/
    To: s{^/var}{/var/run}

    4. Some other layout changes could included breaking the ‘or die’ error catching onto a new line with an indent (makes it easier to spot when not buried at the end of the line) and consolidating the multiple print lines into a single print.

  • Adam Carlton

    In wheezy the link file /var/run (-> /run) is getting set to var_t not var_run_t. Which seems to contradict the file_contexts file.

  • Adam Carlton

    I mean contradict the intention. In other words
    there is a BUG in wheezy’s file_contexts:
    /var/run -d system_u:object_r:var_run_t:s0
    should read
    /var/run system_u:object_r:var_run_t:s0
    because /var/run is a link file not a directory.