• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 and c != "(":
75            c = infile.read(1)
76
77        parens += 1
78        c = infile.read(1)
79        while c and parens != 0:
80            s += c
81            c = infile.read(1)
82            if c == ';':
83                # comment, get rid of rest of the line
84                while c != '\n':
85                    c = infile.read(1)
86            elif c == '(':
87                parens += 1
88            elif c == ')':
89                parens -= 1
90        return s
91
92    def _parseType(self, stmt):
93        m = re.match(r"type\s+(.+)", stmt)
94        self.types.add(m.group(1))
95        return
96
97    def _parseExpandtypeattribute(self, stmt):
98        m = re.match(r"expandtypeattribute\s+\((.+)\)\s+(true|false)", stmt)
99        self.expandtypeattributes[m.group(1)] = m.group(2)
100        return
101
102    def _parseTypeattribute(self, stmt):
103        m = re.match(r"typeattribute\s+(.+)", stmt)
104        self.typeattributes.add(m.group(1))
105        return
106
107    def _parseTypeattributeset(self, stmt):
108        m = re.match(r"typeattributeset\s+(.+?)\s+\((.+?)\)", stmt, flags = re.M |re.S)
109        ta = m.group(1)
110        # this isn't proper expression parsing, but will do for our
111        # current use
112        tas = m.group(2).split()
113
114        if self.typeattributesets.get(ta) is None:
115            self.typeattributesets[ta] = set()
116        self.typeattributesets[ta].update(set(tas))
117        for t in tas:
118            if self.rTypeattributesets.get(t) is None:
119                self.rTypeattributesets[t] = set()
120            self.rTypeattributesets[t].update([ta])
121
122        # check to see if this typeattributeset is a versioned public type
123        pub = re.match(r"(\w+)_\d+_\d+", ta)
124        if pub is not None:
125            self.pubtypes.add(pub.group(1))
126        return
127
128    def _parseStmt(self, stmt):
129        if re.match(r"type\s+.+", stmt):
130            self._parseType(stmt)
131        elif re.match(r"typeattribute\s+.+", stmt):
132            self._parseTypeattribute(stmt)
133        elif re.match(r"typeattributeset\s+.+", stmt):
134            self._parseTypeattributeset(stmt)
135        elif re.match(r"expandtypeattribute\s+.+", stmt):
136            self._parseExpandtypeattribute(stmt)
137        return
138
139if __name__ == '__main__':
140    f = sys.argv[1]
141    p = MiniCilParser(f)
142