The information on this page is largely derived, with necessary modifications, from Creating and enforcing an SELinux policy for a custom application.
Prerequisites
dnf -y install selinux-policy-devel setroubleshoot-server dnf -y group install 'Development Tools' # needed for at least g++ and rpmbuild. Not sure if anything else is needed from this group.
Become root
All of this documentation is to be completed as root.
Creating the service
Create mydaemon.cpp
cat > mydaemon.cpp << EOF #include <iostream> #include <fstream> #include <chrono> #include <ctime> #include <thread> using namespace std; int main() { while (1) { time_t t = chrono::system_clock::to_time_t(chrono::system_clock::now()); ofstream MyFile("/var/log/mydaemon.log", ios_base::app); // app = append, not overwrite MyFile << ctime(&t); MyFile.close(); this_thread::sleep_for(chrono::milliseconds(5000)); } } EOF
Build it
g++ -o /usr/local/bin/mydaemon mydaemon.cpp
Create the systemd unit
cat > /etc/systemd/system/mydaemon.service << EOF [Unit] Description=Simple testing daemon [Service] Type=simple ExecStart=/usr/local/bin/mydaemon [Install] WantedBy=multi-user.target EOF
By default, the unit file has selinux context that systemd cannot access, so fix that and load it:
restorecon /usr/lib/systemd/system/mydaemon.service systemctl daemon-reload
Try to start the service. Notice it fails.
systemctl start mydaemon systemctl status mydaemon
Notice that it's running in unconfined_t
ps -efZ | grep mydaemon
Generate a custom policy for the daemon:
mkdir ~/mydaemon-sepolicy cd ~/mydaemon-sepolicy sepolicy generate --init /usr/local/bin/mydaemon Created the following files: /root/mydaemon-sepolicy/mydaemon.te # Type Enforcement file /root/mydaemon-sepolicy/mydaemon.if # Interface file /root/mydaemon-sepolicy/mydaemon.fc # File Contexts file /root/mydaemon-sepolicy/mydaemon_selinux.spec # Spec file /root/mydaemon-sepolicy/mydaemon.sh # Setup Script
Build it
./mydaemon.sh
Note that the setup script relabels the daemon to the newly created domain mydaemon_exec_t
ls -lZ /usr/local/bin/mydaemon -rwxr-xr-x. 1 root root system_u:object_r:mydaemon_exec_t:s0 24504 Dec 1 15:24 /usr/local/bin/mydaemon
Temporarily set selinux to permissive and clear the audit log
setenforce 0 semodule --reload
Restart the daemon, and check that it now runs confined by SELinux:
systemctl restart mydaemon ps -efZ | grep mydaemon
For your information. (Just get a look at what selinux would have blocked.)
sealert -l "*"
Build whatever new policy you need
mkdir ~/mydaemon-sepolicy2 cd ~/mydaemon-sepolicy2 # Make up a meaningful name for the module, such as "httpdwritehomes" export newmod=mydaemonwritefiles audit2allow -m $newmod -l -i /var/log/audit/audit.log > $newmod.te # Edit the $newmod.te file and verify that it looks like what you want. # Finally, to build & install the new module: checkmodule -M -m -o $newmod.mod $newmod.te semodule_package -o $newmod.pp -m $newmod.mod semodule -i $newmod.pp
Re-enable selinux, restart the daemon, confirm that it’s working properly
setenforce 1 systemctl stop mydaemon ps -eZ | grep mydaemon # Confirm it's not running rm -f /var/log/mydaemon.log systemctl start mydaemon ps -eZ | grep mydaemon # Confirm it's running, and confined by selinux under mydaemon_t system_u:system_r:mydaemon_t:s0 54205 ? 00:00:00 mydaemon # Confirm it's successfully writing cat /var/log/mydaemon.log