[Rpm-maint] [RFC PATCH] install selinux policies from package header

Panu Matilainen pmatilai at laiskiainen.org
Tue Jul 7 10:21:49 UTC 2009


On Mon, 6 Jul 2009, Stephen Lawrence wrote:

> RPM currently has support for security policies to be stored in an rpm
> header but it doesn't currently do anything with the policies. We'd like
> to get some feedback on a prototype implementation that adds support for
> using those policies in an SELinux environment.

First of all thanks for looking into this!

> First, a bit of background. SELinux policy is currently installed
> through %post scripts. This presents several problems. First, this means
> that policy for a given application may not be loaded at the time the
> files are written to disk, preventing those files from being labeled
> properly, because the symbols used to label files need to be in the
> policy loaded into the kernel. Secondly, this means that if multiple
> packages install policy, each of their %post scripts will reload the
> policy, which is a very expensive operation. Consequently, policy is
> generally kept in a single package to avoid this, despite containing
> many application specific policy modules that would be more suited to be
> included in their application package.
> So, what we would like to do is to start including SELinux policy as
> part of the rpm and have rpm install all policies together before files
> start to hit the disk. To do this, we would like to use the already
> supported %policy directive, which stores the policy in the archive
> header.
> We would then install the policy before pretrans. This policy load would
> involve gathering all the policies to be installed from all packages,
> writing them to a temporary location, and calling out to semodule to
> install the SELinux policy modules.
> Obviously I'm glossing over many implementation details that would need
> to be worked out. The point of this email is strictly to get feedback on
> our approach. Below is a patch that implements the beginnings of what I
> describe above. Any and all feedback is appreciated.

Loading the policies at pre-trans stage is how it needs to be done, but 
calling out to semodule is a no-go. It'd work for upgrades more or less, 
but on initial installation (to an empty chroot) the pre-trans stage 
happens in a complete void, there's just nothing there, not even /bin/sh.

It needs to be done through API calls, no way around it. On the surface it 
doesn't look that bad, skipping over details like error handling, 
rpmtsLoadPolicy() might be something like:

static int rpmtsLoadPolicies(rpmts ts)
     int rc;
     rpmte p;
     semanage_handle_t *sh = NULL;
     rpmtsi pi = rpmtsiInit(ts);

     while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
         /* If no pre/post-transaction script, then don't bother. */
         if (!rpmteHavePolicies(p, stag))

         /* only set up semanage transaction if we have policies */
         if (sh == NULL) {
             sh = semanage_handle_create();

         if (rpmteOpen(p, ts, 0)) {
             /* ... fish the policies from te header, b64decode ... */
             semanage_module_install(sh, ...);
             rpmteClose(p, ts, 0);

     if (sh) {

     pi = rpmtsiFree(pi);
     return rc;

...but I've a feeling there's more than one devil in the details. The 
"base" policy seems to be a bit special as it even has a separate loader 
function, which I suppose would have to be loaded first if one is present, 
but how would rpm know what's a base policy and what's not? Are there 
other order dependencies in the modules? I guess not but dunno.

Another open question is upgrade/remove semantics. Maybe it's sufficient 
just to semanage_module_install() on install+upgrade, and 
semanage_module_remove() on non-upgrade removal (direct erase or 
obsoletion), all in the pre-trans stage. I'm just wondering could there be 
cases where successful removal requires the package's policy to be loaded? 
If so, the module removals would either have to be done at the middle of 
transaction individually per package (costly) or do them all at post-trans 
stage, which would seem more symmetric in a sense. And actually quite 
similar to how %pre- and %posttrans happen, might even be 
possible/reasonable to lump their processing to a single function (the 
actual "do stuff" part obviously differs but the transaction set iteration 
and header loading is the same)

And of course it must be possible to disable this functionality. Might be 
sufficient to just hang it on RPMTRANS_FLAG_NOCONTEXTS, or can you think 
of a case where one would want to load policies without actually touching 
the contexts (or the other way around)?

 	- Panu -

More information about the Rpm-maint mailing list