donderdag 17 september 2009

AVC Denials: Example

SELinux logs policy violations to /var/log/audit/audit.log if audit is installed and enabled. If audit is
not installed or enabled, than SELinux sends policy violation notices to dmesg or /var/log/messages.

The policy violations that SELinux logs are called AVC denials. AVC is an abbreviation for Access Vector
Cache. Which is the SELinux cache with Access Vectors. Access vectors are the rules that govern access.

Reading AVC denials properly helps troubleshoot issues. In this article i will talk about, and highlight
some of the information you can retrieve from AVC denials. I will also touch on some of the tools that
assist in listing, parsing and translating SELinux Access Vector Cache denials.

Example of a AVC denial:

avc: denied { getattr } for pid=7604 comm="firefox" path="/usr/lib64/firefox-3.5.3/firefox" dev=dm-2 ino=1311607
scontext=dgrift_u:dgrift_r:gwibber_t:s0-s0:c0.c1023 tcontext=system_u:object_r:mozilla_exec_t:s0 tclass=file

The line above provides much information about what has been denied:

1. What process was denied access.
2. What domain type did the source process operate in when it was denied access.
3. What object or subject was the source process denied access to.
4. What was the object/subject type of the target.
5. What permission was denied.
6. What is the class of the target.
7. What was the process identity of the source.
8. What was the inode number of the target object.
9. What happened.

Security is about managing interaction. Interaction has a source and a target. Interaction involves atleast
a subject as a source (an interacting party) and a subject or object as a target. The target of the
interaction. Subjects are interacting entities, and object non-interacting entities. Subjects can interact
with object, but subjects can also interact with other subjects.

The target class in a AVC denial tells us what the class (origin) of the target in an interaction is.
A source of a interaction is always a subject (interacting entity). Object can not interact and thus can
never be a source of an interaction.

Lets try and connect the dots and see if we can make sense of the example AVC denial above. We will try to
answer each of our 9 questions in the check list:

1. What process was denied access.

comm="firefox" shows use the name of the command that was run. The firefox program was denied access.

2. What domain type did the source
process operate in when it was denied access.

scontext=dgrift_u:dgrift_r:gwibber_t:s0-s0:c0.c1023 shows that the source firefox was operating with the
gwibber_t domain type. The type is the third field in the security context tuple.

3. What object or subject was the source process denied access to.

path="/usr/lib64/firefox-3.5.3/firefox" Shows what the target of the source in this interaction was.

4. What was the object/subject type of the target.

tcontext=system_u:object_r:mozilla_exec_t:s0 shows the type of the target.

5. What permission was denied.

{ getattr } Shows the syscall (permission) that was denied.

6. What is the class of the target.

tclass=file shows that the class of the target in our interaction was file.

7. What was the process identity of the source.

pid=7604 shows that the process id of the source of our interaction was 7604

8. What was the inode number of the target object.

ino=131160 shows that the inode number of the target object in our interaction was 131160.

9. What happened.

denied shows that the particular Access Vector was denied.

We have all the detail that we need to established *what* happend.

1. The command /usr/bin/firefox was executed but some interacting entity.
2. This command was executed with the gwibber_t domain type.
3. The target of the source /usr/bin/firefox was /usr/lib64/firefox-3.5.3/firefox
4. The type of the target was mozilla_exec_t
5. The source /usr/bin/firefox that operated with the gwibber_t domain type was denied the "getattr"
syscall on the target /usr/lib64/firefox-3.5.3/firefox that had type mozilla_exec_t.
6. The class of the target /usr/lib64/firefox-3.5.3/firefox is a file (the target is a file object)
7. The process of /usr/bin/firefox had the process id of 7604 when this Access vector occured.
8. The inode number of the target file object is 131160
9. Access was denied.

These are the SELinux facts:

the /usr/bin/firefox command was denied to get the attributes of the /usr/lib64/firefox-3.5.3/firefox file
source domain type gwibber_t was denied get attribute of a file object with type mozilla_exec_t

What this means is that there was no rule to allow this access, thus access was denied.

From here on out things get less obvious:

We know some facts but this has raised other questions:

1. Are the types of the source and target correct?
2. We know what was denied but we dont know why.
3. Should we allow this access?
4. Does it signal intrusion?
5. If we allow it access what would be the best way to do it.
6. What are the problems if we do it the other way?

The reason that these questions are harder to answer is because it depends on the policy that is created by
the policy author. But if you see an AVC denial we can usually narrow the cause down to:

a. The source and/or the target is mislabelled (wrong type)
b. It is a bug in policy.
c. Intrusion was detected and prevented.

So let's try to answer all these questions:

1. Are the types of the source and target correct?

This is the first thing we must verify. If the types are incorrect than we must correct them first to be able to learn the real reason
about what happend. Objects sometimes get mislabelled. For example if created the object whilst you had SELinux disabled and forgot to
restore the context. Another reason might be that you have moved the file from another location as opposed to copying it, and forgot
the restore the context.

How do we determine whether the types are correct? Well the answer is that we have to dig into some of the properties of the policy.
We have to put ourselves into the shoes of the policy author.

To verify whether the type of the source (gwibber_t) is correct we have to ask ourselves which policy module owns this type?
This is a hard question to answer. Really the only way to figure this out is to grep for the gwibber_t type in the source of the
policy. In this case there is a policy module installed called gwibber.

For example:

grep -r "type gwibber_t" Modules/

We are looking for the declaration of the gwibber_t type. Types are usually declared in files with .te suffixes (type enforcement
source policy files)

So we could narrow our grep a bit:

grep -r "type gwibber_t" Modules/ | grep "\.te"

Modules/gwibber.te:type gwibber_t;
Modules/gwibber.te:type gwibber_tmpfs_t;

The type is declared in the gwibber.te source policy type enforcement file. We can now grep this file for the policy_module
declaration to figure out what the name of the module is:

grep policy_module Modules/gwibber.te
policy_module(gwibber, 0.0.1)

The policy module name is gwibber and the version number is 0.0.1, Now we can determine whether this module is installed:

sudo /usr/sbin/semodule -l | grep gwibber
gwibber 0.0.1

The module is installed, we know that the type gwibber_t is owned by the gwibber module.

Now we should figure out what the type of the firefox command is. the firefox command is located in /usr/bin/firefox.
We can use ls -alZ /usr/sbin/firefox to determine the type of this command:

-rwxr-xr-x. root root system_u:object_r:bin_t:s0 /usr/bin/firefox

The type of the firefox command is bin_t. This type has a special property that is specific to the policy model. You could look up the
properties of this type the same way that we are currently looking up the properties of type gwibber_t.

But to not overly complicate things i will explain the main property of the bin_t type.

The bin_t type is a generic type for executable files in bin and sbin directories. These commands get run with the domain type of the
subject that executed the command. So if a process that was operating with the gwibber_t domain type executed a command with the bin_t
type, than that command would run with the gwibber_t domain type.

With this in we have to figure out whether processes with the gwibber_t domain type are allowed to execute files with the bin_t type:

sudo sesearch --allow -s gwibber_t -t bin_t -c file -p execute
Found 1 semantic av rules:
allow gwibber_t bin_t : file { ioctl read getattr lock execute execute_no_trans open } ;

The sesearch command queries the policy store and looks if there is a rule which allows the source gwibber_t domain type to execute
target objects of the files class with type bin_t.

A line is returned confirming that this is allowed. This tells us that the source in our interaction is likely correclty labelled.
This is what happened. Some process that run with the gwibber_t domain type ran /usr/bin/firefox which has the bin_t type causing the
firefox command to run with the gwibber_t domain type.

Now we need to determine whether the type of our target is correct. In our interaction that fortunatly is pretty easy.
We know the path of our target: /usr/lib64/firefox-3.5.3/firefox
We can run the matchpathcon command to see what type is defined for this location and if that defined type corresponds to the target
type in our avc denial: mozilla_exec_t.

sudo /sbin/matchpathcon /usr/lib64/firefox-3.5.3/firefox
/usr/lib64/firefox-3.5.3/firefox system_u:object_r:mozilla_exec_t:s0

This confirms that the labelling in the interaction is correct for both source and target.

Sometimes however, the full path of the target is not shown in a avc denial. In that case you can use the inode number to find the
full path:

find / -inum 131160
/usr/lib64/firefox-3.5.3/firefox

2. We know what was denied but we dont know why.

This is another hard question to solve. We are no psychics. We cannot read the mind of the policy author.
We can try:

Should gwibber be able to run firefox? It should be able to run the default browser yes but in this case (the case where i am the
policy author of the gwibber policy module) it was decided to not allow this funcionality. It is obvious that the gwibber_t domain
type was not allowed the access/see (get attributes) the mozilla executable file with type mozilla_exec_t. So either that was done on
purpose or it is a bug in the policy.

3. Should we allow this access?
3. Should we allow this access?
4. Does it signal intrusion?
5. If we allow it access what would be the best way to do it.
6. What are the problems if we do it the other way?

Another tough question. if we allow gwibber_t to get attributes of files with type mozilla_exec_t it will probably want more after
that. Chances are that gwibber wants to execute the file (run firefox), since gwibber is designed to open pages in the default
browser.

If we want gwibber to be able to open the browser, do we want to allow gwibber_t to run the browser with the gwibber_t type or should
we lets gwibber_t domain transition to the mozilla_t domain type? Well my personal opinion is to domain transition where ever possible
but it depends on the situation. In this case a domain transition from gwibber_t to mozilla_t via mozilla_exec_t would likely be the
best decision. However this requires that policy is written manually to make it do what we want it to do.

But what if we just want to allow this single access vector? We could use the audit2allow tool to translate the avc denial into policy
language and to create a module. Than we could load the created policy module into the policy store with the semodule command.

echo "avc: denied { getattr } for pid=7604 comm="firefox" path="/usr/lib64/firefox-3.5.3/firefox" dev=dm-2 ino=1311607
scontext=dgrift_u:dgrift_r:gwibber_t:s0-s0:c0.c1023 tcontext=system_u:object_r:mozilla_exec_t:s0 tclass=file" | audit2allow -M
mygwibber; sudo semodule -i mygwibber.pp

Or we could do it ourselves:
echo "policy_module(mygwibber, 0.0.1)" > mygwibber.te;
echo "require { type gwibber_t, mozilla_exec_t; }" >> mygwibber.te;
echo "allow gwibber.te mozilla_exec_t:file getattr;" >> mygwibber.te;
make -f /usr/share/selinux/devel/Makefile mygwibber.pp
sudo semodule -i mygwibber.pp

So:

a. The source and/or the target is mislabelled (wrong type)

The types were correct.

b. It is a bug in policy.

It is a bug in policy because we determined that it is usually behaviour for gwibber to try to run the default browser to display
pages. Either we should allow it gwibber to run the browser (be it with the gwibber_t domain type or by domain transition with the
mozilla_t domain type) or we should make sure that no AVC denials are displayed when gwibber_t tries to access the mozilla executable
file with type mozilla_exec_t.

The rule that i am going to implement is this:

dontaudit gwibber_t mozilla_exec_t:file getattr;

Which says if domain type gwibber_t tries to get attributes of files with type mozilla_exec_t than "dontaudit" which means do not
print an avc denials (e.g. silently deny this)

That is just my personal preference. Its not something fixed. It is my security decision, whether good or bad.

c. Intrusion was detected and prevented.

No not really an intrusion since gwibber is designed to open pages in the default web browser which is firefox. So it is expected
behaviour. However i dont want to allow it. But i dont want to log the AVC denial when it happens either because its not important.

Geen opmerkingen:

Een reactie plaatsen