1# Copyright 2021 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15from os.path import basename 16import re 17import sys 18 19# A very limited parser whose job is to process the compatibility mapping 20# files and retrieve type and attribute information until proper support is 21# built into libsepol 22 23class MiniCilParser: 24 def __init__(self, policyFile): 25 self.types = set() # types declared in mapping 26 self.pubtypes = set() 27 self.expandtypeattributes = {} 28 self.typeattributes = set() # attributes declared in mapping 29 self.typeattributesets = {} # sets defined in mapping 30 self.rTypeattributesets = {} # reverse mapping of above sets 31 self.apiLevel = None 32 33 with open(policyFile, 'r') as infile: 34 s = self._getNextStmt(infile) 35 while s: 36 self._parseStmt(s) 37 s = self._getNextStmt(infile) 38 fn = basename(policyFile) 39 m = re.match(r"(\d+\.\d+).+\.cil", fn) 40 if m: 41 self.apiLevel = m.group(1) 42 43 def unparse(self): 44 def wrapParens(stmt): 45 return "(" + stmt + ")" 46 47 def joinWrapParens(entries): 48 return wrapParens(" ".join(entries)) 49 50 result = "" 51 for ty in sorted(self.types): 52 result += joinWrapParens(["type", ty]) + "\n" 53 54 for ta in sorted(self.typeattributes): 55 result += joinWrapParens(["typeattribute", ta]) + "\n" 56 57 for eta in sorted(self.expandtypeattributes.items(), 58 key=lambda x: x[0]): 59 result += joinWrapParens( 60 ["expandtypeattribute", wrapParens(eta[0]), eta[1]]) + "\n" 61 62 for tas in sorted(self.typeattributesets.items(), key=lambda x: x[0]): 63 result += joinWrapParens( 64 ["typeattributeset", tas[0], 65 joinWrapParens(sorted(tas[1]))]) + "\n" 66 67 return result 68 69 def _getNextStmt(self, infile): 70 parens = 0 71 s = "" 72 c = infile.read(1) 73 # get to first statement 74 while c: 75 if c == ';': 76 # comment, get rid of rest of the line 77 while c != '\n': 78 c = infile.read(1) 79 elif c == '(': 80 break 81 c = infile.read(1) 82 83 parens += 1 84 c = infile.read(1) 85 while c and parens != 0: 86 s += c 87 c = infile.read(1) 88 if c == ';': 89 # comment, get rid of rest of the line 90 while c != '\n': 91 c = infile.read(1) 92 elif c == '(': 93 parens += 1 94 elif c == ')': 95 parens -= 1 96 return s 97 98 def _parseType(self, stmt): 99 m = re.match(r"type\s+(.+)", stmt) 100 self.types.add(m.group(1)) 101 return 102 103 def _parseExpandtypeattribute(self, stmt): 104 m = re.match(r"expandtypeattribute\s+\((.+)\)\s+(true|false)", stmt) 105 self.expandtypeattributes[m.group(1)] = m.group(2) 106 return 107 108 def _parseTypeattribute(self, stmt): 109 m = re.match(r"typeattribute\s+(.+)", stmt) 110 self.typeattributes.add(m.group(1)) 111 return 112 113 def _parseTypeattributeset(self, stmt): 114 m = re.match(r"typeattributeset\s+(.+?)\s+\((.+?)\)", stmt, flags = re.M |re.S) 115 ta = m.group(1) 116 # this isn't proper expression parsing, but will do for our 117 # current use 118 tas = m.group(2).split() 119 120 if self.typeattributesets.get(ta) is None: 121 self.typeattributesets[ta] = set() 122 self.typeattributesets[ta].update(set(tas)) 123 for t in tas: 124 if self.rTypeattributesets.get(t) is None: 125 self.rTypeattributesets[t] = set() 126 self.rTypeattributesets[t].update([ta]) 127 128 # check to see if this typeattributeset is a versioned public type 129 pub = re.match(r"(\w+)_\d+_\d+", ta) 130 if pub is not None: 131 self.pubtypes.add(pub.group(1)) 132 return 133 134 def _parseStmt(self, stmt): 135 if re.match(r"type\s+.+", stmt): 136 self._parseType(stmt) 137 elif re.match(r"typeattribute\s+.+", stmt): 138 self._parseTypeattribute(stmt) 139 elif re.match(r"typeattributeset\s+.+", stmt): 140 self._parseTypeattributeset(stmt) 141 elif re.match(r"expandtypeattribute\s+.+", stmt): 142 self._parseExpandtypeattribute(stmt) 143 return 144 145if __name__ == '__main__': 146 f = sys.argv[1] 147 p = MiniCilParser(f) 148