#!/bin/sh # ---------------------------------------------------------------------- # Copyright (c) 2017 Canonical Ltd. (All rights reserved) # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public # License published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ---------------------------------------------------------------------- APPARMOR_FUNCTIONS=/lib/apparmor/rc.apparmor.functions APPARMORFS=/sys/kernel/security/apparmor PROFILES="${APPARMORFS}/profiles" REMOVE="${APPARMORFS}/.remove" DRY_RUN=0 . $APPARMOR_FUNCTIONS usage() { local progname="$1" local rc="$2" local msg="usage: ${progname} [options] Remove profiles unknown to the system Options: -h, --help Show this help message and exit -n Dry run; don't remove profiles" if [ "$rc" -ne 0 ] ; then echo "$msg" 1>&2 else echo "$msg" fi exit "$rc" } if [ "$#" -gt 1 ] ; then usage "$0" 1 elif [ "$#" -eq 1 ] ; then if [ "$1" = "-h" -o "$1" = "--help" ] ; then usage "$0" 0 elif [ "$1" = "-n" ] ; then DRY_RUN=1 else usage "$0" 1 fi fi # We can't use a -r test here because while $PROFILES is world-readable, # apparmorfs may still return EACCES from open() # # We have to do this check because error checking awk's getline() below is # tricky and, as is, results in an infinite loop when apparmorfs returns an # error from open(). if ! IFS= read line < "$PROFILES" ; then echo "ERROR: Unable to read apparmorfs profiles file" 1>&2 exit 1 elif [ ! -w "$REMOVE" ] ; then echo "ERROR: Unable to write to apparmorfs remove file" 1>&2 exit 1 fi # Clean out running profiles not associated with the current profile # set, excluding the libvirt dynamically generated profiles. # Note that we reverse sort the list of profiles to remove to # ensure that child profiles (e.g. hats) are removed before the # parent. We *do* need to remove the child profile and not rely # on removing the parent profile when the profile has had its # child profile names changed. profiles_names_list | awk ' BEGIN { while (getline < "'${PROFILES}'" ) { str = sub(/ \((enforce|complain)\)$/, "", $0); if (match($0, /^libvirt-[0-9a-f\-]+$/) == 0) arr[$str] = $str } } { if (length(arr[$0]) > 0) { delete arr[$0] } } END { for (key in arr) if (length(arr[key]) > 0) { printf("%s\n", arr[key]) } } ' | LC_COLLATE=C sort -r | \ while IFS= read profile ; do if [ "$DRY_RUN" -ne 0 ]; then echo "Would remove '${profile}'" else echo "Removing '${profile}'" echo -n "$profile" > "${REMOVE}" fi done # will not catch all errors, but still better than nothing exit $?