1#!/bin/bash 2 3# This script uses some heuristics to suggest potential ways to clean up SELinux policy. 4# As these are heuristics, not everything it outputs is an error. 5# It is better to run this on device-specific policy rather than core policy. 6# It requires a device connected to adb. 7# Usage: 8# ./sepolicy_cleanup_check.sh <sepolicy source path> [serial] 9 10if [[ $# -lt 1 ]]; then 11 echo "Usage: $0 <sepolicy source path> [serial]" 12 exit 13fi 14 15sedir=$1 16shift 17 18adb_cmd="adb" 19if [[ $# -eq 1 ]]; then 20 adb_cmd="$adb_cmd -s $1" 21 shift 22fi 23 24$adb_cmd shell id &>/dev/null 25if [[ $? -ne 0 ]]; then 26 echo "Please plug in a device and/or specify a serial" 27 adb devices 28 exit 29fi 30 31echo "Warning: this file uses heuristics, so all of its outputs are not necessarily errors." 32echo "For example, when run on core policy, it will likely find many things that do not exist on a given device but might exist on others." 33 34echo 35echo "Scanning for labels that are not assigned to any files." 36# Find all types. 37grep -r "^type " --exclude=\*.go $sedir --exclude=\*_macros | sed 's/^.*:.*type \([^,]*\)*.*$/\1/' | sort | uniq | while read -r type; do 38 # Find types that are not referenced in *_contexts. 39 if [[ `find $sedir -name "*_contexts" -not -path "*prebuilts*" -exec grep $type '{}' \; |wc -l` -eq 0 ]]; then 40 echo "None for $type" 41 grep -r $type --exclude-dir=prebuilts --exclude=\*.cil $sedir 42 fi 43done 44 45echo 46echo "Scanning for executables that don't exist." 47# Find executable types. 48grep -r "^type .*exec_type" --exclude=\*.go $sedir | sed 's/^.*:.*type \([^,]*\)*.*$/\1/' | sort | uniq | while read -r type; do 49 path_line=`grep -r $type --include=\*_contexts $sedir` 50 # Note that this only examines one entry, even if multiple executables have the same label. 51 # But the file_contexts scan below covers that case. 52 path=`echo $path_line | sed 's/^.*:[^\/]*\([^ ]*\) .*$/\1/'` 53 # Replace character classes and + with *. 54 path=`echo $path | sed 's/\[[^]]*\]/*/' | sed 's/+/*/'` 55 # Check whether the file exists. 56 if [ -n "`$adb_cmd shell ls -lZ $path < /dev/null |& grep "No such file or directory"`" ]; then 57 echo "$path does not exist" 58 fi 59done 60 61echo 62echo "Scanning genfs_contexts for files that don't exist." 63# Find files in genfs_contexts. 64find $sedir -name genfs_contexts -exec grep "^genfscon " '{}' \; | cut -d' ' -f2,3 | sort | uniq | while read -r file_line; do 65 # Extract the full path. 66 path=`echo $file_line | sed 's/rootfs //' | sed 's/sysfs /\/sys/' | sed 's/proc /\/proc/' | sed 's/debugfs /\/sys\/kernel\/debug/' | sed 's/tracefs /\/sys\/kernel\/debug\/tracing/'` 67 # Skip things whose prefix we don't recognize. 68 if [[ $path = *" "* ]]; then 69 continue 70 fi 71 # Check whether the file exists. 72 if [ -n "`$adb_cmd shell ls -lZ $path < /dev/null |& grep "No such file or directory"`" ]; then 73 echo "$path does not exist" 74 fi 75done 76 77echo 78echo "Scanning file_contexts for files that don't exist." 79# Find files in file_contexts. 80find $sedir -name file_contexts -not -path "*prebuilts*" -exec grep "^/" '{}' \; | cut -d' ' -f1 | cut -f1 | sort | uniq | while read -r path; do 81 # Replace (/.*)? with * 82 # Replace (64)? with ?? 83 # Replace (vendor|system/vendor) with /vendor 84 # Replace character classes and + with *. 85 # Replace captures. 86 # Replace \. with . 87 # Replace .* with * 88 # Replace ** with * 89 path=`echo "$path" | sed 's/(\/\.\*)?$//' | sed 's/(64)?/??/' | sed 's/\(vendor|system\/vendor\)/vendor/' | sed 's/\[[^]]*\]/*/' | sed 's/+/*/' | sed 's/(\([^)]*\))/\1/' | sed 's/\\\././g' | sed 's/\.\*/\*/g' | sed 's/\*\*/\*/g'` 90 # Check whether the file exists. 91 if [ -n "`$adb_cmd shell ls -lZ "$path" < /dev/null |& grep "No such file or directory"`" ]; then 92 echo "$path does not exist" 93 fi 94done 95 96echo 97echo "Scanning for rules that are defined in the wrong file." 98echo "That is, rules that do not contain the name of the file." 99# Find .te files. 100find $sedir -name "*.te" -not -path "*prebuilts*" | while read -r file; do 101 filename=`basename $file` 102 filename="${filename%.*}" 103 # Look for lines that don't have the filename in them. 104 lines=$(grep "^[^# }']" $file | grep -v $filename | grep -v "^userdebug_or_eng(\`$" | grep -v "^type " | grep "[,)]" | grep -v "^define(") 105 if [[ -n "$lines" ]]; then 106 echo "$file:" 107 echo "$lines" 108 fi 109done 110 111echo 112echo "Scanning for labels in file_contexts that do not escape '.' properly." 113find $sedir -name file_contexts -not -path "*prebuilts*" -exec grep -H "^[^#].*[^\\]\.[^*]" '{}' \; 114 115echo 116echo "Scanning for rules that use the wrong file/dir macros." 117grep -r ":file.*_dir_perms" --exclude=\*_macros $sedir 118grep -r ":dir.*_file_perms" --exclude=\*_macros $sedir 119