Implement boolean criteria for TE rule query.

Match rules based on the Booleans in the rule's conditional expression.

closes #4
This commit is contained in:
Chris PeBenito 2015-02-11 09:24:09 -05:00
parent a9d2717698
commit de8bbb88b0
5 changed files with 195 additions and 8 deletions

View File

@ -64,11 +64,13 @@ expr.add_argument(
"-p", "--perms", help="Comma separated list of permissions.", metavar="PERMS", default="")
expr.add_argument(
"-D", "--default", help="Default type of the TE/RBAC rule.", default="")
expr.add_argument("-b", "--bool", help="Conditional rules with the Boolean in the expression.",
dest="boolname", metavar="BOOL", default="")
expr.add_argument("-b", "--bool", help="Comma separated list of Booleans in the conditional expression.",
dest="boolean", metavar="BOOL", default="")
opts = parser.add_argument_group("Search options")
opts.add_argument("-e", action="store_true",
opts.add_argument("-eb", action="store_true",
help="Match Boolean list exactly instead of matching any listed Boolean.", dest="boolean_equal")
opts.add_argument("-ep", action="store_true",
help="Match permission set exactly instead of matching any listed permission.", dest="perms_equal")
opts.add_argument("-ds", action="store_false",
help="Match source attributes directly instead of matching member types/roles.", dest="source_indirect")
@ -82,6 +84,8 @@ opts.add_argument("-rc", action="store_true",
help="Use regular expression matching for the object class.", dest="tclass_regex")
opts.add_argument("-rd", action="store_true",
help="Use regular expression matching for the default type/role.", dest="default_regex")
opts.add_argument("-rb", action="store_true",
help="Use regular expression matching for Booleans.", dest="boolean_regex")
args = parser.parse_args()
@ -103,7 +107,8 @@ if args.tertypes:
source=args.source, source_indirect=args.source_indirect, source_regex=args.source_regex,
target=args.target, target_indirect=args.target_indirect, target_regex=args.target_regex,
tclass_regex=args.tclass_regex, perms_equal=args.perms_equal,
default=args.default, default_regex=args.default_regex)
default=args.default, default_regex=args.default_regex,
boolean_regex=args.boolean_regex, boolean_equal=args.boolean_equal)
# these are broken out from the above statement to prevent making a list
# with an empty string in it (split on empty string)
@ -116,6 +121,12 @@ if args.tertypes:
if args.perms:
q.set_perms(args.perms.split(","))
if args.boolean:
if args.boolean_regex:
q.set_boolean(args.boolean)
else:
q.set_boolean(args.boolean.split(","))
for r in sorted(q.results()):
print(r)

View File

@ -33,7 +33,7 @@ def boolean_factory(policy, symbol):
return Boolean(policy, symbol)
try:
return qpol.qpol_bool_t(qpol_policy, symbol)
return Boolean(policy, qpol.qpol_bool_t(policy, symbol))
except ValueError:
raise InvalidBoolean("{0} is not a valid Boolean".format(symbol))
@ -84,7 +84,7 @@ class ConditionalExpr(symbol.PolicySymbol):
for expr_node in self.qpol_symbol.expr_node_iter(self.policy):
expr_node_type = expr_node.expr_type(self.policy)
if expr_node_type == qpol.QPOL_COND_EXPR_BOOL and other == boolean_factory(self.policy, expr_node.bool(self.policy)):
if expr_node_type == qpol.QPOL_COND_EXPR_BOOL and other == boolean_factory(self.policy, expr_node.get_boolean(self.policy)):
return True
return False
@ -150,3 +150,17 @@ class ConditionalExpr(symbol.PolicySymbol):
ret.append(i)
return ' '.join(ret)
@property
def booleans(self):
"""The set of Booleans in the expression."""
bools = set()
for expr_node in self.qpol_symbol.expr_node_iter(self.policy):
expr_node_type = expr_node.expr_type(self.policy)
if expr_node_type == qpol.QPOL_COND_EXPR_BOOL:
bools.add(boolean_factory(self.policy, expr_node.get_boolean(self.policy)))
return bools

View File

@ -16,7 +16,9 @@
# License along with SETools. If not, see
# <http://www.gnu.org/licenses/>.
#
from .policyrep.rule import InvalidRuleUse
import re
from .policyrep.rule import InvalidRuleUse, RuleNotConditional
from . import rulequery
@ -30,7 +32,8 @@ class TERuleQuery(rulequery.RuleQuery):
target="", target_regex=False, target_indirect=True,
tclass="", tclass_regex=False,
perms=set(), perms_equal=False,
default="", default_regex=False):
default="", default_regex=False,
boolean=set(), boolean_regex=False, boolean_equal=False):
"""
Parameter:
policy The policy to query.
@ -68,6 +71,7 @@ class TERuleQuery(rulequery.RuleQuery):
self.set_tclass(tclass, regex=tclass_regex)
self.set_perms(perms, equal=perms_equal)
self.set_default(default, regex=default_regex)
self.set_boolean(boolean, regex=boolean_regex, equal=boolean_equal)
def results(self):
"""Generator which yields all matching TE rules."""
@ -139,9 +143,54 @@ class TERuleQuery(rulequery.RuleQuery):
except InvalidRuleUse:
continue
#
# Match on Boolean in conditional expression
#
if self.boolean:
try:
if not self._match_regex_or_set(
set(str(b) for b in r.conditional.booleans),
self.boolean,
self.boolean_equal,
self.boolean_regex,
self.boolean_cmp):
continue
except RuleNotConditional:
continue
# if we get here, we have matched all available criteria
yield r
def set_boolean(self, boolean, **opts):
"""
Set the Boolean for the TE rule query.
Parameter:
boolean The Boolean names to match in the TE rule
conditional expression.
Options:
regex If true, regular expression matching will be used.
Exceptions:
NameError Invalid permission set keyword option.
"""
self.boolean = boolean
for k in list(opts.keys()):
if k == "regex":
self.boolean_regex = opts[k]
elif k == "equal":
self.boolean_equal = opts[k]
else:
raise NameError("Invalid permission set option: {0}".format(k))
if self.boolean_regex:
self.boolean_cmp = re.compile(self.boolean)
else:
self.boolean_cmp = None
def set_perms(self, perms, **opts):
"""
Set the permission set for the TE rule query.

View File

@ -285,6 +285,68 @@ type test101e;
type_transition test101 test101d:infoflow7 test101e;
type_transition test101 test101e:infoflow7 test101d;
# test 200
# ruletype: unset
# source: unset
# target: unset
# class: unset
# default: unset
# boolean: test200
type test200t1;
type test200t2;
bool test200 false;
bool test200a true;
if (test200) {
allow test200t1 self:infoflow7 super_w;
}
if (test200 && test200a) {
allow test200t2 self:infoflow7 super_w;
}
# test 201
# ruletype: unset
# source: unset
# target: unset
# class: unset
# default: unset
# boolean: test201a test201b
type test201t1;
type test201t2;
bool test201a false;
bool test201b true;
if (test201a) {
allow test201t1 self:infoflow7 super_w;
}
if (test201b) {
allow test201t2 self:infoflow7 super_w;
}
if (test201a && test201b) {
allow test201t1 self:infoflow7 super_unmapped;
}
# test 202
# ruletype: unset
# source: unset
# target: unset
# class: unset
# default: unset
# boolean: test202(a|b)
type test202t1;
type test202t2;
bool test202a false;
bool test202b true;
bool test202c true;
if (test202a) {
allow test202t1 self:infoflow7 super_none;
}
if (test202c) {
allow test202t2 self:infoflow7 super_both;
}
if (test202c || test202a) {
allow test202t2 self:infoflow7 super_unmapped;
}
################################################################################
#users

View File

@ -343,3 +343,54 @@ class TERuleQueryTest(unittest.TestCase):
self.assertEqual(r[1].tclass, "infoflow7")
self.assertEqual(r[1].default, "test101d")
self.assertRaises(RuleNotConditional, getattr, r[1], "conditional")
def test_200_boolean_intersection(self):
"""TE rule query with intersection Boolean set match."""
q = TERuleQuery(self.p, boolean=["test200"])
r = sorted(q.results())
self.assertEqual(len(r), 2)
self.assertEqual(r[0].ruletype, "allow")
self.assertEqual(r[0].source, "test200t1")
self.assertEqual(r[0].target, "test200t1")
self.assertEqual(r[0].tclass, "infoflow7")
self.assertSetEqual(set(["super_w"]), r[0].perms)
self.assertEqual(r[1].ruletype, "allow")
self.assertEqual(r[1].source, "test200t2")
self.assertEqual(r[1].target, "test200t2")
self.assertEqual(r[1].tclass, "infoflow7")
self.assertSetEqual(set(["super_w"]), r[1].perms)
def test_201_boolean_equal(self):
"""TE rule query with equal Boolean set match."""
q = TERuleQuery(self.p, boolean=["test201a", "test201b"], boolean_equal=True)
r = sorted(q.results())
self.assertEqual(len(r), 1)
self.assertEqual(r[0].ruletype, "allow")
self.assertEqual(r[0].source, "test201t1")
self.assertEqual(r[0].target, "test201t1")
self.assertEqual(r[0].tclass, "infoflow7")
self.assertSetEqual(set(["super_unmapped"]), r[0].perms)
def test_202_boolean_regex(self):
"""TE rule query with regex Boolean match."""
q = TERuleQuery(self.p, boolean="test202(a|b)", boolean_regex=True)
r = sorted(q.results())
self.assertEqual(len(r), 2)
self.assertEqual(r[0].ruletype, "allow")
self.assertEqual(r[0].source, "test202t1")
self.assertEqual(r[0].target, "test202t1")
self.assertEqual(r[0].tclass, "infoflow7")
self.assertSetEqual(set(["super_none"]), r[0].perms)
self.assertEqual(r[1].ruletype, "allow")
self.assertEqual(r[1].source, "test202t2")
self.assertEqual(r[1].target, "test202t2")
self.assertEqual(r[1].tclass, "infoflow7")
self.assertSetEqual(set(["super_unmapped"]), r[1].perms)