Dan Walsh's Blog

Got SELinux?

SELinux blocks lots of domains from listing all processes on the system.

Lots of useful information can be optained from reading the process info on a machine, so we would like to block this by default. But sometimes users/policy writers really need to allow their domains to be able to list the processes on a system.

Ole on the Fedora SELinux Users Mail list asked:

I have a problem with SELinux not allowing PHP to list other users' processes with the "ps" command.

If I disable SELinux with "setenforce 0" it works immediately.

Is it possible to allow PHP to do this without disabling SELinux completely?

Processes are listed by reading all of the contents of /proc. SELinux linux labels everything in /proc based on the label of the process.

If you want a confined process to run ps, it needs to list /proc/PID, it needs to read certain files in this directory, needs to read symbolic links in this directory and needs to getattr on the process. When writing policy we have added a macro for this access.

If we wanted to allow one process type (myuser_t) to read another process /proc data on sshd (sshd_t), we would need to write a line like:

ps_process_pattern(myuser_t, sshd_t)

What if I want to allow a type to list all processes types?

In SELinux policy language we use attributes are used to group multiple types together. SELinux calls processes "domains". When we write policy we always give process types the domain attribute.

So if you wanted to allow a process myuser_t to list all the processes on a system, you would write a rule like.

ps_process_pattern(myuser_t, domain)

Dominic Grift answered Ole question by suggesting he install a local policy module that looked like:

policy_module(mytest, 1.0.0)
gen_require(`
type httpd_t;
attribute domain;
')
ps_process_pattern(httpd_t, domain)
This works great. Note that the apache daemon runs all php scripts within its process space, to they run as httpd_t.
Another solution would be to use an interface that we have defined in policy to allow this, domain_read_all_domains_state.
The /usr/share/selinux/devel/include/kernel/domain.if interface file defines several interfaces that can be used to interact with all domains. An alternative policy module could have been written:
policy_module(mytest, 1.0.0)
gen_require(`
type httpd_t;
')
domain_read_all_domains_state(httpd_t)