I need a routine to configure the fcontext for many paths. Currently I maintain a bash script calling semanage to do that. But the task seems quite verbose. The main issue here is:

  1. I cannot find a simple command force update the rule for an object. I need to use semanage fcontext -l | grep <object> to find out if the object exists then I have to choose from -a or -m depends on the result. The command are really slow, around 0.5-1sec per call. Is there existing tool can just force update the rule?

  2. the semanage fcontext calls are very slow, is there a way to use conf file to define the rules? There is a file /etc/selinux/targeted/contexts/files/file_contexts.local but it does not suppose to be edited manually.


Though the custom policy module can be the canonical way to handle rules in many paths. However, the semodule -i actually way slower than loop the semanager commands.

Here is an example of mytest.fc

/var/run/mytest/afolder(/.*)?  gen_context(system_u:object_r:httpd_sys_content_t, s0)
/var/run/mytest/bfolder(/.*)?  gen_context(system_u:object_r:httpd_sys_rw_content_t, s0)
/var/run/mytest/cfolder(/.*)?  gen_context(system_u:object_r:httpd_sys_content_t, s0)
/var/spool/mytest/alink  gen_context(system_u:object_r:httpd_sys_content_t, s0)
/var/spool/mytest/blink  gen_context(system_u:object_r:httpd_sys_rw_content_t, s0)
/var/spool/mytest/clink  gen_context(system_u:object_r:httpd_sys_content_t, s0)

My example script version:

set -x

for _path in "${httpd_sys_content_paths[@]}"
    set +e
    semanage fcontext -d "${_path}"
    set -e
    semanage fcontext -a -s system_u -t httpd_sys_content_t "${_path}"


for _path in "${httpd_sys_rw_content_paths[@]}"
    set +e
    semanage fcontext -d "${_path}"
    set -e
    semanage fcontext -a -s system_u -t httpd_sys_rw_content_t "${_path}"

semodule -i takes 35 secs. loop takes 25 secs.

  • I updated my answer to include a quicker option to get what you want, including an example.
    – Edward
    Oct 5, 2021 at 7:54

1 Answer 1


You are absolutely right that semanage fcontext is slow. But then, it was never designed to be run consecutively in batch mode.

Therefore, I would advise you to create your own custom SELinux policy. For RHEL derivatives, this involves installing the policycoreutils-devel package (which in turn will tag along selinux-policy-devel).

There are two possibilities from here. The first option is quick and dirty. The second option is more laborious but will give you more power.

Option 1 - simple policy package using make

Let's say you have a directory /unixsetest containing one file named testfile, both having the default SELinux file context of default_t:

$ ls -laZ /unixsetest
drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 .
-rw-r--r--. root root unconfined_u:object_r:default_t:s0 testfile

Now, suppose you want the testfile to get file context admin_home_t and you don't want to use semanage fcontext for the reasons you stated in your question.

Create a file named unixsetest.te (type enforcement) with the following contents:

policy_module(unixsetest, 1.0)

Create a file named unixsetest.fc (file context definitions) with the following contents:

/unixsetest(/.*)?   --  gen_context(system_u:object_r:admin_home_t,s0)

Now, compile this into your custom made SELinux policy by issuing:

$ make -f /usr/share/selinux/devel/Makefile
Compiling targeted unixsetest module
/usr/bin/checkmodule:  loading policy configuration from tmp/unixsetest.tmp
/usr/bin/checkmodule:  policy configuration loaded
/usr/bin/checkmodule:  writing binary representation (version 19) to tmp/unixsetest.mod
Creating targeted unixsetest.pp policy package
rm tmp/unixsetest.mod.fc tmp/unixsetest.mod

and install it:

$ semodule -i unixsetest.pp

Confirm it's loaded:

$ semodule -l | grep unixsetest
unixsetest      1.0

Confirm the file contexts are loaded into the file context definition database:

$ semanage fcontext -l | grep admin_home_t
/root(/.*)?                                        all files          system_u:object_r:admin_home_t:s0
/unixsetest(/.*)?                                  regular file       system_u:object_r:admin_home_t:s0

(note that the first line is part of the OS base SElinux policy, and the second one is the one we added through our custom policy file)

Now, apply the file contexts using restorecon:

$ restorecon -Rv /unixsetest/
restorecon reset /unixsetest/testfile context unconfined_u:object_r:default_t:s0->unconfined_u:object_r:admin_home_t:s0

It worked:

 ls -laZ /unixsetest
drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 .
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 testfile

Option 2 - complex policy (RPM) package using sepolicy-generate toolset

You will now have access to the sepolicy-generate tool. Run man sepolicy-generate to check what it can do. It's specifically meant for RPM based installs and tightly integrates the policy installation with your package installation.

You create a policy from template by running sepolicy generate with an appropriate parameter that specifies what you want to do:

       Confined Applications

       sepolicy generate --application [-n NAME] [-u USER ]command [-w WRITE_PATH ]
       sepolicy generate --cgi [-n NAME] command [-w WRITE_PATH ]
       sepolicy generate --dbus [-n NAME] command [-w WRITE_PATH ]
       sepolicy generate --inetd [-n NAME] command [-w WRITE_PATH ]
       sepolicy generate --init [-n NAME] command [-w WRITE_PATH ]

       Confined Users

       sepolicy generate --admin_user [-r TRANSITION_ROLE] -n NAME
       sepolicy generate --confined_admin -n NAME [-a ADMIN_DOMAIN] [-u USER] [-n NAME] [-w WRITE_PATH]
       sepolicy generate --desktop_user -n NAME [-w WRITE_PATH]
       sepolicy generate --term_user -n NAME [-w WRITE_PATH]
       sepolicy generate --x_user -n NAME [-w WRITE_PATH]

       Miscellaneous Policy

       sepolicy generate --customize -d DOMAIN -n NAME [-a ADMIN_DOMAIN]
       sepolicy generate --newtype -t type -n NAME
       sepolicy generate --sandbox -n NAME

A policy package will consist of the following 5 files:

       Type Enforcing File NAME.te
       This file can be used to define all the types rules for a particular domain.

       Note: Policy generated by sepolicy generate will automatically add a permissive DOMAIN  to
       your  te  file.   When  you  are  satisfied that your policy works, you need to remove the
       permissive line from the te file to run your domain in enforcing mode.

       Interface File NAME.if
       This file defines the interfaces for the types generated in the te file, which can be used
       by other policy domains.

       File Context NAME.fc
       This file defines the default file context for the system, it takes the file types created
       in the te file and associates file paths to the types.  Tools like restorecon and RPM will
       use these paths to put down labels.

       RPM Spec File NAME_selinux.spec
       This  file  is  an  RPM  SPEC  file  that  can be used to install the SELinux policy on to
       machines and setup the labeling. The spec file also installs the interface file and a  man
       page  describing  the  policy.   You  can use sepolicy manpage -d NAME to generate the man

       Shell File NAME.sh
       This is a helper shell script to compile, install  and  fix  the  labeling  on  your  test
       system.   It  will also generate a man page based on the installed policy, and compile and
       build an RPM suitable to be installed on other machines

Of course, you would be specifically interested in the .fc files.

There are good tutorials out there that can assist you. I would specifically recommend the RH documentation at https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/using_selinux/writing-a-custom-selinux-policy_using-selinux and https://linuxconcept.com/tutorial/extending-generated-selinux-policies/.

  • thanks a lot But I cannot find any document about the Syntax of file context description especially the file type -- or -d or other
    – Wang
    May 12, 2022 at 11:34
  • at least from what I tested, the semodule install actually much slower than using semanager in a loop, 5 rules in fc file results in 35sec and loop the semanager only took 25sec :( what the hell.
    – Wang
    May 12, 2022 at 12:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .