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
page.
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/.