donderdag 16 december 2010

Note to self: all the stuff a pulseaudio client needs.

basically i figured out about three scenarios so far:

1: The basics.
Pulseaudio is running normally, and the pulseaudio client needs to make some sound i guess

# manage a pulse-shm file in /dev/shm
manage_files_pattern($1, $2_tmpfs_t, $2_tmpfs_t)
fs_tmpfs_filetrans($1_t, $2_tmpfs_t, file)

# allow the user of the app to manage and relabel that file as well
allow $3 $2_tmpfs_t:file { relabel_file_perms manage_file_perms };

# 1. This add an attribute to the pulse client process so that i can allow each pulse client progress to signull any other pulse client process
# 2, This also adds an attribute to the pulse client tmpfs file so that i can allow each pulse client to read write and delete any others pulse client tmpfs file.
gnome_pulseaudio_client($1, $2)
# read write pulseaudio files in ~/pulse (a directory that is actually owned by gnome settings daemon)
# read gnome settings daemon home content for example some symlink in ~/.pulse to a pulseaudio sock file
# connect to pulseaudio with a unix stream socket
gnome_stream_connect_gsettingsd_pulseaudio($1, $2)
# search /tmp/pulse-*
# set attributes of ~/.pulse directory

# manage /.cache sound-event-cache files.

2: The not so basics.
These pulse client seem to be required to be able to (re) start the main pulseaudio process as well in some particular cases)

# domain transition to the gnome settingsd daemon pulseaudio domain when pulseaudio is executed.
gnome_spec_domtrans_gsettingsd_pulseaudio($1, $2)

3: When pulseaudio is not running.
When you kill pulseaudio and run a pulseaudio client app. It, i guess, expects some pulse audio network functionality because pulse is not running on the local system.

# the pulse client is trying to find pulseaudio on the network i guess...
allow $1 self:netlink_route_socket r_netlink_socket_perms;
allow $1 self:tcp_socket create_socket_perms;
allow $1 self:unix_dgram_socket sendto;


# if that isnt enough, the pulseaudio client wants to be a dbus system bus client. Dont ask me why but
its probably looking for pulseaudio run as a dbus system domain or init daemon.

..Heck it may even need more like maybe sysnet_read_config, i have not been able to confirm this yet.

The amount of access(policy) a simple gui application needs to be able to spit out a sound with pulseaudio is simply amazing.

maandag 29 november 2010

My Fedora 14 policy for the adventurous.

My Fedora 14 policy for the adventurous.

I have been working on a policy for Fedora 14. Three different policies actually. One for a minimal fedora installation (--nobase), one for a minimal fedora installation with libvirt and a policy for a minimal gnome desktop system.

The minimal policy for Fedora 14 gnome desktops is the interesting one. It aims to confine the gnome desktop on workstations. That means it supports almost none system services, excepts the base essentials. It does not have policy for any mail servers, it does have policy for ssh and even httpd. Http policy because gnome-user-share relies on it (dav)

What it lacks in system services it makes up for in application domains. That is to say it supports some gnome apps, and the user apps that do not have policy should be able to make to work by toggling the gnome_$1_targeted boolean where $1 is your user role prefix. Caution though that this hasnt been tested yet because my sole priority lies with a confined gnome, and this is enough work as is.

There are atleast some things to do if one decides to give it a spin.

One should add the following directories to /etc/skel:

One should also modify /usr/share/dracut/modules.d/98selinux/

comment out:

mount --bind /dev "$NEWROOT/dev"
chroot "$NEWROOT" /sbin/restorecon -R /dev

..and then use dracut to build a new initramfs for your current kernel.

Also fix /root:

semanage fcontext -a -e /home/joe /root
restorecon -R -v /root

Typically you would:

setenforce 0
rpm -ev selinux-policy selinux-policy-targeted
rpm -Uvh selinux-policy-2.20100524-1.fc14.noarch.rpm selinux-policy-bare_gui-2.20100524-1.fc14.noarch.rpm
edit /etc/selinux/config and set selinux back to enforcing and point to bare_gui instead of targeted
relabel the file system
best to add a new user (make it staff_u as its user_u by default (sorry no unconfined_u in this policy by default)
make sure to add the user to sudo:
echo "joe ALL=(ALL) ROLE=sysadm_r TYPE=sysadm_t ALL" > /etc/sudoers.d/joe
chmod 0440 /etc/sudoers.d/joe

This policy confines all domains. also kernel_t and rpm_t. installation of packages and updting of packages should probably be done in permissive mode for now because the rpm domain needs some more loving. (common packages will work but dont try to install a kernel in enforcing mode or some service that gets restarted in the post-install script.

As said, this only works with gnome if it works at all (dont worry i am using it on my desktops) but only try this if youre a bit familar with selinux, are feeling adventurous and if you dont panic quickly.

By default the minimal gnome environment is confined. Gnome apps by default arent allowed to interact with users and often arent allowed to run generic applications. For example the printer applet currently is not confined (i dont like printing its a waste of paper and ink), thus gnome will not be able to run the printer applet until a policy for it is implemented.

The idea is that gnome can easily be allowed to interact with these generic apps and be allowed to communicate with users by toggling the gnome_$1_targeted boolean. However this is still untested.

Youll notice that youll have to unlock youre gnome keyring on each login. I am not sure why but gnome keyring daemon or whatever runs it (probably dbus, maybe xdm?) tries to manipulate selinux into running in the user domain which i forcefully prevent so that it can be made to run confined.

If something is confined then youll be able to run it in a confined environment with gnome_$1_targeted boolean set to off, Else you wont be able to run it untill some policy for it gets implemented.

The apps you are able to run may not be confined perfectly yet for all use cases (its a lot of work).

Stuff that works for me:

a lot of default gnome apps/applets/session services

gnome schedule

Stuff that is not supported (atleast):


So one should be able to do some of the basics.

Why confining the desktop? Not so much to protect generic user content. I use to think this is important but as my policy evolved i discovered that the important thing here is the integrity of gnome and user apps.

For example: protect access to your keyring, gpg data, ssh data, firefox data etc.

Not protecting access to your generic ~/.porn directory

So how would you get started?

We you can get a tar ball of a recent snapshot here:

Just put the tarball in your ~/rpmbuild/SOURCES directory. Extract the support/selinux-policy.spec from the tarball and put that into ~/rpmbuild/SPECS/
then just rpmbuild -ba ~/rpmbuild/SPECS/selinux-policy.spec
it will spit out 3 packages by default (bare_gui and its docs package) which you can install. You do not require the docs rpm but installing it doesnt hurt either.

If you want to try the bare or bare_virt model you can do so by editing the selinux-policy.spec and set the %define for that model to 1. it will build an rpm for that aswell.

Remember, expect plenty boogs i would love to receive some feedback or even help in improving the policy. It is a lot of work but the concept is very powerful. By confining the layer between the user and the system (the desktop) we achieve a lot more flexibility. We can then define what each user domain can and cannot do by simply implementing a boolean.

The idea about the bare and bare_virt models is that its strict, the unconfined module is install but not used. Another important property of bare and bare_virt is small footprint. It only installs the bare minimum modules which keeps the policy small. if one decides to run a service that is not currently supported in bare or bare_virt then one can use loadable module to implement it. The policy is focussed on advanced administrators that value small foot print and want total control over have gets installed and what not.

Questions comments? domg472 at gmail dot com

Some background information:

the policy is based off of recent refpolicy. refpolicy aims the be a base for basically any kind of model. Unfortunately i had to edit refpolicy atleast to remove unconfined_domains ( i think refpolicy probably shouldnt have unconfined domains as its easier to add and unconfined domain than to remove one) also i had to remove and/or redo most of refpolicies user application policies. I think it may be better for refpolicy to ignore user application policies or atleast prefix them all. domains like ssh_t arent helpful in a confined user space, as a confined user space relies heavily on user role prefixes.

Why not base it on fedora policy?

All of the above discussed issues apply, plus. Fedora tends to avoid issues by adding modules to base. This causes problems. My policy only has modules in the kernel layer in base all other modules can be disabled in theory. Fedora focusses on usability. little things like easily allowing access to all user content makes it hard to confine the user space.

zaterdag 7 augustus 2010

user home directory contexts

Some where in this commit: 0bf4290c235b514c39ed9c8d3f3f2fbb95f60cfa ( in one of the file context specifications there ) is something that makes and breaks whatever creates the per user home directory contexts.

Without it, semodule (what use to be genhomedircon?) only creates contexts for the "__default__" login.

It took me almost a day to narrow it down to this. I would like to know which file context specification exactly is causing it and why

donderdag 5 augustus 2010

The advantages and disadvantages of domain prefixes.

I am trying to merge restricted xwindows users and common users. The idea is to make them both use the same policy and be able to lock down what we know as user_t to a restricted user that we know as xguest by toggling booleans. That will make it easier to adept user environments to meet your requirement. You do not have to write custom policy. Simply enable/disable the functionality that you need with booleans and go.

To achieve this i use the good old per_role_templates. We used to use them for role based separation, But once user based separation was introduced there seemed to be not much use to these templates any more. However the domain prefixes used in the per role templates can play an important role in enabling and disabling functionality for different users using the same policy. We can use the domain prefix to define tunable policy.

user joe is allowed to access the network via his web browser. User jane can only access the network with her favourite game. Both use the same policy but have different booleans toggled.

But consider this: joe is allowed to use the browser. The browser can use stuff like java, flash, a video player, email client etc. Its not joe directly run those its the browser running it for joe. So how is it achieved that when it is allowed that joe can use the web browser, that joe can also watch a video clip via his web browser. Or that joe is not allowed to watch video via his browser but some other user is permitted that.

This, i believe can be achieved by called per_role_templates in per_role_templates.

I tried this before in more than one ways and always stumbled on duplicate declarations or out of scope issues. Today i tried a different approach. To avoid duplicate declarations i decided to try and split the per_role_templates into templates for policy and for declarations. The declaration per role templates should only be called by user domains. Whilst the policy per role templates can additionally be called by other policy per role templates. This way booleans, types and attributes are declared once but can be used more than once. For example user X can connect to a streaming port if he runs totem, but he can also connect to a streaming port if he runs totem via his browser. The same can be done for things like java, gpg, flash, web browsers, you name it

Another thing i have to deal with is xserver duplicated declarations, and so i also split those declarations for the policy and added the declaration interface to the per role declaration template for the various applications and the policy to the per role policy template.

This stuff becomes important if you truly want to confine the user space. Take for example nautilus. If you click on a video file in nautilus. How does the SELinux know who did it and thus who's policy to apply? All it knows is that nautilus ran the video file and nautilus is not a user its an application. There are may more such examples. Domain prefixes can help here.

There are also issues with calling per role templates from per role templates. Consider this. You can click on a web url in an E-mail message and you can also use the E-mail client from the web browser. So you called the E-mail per role template from the browser per role template, and you call the browser per role template from the E-mail per role template. This will get you into a loop that never ends. You can wait until you way less than a ounce and policy will still not finish compiling. So that is a issue to consider.

Just to show you what a per role declaration template for a GUI app would look like:

## Role access for mozilla declarations.

## Prefix to be used

## Role allowed access

attribute mozilla_domain;
type mozilla_exec_t;


## Allow Mozilla to execute anonymous memory (execmem))
## files.


gen_tunable(mozilla_$1_execmem, false)


## Allow Mozilla to read all user home.
## files.


gen_tunable(mozilla_$1_read_content, false)


## Network access for mozilla.
## files.


gen_tunable(mozilla_$1_network_connect, false)

type $1_mozilla_t, mozilla_domain;
application_domain($1_mozilla_t, mozilla_exec_t)

role $2 types $1_mozilla_t;


I am aware that this is a pretty dirty hack, and i am not even sure if this indeed works out the way it appears, but i am just glad and hopeful that it does.

zondag 25 juli 2010

About dbus_connect_session_bus and dbus_session_domain. (and other interfaces that include the dbus_session_type attribute)

These interfaces currently use the session_bus_type attribute in Fedora.
The problem is that all restricted xwindows and the unconfined users have this attribute assigned to their dbus domain.

Take for example telepathy, which is a framework that is started by dbus session domains. If you use the dbus_session_domain() interface to start telepathy processes, then this means all restricted xwindows and the unconfined users automatically transition to the telepathy domains when they run telepathy programs from their dbus domains.

Same goes for the dbus_connect_session_bus() interface in terms of which process that acquire service to which dbus session domains.

In my branch i went ahead to try and fix this. Instead of using the session_bus_type attribute i use $1_dbusd_t type instead. This way i can define which dbus session can start a program that needs to be started by session dbus domains.

The problem is that the compiler does not like and permit this. You will run into duplicate declaration issues of the dbus session type ($1_dbusd_t).

There is a way out of this but it is an ugly work around: Call the interfaces described above in the same optional policy block as where the dbus_role_role is called from.

By the way: i do not see how dbus can be considered optional.

The end result is that domains started by dbus session domains can not be optional and should be compiled into the base module.

Which programs am i talking about? For starters Gnome. Stuff like Gnome configuration daemon, settings daemon, keyring daemon, VFS daemon etc. Then Telepathy, Empathy, Gnome DVB daemon, Vino and who knows what else.

Also: The dbus_session_bus_client is, in my view, too coarse. It also uses the session_bus_type attribute, allowing the caller to send DBUS messages to all dbus session domains and allowing the caller to stream socket connect to all dbus session domains.

This is what i am currently using for the two interfaces described above (i left other interfaces affected by dbus_session_type in the current state for now)

## Connect to the specified session BUS
## for service (acquire_svc).

## Prefix to be used.

## Domain allowed access.

type $1_dbusd_t;
class dbus acquire_svc;

allow $2 $1_dbusd_t:dbus acquire_svc;

## Allow a application domain to be started
## by the session dbus.

## Domain allowed to transition.

## Type to be used as a domain.

## Type of the program to be used as an
## entry point to this domain.

type $1_dbusd_t;

domtrans_pattern($1_dbusd_t, $3, $2)


Moral of this article: I would be nice if we came up with a proper solution for the issues i described.

My branch is "hacked" in a way that it works for a large part but it means that my branch diverged even further from upstream than it already did...

As always: Changes i have made can be reviewed in my Git repository.

zaterdag 17 juli 2010

My thoughts on the user domain.

- Unconfined_t users are unrestricted except: exec{mod,heap,stack,mem}. They stay in the unconfined domain wherever possible. Sometimes they transition to other unconfined domains. This is only done for the type transition functionality. (to make sure objects get created with the right types)

- Common users are restricted in the sense that they transition to restricted domains where possible. Besides that, common users should be limited in their functionality as little as possible. They should be able to do anything a normal Linux user can do except run setuid applications. Common users can be divided into the following:

user_u: plain common user. should "feel" unrestricted, but domain transitions wherever possible. Also can not run setuid applications.

staff_u: main difference with user_u is that staff users CAN run setuid applications.

sysadmin_u: should be able to do most everything a normal root can by domain transitioning wherever possible.

- Restricted users/restricted Xwindows users, domain transition where ever possible but can only do what they should be able to do. Thus by default the restricted user templates should have limited functionality. Ofcourse these user can not run setuid applications either. Examples of restricted users are.

guest_u: least privilege restricted login users with only access via ssh, no network access. no setuid.
xguest_u: least privilege restricted login users with only access via xdm. no network access. no setuid.

These restricted users are almost never tailor made for a specific need. (although xguest is currently modified to be allowed more then it should by default in my view)

Basically one would modify restricted users and restricted xwindows users to allow then exactly what they need plus/minus some policy that is tunable on the fly.

- Base users: Are even more limited than restricted users. They also cannot manage any user content. They are a base for task specific roles. privileged or unprivileged. Same as with restricted users these base users need to be tailored because by default all you can do is sudo to them (if you have access to setuid)
Examples of base user usage is: webadm, dbadm

What got me to blog about this? As staff user i was able to run traceroute in the staff_t domain. I was under the assumption that i should have domain transitioned and that user_ping boolean would have denied access.

Looking closer in the netutils policy i found conflicting rules. There were conditional transition interfaces available (using user_ping condifition) and there was main tunable policy where ping and traceroute are not able to use terminals if user_ping is set to false. This got me curious. Should this apply to common users? The answer in my view is: no.

Common users should always be able to run traceroute and ping but they should domain transition to the respective domains to do so.

That leaves us with the conditional interfaces. They can be used with restricted users. If you want to design a restricted user with permission to ping or traceroute on the fly, then you can use these booleans. They are not implemented into the restricted user templates by default because this is not core functionality. plus you may want to use this boolean for one class of restricted users but not for another class.

I ended up, removing the tunable_policy from the netutils type enforcement source policy file.

The conclusion i take away from this and other experiences is that there is some confusion about how the various user domains should behave. Over time , the user domain templates have become inconsistent (at least in Fedora.

Some other examples are that base users can run all applications and can run usr_t files.

dinsdag 13 juli 2010

Rethinking interaction with user content.

In the user space there is often a lot of policy to write that defines how users can interact with user content. We usually use the role templates for this. If an confined app create user home, tmp and tmpfs content. We have to allow the user running the app to manage and relabel this content as well.

In Fedora a start was made to simplify this a bit. Users that have access to the userdom_manage_home_role template are able to manage and relabel any content that is declared userdom_user_home_content. This way we do not have to explicitly define that a user can manage/ relabel some confined apps user home content. Less policy to write. Fedora has this idea only implemented for user_home_content and not for user_tmp or tmpfs_content.

The userdom_manage_user_home_role is an old template that dates back to the time when we used roles to separate access to content. Also Fedora combines policy to manage/ relabel and do a bunch of other stuff in this single template. This is not really tidy.

Ive been wanting the idea that Fedora implemented for user home content, for user_tmp and tmpfs content as well. It might save me from writing more policy then strictly required. Hopefully also for pulseaudio which requires processes to manage files on tmpfs. Each application that uses pulseaudio needs to be able to read and delete every other apps pulseaudio tmpfs file, and then send a null signal that the application that owned the tmpfs file it deleted or read. A LOT of policy, which i am hoping to simplify.

There are some things to consider as well. We have different classes of users. We have unconfined users, which obviously should be able to manage all user content. We also have confined common users. These users are restricted but should behave as normal Linux users as much as possible. Thus should also be able to manage and relabel all user content.

Then there are the restricted users. These users have least privileges required. There are two kinds of those. restricted users and restricted xwindows users. An example of an restricted user domain is guest_t, and an example of an restricted xwindows user is xguest_t.

restricted xwindows users need to be able to manage and relabel user content like pulseaudio tmp, tmpfs and user content. And content like Gnome content, Gconf, Window manager, home bin,cert,video, audio etc.

normal restricted users like guest only need to be able to manage generic user content.

Xguest_t also needs some special permission besides the basic restricted xwindows permissions, namely managing and relabelling mozilla_user_content and nsplugin_user_content. and since mozilla_t can transition to for example totem_t, these users should also be able to manage totem user content for example.

So i started by declaring three attributes: user_home_type, user_tmp_type and user_tmpfs_type. These attributes get assigned to all user content. So if an user app manages a file in home, then the type of that content is assigned the user_home_type attribute. If it manages a file on tmpfs it gets assigned the user_tmpfs_type attribute and if it manages a file in tmp the type of that content gets assigned the user_tmp_type attributes. This is done in the userdom_user (home,tmp,tmpfs) content templates which should be used if a type for that purpose is declared.

I have replaced the userdom_manage (home.tmp,tmpfs) role templates by templates that differentiate between generic user content and all user content. If have also separated the manage, relabel and file transition permissions.

The way i plan to use this is as follows: The userdom_login_user_template is shared by all login users (except unconfined users in fedora) So that means both common and restricted users. Therefore, if i add the userdom_manage_all_home_content template call there then that would mean that restricted users can manage all user content. Not what i want. Instead i will add permission to manage relabel and file transition to generic user content to this template. For common users i additionally plan to add permissions to manage and relabel all user content. Unconfined users also get access to manage and relabel all content in the unconfined user module obviously.

Next thing i plan to do is to extend the restricted_xwindows template to permit managing and relabelling of content that is required for GUI interfaces like gnome content etc.

Permissions specific to xguest like managing mozilla user content (xguest is permitted to un firefox in the mozilla_t domain) etcetera will be added to the xguest module.

With this i hope to achieve that i can simplify user content and at the same time keep privileges as tight as possible.

If you want to see what i have implemented of above thus farm have a look in my Git repository. Use Git log/show to find and review the related commits.

maandag 12 juli 2010

Targeted configured semi-strict with UBAC for Fedora/Redhat distros.

I am maintaining an SELinux policy that is based off of Fedoras' SELinux policy and it aims to merge changes refpolicy as much as possible. It use to have only rather minor differences compared to refpolicy and Fedora but lately it has been diverging pretty much. The source policy is available in my personal shared Git repository and depending on my time it is updated pretty often. I aim to merge any Fedora and refpolicy updates as much as possible as soon as possible. In theory it is latest Fedora policy with refpolicy changes and my own changes. In practice its Fedora plus/minus some bugs/features that i introduced.

The main property of my policy is that, besides the usual, it aims to confine the user space by default.
As opposed to Fedora, my policy has user based access control enabled. This feature aims to isolate selinux users. In practice it has some rough edges and gothas but it is worth it. So one of the issues is that one has to make sure that the selinux identity field in the security context tuple of user home directories is labeled properly. This is a problem when you add new users. So if a new user is added one should chcon -R -u newuser_u /home/newuser. The second issue is system administration. In my policy, root is mapped to sysadm_u selinux identity, but usually logins as root are not encouraged, and so one logs in as staff_u and then role transitions to either sysadm_r or unconfined_r. This means that you will be root in a sufficient domain but with a ubac constraints. Fortunately unconfined_t has access to the system_r role and can use runcon to run commands using the system_u selinux identity. This is required for many sysadm commands. Example: runcon -u system_u useradd joe.

My policy installs with root mapped to the selinux identity of root but the root selinux identity does not have default contexts for unconfined. Meaning root cannot login as unconfined_t. Root logs in, in the sysadm_t domain. That should be sufficient. On installation the unconfined module is disabled. It can optionally manually be enabled after installation. updating policy will not try to disable it again if you did. The unconfined_u selinux user mapping was removed by default. You can manually add it if required but my policy does not encourage unconfined logins. This is also why unconfined_login boolean is set to false by default.

Users that need to have access to privileged domains and dacs root should be mapped to staff_u. These users should use sudo to change to root and to role transition:

echo "joe ALL=(ALL) TYPE=unconfined_t ROLE=unconfined_r ALL" >> /etc/sudoers

My policy adds some confinement for some user apps. Most notably currently:
firefox, nsplugin, totem, telepathy, mutt, thunderbird, elinks, irssi, metacity, gnome dvb, seahorse-daemon, vino_server and others.

So it is targeted policy that is configured in a semi strict fashion. unconfined logins by default are prohibited but the unconfined role/domain can be used as an replacement for sysadm_r/sysadm_t to use with sudo. Also the policy has selinux user isolation, so the various selinux users cannot interfere with eachother.

To make an rpm of my policy is pretty straight forward on fedora.
You can clone my refpolicy repository:

git clone git://

or update it after you cloned it:

cd refpolicy; git pull

(Mind you that my IP address is dynamic. It does not change often but it can change. Just "/whois" me on to get my current IP address and use that.

To determine my main policy version either look at the tags or see "Version ; .." in the spec file in "redhat/selinux-policy.spec"

Replace the version number with the version number in the following commands:

git archive --format=tar --prefix=refpolicy-3.8.6/ refpolicy | gzip > ~/rpmbuild/SOURCES/refpolicy-3.8.6.tar.gz

git diff refpolicy master > ~/rpmbuild/SOURCES/refpolicy-3.8.6.patch

Make sure the path exists (install rpmdevtools) run rpmdev-setuptree.

Next copy the redhat/selinux-policy.spec from the Git repository:

cp redhat/selinux-policy.spec ~/rpmbuild/SPECS/

And build the packages:

cd ~/rpmbuild/SOURCES/; rpmbuild -ba ../SPECS/selinux-policy.spec

If you're installing my policy for the first time. e.g. if your current installed policy is stock redhat/fedora policy, then it is encouraged to start clean.

This means you will lose any modifications that you may have made:

setenforce 0
yum erase selinux-policy selinux-policy-targeted
mv /etc/selinux /etc/selinux.backup
yum install selinux*.rpm (the build rpms)
touch /.autorelabel && reboot

on reboot login as root, you should be in sysadm_t domain and you should be able to add/ fix your login user mapping to staff_u. Once youre login user is mapped to staff_u be sure to fix your login users home and tmp directories context:
semanage login -a -s staff_u -r s0-s0:c0.c1023 joe
chcon -R -u staff_u /home/joe
chcon -R -u staff_u /tmp/joe
chcon -R -u staff_u /var/tmp/joe

That should be sufficient.

If pulseadio does not start, then remove ~/.esd_auth ~/.pulse /tmp/.esd* and relogin or restart pulse.
Also you may when you first log in get AVC denials for stuff like metacity trying to access ~/.config (staff_wm_t -> user_home_t), and maybe others as well, ignore it. This is because that directory and others at that point are not restored yet. restorecond -u runs in a gnome-session and should have restored your home directory contexts in the mean time.

Be prepared to stumble on bugs, issues etcetera. Feel free to contact me if you have questions or comments. Patches welcome.

I am using this policy myself on two desktop systems (fedora13/Gnome) and several headless servers.

Warning: Only consider trying this if you are familiar to, and not intimidated by SELinux.

zondag 14 februari 2010

About apache_content_template

In refpolicy there are about eight modules that have calls to apache_content_template in their private policy. These template calls are located in optional policy blocks. This is so that these modules do not depend on the apache module being present.

The problem is that seven out of these eight modules have file context specifications containing a executable type, that is declared in the apache content template, in their file context file. As far as i know file context specifications are never optional.

So even though calls to apache content template are optional, they really aren't because the file context specifications that accompany them are not optional.

This means that eight modules depend on the apache module being installed. Try to de-install the apache module (semodule -r apache) and you will be presented with some very unclear errors. Most people will not know what to do.

So how can we fix that?

Well here is an example. We use the apache_cgi_domain() instead:

# BackupPC admin private declarations.

type backuppc_admin_t, backuppc_domains;
type backuppc_admin_exec_t;
domain_entry_file(backuppc_admin_t, backuppc_admin_exec_t)
role system_r types backuppc_admin_t;

# BackupPC admin private policy.

apache_cgi_domain(backuppc_admin_t, backuppc_admin_exec_t)

/usr/share/BackupPC/sbin/BackupPC_Admin -- gen_context(system_u:object_r:backuppc_admin_exec_t, s0)

This way we can make the call to apache_cgi_domain() *really* optional. It is a bit more work initially but in my view this is maintainable unlike apache_content_template.

donderdag 14 januari 2010

Test Git daemon policy.

Clone my latest selinux-modules git repository:

git clone git://
cd selinux-modules && make -f /usr/share/selinux/devel/Makefile gitd.pp
semodule -d git; semodule -i gitd.pp
cp gitd.if /usr/share/selinux/devel/include/services/gitd.if

To test the Git session server you should build a custom module calling the gitd_session_role template for your role:

echo "policy_module(mygittest, 1.0.0)" > mygittest.te;
echo "optional_policy(\`" >> mygittest.te;
echo "gen_require(\`" >> mygittest.te;
echo "# Assuming you want to test as unconfined_t" >> mygittest.te;
echo "type unconfined_t;" >> mygittest.te;
echo "role unconfined_r;" >> mygittest.te;
echo "')" >> mygittest.te;
echo "gitd_session_role(unconfined_r, unconfined_t)" >> mygittest.te;
echo "')" >> mygittest.te;

make -f /usr/share/selinux/devel/Makefile mygittest.pp
semodule -i mygittest.pp

Make sure that port tcp:9418 open and that tcp-wrappers is configured to accept connectivity on this port.

install git-daemon and its dependencies: yum install git-daemon.

You must edit /etc/xinetd.d/git. set "disable" to "no", "server" to "/usr/libexec/git-core/git-daemon", and remove the "daemon" argument from "server_args". Keep an eye on /var/log/messages in case it behaves strange.

Restore the following contexts:

restorecon -R -v /var/lib/git
restorecon -v /usr/libexec/git-core/git-daemon
restorecon -v ~/.gitconfig
restorecon -v ~/public_git

Start xinetd: service xinetd start.

Set up a default git shell user for generic shared repositories:

groupadd git
useradd -Z git_shell_u -M -s /usr/bin/git-shell joe
usermod -a -G git joe
passwd joe

Set up a bare "test" shared repostory:

mkdir /var/lib/git/test.git
cd /var/lib/git/test.git && git --bare init
chown -R root:git /var/lib/git/test.git
chmod -R g+w /var/lib/git/test.git
chmod -R g+s /var/lib/git/test.git
chmod -R +t /var/lib/git/test.git

From your "normal" user account clone the bare repository:

git clone git://localhost/test.git
cd test

Make changes to it:

echo "test" > test;
git init
git add .
git commit -a -s -m "My initial commit."

As user "joe" push to the shared repository:

git push --all git+ssh://joe@localhost/var/lib/git/test.git
git pull
git status
git show

Testing Git session:

Stop xinetd and in your "normal" (we are done with "joe" for now) user home directory make sure ~/public_git exists.
restorecon -R -v /public_git
Previously we called a "gitd_session_role" template for users operating in the unconfined_t domain. This means when your id -Z returns: unconfined_u:unconfined_r:unconfined_t:s0, git with the daemon option will run in a Git session SELinux environment for you.

Create a new personal repository in ~/public_git:

mkdir ~/public_git/hello
cd ~/public_git/hello
git init
echo "hello" > hello
git add .
git commit -a -s -m "My initial commit."

Serve your personal repository with the following command:

git daemon --export-all --user-path=public_git

In another terminal clone the repository:

git clone git://localhost/~yourloginnamehere/hello

Make a commit to it:

cd hello
echo "bye" >> hello
git commit -a -s -m "Add good bye"

Push the change to your personal repository:

git push --all ssh://yourloginnamehere@localhost/~/public_git/hello

Hosting personal repositories with Git system daemon.

Stop your Git session daemon (ctrl-c) and start xinetd.

Set the boolean to allow the Git system daemon to search user home directories for personal Git repositories to serve:

setsebool gitd_system_enable_homedirs on

Now clone the personal repository again:

git clone git://localhost/~yourloginnamehere/hello
cd hello
echo "hi" >> hello
git commit -a -s -m "Added Hi."

And push to the personal repository:

git push --all ssh://yourloginnamehere@localhost/~/public_git/hello

Create a customized Git Shell user that has access to a restricted shared repository (besides having access to any generic system repositories) Also create a restricted repository and allow our created Git shell user access to this new restricted repository.

echo "policy_module(secret_git_shell, 1.0.0)" > secret_git_shell.te;
echo "gitd_role_template(secret_git_shell)" >> secret_git_shell.te;
echo "gitd_content_template(secret)" >> secret_git_shell.te;
echo "gitd_content_delegation(secret_git_shell_t, gitd_secret_content_t)" >> secret_git_shell.te;
echo "gen_user(secret_git_shell_u, user, secret_git_shell_r, s0, s0)" >> secret_git_shell.te;

echo "/var/lib/git/secret\.git(/.*)? gen_context(system_u:object_r:gitd_secret_content_t, s0)" > secret_git_shell.fc;

make -f /usr/share/selinux/devel/Makefile secret_git_shell.pp
semodule -i secret_git_shell.pp

Create a secret Git shell user:

useradd -Z secret_git_shell_u -M -s /usr/bin/git-shell jane
usermod -a -G git jane
passwd jane

Create a bare secret shared repository:

mkdir /var/lib/git/secret.git
cd /var/lib/git/secret.git && git --bare init
chown -R root:git /var/lib/git/secret.git
chmod -R g+w /var/lib/git/secret.git
chmod -R g+s /var/lib/git/secret.git
chmod -R +t /var/lib/git/secret.git

Restore the context of the secret repository:

restorecon -R -v /var/lib/git/secret.git

Everyone can read it but only jane can push to it. As a "normal" user clone the secret repository.

git clone git://localhost/secret.git
cd secret
echo "secret" > secret
git init
git add .
git commit -a -s -m "My first commit."

Push it as user "jane"

git push --all git+ssh://jane@localhost/var/lib/git/secret.git
git pull
git status
git show

Make another commit:

echo "Joe here" >> secret
git commit -a -s -m "add Joe here"

Now try to push it as user "joe" (joe can push generic shared repositories but joe is not allowed to push to the secret repository)

git push --all git+ssh://joe@localhost/var/lib/git/secret.git