Joel Galenson | c432731 | 2018-08-31 13:41:37 -0700 | [diff] [blame] | 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 | |
| 10 | if [[ $# -lt 1 ]]; then |
| 11 | echo "Usage: $0 <sepolicy source path> [serial]" |
| 12 | exit |
| 13 | fi |
| 14 | |
| 15 | sedir=$1 |
| 16 | shift |
| 17 | |
| 18 | adb_cmd="adb" |
| 19 | if [[ $# -eq 1 ]]; then |
| 20 | adb_cmd="$adb_cmd -s $1" |
| 21 | shift |
| 22 | fi |
| 23 | |
| 24 | $adb_cmd shell id &>/dev/null |
| 25 | if [[ $? -ne 0 ]]; then |
| 26 | echo "Please plug in a device and/or specify a serial" |
| 27 | adb devices |
| 28 | exit |
| 29 | fi |
| 30 | |
| 31 | echo "Warning: this file uses heuristics, so all of its outputs are not necessarily errors." |
| 32 | echo "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 | |
| 34 | echo |
| 35 | echo "Scanning for labels that are not assigned to any files." |
| 36 | # Find all types. |
| 37 | grep -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 |
| 43 | done |
| 44 | |
| 45 | echo |
| 46 | echo "Scanning for executables that don't exist." |
| 47 | # Find executable types. |
| 48 | grep -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 |
| 59 | done |
| 60 | |
| 61 | echo |
| 62 | echo "Scanning genfs_contexts for files that don't exist." |
| 63 | # Find files in genfs_contexts. |
| 64 | find $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 |
| 75 | done |
| 76 | |
| 77 | echo |
| 78 | echo "Scanning file_contexts for files that don't exist." |
| 79 | # Find files in file_contexts. |
| 80 | find $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 |
| 94 | done |
| 95 | |
| 96 | echo |
| 97 | echo "Scanning for rules that are defined in the wrong file." |
| 98 | echo "That is, rules that do not contain the name of the file." |
| 99 | # Find .te files. |
| 100 | find $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 |
| 109 | done |
| 110 | |
| 111 | echo |
| 112 | echo "Scanning for rules that use the wrong file/dir macros." |
| 113 | grep -r ":file.*_dir_perms" --exclude=\*_macros $sedir |
| 114 | grep -r ":dir.*_file_perms" --exclude=\*_macros $sedir |