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

Joshua Brindle method at manicmethod.com
Tue Jul 7 13:19:08 UTC 2009

Panu Matilainen wrote:
> Hi,
> On Mon, 6 Jul 2009, Stephen Lawrence wrote:

>> 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:

We wanted to fork/exec semodule because there would be a domain transition and 
we could give semodule permission to update the policy without giving rpm that 
permission. This feeds in to our ultimate desire to break RPM in to less 
privileged pieces.

FWIW the library executes apps as well, for example setfiles is run to validate 
the file contexts files when new policy is loaded. This is how we break out 
functionality in SELinux to let pieces be less privileged. I don't think we can 
attain our end goals if fork/exec is never allowed.

> 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))
> continue;
> /* only set up semanage transaction if we have policies */
> if (sh == NULL) {
> sh = semanage_handle_create();
> semanage_connect(sh);
> semanage_begin_transaction(sh);
> }
> if (rpmteOpen(p, ts, 0)) {
> /* ... fish the policies from te header, b64decode ... */
> semanage_module_install(sh, ...);
> rpmteClose(p, ts, 0);
> }
> }
> if (sh) {
> semanage_commit(sh);
> semanage_disconnect(sh);
> semanage_handle_destroy(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.

Currently base policies are special, we intend for that to go away in some other 
work we are doing (as well as the binary modules going away and shipping only 
policy source to end systems)

> 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)

removal is a tough nut to crack, it leaves files unlabeled that may not be 
removed when the rpm is removed (eg., web pages, databases) and we don't want 
that. Additionally we don't want add/remove semantics to break if rpm's change 
names. This is something we are working on solving, this patch was only the very 
first step.

> 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)?

It appeared that you ran out of flags and I'm not sure hanging it on the 
nocontexts flag is appropriate. Please advise.

More information about the Rpm-maint mailing list