You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

380 lines
8.0 KiB

  1. #!/bin/sh
  2. log_write() {
  3. local facility=kern.$1
  4. logger -t AppArmor -p $facility "$2"
  5. }
  6. AA_STATUS=/usr/sbin/aa-status
  7. SECURITYFS=/sys/kernel/security
  8. SFS_MOUNTPOINT="${SECURITYFS}/apparmor"
  9. PARSER=/sbin/apparmor_parser
  10. PARSER_OPTS=
  11. ADDITIONAL_PROFILE_DIR=
  12. [ -d /etc/apparmor.d ] && PROFILE_DIRS=/etc/apparmor.d ||
  13. log_write warning "Unable to find profiles: /etc/apparmor.d"
  14. [ -n "$ADDITIONAL_PROFILE_DIR" ] && [ -d "$ADDITIONAL_PROFILE_DIR" ] &&
  15. PROFILE_DIRS="$PROFILE_DIRS $ADDITIONAL_PROFILE_DIR"
  16. dir_is_empty() {
  17. [ "$(du -s $1 | cut -f 1)" -eq 0 ] && return 0 || return 1
  18. }
  19. profiles_loaded_count() {
  20. [ -f ${SFS_MOUNTPOINT}/profiles ] &&
  21. return $(cat "${SFS_MOUNTPOINT}/profiles" | wc -l) || return 0
  22. }
  23. is_profiles_loaded() {
  24. [ -f ${SFS_MOUNTPOINT}/profiles ] && {
  25. rc=$(cat "${SFS_MOUNTPOINT}/profiles" | wc -l)
  26. [ "$rc" -ne 0 ] && return 0 || return 1
  27. }
  28. return 1
  29. }
  30. is_container_with_internal_policy() {
  31. local ns_stacked_path="${SFS_MOUNTPOINT}/.ns_stacked"
  32. local ns_name_path="${SFS_MOUNTPOINT}/.ns_name"
  33. local ns_stacked
  34. local ns_name
  35. if ! [ -f "$ns_stacked_path" ] || ! [ -f "$ns_name_path" ]; then
  36. return 1
  37. fi
  38. read -r ns_stacked < "$ns_stacked_path"
  39. if [ "$ns_stacked" != "yes" ]; then
  40. return 1
  41. fi
  42. # LXD and LXC set up AppArmor namespaces starting with "lxd-" and
  43. # "lxc-", respectively. Return non-zero for all other namespace
  44. # identifiers.
  45. read -r ns_name < "$ns_name_path"
  46. if [ "${ns_name#lxd-*}" = "$ns_name" ] && \
  47. [ "${ns_name#lxc-*}" = "$ns_name" ]; then
  48. return 1
  49. fi
  50. return 0
  51. }
  52. skip_profile() {
  53. local profile="$1"
  54. if [ "${profile%.rpmnew}" != "$profile" ] || \
  55. [ "${profile%.rpmsave}" != "$profile" ] || \
  56. [ "${profile%.orig}" != "$profile" ] || \
  57. [ "${profile%.rej}" != "$profile" ] || \
  58. [ "${profile%\~}" != "$profile" ] ; then
  59. return 1
  60. fi
  61. # Silently ignore the dpkg, pacman, ipk and xbps files
  62. if [ "${profile%.dpkg-new}" != "$profile" ] || \
  63. [ "${profile%.dpkg-old}" != "$profile" ] || \
  64. [ "${profile%.dpkg-dist}" != "$profile" ] || \
  65. [ "${profile%.dpkg-bak}" != "$profile" ] || \
  66. [ "${profile%.dpkg-remove}" != "$profile" ] || \
  67. [ "${profile%.ipk}" != "$profile" ] || \
  68. [ "${profile%.ipk-new}" != "$profile" ] || \
  69. [ "${profile%.ipk-old}" != "$profile" ] || \
  70. [ "${profile%.ipk-dist}" != "$profile" ] || \
  71. [ "${profile%.ipk-bak}" != "$profile" ] || \
  72. [ "${profile%.ipk-remove}" != "$profile" ] || \
  73. [ "${profile%.pacsave}" != "$profile" ] || \
  74. [ "${profile%.pacnew}" != "$profile" ] ; then
  75. return 2
  76. fi
  77. $(echo "$profile" | grep -E -q '^.+\.new-[0-9\.]+_[0-9]+$'); [ "$?" -eq 0 ] && return 2
  78. return 0
  79. }
  80. __parse_profiles_dir() {
  81. local parser_cmd="$1"
  82. local profile_dir="$2"
  83. local status=0
  84. [ -x "$PARSER" ] || {
  85. log_write err "Unable to execute AppArmor parser"
  86. return 1
  87. }
  88. [ -d "$profile_dir" ] || {
  89. log_write warning "AppArmor profiles not found: $profile_dir"
  90. return 1
  91. }
  92. dir_is_empty "$profile_dir"; [ "$?" -eq 0 ] && {
  93. log_write err "No profiles found in $profile_dir"
  94. return 1
  95. }
  96. local nprocs=$(cat /proc/cpuinfo |grep "processor\t:"|wc -l)
  97. local rc=0
  98. local xargs_args=""
  99. [ "$nprocs" -ge 2 ] && xargs_args="--max-procs=$nprocs"
  100. "$PARSER" $PARSER_OPTS "$parser_cmd" -- "$profile_dir" || {
  101. for profile in "$profile_dir"/*; do
  102. skip_profile "$profile"
  103. skip=$?
  104. [ "$skip" -ne 0 ] && {
  105. [ "$skip" -ne 2 ] && log_write info "Skipped loading profile $profile"
  106. continue
  107. }
  108. [ -f "$profile" ] || continue
  109. echo "$profile"
  110. done | \
  111. # Use xargs to parallelize calls to the parser over all CPUs
  112. /usr/libexec/xargs-findutils -n1 -d"\n" $xargs_args \
  113. "$PARSER" $PARSER_OPTS "$parser_cmd" --
  114. [ "$?" -ne 0 ] && {
  115. rc=1
  116. log_write err "At least one profile failed to load"
  117. }
  118. }
  119. return $rc
  120. }
  121. parse_profiles() {
  122. case "$1" in
  123. load)
  124. PARSER_CMD="--add"
  125. PARSER_MSG="Loading profiles"
  126. ;;
  127. reload)
  128. PARSER_CMD="--replace"
  129. PARSER_MSG="Reloading profiles"
  130. ;;
  131. *)
  132. log_write err "Unknown parameter $1"
  133. log_write info "parse_profiles parameter must be either 'load' or 'reload'"
  134. return 1
  135. ;;
  136. esac
  137. log_write info "$PARSER_MSG"
  138. [ -w "$SFS_MOUNTPOINT/.load" ] || {
  139. log_write err "${SFS_MOUNTPOINT}/.load not writable"
  140. return 1
  141. }
  142. [ -f "$PARSER" ] || {
  143. log_write err "AppArmor parser not found"
  144. return 1
  145. }
  146. # run parser on all profiles
  147. local rc=0
  148. for profile_dir in $PROFILE_DIRS; do
  149. __parse_profiles_dir "$PARSER_CMD" "$profile_dir" || rc=$?
  150. done
  151. return $rc
  152. }
  153. is_apparmor_loaded() {
  154. is_securityfs_mounted; [ "$?" -eq 0 ] || {
  155. mount_securityfs
  156. }
  157. [ -f "${SFS_MOUNTPOINT}/profiles" ] && return 0
  158. [ -d /sys/module/apparmor ] && return 0 || return 1
  159. }
  160. is_securityfs_mounted() {
  161. [ -d "$SECURITYFS" ] && {
  162. grep -q securityfs /proc/filesystems && grep -q securityfs /proc/mounts
  163. return $?
  164. }
  165. return 1
  166. }
  167. mount_securityfs() {
  168. local rc=0
  169. grep -q securityfs /proc/filesystems; [ "$?" -eq 0 ] && {
  170. mount -t securityfs securityfs "$SECURITYFS"
  171. rc=$?
  172. [ "$rc" -eq 0 ] && log_write info "Mounting securityfs" ||
  173. log_write err "Failed to mount securityfs"
  174. }
  175. return $rc
  176. }
  177. apparmor_start() {
  178. local announced=0
  179. is_securityfs_mounted; [ "$?" -ne 0 ] && {
  180. log_write info "Starting AppArmor"
  181. announced=1
  182. mount_securityfs; [ "$?" -eq 0 ] || return $?
  183. }
  184. is_apparmor_loaded; [ "$?" -eq 0 ] || {
  185. [ "$announced" -eq 0 ] && log_write info "Starting AppArmor"
  186. announced=1
  187. log_write err "AppArmor kernel support is not present"
  188. return 1
  189. }
  190. [ -d /var/lib/apparmor ] || mkdir -p /var/lib/apparmor > /dev/null
  191. is_profiles_loaded; [ "$?" -eq 0 ] || {
  192. [ "$announced" -eq 0 ] && log_write info "Starting AppArmor"
  193. announced=1
  194. parse_profiles load
  195. return $?
  196. } || {
  197. parse_profiles reload
  198. return $?
  199. }
  200. }
  201. remove_profiles() {
  202. log_write info "Unloading profiles"
  203. is_apparmor_loaded; [ "$?" -eq 0 ] || {
  204. log_write err "AppArmor kernel support is not present"
  205. return 1
  206. }
  207. [ -w "$SFS_MOUNTPOINT/.remove" ] || {
  208. log_write err "${SFS_MOUNTPOINT}/.remove not writable"
  209. return 1
  210. }
  211. [ -x "$PARSER" ] || {
  212. log_write err "Unable to execute AppArmor parser"
  213. return 1
  214. }
  215. local rc=0
  216. sed -e "s/ (\(enforce\|complain\))$//" "$SFS_MOUNTPOINT/profiles" | \
  217. LC_COLLATE=C sort | grep -v // | {
  218. while read -r profile ; do
  219. printf "%s" "$profile" > "$SFS_MOUNTPOINT/.remove"
  220. result=$?
  221. [ "$result" -eq 0 ] || rc=$result
  222. done
  223. }
  224. return $rc
  225. }
  226. apparmor_stop() {
  227. is_apparmor_loaded; [ "$?" -eq 0 ] || return 1
  228. is_profiles_loaded; [ "$?" -eq 0 ] && {
  229. log_write info "Stopping AppArmor"
  230. remove_profiles
  231. return $?
  232. } || return 0
  233. }
  234. apparmor_restart() {
  235. is_profiles_loaded; [ "$?" -eq 0 ] || {
  236. apparmor_start
  237. return $?
  238. }
  239. is_apparmor_loaded; [ "$?" -eq 0 ] || {
  240. apparmor_start
  241. return $?
  242. }
  243. log_write info "Restarting AppArmor"
  244. parse_profiles reload
  245. return $?
  246. }
  247. apparmor_reload() {
  248. is_profiles_loaded; [ "$?" -eq 0 ] || {
  249. apparmor_start
  250. return $?
  251. }
  252. is_apparmor_loaded; [ "$?" -eq 0 ] || {
  253. apparmor_start
  254. return $?
  255. }
  256. log_write info "Reloading AppArmor"
  257. parse_profiles reload
  258. return $?
  259. }
  260. apparmor_list_profiles() {
  261. is_apparmor_loaded; [ "$?" -eq 0 ] || {
  262. echo "AppArmor kernel support is not present"
  263. return 1
  264. }
  265. [ -x "$PARSER" ] || {
  266. echo "Unable to execute AppArmor parser"
  267. return 1
  268. }
  269. # run parser on all profiles
  270. for profile_dir in $PROFILE_DIRS; do
  271. [ -d "$profile_dir" ] || {
  272. echo "AppArmor profiles not found: $profile_dir"
  273. continue
  274. }
  275. for profile in "$profile_dir"/*; do
  276. if skip_profile "$profile" && [ -f "$profile" ] ; then
  277. LIST_ADD=$("$PARSER" -N "$profile" )
  278. [ "$?" -eq 0 ] && echo "$LIST_ADD"
  279. fi
  280. done
  281. done
  282. return 0
  283. }
  284. apparmor_status() {
  285. is_apparmor_loaded; [ "$?" -eq 0 ] || {
  286. echo "AppArmor kernel support is not present"
  287. return 1
  288. }
  289. [ -x "$AA_STATUS" ] && {
  290. "$AA_STATUS" --verbose
  291. return $?
  292. }
  293. echo "AppArmor is enabled."
  294. echo "Install apparmor-utils to receive more detailed status"
  295. echo "information or examine $SFS_MOUNTPOINT directly."
  296. return 0
  297. }