#814 Add SELinux Independent Policy Guidelines
Opened 11 months ago by vmojzis. Modified 6 days ago
vmojzis/packaging-committee master  into  master

@@ -0,0 +1,53 @@ 

+ # defining macros needed by SELinux

+ %global selinuxtype targeted

+ %global moduletype contrib

+ %global modulename myapp

+ 

+ Name: myapp-selinux

+ Version: 1.0

+ Release: 1%{?dist}

+ License: GPLv2

+ URL: # URL to git repository with policy source files

+ Summary: SELinux policies for product

+ Source0: # archive with SELinux policy sources. e.g: myapp-selinux.tar

+ BuildRequires: selinux-policy

+ BuildRequires: selinux-policy-devel

+ BuildArch: noarch

+ %{?selinux_requires}

+ %description

+ SELinux policy modules for product.

+ 

+ %prep

+ %setup -q

+ 

+ %build

+ make

+ 

+ %pre

+ %selinux_relabel_pre -s %{selinuxtype}

+ 

+ %install

+ # install policy modules

+ install -D -m 0644 %{modulename}.pp.bz2 %{buildroot}%{_datadir}/selinux/packages/%{selinuxtype}

+ 

+ %check

+ 

+ %post

+ %selinux_modules_install -s %{selinuxtype} %{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.bz2

+ 

+ %postun

+ if [ $1 -eq 0 ]; then

+     %selinux_modules_uninstall -s %{selinuxtype} %{modulename}

+ fi

+ 

+ %posttrans

+ %selinux_relabel_post -s %{selinuxtype}

+ 

+ %files

+ %{_datadir}/selinux/packages/%{modulename}.pp.*

+ %ghost %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{modulename}

+ %license COPYING

+ 

+ %changelog

+ * Mon Jan 01 2017 Author Name <Author@mail-example.com> - 0.1.0-1

+ - First Build 

\ No newline at end of file

@@ -0,0 +1,1 @@ 

+ /sbin/myapp --  gen_context(system_u:object_r:myapp_exec_t,s0)

@@ -0,0 +1,2 @@ 

+ ##

+ My app service. 

\ No newline at end of file

@@ -0,0 +1,8 @@ 

+ policy_module(myapp,1.0)

+ 

+ type myapp_t;

+ type myapp_exec_t;

+ init_daemon_domain(myapp_t, myapp_exec_t)

+ 

+ # Grant myapp_t the signal privilege

+ allow myapp_t self:process { signal }; 

\ No newline at end of file

@@ -0,0 +1,344 @@ 

+ = SELinux Independent Policy Guidelines

+ 

+ [[creating-own-product-policies]]

+ == Creating Own Product Policies

+ 

+ In Fedora, there is a lot of applications and daemons 

+ which require customized SELinux security policy.

+ The former approach with providing all policies only as a part of the system 

+ has been enhanced by the option to create custom product policy.

+ 

+ With the possibility to create custom product policy, 

+ required changes in a policy can be released immediately,

+ so the product package maintainer does not need to wait 

+ for another SELinux policy package release.

+ In other words, 

+ a product SELinux policy is always synchronized 

+ with the corresponding product (package).

+ 

+ This chapter is dedicated to shipping custom SELinux security module 

+ as a subpackage for a daemon or an application.

+ 

+ 

+ 

+ [[independent-selinux-policy]]

+ == Independent SELinux Policy

+ 

+ While considering custom product policy,

+ a product maintainer has two options:

+ 

+ * Write his own SELinux policy from scratch

+ and ask SELinux team for policy review.

+ Note that a guide how to write an SELinux policy from scratch 

+ is not a part of this chapter (See `sepolicy generate` tool).

+ * Extract an SELinux policy from a distribution policy package.

+ The Git repository with distribution policies is located on

+ https://github.com/fedora-selinux/selinux-policy

+ and

+ https://github.com/fedora-selinux/selinux-policy-contrib.

+ 

+ CAUTION: Distribution policies have GPL license,

+ so any policy extracted from Distribution policy

+ must have a GPL compatible license.

+ 

+ [[agreement-workflow]]

+ == Agreement workflow

+ 

+ Before you start with shipping custom product policies, 

+ let the SELinux team know about your intentions. 

+ To do this, use SELinux Fedora mailing list or contact SELinux policy maintainer:

+ 

+ * mailto:selinux-policy-owner@fedoraproject.org[SELinux Policy maintainer]

+ * selinux@lists.fedoraproject.org

+ 

+ 

+ [[preparing-sources-for-the-policy-repository]]

+ == Preparing sources for the Policy repository

+ 

+ It is recommended to create a Git repository for the SELinux policy sources.

+ 

+ Corresponding policy module can than be extracted from

+ https://github.com/fedora-selinux/selinux-policy-contrib[selinux-policy-contrib repository].

+ If there is no policy for the product, 

+ new policy should be created in this step and added to the repository.

+ 

+ When the custom policy is ready,

+ the product maintainer should create a build script (e.g. Makefile),

+ attach a license file and make sure the policy compiles properly.

+ 

+ A Makefile generated by `sepolicy generate`,

+ or the following command, can be used to compile the policy source:

+ ....

+ make -f /usr/share/selinux/devel/Makefile <module name>.pp

+ ....

+ 

+ 

+ [[policy-source-examples]]

+ === Policy source examples

+ 

+ For the purpose of this example, we create a policy named myapp:

+ 

+ .myapp.te

+ [source]

+ ----

+ include::{examplesdir}/selinux/myapp.te[]

+ ----

+ .myapp.fc

+ [source]

+ ----

+ include::{examplesdir}/selinux/myapp.fc[]

+ ----

+ .myapp.if

+ [source]

+ ----

+ include::{examplesdir}/selinux/myapp.if[]

+ ----

+ 

+ The SELinux policy Git repository should contain the following files

+ (replace myapp with a name of your product):

+ 

+ ....

+ $ ls

+ Makefile  myapp.fc  myapp.if  myapp.te COPYING

+ ....

+ 

+ 

+ [[using-custom-interfaces]]

+ === Using custom interfaces

+ 

+ The interface file of the custom policy module

+ is *not* installed in the system 

+ because it would conflict with the interface file of the distribution module.

+ Therefore any changes to it will not have effect on other policy modules.

+ In order to use custom interfaces

+ it is necessary to create new interface file with unique name (_ipp-[modulename].if_)

+ and include it in the new package as follows:

+ 

+ ....

+ %install

+ install -D -p -m 644 ipp-%{modulename}.if %{buildroot}%{_datadir}/selinux/devel/include/%{moduletype}

+ 

+ %files

+ %{_datadir}/selinux/devel/include/%{moduletype}/ipp-%{modulename}.if

+ ....

+ 

+ CAUTION: All custom interfaces _must_ be prefixed with "ipp_"

+ not to be confused with distribution interfaces.

+ 

+ Changes to interfaces of the original module

+ can only be delivered via distribution selinux-policy-* packages.

+ If such a change is necessary, please contact the SELinux team,

+ or submit a pull request.

+ Please bear in mind that such changes will influence other policy modules

+ that use given interface.

+ 

+ [[custom-policy-modules-and-distribution-policy]]

+ === Custom policy modules and distribution policy

+ 

+ It's important to note that distribution policies _should not_ use

+ interfaces from removable policy modules.

+ 

+ When using types from custom policy modules

+ _stub_ interfaces should be used instead of directly requiring given type.

+ Stub interface is defined and used in distribution module as follows.

+ 

+ .distribution_module.if

+ ....

+ ...

+ ...

+ ########################################

+ ## <summary>

+ ##  DBUS stub interface.  No access allowed.

+ ## </summary>

+ ## <param name="domain" unused="true">

+ ## <summary>

+ ##  Domain allowed access

+ ## </summary>

+ ## </param>

+ #

+ interface(`distro_stub',`

+     gen_require(`

+         type dystro_t;

+     ')

+ ')

+ ...

+ ...

+ ....

+ 

+ .myapp.te

+ ....

+ ...

+ ...

+ optional_policy(`

+     distro_stub()

+     allow distro_t myapp_log_t:file read_file_perms;

+ ')

+ ...

+ ...

+     

+ ....

+ 

+ As with any type defined outside of _SELinux policy base modules_,

+ _optional_policy_ block must be used

+ when using types from removable modules in distribution policy.

+ 

+ [[example-spec-file]]

+ == Example Spec File

+ 

+ When a Git repository with SELinux policy sources is ready, 

+ create your product .spec file (rpmbuild configuration file).

+ 

+ You can use the following example as a template:

+ 

+ .myapp-selinux.spec

+ [source]

+ ----

+ include::{examplesdir}/selinux/myapp-selinux.spec[]

+ ----

+ 

+ 

+ [[adding-dependency-to-the-spec-file-of-corresponding-package]]

+ === Adding dependency to the spec file of corresponding package

+ 

+ The *-selinux package should only be required on SELinux enabled systems.

+ Therefore the following rich dependency syntax should be used:

+ 

+ ....

+ Requires: (%{name}-selinux if selinux-policy-%{selinuxtype})

+ ....

+ 

+ This ensures that the *-selinux package and all it's dependencies

+ are not pulled into containers and other systems that do not use SELinux.

+ 

+ [[selinux-policy-module-priorities]]

+ === SELinux Policy module priorities

+ 

+ Policy modules can be installed with different priorities.

+ When multiple modules of the same name exist in the system,

+ only the module with the highest priority takes effect.

+ 

+ Distribution policy modules are installed with priority of 100.

+ Custom policy should always be shipped with priority of 200

+ to override distribution policy.

+ This value is contained inside the _selinux_modules_install_ macro

+ and should not be changed.

+ 

+ Note that _semodule_ installs policy modules with priority of 400 by default.

+ 

+ See

+ https://plautrba.fedorapeople.org/selinux-modules-and-priority.html[SELinux modules and priority]

+ for more details about module priority.

+ 

+ [[building-a-package-with-an-selinux-product-policy]]

+ == Building a Package with an SELinux Product Policy

+ 

+ [[setting-booleans-during-an-product-policy-installation]]

+ === Setting Booleans During an Product Policy Installation

+ 

+ In some cases, it is necessary to enable or disable some booleans

+ defined in a system security policy.

+ This change should be done during the installation phase

+ of the SELinux product package and it should also follow a couple of rules.

+ 

+ WARNING: Setting generic booleans can open security holes in the system!

+ 

+ To change system booleans, use the following steps:

+ 

+ * Find a boolean that fits your needs best.

+ Try to avoid generic booleans, which allow many things

+ and their change could bring security holes to the system.

+ 

+ * Specify booleans in the following format in the .spec file:

+ +

+ ....

+ # default boolean values need to be changed due to product policy

+ # the change is performed by "%selinux_set_booleans" macro in %post phase

+ %global selinuxbooleans booleanname=1 booleanname2=0

+                                     

+ ....

+ * It is necessary to use special macro _%selinux_set_booleans

+ during "%post" phase of rpmbuild

+ to make sure that the specified boolean values are set.

+ 

+ See the following example:

+ +

+ ....

+ %post

+ %selinux_modules_install -s %{selinuxtype} %{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.bz2

+ %selinux_set_booleans -s %{selinuxtype} %{selinuxbooleans}

+ 

+ %postun

+ %selinux_modules_uninstall -s %{selinuxtype} %{modulename}

+ %selinux_unset_booleans -s %{selinuxtype} %{selinuxbooleans}

+                                     

+ ....

+ 

+ The boolean macros mentioned above behave as follows:

+ 

+ * The value of each boolean set using "%selinux_set_booleans" is recorded

+ and will be reset to the original value when "%selinux_unset_booleans" is called

+ 

+ * Number of calls to "%selinux_set_booleans" and "%selinux_unset_booleans"

+ has to match in order for this mechanism to work properly

+ 

+ [[port-labeling]]

+ === Port Labeling

+ 

+ If your product policy does not define port labels (such as "product_port_t"),

+ you can skip this section.

+ 

+ You should assign a port number and a port type to every port label.

+ Assigning a port label should be done in %post install phase.

+ For example, for the TCP 1111 port, the

+ `semanage port -a -t product_port_t -p tcp 1111`

+ command should be added to the if statement in the .spec file:

+ 

+ ....

+ if %{_sbindir}/selinuxenabled ; then

+      %{_sbindir}/semanage port -a -t product_port_t -p tcp 1111

+ fi

+ ....

+ 

+ Where the `a`, `t`, and `p` of the `semanage` command mean the

+ following:

+ 

+ ....

+ -a   Add a record of the specified object type

+ -t   SELinux type for the port

+ -p   Protocol  for  the  specified  port  (tcp|udp)

+ ....

+ 

+ For the %post uninstall phase, the port assignment should be removed.

+ To do this, add the

+ `semanage port -d -t <PORT>`

+ command in your .spec file. 

+ For example:

+ 

+ ....

+ if %{_sbindir}/selinuxenabled ; then

+     %{_sbindir}/semanage port -d  -p tcp -t product_port_t

+ fi

+ ....

+ 

+ [[removing-your-product-policy-from-the-system-policy]]

+ == Removing your Product Policy from the System Policy

+ 

+ When your own product SELinux subpackage is ready for a release,

+ contact the SELinux policy maintainer.

+ He should remove the product policy from the SELinux distribution policy

+ and update the package.

+ You should then add a dependency on the new selinux-policy package:

+ 

+ ....

+ # Version of selinux-policy when product policy was removed

+ %global selinux_policyver POLICY_VERSION

+ Requires: selinux-policy >= %{selinux_policyver}

+ ....

+ 

+ If the released policy was not part of the distribution policy,

+ there is no need to add a version dependency to your .spec file.

+ 

+ Now your SELinux subpackage is ready for release.

+ It is recommended to create a group update

+ together with selinux-policy package

+ to ensure that the updating process will be successful.

Please provide such makefile as part of selinux-devel or such package so that packagers do not have to copy it over and over

So after reading this, I think different structure should be used, probably something like:

  • BuildRequires
  • %build section, which commands to execute in order to build policy (note the makefile comment above, so plain commands + example with using makefile, not the makefile itself)
  • %install section, where to install, some small example which files to install and where
  • Scriptlets
    applying policy
    port labelling
  • Example spec
  • Links to some examples which mention how to write a policy

probably %build, %install and scriptlets should be a subsections of port labels / other policies

None of this "git repository setup" section belongs in the packaging guidelines. I would completely remove lines 50 through 131.

I believe this needs to be converted to prescriptive language. If we're saying that manipulating booleans in this way is a requirement, then use "MUST" and such. Right now I can't tell if "it is necessary" means that the macro is the way to do this kind of thing, or if the package has to take these steps.

What is a "product" in this context? It's not a term we use elsewhere in the guidelines.

Please follow semantic line breaks: http://sembr.org/

Sorry, I'll fix that.

What is a "product" in this context? It's not a term we use elsewhere in the guidelines.

Application or daemon. As specified in the first sentence of the section.

IMO this should not be in guidelines.

I believe the "Extraction process" is important. Especially for people who are new to writing SELinux policy. Should we move it to our wiki page and reference in this document, or what would be the best approach?

None of this "git repository setup" section belongs in the packaging guidelines. I would completely remove lines 50 through 131.

This part is in place to suggest keeping the SELinux policy sources in a separate repository to minimize synchronization issues with distribution policy (during the transitional period when the policy module is in both "selinux-policy-{targeted|mls}" and "foo-selinux" packages).

Please provide such makefile as part of selinux-devel or such package so that packagers do not have to copy it over and over

The makefile is not necessary, but it's nice to have. The idea here is that the maintainer will customize the makefile with all that is necessary for the module installation (switching booleans, adding port mappings, etc.).
The module compilation is actually done using a makefile provided by selinux-policy-devel (make -f ${SHAREDIR}/selinux/devel/Makefile $@).

I believe this needs to be converted to prescriptive language. If we're saying that manipulating booleans in this way is a requirement, then use "MUST" and such. Right now I can't tell if "it is necessary" means that the macro is the way to do this kind of thing, or if the package has to take these steps.

I'll reword the section. It only describes the behaviour of the macros.

1 new commit added

  • Update based on comments from the packaging committee
11 months ago

2 new commits added

  • Update based on comments from the packaging committee
  • Add SELinux Independent Policy Guidelines
10 months ago

as said earlier, this doesn't belong to Packaging Guidelines.

why is this makefile needed? Just create necessary RPM macro for it.

why is this makefile needed? Just create necessary RPM macro for it.

The makefile makes it possible to easily use the policy outside of an RPM. Also, it is consistent with policies generated by "sepolicy generate".
However, an RPM macro is a good idea. We could let maintainers decide what they want to use.

Updated:
- Describe Makefile as optional
- Remove "Git Repository setup" section
- Change section label syntax to work with "asciidoc" properly

1 new commit added

  • Update based on comments from the packaging committee
5 months ago

Could someone please have a look at the updated document?

also, you can drop square brackets since there is no good replacement.

I'm not happy with this wording. Probably something like create a build script (e.g. Makefile)?

But this is definitely important note. Probably annotate it with CAUTION: and move somewhere above where text is about whether to write from scratch or extract it from selinux-policy? I know it is obvious that people should look at license of the project they are taking code from, but it won't hurt anybody to repeat it again.

If sepolicy generate generates it, let's remove this section and put somewhere above something like You can use sepolicy generate to start new project or something like that?

Especially because it is already distributed by selinux. Let's just say that packagers can use this command to compile their policies.

this should be executed by brp-* script in RPM, mind opening RFE or sending patch on https://github.com/rpm-software-management/rpm ?

You can annotate file names in asciidoctor syntax (see Rust.adoc for some example).

Let's remove this section entirely. Guidelines is not the place where you describe how to set up git repo and archive files.

Just use install -D to create directory so that previous line is not needed

As I said, guidelines is not a tutorial. Just put one complete spec file in Expamles section on this page

I would prefer if it would be .pp* so that if we ever change archive format we won't have to redo all specs. Does selinux support different compression formats?

would appreciate if you could tell what this "200" means

hi @vmojzis, I took a quick look on page. It does look better, but I left some comments.

Basically guidelines is the page where you describe things like "you MUST call %selinux_foo_bar in %post", "you MUST NOT depend on custom interfaces blah" and so on.

It definitely should have some examples and some quick guide how to actually package selinux policies, but not how to create tarball and create license file.

Thank you. Updated and rebased.

would appreciate if you could tell what this "200" means

That is the priority of the new module. As described in the "SELinux Policy module priorities" section, all custom policy modules are shipped with this priority.

rebased onto d50c101

2 months ago

Thank you for the review. Updated and rebased.

Could someone please review the latest changes?