aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Vander Stoep <jeffv@google.com>2017-08-17 14:12:44 -0700
committerJeff Vander Stoep <jeffv@google.com>2017-08-24 15:46:48 -0700
commitdec443e7c55bc615b0b5126ed2f02f5d5e6373ce (patch)
tree6334a8a85cd9bc4e5251cf93ff0e1ba95899cbb0
parent2d206969b4f9fd59da95019f52ba72e9ac1418ed (diff)
downloadandroid_system_sepolicy-dec443e7c55bc615b0b5126ed2f02f5d5e6373ce.tar.gz
android_system_sepolicy-dec443e7c55bc615b0b5126ed2f02f5d5e6373ce.tar.bz2
android_system_sepolicy-dec443e7c55bc615b0b5126ed2f02f5d5e6373ce.zip
add searchpolicy.py for automated tests
searchpolicy.py provides a subset of the functionality of sesearch. The primary benefit being that it's entirely built in-tree and thus can be packaged for use in automated tests included compatibility test suites. Example searchpolicy.py --libpath out/host/linux-x86/lib64/ --allow --source domain Bug: 63397379 Test: Identical output with sesearch for the following commands --allow --source domain --allow --target domain --allow --target appdomain -p ioctl,open --allow --source lmkd -c file -p ioctl,open --allow --source lmkd -c file,dir -p ioctl,open Change-Id: I89a6c333f1f519d9171fbc1aafe27eaf5ad247f0
-rw-r--r--Android.mk1
-rw-r--r--tests/Android.bp7
-rw-r--r--tests/include/sepol_wrap.h3
-rw-r--r--tests/policy.py116
-rw-r--r--tests/searchpolicy.py73
-rw-r--r--tests/sepol_wrap.cpp67
-rw-r--r--tests/treble_sepolicy_tests.py2
7 files changed, 235 insertions, 34 deletions
diff --git a/Android.mk b/Android.mk
index 5fbed9a7..b666a7ee 100644
--- a/Android.mk
+++ b/Android.mk
@@ -224,6 +224,7 @@ LOCAL_REQUIRED_MODULES += \
plat_seapp_contexts \
plat_service_contexts \
plat_hwservice_contexts \
+ searchpolicy.py \
vndservice_contexts \
ifneq ($(with_asan),true)
diff --git a/tests/Android.bp b/tests/Android.bp
index 19aca9cc..75bc91c8 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -32,3 +32,10 @@ cc_prebuilt_binary {
host_supported: true,
required: ["policy.py"],
}
+
+cc_prebuilt_binary {
+ name: "searchpolicy.py",
+ srcs: ["searchpolicy.py"],
+ host_supported: true,
+ required: ["policy.py"],
+}
diff --git a/tests/include/sepol_wrap.h b/tests/include/sepol_wrap.h
index 5615913e..2357421c 100644
--- a/tests/include/sepol_wrap.h
+++ b/tests/include/sepol_wrap.h
@@ -9,6 +9,9 @@ void destroy_policy(void *policydbp);
void *init_avtab(void *policydbp);
void *init_cond_avtab(void *policydbp);
void destroy_avtab(void *avtab_iterp);
+void *init_expanded_avtab(void *policydbp);
+void *init_expanded_cond_avtab(void *policydbp);
+void destroy_expanded_avtab(void *avtab_iterp);
int get_type(char *out, size_t max_size, void *policydbp, void *type_iterp);
void *init_type_iter(void *policydbp, const char *type, bool is_attr);
void destroy_type_iter(void *type_iterp);
diff --git a/tests/policy.py b/tests/policy.py
index b8a36212..a0ddb909 100644
--- a/tests/policy.py
+++ b/tests/policy.py
@@ -41,7 +41,8 @@ class TERule:
self.rule = rule
class Policy:
- __Rules = None
+ __ExpandedRules = set()
+ __Rules = set()
__FcDict = None
__libsepolwrap = None
__policydbP = None
@@ -97,6 +98,50 @@ class Policy:
self.__libsepolwrap.destroy_type_iter(TypeIterP)
return TypeAttr
+ def __TERuleMatch(self, Rule, **kwargs):
+ # Match source type
+ if ("scontext" in kwargs and
+ len(kwargs['scontext']) > 0 and
+ Rule.sctx not in kwargs['scontext']):
+ return False
+ # Match target type
+ if ("tcontext" in kwargs and
+ len(kwargs['tcontext']) > 0 and
+ Rule.tctx not in kwargs['tcontext']):
+ return False
+ # Match target class
+ if ("tclass" in kwargs and
+ len(kwargs['tclass']) > 0 and
+ not bool(set([Rule.tclass]) & kwargs['tclass'])):
+ return False
+ # Match any perms
+ if ("perms" in kwargs and
+ len(kwargs['perms']) > 0 and
+ not bool(Rule.perms & kwargs['perms'])):
+ return False
+ return True
+
+ # resolve a type to its attributes or
+ # resolve an attribute to its types and attributes
+ # For example if scontext is the domain attribute, then we need to
+ # include all types with the domain attribute such as untrusted_app and
+ # priv_app and all the attributes of those types such as appdomain.
+ def ResolveTypeAttribute(self, Type):
+ types = self.GetAllTypes(False)
+ attributes = self.GetAllTypes(True)
+
+ if Type in types:
+ return self.QueryTypeAttribute(Type, False)
+ elif Type in attributes:
+ TypesAndAttributes = set()
+ Types = self.QueryTypeAttribute(Type, True)
+ TypesAndAttributes |= Types
+ for T in Types:
+ TypesAndAttributes |= self.QueryTypeAttribute(T, False)
+ return TypesAndAttributes
+ else:
+ return set()
+
# Return all TERules that match:
# (any scontext) or (any tcontext) or (any tclass) or (any perms),
# perms.
@@ -106,23 +151,32 @@ class Policy:
# Will return any rule with:
# (tcontext="foo" or tcontext="bar") and ("entrypoint" in perms)
def QueryTERule(self, **kwargs):
- if self.__Rules is None:
+ if len(self.__Rules) == 0:
self.__InitTERules()
+
+ # add any matching types and attributes for scontext and tcontext
+ if ("scontext" in kwargs and len(kwargs['scontext']) > 0):
+ scontext = set()
+ for sctx in kwargs['scontext']:
+ scontext |= self.ResolveTypeAttribute(sctx)
+ kwargs['scontext'] = scontext
+ if ("tcontext" in kwargs and len(kwargs['tcontext']) > 0):
+ tcontext = set()
+ for tctx in kwargs['tcontext']:
+ tcontext |= self.ResolveTypeAttribute(tctx)
+ kwargs['tcontext'] = tcontext
for Rule in self.__Rules:
- # Match source type
- if "scontext" in kwargs and Rule.sctx not in kwargs['scontext']:
- continue
- # Match target type
- if "tcontext" in kwargs and Rule.tctx not in kwargs['tcontext']:
- continue
- # Match target class
- if "tclass" in kwargs and Rule.tclass not in kwargs['tclass']:
- continue
- # Match any perms
- if "perms" in kwargs and not bool(Rule.perms & set(kwargs['perms'])):
- continue
- yield Rule
+ if self.__TERuleMatch(Rule, **kwargs):
+ yield Rule
+ # Same as QueryTERule but only using the expanded ruleset.
+ # i.e. all attributes have been expanded to their various types.
+ def QueryExpandedTERule(self, **kwargs):
+ if len(self.__ExpandedRules) == 0:
+ self.__InitExpandedTERules()
+ for Rule in self.__ExpandedRules:
+ if self.__TERuleMatch(Rule, **kwargs):
+ yield Rule
def GetAllTypes(self, isAttr):
TypeIterP = self.__libsepolwrap.init_type_iter(self.__policydbP, None, isAttr)
@@ -155,9 +209,9 @@ class Policy:
return Types
- def __GetTERules(self, policydbP, avtabIterP):
- if self.__Rules is None:
- self.__Rules = set()
+ def __GetTERules(self, policydbP, avtabIterP, Rules):
+ if Rules is None:
+ Rules = set()
buf = create_string_buffer(self.__BUFSIZE)
ret = 0
while True:
@@ -165,7 +219,7 @@ class Policy:
policydbP, avtabIterP)
if ret == 0:
Rule = TERule(buf.value)
- self.__Rules.add(Rule)
+ Rules.add(Rule)
continue
if ret == 1:
break;
@@ -176,14 +230,26 @@ class Policy:
avtabIterP = self.__libsepolwrap.init_avtab(self.__policydbP)
if (avtabIterP == None):
sys.exit("Failed to initialize avtab")
- self.__GetTERules(self.__policydbP, avtabIterP)
+ self.__GetTERules(self.__policydbP, avtabIterP, self.__Rules)
self.__libsepolwrap.destroy_avtab(avtabIterP)
avtabIterP = self.__libsepolwrap.init_cond_avtab(self.__policydbP)
if (avtabIterP == None):
sys.exit("Failed to initialize conditional avtab")
- self.__GetTERules(self.__policydbP, avtabIterP)
+ self.__GetTERules(self.__policydbP, avtabIterP, self.__Rules)
self.__libsepolwrap.destroy_avtab(avtabIterP)
+ def __InitExpandedTERules(self):
+ avtabIterP = self.__libsepolwrap.init_expanded_avtab(self.__policydbP)
+ if (avtabIterP == None):
+ sys.exit("Failed to initialize avtab")
+ self.__GetTERules(self.__policydbP, avtabIterP, self.__ExpandedRules)
+ self.__libsepolwrap.destroy_expanded_avtab(avtabIterP)
+ avtabIterP = self.__libsepolwrap.init_expanded_cond_avtab(self.__policydbP)
+ if (avtabIterP == None):
+ sys.exit("Failed to initialize conditional avtab")
+ self.__GetTERules(self.__policydbP, avtabIterP, self.__ExpandedRules)
+ self.__libsepolwrap.destroy_expanded_avtab(avtabIterP)
+
# load ctypes-ified libsepol wrapper
def __InitLibsepolwrap(self, LibPath):
if "linux" in sys.platform:
@@ -201,6 +267,14 @@ class Policy:
lib.load_policy.argtypes = [c_char_p]
# void destroy_policy(void *policydbp);
lib.destroy_policy.argtypes = [c_void_p]
+ # void *init_expanded_avtab(void *policydbp);
+ lib.init_expanded_avtab.restype = c_void_p
+ lib.init_expanded_avtab.argtypes = [c_void_p]
+ # void *init_expanded_cond_avtab(void *policydbp);
+ lib.init_expanded_cond_avtab.restype = c_void_p
+ lib.init_expanded_cond_avtab.argtypes = [c_void_p]
+ # void destroy_expanded_avtab(void *avtab_iterp);
+ lib.destroy_expanded_avtab.argtypes = [c_void_p]
# void *init_avtab(void *policydbp);
lib.init_avtab.restype = c_void_p
lib.init_avtab.argtypes = [c_void_p]
diff --git a/tests/searchpolicy.py b/tests/searchpolicy.py
new file mode 100644
index 00000000..ff9318b7
--- /dev/null
+++ b/tests/searchpolicy.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+
+import argparse
+import policy
+
+parser = argparse.ArgumentParser(
+ description="SELinux policy rule search tool. Intended to have a similar "
+ + "API as sesearch, but simplified to use only code availabe in AOSP")
+parser.add_argument("policy", help="Path to the SELinux policy to search.", nargs="?")
+parser.add_argument("--libpath", dest="libpath", help="Path to the libsepolwrap.so", nargs="?")
+tertypes = parser.add_argument_group("TE Rule Types")
+tertypes.add_argument("--allow", action="append_const",
+ const="allow", dest="tertypes",
+ help="Search allow rules.")
+expr = parser.add_argument_group("Expressions")
+expr.add_argument("-s", "--source",
+ help="Source type/role of the TE/RBAC rule.")
+expr.add_argument("-t", "--target",
+ help="Target type/role of the TE/RBAC rule.")
+expr.add_argument("-c", "--class", dest="tclass",
+ help="Comma separated list of object classes")
+expr.add_argument("-p", "--perms", metavar="PERMS",
+ help="Comma separated list of permissions.")
+
+args = parser.parse_args()
+
+if not args.tertypes:
+ parser.error("Must specify \"--allow\"")
+
+if not args.policy:
+ parser.error("Must include path to policy")
+if not args.libpath:
+ parser.error("Must include path to libsepolwrap library")
+
+if not (args.source or args.target or args.tclass or args.perms):
+ parser.error("Must something to filter on, e.g. --source, --target, etc.")
+
+pol = policy.Policy(args.policy, None, args.libpath)
+
+if args.source:
+ scontext = {args.source}
+else:
+ scontext = set()
+if args.target:
+ tcontext = {args.target}
+else:
+ tcontext = set()
+if args.tclass:
+ tclass = set(args.tclass.split(","))
+else:
+ tclass = set()
+if args.perms:
+ perms = set(args.perms.split(","))
+else:
+ perms = set()
+
+TERules = pol.QueryTERule(scontext=scontext,
+ tcontext=tcontext,
+ tclass=tclass,
+ perms=perms)
+
+# format rules for printing
+rules = []
+for r in TERules:
+ if len(r.perms) > 1:
+ rules.append("allow " + r.sctx + " " + r.tctx + ":" + r.tclass + " { " +
+ " ".join(r.perms) + " };")
+ else:
+ rules.append("allow " + r.sctx + " " + r.tctx + ":" + r.tclass + " " +
+ " ".join(r.perms) + ";")
+
+for r in sorted(rules):
+ print r
diff --git a/tests/sepol_wrap.cpp b/tests/sepol_wrap.cpp
index 8fea2d5b..d537b7e0 100644
--- a/tests/sepol_wrap.cpp
+++ b/tests/sepol_wrap.cpp
@@ -181,7 +181,7 @@ void *load_policy(const char *policy_path)
/* items needed to iterate over the avtab */
struct avtab_iter {
- avtab_t avtab;
+ avtab_t *avtab;
uint32_t i;
avtab_ptr_t cur;
};
@@ -198,9 +198,9 @@ static int get_avtab_allow_rule(char *out, size_t max_size, policydb_t *db,
{
size_t len;
- for (; avtab_i->i < avtab_i->avtab.nslot; (avtab_i->i)++) {
+ for (; avtab_i->i < avtab_i->avtab->nslot; (avtab_i->i)++) {
if (avtab_i->cur == NULL) {
- avtab_i->cur = avtab_i->avtab.htable[avtab_i->i];
+ avtab_i->cur = avtab_i->avtab->htable[avtab_i->i];
}
for (; avtab_i->cur; avtab_i->cur = (avtab_i->cur)->next) {
if (!((avtab_i->cur)->key.specified & AVTAB_ALLOWED)) continue;
@@ -233,6 +233,37 @@ int get_allow_rule(char *out, size_t len, void *policydbp, void *avtab_iterp)
return get_avtab_allow_rule(out, len, db, avtab_i);
}
+static avtab_iter *init_avtab_common(avtab_t *in)
+{
+ struct avtab_iter *out = (struct avtab_iter *)
+ calloc(1, sizeof(struct avtab_iter));
+ if (!out) {
+ std::cerr << "Failed to allocate avtab iterator" << std::endl;
+ return NULL;
+ }
+
+ out->avtab = in;
+ return out;
+}
+
+void *init_avtab(void *policydbp)
+{
+ policydb_t *p = static_cast<policydb_t *>(policydbp);
+ return static_cast<void *>(init_avtab_common(&p->te_avtab));
+}
+
+void *init_cond_avtab(void *policydbp)
+{
+ policydb_t *p = static_cast<policydb_t *>(policydbp);
+ return static_cast<void *>(init_avtab_common(&p->te_cond_avtab));
+}
+
+void destroy_avtab(void *avtab_iterp)
+{
+ struct avtab_iter *avtab_i = static_cast<struct avtab_iter *>(avtab_iterp);
+ free(avtab_i);
+}
+
/*
* <sepol/policydb/expand.h->conditional.h> uses 'bool' as a variable name
* inside extern "C" { .. } construct, which clang doesn't like.
@@ -240,45 +271,57 @@ int get_allow_rule(char *out, size_t len, void *policydbp, void *avtab_iterp)
*/
extern "C" int expand_avtab(policydb_t *p, avtab_t *a, avtab_t *expa);
-static avtab_iter *init_avtab_common(avtab_t *in, policydb_t *p)
+static avtab_iter *init_expanded_avtab_common(avtab_t *in, policydb_t *p)
{
struct avtab_iter *out = (struct avtab_iter *)
calloc(1, sizeof(struct avtab_iter));
if (!out) {
+ std::cerr << "Failed to allocate avtab iterator" << std::endl;
+ return NULL;
+ }
+
+ avtab_t *avtab = (avtab_t *) calloc(1, sizeof(avtab_t));
+
+ if (!avtab) {
std::cerr << "Failed to allocate avtab" << std::endl;
+ free(out);
return NULL;
}
- if (avtab_init(&out->avtab)) {
+ out->avtab = avtab;
+ if (avtab_init(out->avtab)) {
std::cerr << "Failed to initialize avtab" << std::endl;
+ free(avtab);
free(out);
return NULL;
}
- if (expand_avtab(p, in, &out->avtab)) {
+ if (expand_avtab(p, in, out->avtab)) {
std::cerr << "Failed to expand avtab" << std::endl;
+ free(avtab);
free(out);
return NULL;
}
return out;
}
-void *init_avtab(void *policydbp)
+void *init_expanded_avtab(void *policydbp)
{
policydb_t *p = static_cast<policydb_t *>(policydbp);
- return static_cast<void *>(init_avtab_common(&p->te_avtab, p));
+ return static_cast<void *>(init_expanded_avtab_common(&p->te_avtab, p));
}
-void *init_cond_avtab(void *policydbp)
+void *init_expanded_cond_avtab(void *policydbp)
{
policydb_t *p = static_cast<policydb_t *>(policydbp);
- return static_cast<void *>(init_avtab_common(&p->te_cond_avtab, p));
+ return static_cast<void *>(init_expanded_avtab_common(&p->te_cond_avtab, p));
}
-void destroy_avtab(void *avtab_iterp)
+void destroy_expanded_avtab(void *avtab_iterp)
{
struct avtab_iter *avtab_i = static_cast<struct avtab_iter *>(avtab_iterp);
- avtab_destroy(&avtab_i->avtab);
+ avtab_destroy(avtab_i->avtab);
+ free(avtab_i->avtab);
free(avtab_i);
}
diff --git a/tests/treble_sepolicy_tests.py b/tests/treble_sepolicy_tests.py
index 58fd85bc..0e0c0c2c 100644
--- a/tests/treble_sepolicy_tests.py
+++ b/tests/treble_sepolicy_tests.py
@@ -129,7 +129,7 @@ def GetCoreDomains():
#
def GetDomainEntrypoints(pol):
global alldomains
- for x in pol.QueryTERule(tclass="file", perms=["entrypoint"]):
+ for x in pol.QueryExpandedTERule(tclass=set(["file"]), perms=set(["entrypoint"])):
if not x.sctx in alldomains:
continue
alldomains[x.sctx].entrypoints.append(str(x.tctx))