mirror of
https://github.com/SELinuxProject/setools
synced 2025-02-28 18:11:27 +00:00
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:
parent
a9d2717698
commit
de8bbb88b0
19
sesearch
19
sesearch
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user