#!/usr/bin/env bash # # JbTecWiz Support Centre -- generated fix script # # Fault : AppArmor is blocking an application # Fix : Add the specific permission to the profile # Source: https://jbtecwiz.com/support/lnx-sec-apparmor # # Run as : Root shell # Expect : 30 minutes # Risk : medium # Reversible : yes # # WHEN THIS IS THE RIGHT FIX # You know what is being denied. # # HOW TO UNDO IT # Remove the added lines from the local file and reload the profile. # # Walks the fix one step at a time and asks before each. Steps with no # command are yours to do -- it prints those and waits. DRYRUN=1 prints # without executing; UNATTENDED=1 does not ask. # # -------------------------------------------------------------------- # NO WARRANTY - USE AT YOUR OWN RISK # # This script is provided by JbTecWiz as-is and with no warranty of any # kind, express or implied. You run it entirely at your own risk. # # JbTecWiz accepts no liability for any loss or damage arising from its # use, including but not limited to data loss, downtime, or configuration # changes that turn out to be wrong for your system. # # You are responsible for reading this script before running it, for # satisfying yourself that it suits the machine in front of you, and for # having a working backup first. Some steps cannot be undone. # -------------------------------------------------------------------- set -uo pipefail DRYRUN="${DRYRUN:-0}" UNATTENDED="${UNATTENDED:-0}" failed=0 if [ "$(id -u)" -ne 0 ]; then echo " This fix is documented as needing root. Re-run with sudo." >&2 exit 3 fi rule() { printf "\n%s\n" "$(printf '-%.0s' $(seq 1 70))"; if [ $# -gt 0 ]; then echo "$1"; fi; } prose() { echo "$1" | fold -s -w 74 | sed "s/^/ /"; } # Returns 0 when the caller should run the command, 1 when it should not. # A manual step always returns 1 -- there is nothing for the caller to run. step() { # step [command lines...] local n="$1" dotext="$2" why="$3" mode="$4"; shift 4 rule " Step $n of 5" prose "$dotext" if [ -n "$why" ]; then echo; prose "$why"; fi if [ "$mode" = "manual" ]; then echo; echo " -> Do this yourself, then press Enter to carry on." if [ "$UNATTENDED" = "0" ] && [ "$DRYRUN" = "0" ]; then read -r _; fi return 1 fi echo; printf " %s\n" "$@"; echo if [ "$DRYRUN" = "1" ]; then echo " (dry run -- not executed)"; return 1; fi if [ "$UNATTENDED" = "0" ]; then read -r -p " Run this step? [Y]es / [S]kip / [Q]uit " a case "$a" in [Qq]*) echo " Stopped at your request."; exit 0 ;; [Ss]*) echo " Skipped."; return 1 ;; esac fi return 0 } rule echo " AppArmor is blocking an application" echo " Add the specific permission to the profile" echo echo " Risk: medium Reversible 30 minutes" echo prose 'No warranty. Use at your own risk - JbTecWiz accepts no liability. Read it before you run it, and have a backup.' rule echo if [ "$UNATTENDED" = "0" ] && [ "$DRYRUN" = "0" ]; then read -r -p " Ready? [y/N] " go case "$go" in [Yy]*) ;; *) echo " Nothing was changed."; exit 0;; esac fi if step 1 'Use the local override file so the change survives a package upgrade.' 'Editing the shipped profile works until the package updates and replaces it. The local directory is included by the main profile precisely so site changes are kept separate.' cmd 'sudo ls /etc/apparmor.d/local/'; then sudo ls /etc/apparmor.d/local/ if [ $? -ne 0 ]; then failed=$((failed+1)) echo " Step 1 failed. The rest of the fix may depend on it." >&2 fi fi if step 2 'Add the rule for the new path.' '' cmd 'echo '\''/srv/mysql/** rwk,'\'' | sudo tee -a /etc/apparmor.d/local/usr.sbin.mysqld'; then echo '/srv/mysql/** rwk,' | sudo tee -a /etc/apparmor.d/local/usr.sbin.mysqld if [ $? -ne 0 ]; then failed=$((failed+1)) echo " Step 2 failed. The rest of the fix may depend on it." >&2 fi fi if step 3 'Reload the profile.' '' cmd 'sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.mysqld'; then sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.mysqld if [ $? -ne 0 ]; then failed=$((failed+1)) echo " Step 3 failed. The rest of the fix may depend on it." >&2 fi fi if step 4 'Alternatively, use the interactive tool, which reads the denials and proposes rules.' '' cmd 'sudo aa-logprof'; then sudo aa-logprof if [ $? -ne 0 ]; then failed=$((failed+1)) echo " Step 4 failed. The rest of the fix may depend on it." >&2 fi fi if step 5 'Put the profile back into enforcing mode and re-test.' '' cmd 'sudo aa-enforce /usr/sbin/mysqld' 'sudo aa-status | grep mysqld'; then sudo aa-enforce /usr/sbin/mysqld sudo aa-status | grep mysqld if [ $? -ne 0 ]; then failed=$((failed+1)) echo " Step 5 failed. The rest of the fix may depend on it." >&2 fi fi rule " Confirm it worked" prose 'The application works with the profile enforcing and no new denials appear.' if [ "$DRYRUN" = "0" ]; then sudo aa-status | head -10 sudo dmesg -T | grep -ci 'apparmor.*DENIED' fi rule if [ "$failed" -gt 0 ]; then echo " Finished with $failed failed step(s)." echo " Read the full write-up at https://jbtecwiz.com/support/lnx-sec-apparmor" else echo " Finished." fi echo prose 'To undo: Remove the added lines from the local file and reload the profile.' rule