diff mbox series

[meta-selinux,wrynose] package-labeling: Add postinst command for labeling

Message ID 20260807131529.422685-1-yannik.tannhaeuser@gmail.com
State New
Headers show
Series [meta-selinux,wrynose] package-labeling: Add postinst command for labeling | expand

Commit Message

Yannik Tannhaeuser Aug. 7, 2026, 1:15 p.m. UTC
Files inside packages are not labeled if you are adding SELinux
to the DISTRO_FEATURES.

If SELinux is enabled and further packages are installed on the
target, these files don't have an SELinux label.
For labeling the files after installation each package gets
a postinst script which labels the files after installation
using restorecon. restorecon accesses the current loaded
policy's file context.

For adding the postinst instructions, an additional task is
appended to each recipe which holds "class-target" in its
OVERRIDES variable.

Signed-off-by: Yannik Tannhaeuser <yannik.tannhaeuser@gmail.com>
---
 README                                   |  4 ++
 classes/selinux-package-labeling.bbclass | 76 ++++++++++++++++++++++++
 2 files changed, 80 insertions(+)
 create mode 100644 classes/selinux-package-labeling.bbclass
diff mbox series

Patch

diff --git a/README b/README
index ae011f3..232da2b 100644
--- a/README
+++ b/README
@@ -46,6 +46,10 @@  to be tailored for your environment.
 * Enable the refpolicy-mls:
 e.g. PREFERRED_PROVIDER_virtual/refpolicy ?= "refpolicy-mls"
 
+In order to activate the labeling mechanism for packages you have to add
+'selinux-package-labeling' to the INHERIT variable in your local.conf.
+e.g. INHERIT += "selinux-package-labeling"
+
 
 Using different init manager
 ----------------------------
diff --git a/classes/selinux-package-labeling.bbclass b/classes/selinux-package-labeling.bbclass
new file mode 100644
index 0000000..0edc284
--- /dev/null
+++ b/classes/selinux-package-labeling.bbclass
@@ -0,0 +1,76 @@ 
+def get_installed_folders_and_files(folder):
+    folders_and_files = []
+    if folder[-1] == "/":
+        # remove trailing slash, so it won't be removed later
+        folder = folder[:-1]
+    for walkroot, _, _files in os.walk(folder):
+        if walkroot == folder:
+            # The root folder should never be labeled when installing a package
+            continue
+        folders_and_files.append(walkroot.replace(folder, ""))
+        for file in _files:
+            folders_and_files.append(os.path.join(walkroot, file).replace(folder, ""))
+
+    return folders_and_files
+
+
+def get_installed_items(d, pkg):
+    pkgdest = d.getVar('PKGDEST')
+    pkg_folder = os.path.join(pkgdest, pkg)
+    retval = get_installed_folders_and_files(pkg_folder)
+
+    return retval
+
+
+python do_add_labels_in_postinst() {
+    packages = d.getVar('PACKAGES')
+    for pkg in packages.split():
+        # get the files inside the package
+        items = get_installed_items(d, pkg)
+
+        if not items:
+            continue
+
+        postinst = d.getVar('pkg_postinst:%s' % pkg)
+
+        # Circular dependencies in postscript happen, if two recipes depends on
+        # each other and both have a postinst script. As we label the newly installed files
+        # in the postinst script, we can ignore these circular dependencies if only one
+        # of the pkg have a postinst script. The check takes place in
+        # rootfs.py:_get_delayed_postinsts_common
+        if d.getVar("IGNORE_POSTINST_CIRCULAR_DEPENDENCY_{}".format(pkg)) and postinst:
+             bb.fatal("Circular dependency shall be ignored, but postinst script is given")
+
+        # Create the postinst script, which uses restorecon (busybox-util) for labeling
+        # add an empty line so that we don't append on a existing line.
+        relabel_command = d.getVar("PKG_RESTORECON")
+        postinst_labeling_command = "\t\t\techo -e \"{}\" | " \
+            "{}\n".format("\n".join(sorted(items)), relabel_command)
+
+        if not postinst:
+            postinst = '#!/bin/sh'
+        postinst += "\nif [ x\"$D\" = \"x\" ]; then\n"
+        postinst += "\tif command -v selinuxenabled > /dev/null 2>&1; then\n"
+        postinst += "\t\tif selinuxenabled; then\n"
+        postinst += postinst_labeling_command
+        postinst += "\t\tfi\n"
+        postinst += "\tfi\n"
+        postinst += "fi\n"
+
+        d.setVar('pkg_postinst:' + pkg, postinst)
+}
+
+# The restorecon binary gets the paths via stdin
+PKG_RESTORECON ?= "/sbin/restorecon -i -f -"
+
+python () {
+    if not bb.utils.contains('DISTRO_FEATURES', 'selinux', True, False, d):
+        # Only add the postinst label command if selinux is enabled
+        return
+
+    if bb.data.inherits_class('packagegroup', d):
+        return
+
+    if "class-target" in d.getVar("OVERRIDES").split(":"):
+        d.appendVar("PACKAGE_POSTPROCESS_FUNCS", "do_add_labels_in_postinst")
+}