summarylogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.SRCINFO16
-rw-r--r--PKGBUILD24
-rwxr-xr-xfollow_hook.py134
-rw-r--r--hook_tracking_db.txt151
-rw-r--r--relabel-selinux.hook12
-rwxr-xr-xselinux-alpm-hook85
6 files changed, 422 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO
new file mode 100644
index 000000000000..bf905b444978
--- /dev/null
+++ b/.SRCINFO
@@ -0,0 +1,16 @@
+pkgbase = selinux-alpm-hook
+ pkgdesc = SELinux ALPM hook
+ pkgver = 0.1
+ pkgrel = 1
+ url = https://github.com/archlinuxhardened/selinux
+ arch = any
+ groups = selinux
+ license = GPL
+ depends = policycoreutils
+ source = relabel-selinux.hook
+ source = selinux-alpm-hook
+ sha256sums = 4df844a89a50fe1caebe0cb92fc925b3dedf7a1a8258eef53f0dd328c1cc089e
+ sha256sums = 983695a355aeec32bd4dc16a4586f560d730e269cef3fe9aaede82ea0245862b
+
+pkgname = selinux-alpm-hook
+
diff --git a/PKGBUILD b/PKGBUILD
new file mode 100644
index 000000000000..806be4b5773c
--- /dev/null
+++ b/PKGBUILD
@@ -0,0 +1,24 @@
+# Maintainer: Nicolas Iooss (nicolas <dot> iooss <at> m4x <dot> org)
+
+pkgname=selinux-alpm-hook
+pkgver=0.1
+pkgrel=1
+pkgdesc="SELinux ALPM hook"
+arch=('any')
+url="https://github.com/archlinuxhardened/selinux"
+license=('GPL')
+groups=('selinux')
+depends=('policycoreutils')
+source=('relabel-selinux.hook'
+ 'selinux-alpm-hook')
+sha256sums=('4df844a89a50fe1caebe0cb92fc925b3dedf7a1a8258eef53f0dd328c1cc089e'
+ '983695a355aeec32bd4dc16a4586f560d730e269cef3fe9aaede82ea0245862b')
+
+package() {
+ cd "${srcdir}"
+
+ # Prefix the hook file with "zz-" so that it is run after all other hooks
+ install -D -m 644 'relabel-selinux.hook' "${pkgdir}/usr/share/libalpm/hooks/zzz-relabel-selinux.hook"
+
+ install -D -m 755 'selinux-alpm-hook' "${pkgdir}/usr/share/libalpm/scripts/selinux-alpm-hook"
+}
diff --git a/follow_hook.py b/follow_hook.py
new file mode 100755
index 000000000000..6e15fd2ee3bd
--- /dev/null
+++ b/follow_hook.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+"""Follow which hook is handled by the SELinux ALPM hook"""
+import logging
+import re
+import os.path
+import subprocess
+import sys
+
+
+ALPM_HOOK_DIR = '/usr/share/libalpm/hooks/'
+FOLLOW_DB = os.path.join(os.path.dirname(__file__), 'hook_tracking_db.txt')
+
+logger = logging.getLogger(__name__)
+
+
+def run_pacman(args):
+ """Run a pacman command and return its output"""
+ proc = subprocess.Popen(
+ ['pacman'] + args,
+ env={'LANG': 'C'},
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ output = proc.stdout.read()
+ retval = proc.wait()
+ if retval:
+ errmsg = proc.communicate()[1].decode('ascii', errors='ignore').strip()
+ logger.error("pacman error %d: %s", retval, errmsg)
+ return
+ return output.decode('ascii', errors='ignore')
+
+
+def find_package_hooks():
+ """Find all available package hooks in Arch Linux repositories
+
+ This uses the file database, which needs to be updated with "pacman -Fy"
+
+ Yield (repo/package name, hook name) tuples
+ """
+ alpm_hookdir_no_leading_slash = ALPM_HOOK_DIR.lstrip('/')
+ pkglist = run_pacman(['-Fqo', ALPM_HOOK_DIR]) or ''
+ for pkgname in pkglist.splitlines():
+ filelist = run_pacman(['-Fql', pkgname]) or ''
+ for filename in filelist.splitlines():
+ if filename.startswith(alpm_hookdir_no_leading_slash):
+ hookname = filename[len(alpm_hookdir_no_leading_slash):]
+ if hookname and hookname.endswith('.hook'):
+ yield (pkgname, hookname)
+
+
+def get_repo_version(pkgname):
+ """Get the version of the package in the repositories"""
+ # This function can be called with a "repo/pkgname" argument
+ pkgname = pkgname.split('/')[-1]
+ pkginfo = run_pacman(['-Si', pkgname]) or ''
+ for line in pkginfo.splitlines():
+ line = line.rstrip()
+ matches = re.match(r'^Version\s*:\s*(\S+)$', line, re.I)
+ if matches is not None:
+ return matches.group(1)
+ logger.error("Unable to find the version of package %s", pkgname)
+
+
+def read_pkghook_db():
+ """Read the package hook tracking database file"""
+ pkghookdb = {}
+ with open(FOLLOW_DB, 'r') as fdb:
+ for line in fdb:
+ line = line.strip()
+ if not line or line.startswith('#'):
+ continue
+ try:
+ pkg, ver, hook = line.split()
+ except ValueError:
+ # Ignore invalid lines
+ logger.warning("Invalid line in tracking database: %r", line)
+ continue
+ else:
+ pkghookdb[(pkg, hook)] = ver
+ return pkghookdb
+
+
+def main():
+ current_pkghook_db = read_pkghook_db()
+ everything_ok = True
+ for pkg, hook in find_package_hooks():
+ # Get the versions in the package repositories
+ last_ver = get_repo_version(pkg)
+ if last_ver is None:
+ everything_ok = False
+ continue
+ # ... and in the tracking database
+ cur_ver = current_pkghook_db.get((pkg, hook))
+
+ if last_ver == cur_ver:
+ logger.info("OK %s %s %s", pkg, cur_ver, hook)
+ continue
+ everything_ok = False
+ if cur_ver is None:
+ logger.info("New hook:")
+ else:
+ logger.info("Upgrade needed for %s: %s -> %s",
+ pkg, cur_ver, last_ver)
+ logger.info(" DB line: %s %s %s", pkg, last_ver, hook)
+ hookfile = os.path.join(ALPM_HOOK_DIR, hook)
+ logger.info(" File: %s", hookfile)
+ # Try to find the Exec line in the file
+ if os.path.exists(hookfile):
+ exec_lines = []
+ target_lines = []
+ need_target = False
+ with open(hookfile, 'r') as fhook:
+ for line in fhook:
+ line = line.rstrip()
+ if line.startswith('Exec'):
+ exec_lines.append(line)
+ elif line.startswith('Target'):
+ target_lines.append(line)
+ elif line.startswith('NeedsTargets'):
+ need_target = True
+ # Show Target lines if NeedsTargets was found
+ if need_target:
+ for line in target_lines:
+ logger.info(" # %s", line)
+ for line in exec_lines:
+ logger.info(" # %s", line)
+ if everything_ok:
+ logger.info("Remember to run sudo pacman -Fy to update pacman db")
+ return 0
+
+
+if __name__ == '__main__':
+ logging.basicConfig(
+ format='[%(levelname)s] %(message)s',
+ level=logging.DEBUG)
+ sys.exit(main())
diff --git a/hook_tracking_db.txt b/hook_tracking_db.txt
new file mode 100644
index 000000000000..5ad840f63041
--- /dev/null
+++ b/hook_tracking_db.txt
@@ -0,0 +1,151 @@
+# Track which hook is handled by SELinux ALPM hook
+# Format: repo/pkgname pkgver hookname
+
+# Exec = /usr/bin/update-ca-trust
+core/ca-certificates-utils 20170307-1 update-ca-trust.hook
+
+# Exec=/usr/bin/gio-querymodules /usr/lib/gio/modules
+core/glib2 2.50.3-1 gio-querymodules.hook
+
+# Exec = /usr/bin/glib-compile-schemas /usr/share/glib-2.0/schemas
+core/glib2 2.50.3-1 glib-compile-schemas.hook
+
+# Exec = /usr/bin/mkinitcpio -p linux
+core/linux 4.10.10-1 90-linux.hook
+
+# Exec = /usr/bin/mkinitcpio -p linux-lts
+core/linux-lts 4.9.22-1 90-linux-lts.hook
+
+# Exec = /usr/bin/systemd-hwdb --usr update
+core/systemd 232-8 systemd-hwdb.hook
+
+# Target = usr/lib/sysusers.d/*.conf
+# Exec = /bin/sh -c 'while read -r f; do /usr/bin/systemd-sysusers "/$f" ; done'
+core/systemd 232-8 systemd-sysusers.hook
+
+# Target = usr/lib/tmpfiles.d/*.conf
+# Exec = /bin/sh -c 'while read -r f; do /usr/bin/systemd-tmpfiles --create "/$f"; done'
+core/systemd 232-8 systemd-tmpfiles.hook
+
+# Exec = /usr/bin/touch -c /usr
+core/systemd 232-8 systemd-update.hook
+
+# Target = usr/share/info/*
+# Exec = /bin/sh -c 'while read -r f; do install-info "$f" /usr/share/info/dir 2> /dev/null; done
+core/texinfo 6.3-1 texinfo-install.hook
+
+# Target = usr/share/info/*
+# Exec = /bin/sh -c 'while read -r f; do install-info --delete "$f" /usr/share/info/dir 2> /dev/null; done'
+core/texinfo 6.3-1 texinfo-remove.hook
+
+# Exec = /usr/bin/appstreamcli refresh-index --force
+extra/appstream 0.10.6-1 update-appstream-index.hook
+
+# Exec = /usr/bin/update-desktop-database --quiet
+extra/desktop-file-utils 0.23-1 update-desktop-database.hook
+
+# Exec = /usr/lib/dkms/alpm-hook install
+extra/dkms 2.3-2 70-dkms-install.hook
+
+# Exec = /usr/bin/perl -e "$SIG{PIPE}='DEFAULT'; exec('/usr/lib/dkms/alpm-hook', 'remove');
+extra/dkms 2.3-2 70-dkms-remove.hook
+
+# Exec = /usr/bin/fc-cache -s
+extra/fontconfig 2.12.1-4 fontconfig.hook
+
+# Target = usr/share/gconf/schemas/*.schemas
+# Exec = /bin/bash -c 'while read -r f; do f=$(basename "$f" .schemas); /usr/bin/gconfpkg --install $f; done'
+extra/gconf 3.2.6-5 gconf-install.hook
+
+# Exec = /bin/bash -c 'while read -r f; do f=$(basename "$f" .schemas); /usr/bin/gconfpkg --uninstall $f; done'
+extra/gconf 3.2.6-5 gconf-remove.hook
+
+# Exec = /usr/bin/gdk-pixbuf-query-loaders --update-cache
+extra/gdk-pixbuf2 2.36.5-1 gdk-pixbuf-query-loaders.hook
+
+# Target = usr/share/icons/*/
+# Target = !usr/share/icons/*/?*
+# Exec = /usr/share/libalpm/scripts/gtk-update-icon-cache
+extra/gtk-update-icon-cache 3.22.10-1 gtk-update-icon-cache.hook
+
+# Exec = /usr/bin/gtk-query-immodules-2.0 --update-cache
+extra/gtk2 2.24.31-1 gtk-query-immodules-2.0.hook
+
+# Exec = /usr/bin/gtk-query-immodules-3.0 --update-cache
+extra/gtk3 3.22.10-1 gtk-query-immodules-3.0.hook
+
+# Exec = /bin/sh -c 'killall -q -s USR1 gvfsd || true'
+extra/gvfs 1.30.3+4+gd79b4650-1 gvfsd.hook
+
+# Exec = /usr/bin/mkinitcpio -p linux-zen
+extra/linux-zen 4.10.10-1 90-linux-zen.hook
+
+# Exec = /usr/bin/update-mime-database /usr/share/mime
+extra/shared-mime-info 1.8-1 update-mime-database.hook
+
+# Exec = /usr/share/libalpm/scripts/mktexlsr
+extra/texlive-bin 2016.41290-10 mktexlsr.hook
+
+# Exec = /usr/share/libalpm/scripts/texlive-fmtutil
+extra/texlive-bin 2016.41290-10 texlive-fmtutil.hook
+
+# Exec = /usr/share/libalpm/scripts/texlive-updmap
+extra/texlive-bin 2016.41290-10 texlive-updmap.hook
+
+# Exec = /usr/bin/vim -es --cmd ":helptags /usr/share/vim/vimfiles/doc" --cmd ":q"
+extra/vim-runtime 8.0.0427-1 vimdoc.hook
+
+# Exec = /usr/lib/vlc/vlc-cache-gen -f /usr/lib/vlc/plugins
+extra/vlc 2.2.4-8 update-vlc-plugin-cache.hook
+
+# Target = usr/share/fonts/*/
+# Target = !usr/share/fonts/encodings/*
+# Exec = /usr/share/libalpm/scripts/xorg-mkfontdir
+extra/xorg-mkfontdir 1.0.7-8 xorg-mkfontdir.hook
+
+# Exec = /usr/bin/etckeeper pre-install
+community/etckeeper 1.18.6-1 05-etckeeper-pre-install.hook
+
+# Exec = /usr/bin/etckeeper post-install
+community/etckeeper 1.18.6-1 zz-etckeeper-post-install.hook
+
+# Exec = /bin/bash -c "cd /usr/share/doc/ghc/html/libraries && ./gen_contents_index"
+community/ghc 8.0.1-1 ghc-rebuild-doc-index.hook
+
+# Target = usr/share/haskell/register/*.sh
+# Exec = /bin/sh -c 'while read -r f; do /bin/sh "/$f" ; done'
+community/ghc 8.0.1-1 ghc-register.hook
+
+# Target = usr/share/haskell/unregister/*.sh
+# Exec = /bin/sh -c 'while read -r f; do /bin/sh "/$f" ; done'
+community/ghc 8.0.1-1 ghc-unregister.hook
+
+# Exec = /usr/bin/mkinitcpio -p linux-grsec
+community/linux-grsec 1:4.9.22.r201704120836-1 99-linux-grsec.hook
+
+# Exec = /usr/share/libalpm/scripts/snap-pac pre
+community/snap-pac 1.1-1 00_snapper-pre.hook
+
+# Exec = /usr/bin/bash -c "rm -f /tmp/snap-pac-pre_*"
+community/snap-pac 1.1-1 10_snap-pac-removal.hook
+
+# Exec = /usr/share/libalpm/scripts/snap-pac post
+community/snap-pac 1.1-1 zy_snapper-post.hook
+
+# Exec = /usr/bin/true
+community/snap-pac 1.1-1 zz_snap-pac-install.hook
+
+# Exec = /bin/cp -f /etc/trusted-key.key /etc/unbound/
+community/unbound 1.6.1-3 unbound-key.hook
+
+# Exec = /usr/bin/fc-cache-32 -s
+multilib/lib32-fontconfig 2.12.1-4 lib32-fontconfig.hook
+
+# Exec = /usr/bin/gdk-pixbuf-query-loaders-32 --update-cache
+multilib/lib32-gdk-pixbuf2 2.36.2-2 gdk-pixbuf-query-loaders-32.hook
+
+# Exec = /usr/bin/gio-querymodules-32 /usr/lib32/gio/module
+multilib/lib32-glib2 2.50.1-2 gio-querymodules-32.hook
+
+# Exec = /bin/sh -c "GTK_PATH=/usr/lib32/gtk-3.0 /usr/bin/gtk-query-immodules-3.0-32 --update-cache"
+multilib/lib32-gtk3 3.22.7-1 gtk-query-immodules-3.0-32.hook
diff --git a/relabel-selinux.hook b/relabel-selinux.hook
new file mode 100644
index 000000000000..451a23aaf6ab
--- /dev/null
+++ b/relabel-selinux.hook
@@ -0,0 +1,12 @@
+[Trigger]
+Operation = Install
+Operation = Upgrade
+Type = File
+Target = *
+
+[Action]
+Description = SELinux: relabel installed files
+Depends = policycoreutils
+When = PostTransaction
+Exec = /usr/share/libalpm/scripts/selinux-alpm-hook
+NeedsTargets
diff --git a/selinux-alpm-hook b/selinux-alpm-hook
new file mode 100755
index 000000000000..3d7ac26d1dfa
--- /dev/null
+++ b/selinux-alpm-hook
@@ -0,0 +1,85 @@
+#!/bin/bash
+# SELinux ALPM hook
+# Relabel installed files after an install or an update
+
+# Define a function to print an error mesage and exit
+die() {
+ echo >&2 "$@"
+ exit 1
+}
+
+# Verify that the hook is running with / as current working directory
+if [ "$(pwd)" != '/' ]; then
+ die 'Hook is being executed outside of root directory. Aborting.'
+fi
+
+# Do not do anything if SELinux is disabled
+if sestatus | grep '^SELinux status:\s*disabled' > /dev/null; then
+ exit 0
+fi
+
+# Read package files from stdin, as restorecon may error out on any non-existing file
+echo 'Relabeling package files...'
+while read -r FILE; do
+ if [ -e "$FILE" ] || [ -L "$FILE" ] ; then
+ /usr/bin/restorecon -F "$FILE" || die "Error while relabeling $FILE"
+ else
+ # Only show a warning when a file does not exist as this is not fatal
+ echo "Ugh, an installed file does not exist: $FILE"
+ fi
+done
+
+# The install hooks of packages create files which got labelled with the wrong SELinux user
+# (e.g. sysadm_u instead of system_u). Relabel all these files too.
+# Check the order of this list with: sed -n '/^GEN_DIRS=/,/^)/{/^ /p}' |LANG=C sort -c
+echo 'Relabeling generated directories...'
+GEN_DIRS=(
+ '/boot/' # linux:99-linux.hook
+ '/etc/ca-certificates/extracted/' # ca-certificates-utils:update-ca-trust.hook
+ '/etc/gconf/' # gconf:gconf-install.hook
+ '/etc/ld.so.cache' # glibc install: ldconfig -r .
+ '/etc/pacman.d/gnupg/' # archlinux-keyring install: pacman-key --populate archlinux
+ '/etc/ssl/certs/' # ca-certificates-utils:update-ca-trust.hook
+ '/etc/texmf/ls-R' # texlive-bin install: mktexlsr
+ '/etc/udev/hwdb.bin' # systemd:udev-hwdb.hook
+ '/etc/unbound/trusted-key.key' # unbound:unbound-key.hook
+ '/usr/lib/gdk-pixbuf-*/*/loaders.cache' # gdk-pixbuf2:gdk-pixbuf-query-loaders.hook
+ '/usr/lib/ghc-*/package.conf.d/' # ghc:ghc-register.hook, ghc:ghc-unregister.hook
+ '/usr/lib/gio/modules/' # glib2:gio-querymodules.hook
+ '/usr/lib/graphviz/' # graphviz install: dot -c
+ '/usr/lib/gtk-2.0/' # gtk2:gtk-query-immodules-2.0.hook
+ '/usr/lib/gtk-3.0/' # gtk3:gtk-query-immodules-3.0.hook
+ '/usr/lib/locale/locale-archive' # glibc install: locale-gen
+ '/usr/lib/modules/' # dkms:70-dkms-install.hook
+ '/usr/lib/vlc/plugins/plugins.dat' # vlc:update-vlc-plugin-cache.hook
+ '/usr/lib32/gdk-pixbuf-*/*/loaders.cache' # lib32-gdk-pixbuf2 install: gdk-pixbuf-query-loaders-32 --update-cache
+ '/usr/lib32/gio/modules/' # lib32-glib2:gio-querymodules-32.hook
+ '/usr/lib32/gtk-3.0/' # lib32-gtk3:gtk-query-immodules-3.0-32.hook
+ '/usr/share/.mono/certs' # mono install: cert-sync /etc/ssl/certs/ca-certificates.crt
+ '/usr/share/applications/mimeinfo.cache' # desktop-file-utils:update-desktop-database.hook
+ '/usr/share/doc/ghc/html/libraries/' # ghc:ghc-rebuild-doc-index.hook
+ '/usr/share/fonts/' # xorg-mkfontdir:xorg-mkfontdir.hook
+ '/usr/share/glib-2.0/schemas/' # glib2:glib-compile-schemes.hook
+ '/usr/share/icons/' # gtk-update-icon-cache:gtk-update-icon-cache.hook
+ '/usr/share/info/dir' # texinfo:texinfo-install.hook
+ '/usr/share/mime/' # shared-mime-info:update-mime-database.hook
+ '/usr/share/texmf*/ls-R' # texlive-bin:mktexlsr.hook
+ '/usr/share/vim/vimfiles/doc/tags' # vim-runtime:vimdoc.hook
+ '/var/cache/fontconfig/' # fontconfig:fontconfig.hook
+ '/var/cache/ldconfig/' # glibc install: ldconfig -r .
+ '/var/cache/man/' # man-db timer
+ '/var/cache/pacman/' # pacman
+ '/var/lib/dkms/' # dkms:70-dkms-install.hook
+ '/var/lib/pacman/' # pacman
+ '/var/lib/systemd/catalog/database' # systemd install: journalctl --update-catalog
+ '/var/lib/texmf/' # texlive-bin:mktexlsr.hook
+)
+
+# Do NOT put quotes around the array, so that wildcards get expanded
+# shellcheck disable=SC2068
+for DIR in ${GEN_DIRS[@]}; do
+ # Only relabel directories which exist
+ if [ -e "$DIR" ]; then
+ /usr/bin/restorecon -RF "$DIR" || die "Error while relabeling generated directories"
+ fi
+done