Skip to content
Snippets Groups Projects
Commit 72365536 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Improve data separation test coverage"

parents 9e6c8677 370a52fe
No related branches found
No related tags found
No related merge requests found
...@@ -33,9 +33,10 @@ python_defaults { ...@@ -33,9 +33,10 @@ python_defaults {
python_binary_host { python_binary_host {
name: "treble_sepolicy_tests", name: "treble_sepolicy_tests",
srcs: [ srcs: [
"treble_sepolicy_tests.py", "FcSort.py",
"mini_parser.py", "mini_parser.py",
"policy.py", "policy.py",
"treble_sepolicy_tests.py",
], ],
required: ["libsepolwrap"], required: ["libsepolwrap"],
defaults: ["py2_only"], defaults: ["py2_only"],
...@@ -44,8 +45,9 @@ python_binary_host { ...@@ -44,8 +45,9 @@ python_binary_host {
python_binary_host { python_binary_host {
name: "sepolicy_tests", name: "sepolicy_tests",
srcs: [ srcs: [
"sepolicy_tests.py", "FcSort.py",
"policy.py", "policy.py",
"sepolicy_tests.py",
], ],
required: ["libsepolwrap"], required: ["libsepolwrap"],
defaults: ["py2_only"], defaults: ["py2_only"],
......
#!/usr/bin/env python
import sys
import os
class FileContextsNode:
path = None
fileType = None
context = None
Type = None
meta = None
stemLen = None
strLen = None
Type = None
def __init__(self, path, fileType, context, meta, stemLen, strLen):
self.path = path
self.fileType = fileType
self.context = context
self.meta = meta
self.stemLen = stemLen
self.strlen = strLen
self.Type = context.split(":")[2]
metaChars = frozenset(['.', '^', '$', '?', '*', '+', '|', '[', '(', '{'])
escapedMetaChars = frozenset(['\.', '\^', '\$', '\?', '\*', '\+', '\|', '\[', '\(', '\{'])
def getStemLen(path):
global metaChars
stemLen = 0
i = 0
while i < len(path):
if path[i] == "\\":
i += 1
elif path[i] in metaChars:
break
stemLen += 1
i += 1
return stemLen
def getIsMeta(path):
global metaChars
global escapedMetaChars
metaCharsCount = 0
escapedMetaCharsCount = 0
for c in metaChars:
if c in path:
metaCharsCount += 1
for c in escapedMetaChars:
if c in path:
escapedMetaCharsCount += 1
return metaCharsCount > escapedMetaCharsCount
def CreateNode(line):
global metaChars
if (len(line) == 0) or (line[0] == '#'):
return None
split = line.split()
path = split[0].strip()
context = split[-1].strip()
fileType = None
if len(split) == 3:
fileType = split[1].strip()
meta = getIsMeta(path)
stemLen = getStemLen(path)
strLen = len(path.replace("\\", ""))
return FileContextsNode(path, fileType, context, meta, stemLen, strLen)
def ReadFileContexts(files):
fc = []
for f in files:
fd = open(f)
for line in fd:
node = CreateNode(line.strip())
if node != None:
fc.append(node)
return fc
# Comparator function for list.sort() based off of fc_sort.c
# Compares two FileContextNodes a and b and returns 1 if a is more
# specific or -1 if b is more specific.
def compare(a, b):
# The regex without metachars is more specific
if a.meta and not b.meta:
return -1
if b.meta and not a.meta:
return 1
# The regex with longer stemlen (regex before any meta characters) is more specific.
if a.stemLen < b.stemLen:
return -1
if b.stemLen < a.stemLen:
return 1
# The regex with longer string length is more specific
if a.strLen < b.strLen:
return -1
if b.strLen < a.strLen:
return 1
# A regex with a fileType defined (e.g. file, dir) is more specific.
if a.fileType is None and b.fileType is not None:
return -1
if b.fileType is None and a.fileType is not None:
return 1
# Regexes are equally specific.
return 0
def FcSort(files):
for f in files:
if not os.path.exists(f):
sys.exit("Error: File_contexts file " + f + " does not exist\n")
Fc = ReadFileContexts(files)
Fc.sort(cmp=compare)
return Fc
if __name__ == '__main__':
if len(sys.argv) < 2:
sys.exit("Usage: fc_sort.py <file_contexts 1> <file_contexts 2> <file_contexts 3>")
FcSorted = FcSort(sys.argv[1:])
...@@ -3,6 +3,7 @@ import re ...@@ -3,6 +3,7 @@ import re
import os import os
import sys import sys
import platform import platform
import FcSort
### ###
# Check whether the regex will match a file path starting with the provided # Check whether the regex will match a file path starting with the provided
...@@ -45,10 +46,26 @@ class Policy: ...@@ -45,10 +46,26 @@ class Policy:
__ExpandedRules = set() __ExpandedRules = set()
__Rules = set() __Rules = set()
__FcDict = None __FcDict = None
__FcSorted = None
__libsepolwrap = None __libsepolwrap = None
__policydbP = None __policydbP = None
__BUFSIZE = 2048 __BUFSIZE = 2048
def AssertPathTypesDoNotHaveAttr(self, MatchPrefix, DoNotMatchPrefix, Attr):
# Query policy for the types associated with Attr
TypesPol = self.QueryTypeAttribute(Attr, True)
# Search file_contexts to find types associated with input paths.
TypesFc = self.__GetTypesByFilePathPrefix(MatchPrefix, DoNotMatchPrefix)
violators = TypesFc.intersection(TypesPol)
ret = ""
if len(violators) > 0:
ret += "The following types on "
ret += " ".join(str(x) for x in sorted(MatchPrefix))
ret += " must not be associated with the "
ret += "\"" + Attr + "\" attribute: "
ret += " ".join(str(x) for x in sorted(violators)) + "\n"
return ret
# Check that path prefixes that match MatchPrefix, and do not Match # Check that path prefixes that match MatchPrefix, and do not Match
# DoNotMatchPrefix have the attribute Attr. # DoNotMatchPrefix have the attribute Attr.
# For example assert that all types in /sys, and not in /sys/kernel/debugfs # For example assert that all types in /sys, and not in /sys/kernel/debugfs
...@@ -198,18 +215,51 @@ class Policy: ...@@ -198,18 +215,51 @@ class Policy:
self.__libsepolwrap.destroy_type_iter(TypeIterP) self.__libsepolwrap.destroy_type_iter(TypeIterP)
return AllTypes return AllTypes
def __ExactMatchPathPrefix(self, pathregex, prefix):
pattern = re.compile('^' + pathregex + "$")
if pattern.match(prefix):
return True
return False
# Return a tuple (prefix, i) where i is the index of the most specific
# match of prefix in the sorted file_contexts. This is useful for limiting a
# file_contexts search to matches that are more specific and omitting less
# specific matches. For example, finding all matches to prefix /data/vendor
# should not include /data(/.*)? if /data/vendor(/.*)? is also specified.
def __FcSortedIndex(self, prefix):
index = 0
for i in range(0, len(self.__FcSorted)):
if self.__ExactMatchPathPrefix(self.__FcSorted[i].path, prefix):
index = i
return prefix, index
# Return a tuple of (path, Type) for all matching paths. Use the sorted
# file_contexts and index returned from __FcSortedIndex() to limit results
# to results that are more specific than the prefix.
def __MatchPathPrefixTypes(self, prefix, index):
PathType = []
for i in range(index, len(self.__FcSorted)):
if MatchPathPrefix(self.__FcSorted[i].path, prefix):
PathType.append((self.__FcSorted[i].path, self.__FcSorted[i].Type))
return PathType
# Return types that match MatchPrefixes but do not match
# DoNotMatchPrefixes
def __GetTypesByFilePathPrefix(self, MatchPrefixes, DoNotMatchPrefixes): def __GetTypesByFilePathPrefix(self, MatchPrefixes, DoNotMatchPrefixes):
Types = set() Types = set()
for Type in self.__FcDict:
for pathregex in self.__FcDict[Type]: MatchPrefixesWithIndex = []
if not MatchPathPrefixes(pathregex, MatchPrefixes): for MatchPrefix in MatchPrefixes:
continue MatchPrefixesWithIndex.append(self.__FcSortedIndex(MatchPrefix))
if MatchPathPrefixes(pathregex, DoNotMatchPrefixes):
for MatchPrefixWithIndex in MatchPrefixesWithIndex:
PathTypes = self.__MatchPathPrefixTypes(*MatchPrefixWithIndex)
for PathType in PathTypes:
if MatchPathPrefixes(PathType[0], DoNotMatchPrefixes):
continue continue
Types.add(Type) Types.add(PathType[1])
return Types return Types
def __GetTERules(self, policydbP, avtabIterP, Rules): def __GetTERules(self, policydbP, avtabIterP, Rules):
if Rules is None: if Rules is None:
Rules = set() Rules = set()
...@@ -313,6 +363,7 @@ class Policy: ...@@ -313,6 +363,7 @@ class Policy:
self.__FcDict[t] = [rec[0]] self.__FcDict[t] = [rec[0]]
except: except:
pass pass
self.__FcSorted = FcSort.FcSort(FcPaths)
# load policy # load policy
def __InitPolicy(self, PolicyPath): def __InitPolicy(self, PolicyPath):
......
...@@ -24,8 +24,8 @@ def TestVendorTypeViolations(pol): ...@@ -24,8 +24,8 @@ def TestVendorTypeViolations(pol):
return pol.AssertPathTypesHaveAttr(["/vendor/"], [], "vendor_file_type") return pol.AssertPathTypesHaveAttr(["/vendor/"], [], "vendor_file_type")
def TestCoreDataTypeViolations(pol): def TestCoreDataTypeViolations(pol):
return pol.AssertPathTypesHaveAttr(["/data/"], ["/data/vendor/", return pol.AssertPathTypesHaveAttr(["/data/"], ["/data/vendor",
"/data/vendor_ce/", "/data/vendor_de/"], "core_data_file_type") "/data/vendor_ce", "/data/vendor_de"], "core_data_file_type")
### ###
# extend OptionParser to allow the same option flag to be used multiple times. # extend OptionParser to allow the same option flag to be used multiple times.
......
...@@ -71,6 +71,7 @@ alldomains = {} ...@@ -71,6 +71,7 @@ alldomains = {}
coredomains = set() coredomains = set()
appdomains = set() appdomains = set()
vendordomains = set() vendordomains = set()
pol = None
# compat vars # compat vars
alltypes = set() alltypes = set()
...@@ -287,6 +288,12 @@ def TestViolatorAttributes(): ...@@ -287,6 +288,12 @@ def TestViolatorAttributes():
ret += TestViolatorAttribute("vendor_executes_system_violators") ret += TestViolatorAttribute("vendor_executes_system_violators")
return ret return ret
# TODO move this to sepolicy_tests
def TestCoreDataTypeViolations():
global pol
return pol.AssertPathTypesDoNotHaveAttr(["/data/vendor/", "/data/vendor_ce/",
"/data/vendor_de/"], [], "core_data_file_type")
### ###
# extend OptionParser to allow the same option flag to be used multiple times. # extend OptionParser to allow the same option flag to be used multiple times.
# This is used to allow multiple file_contexts files and tests to be # This is used to allow multiple file_contexts files and tests to be
...@@ -305,6 +312,7 @@ class MultipleOption(Option): ...@@ -305,6 +312,7 @@ class MultipleOption(Option):
Option.take_action(self, action, dest, opt, value, values, parser) Option.take_action(self, action, dest, opt, value, values, parser)
Tests = {"CoredomainViolations": TestCoredomainViolations, Tests = {"CoredomainViolations": TestCoredomainViolations,
"CoreDatatypeViolations": TestCoreDataTypeViolations,
"TrebleCompatMapping": TestTrebleCompatMapping, "TrebleCompatMapping": TestTrebleCompatMapping,
"ViolatorAttributes": TestViolatorAttributes} "ViolatorAttributes": TestViolatorAttributes}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment