mirror of
https://github.com/SELinuxProject/setools
synced 2025-03-03 03:18:28 +00:00
Change range constructor to use regular levels instead of semantic ones.
This affords better error reporting since levels can be invalid for several reasons. * Fix memory leak in qpol_semantic_level * Add unit tests
This commit is contained in:
parent
9c7ece4ad2
commit
a8d7f740b2
@ -258,9 +258,10 @@ extern "C"
|
||||
extern int qpol_policy_get_semantic_level_by_name(const qpol_policy_t * policy, const char *name, const qpol_semantic_level_t ** datum);
|
||||
extern int qpol_semantic_level_add_cats_by_name(const qpol_policy_t * policy, const qpol_semantic_level_t * level, const char *low, const char *high);
|
||||
extern int qpol_mls_level_from_semantic_level(const qpol_policy_t * policy, const qpol_semantic_level_t * src, qpol_mls_level_t **dest);
|
||||
extern void qpol_semantic_level_destroy(qpol_semantic_level_t * level);
|
||||
|
||||
/* semantic ranges */
|
||||
extern int qpol_policy_get_mls_range_from_semantic_levels(const qpol_policy_t * policy, const qpol_semantic_level_t * low, const qpol_semantic_level_t *high, qpol_mls_range_t **dest);
|
||||
extern int qpol_policy_get_mls_range_from_mls_levels(const qpol_policy_t * policy, const qpol_mls_level_t * low, const qpol_mls_level_t *high, qpol_mls_range_t **dest);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -541,12 +541,11 @@ int qpol_cat_get_alias_iter(const qpol_policy_t * policy, const qpol_cat_t * dat
|
||||
}
|
||||
|
||||
/* mls range */
|
||||
int qpol_policy_get_mls_range_from_semantic_levels(const qpol_policy_t * policy, const qpol_semantic_level_t *low, const qpol_semantic_level_t *high, qpol_mls_range_t **dest)
|
||||
int qpol_policy_get_mls_range_from_mls_levels(const qpol_policy_t * policy, const qpol_mls_level_t *low, const qpol_mls_level_t *high, qpol_mls_range_t **dest)
|
||||
{
|
||||
policydb_t *db = NULL;
|
||||
mls_range_t *internal_range = NULL;
|
||||
mls_semantic_range_t *internal_semantic = NULL;
|
||||
mls_semantic_level_t *internal_low = NULL, *internal_high = NULL;
|
||||
mls_level_t *internal_low = NULL, *internal_high = NULL;
|
||||
|
||||
if (policy == NULL || low == NULL || high == NULL || dest == NULL) {
|
||||
if (dest != NULL)
|
||||
@ -556,50 +555,40 @@ int qpol_policy_get_mls_range_from_semantic_levels(const qpol_policy_t * policy,
|
||||
return STATUS_ERR;
|
||||
}
|
||||
|
||||
internal_low = (mls_semantic_level_t*)low;
|
||||
internal_high = (mls_semantic_level_t*)high;
|
||||
db = &policy->p->p;
|
||||
*dest = NULL;
|
||||
internal_low = (mls_level_t*)low;
|
||||
internal_high = (mls_level_t*)high;
|
||||
|
||||
internal_semantic = malloc(sizeof(mls_semantic_range_t));
|
||||
if (!internal_semantic) {
|
||||
if (!mls_level_dom(internal_high, internal_low)) {
|
||||
ERR(policy, "%s", strerror(EINVAL));
|
||||
errno = EINVAL;
|
||||
return STATUS_ERR;
|
||||
}
|
||||
mls_semantic_range_init(internal_semantic);
|
||||
|
||||
internal_range = malloc(sizeof(mls_range_t));
|
||||
if (!internal_range) {
|
||||
mls_semantic_range_destroy(internal_semantic);
|
||||
ERR(policy, "%s", strerror(EINVAL));
|
||||
ERR(policy, "%s", strerror(errno));
|
||||
return STATUS_ERR;
|
||||
}
|
||||
mls_range_init(internal_range);
|
||||
|
||||
db = &policy->p->p;
|
||||
if(mls_semantic_level_cpy(&internal_semantic->level[0], internal_low) < 0) {
|
||||
goto err;
|
||||
}
|
||||
if (mls_semantic_level_cpy(&internal_semantic->level[1], internal_high) < 0) {
|
||||
if (mls_level_cpy(&internal_range->level[0], internal_low) < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if(mls_semantic_range_expand(internal_semantic, internal_range, db, policy->sh) < 0) {
|
||||
ERR(policy, "%s", strerror(EINVAL));
|
||||
if (mls_level_cpy(&internal_range->level[1], internal_high) < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
*dest = (qpol_mls_range_t*) internal_range;
|
||||
|
||||
mls_semantic_range_destroy(internal_semantic);
|
||||
free(internal_semantic);
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
err:
|
||||
mls_range_destroy(internal_range);
|
||||
mls_semantic_range_destroy(internal_semantic);
|
||||
free(internal_range);
|
||||
free(internal_semantic);
|
||||
errno = EINVAL;
|
||||
errno = ENOMEM;
|
||||
return STATUS_ERR;
|
||||
}
|
||||
|
||||
@ -835,3 +824,14 @@ int qpol_semantic_level_add_cats_by_name(const qpol_policy_t * policy, const qpo
|
||||
errno = ENOENT;
|
||||
return STATUS_ERR;
|
||||
}
|
||||
|
||||
void qpol_semantic_level_destroy(qpol_semantic_level_t * level)
|
||||
{
|
||||
|
||||
if (level == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
mls_semantic_level_destroy((mls_semantic_level_t*) level);
|
||||
free(level);
|
||||
}
|
||||
|
@ -87,15 +87,21 @@ def sensitivity_factory(policy, symbol):
|
||||
raise InvalidSensitivity("{0} is not a valid sensitivity".format(symbol))
|
||||
|
||||
|
||||
def _build_semantic_level(policy, level):
|
||||
"""Parse the level string and construct a qpol semantic representation."""
|
||||
sens_split = level.split(":")
|
||||
def level_factory(policy, symbol):
|
||||
"""
|
||||
Factory function for creating MLS level objects (e.g. levels used
|
||||
in contexts of labeling statements)
|
||||
"""
|
||||
if isinstance(symbol, qpol.qpol_mls_level_t):
|
||||
return MLSLevel(policy, symbol)
|
||||
|
||||
sens_split = symbol.split(":")
|
||||
|
||||
sens = sens_split[0]
|
||||
try:
|
||||
semantic_level = qpol.qpol_semantic_level_t(policy, sens)
|
||||
except ValueError:
|
||||
raise InvalidLevel("{0} is not a valid sensitivity".format(sens))
|
||||
raise InvalidLevel("{0} is invalid ({1} is not a valid sensitivity)".format(symbol, sens))
|
||||
|
||||
try:
|
||||
cats = sens_split[1]
|
||||
@ -109,34 +115,24 @@ def _build_semantic_level(policy, level):
|
||||
try:
|
||||
semantic_level.add_cats(policy, catrange[0], catrange[1])
|
||||
except ValueError:
|
||||
raise InvalidLevel("{0} is not a valid category range".format(group))
|
||||
raise InvalidLevel("{0} is invalid ({1} is not a valid category range)".
|
||||
format(symbol, group))
|
||||
elif len(catrange) == 1:
|
||||
try:
|
||||
semantic_level.add_cats(policy, catrange[0], catrange[0])
|
||||
except ValueError:
|
||||
raise InvalidLevel("{0} is not a valid category".format(group))
|
||||
raise InvalidLevel("{0} is invalid ({1} is not a valid category)".
|
||||
format(symbol, group))
|
||||
else:
|
||||
# may not be possible to get here
|
||||
raise InvalidLevel("{0} is not a valid category range".format(group))
|
||||
|
||||
return semantic_level
|
||||
|
||||
|
||||
def level_factory(policy, symbol):
|
||||
"""
|
||||
Factory function for creating MLS level objects (e.g. levels used
|
||||
in contexts of labeling statements)
|
||||
"""
|
||||
if isinstance(symbol, qpol.qpol_mls_level_t):
|
||||
return MLSLevel(policy, symbol)
|
||||
|
||||
semantic_level = _build_semantic_level(policy, symbol)
|
||||
raise InvalidLevel("{0} is invalid (level parsing error)".format(symbol))
|
||||
|
||||
# convert to level object
|
||||
try:
|
||||
policy_level = qpol.qpol_mls_level_t(policy, semantic_level)
|
||||
except ValueError:
|
||||
raise InvalidLevel("{0} is not a valid level".format(symbol))
|
||||
raise InvalidLevel(
|
||||
"{0} is invalid (one or more categories are not associated with the sensitivity)".
|
||||
format(symbol))
|
||||
|
||||
return MLSLevel(policy, policy_level)
|
||||
|
||||
@ -165,12 +161,12 @@ def range_factory(policy, symbol):
|
||||
levels = symbol.split("-")
|
||||
|
||||
try:
|
||||
low = _build_semantic_level(policy, levels[0])
|
||||
low = level_factory(policy, levels[0])
|
||||
except InvalidLevel as e:
|
||||
raise InvalidRange("{0} is not a valid range ({1}).".format(symbol, e))
|
||||
|
||||
try:
|
||||
high = _build_semantic_level(policy, levels[1])
|
||||
high = level_factory(policy, levels[1])
|
||||
except InvalidLevel as e:
|
||||
raise InvalidRange("{0} is not a valid range ({1}).".format(symbol, e))
|
||||
except IndexError:
|
||||
@ -178,11 +174,10 @@ def range_factory(policy, symbol):
|
||||
|
||||
# convert to range object
|
||||
try:
|
||||
policy_range = qpol.qpol_mls_range_t(policy, low, high)
|
||||
policy_range = qpol.qpol_mls_range_t(policy, low.qpol_symbol, high.qpol_symbol)
|
||||
except ValueError:
|
||||
# this can be due to one of the semantic levels being invalid (category not allowed in
|
||||
# level) or the high level does not dominate the low level. Can't tell which one.
|
||||
raise InvalidLevel("{0} is not a valid range".format(symbol))
|
||||
raise InvalidRange("{0} is not a valid range ({1} is not dominated by {2})".
|
||||
format(symbol, levels[0], levels[1]))
|
||||
|
||||
return MLSRange(policy, policy_range)
|
||||
|
||||
|
@ -1523,17 +1523,25 @@ typedef struct qpol_cat {} qpol_cat_t;
|
||||
/* qpol mls range */
|
||||
typedef struct qpol_mls_range {} qpol_mls_range_t;
|
||||
%extend qpol_mls_range {
|
||||
# TODO: determine how to conditionally destroy this range.
|
||||
# It should only be destroyed if it was looked up (user-entered)
|
||||
# Otherwise qpol will destroy the others when the policy closes.
|
||||
%exception qpol_mls_range {
|
||||
$action
|
||||
if (!result) {
|
||||
PyErr_SetString(PyExc_ValueError, "Invalid range.");
|
||||
if (errno == EINVAL) {
|
||||
PyErr_SetString(PyExc_ValueError, "Invalid range.");
|
||||
} else {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
qpol_mls_range(qpol_policy_t *p, qpol_semantic_level_t *l, qpol_semantic_level_t *h) {
|
||||
qpol_mls_range(qpol_policy_t *p, qpol_mls_level_t *l, qpol_mls_level_t *h) {
|
||||
qpol_mls_range_t *range;
|
||||
qpol_policy_get_mls_range_from_semantic_levels(p, l, h, &range);
|
||||
qpol_policy_get_mls_range_from_mls_levels(p, l, h, &range);
|
||||
return range;
|
||||
}
|
||||
|
||||
@ -1586,7 +1594,7 @@ typedef struct qpol_semantic_level {} qpol_semantic_level_t;
|
||||
};
|
||||
|
||||
~qpol_semantic_level() {
|
||||
/* mls_semantic_level_destroy(self); */
|
||||
qpol_semantic_level_destroy(self);
|
||||
return;
|
||||
};
|
||||
|
||||
|
18
tests/policyrep/__init__.py
Normal file
18
tests/policyrep/__init__.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Copyright 2015, Tresys Technology, LLC
|
||||
#
|
||||
# This file is part of SETools.
|
||||
#
|
||||
# SETools is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# SETools is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with SETools. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from . import mls
|
136
tests/policyrep/mls.conf
Normal file
136
tests/policyrep/mls.conf
Normal file
@ -0,0 +1,136 @@
|
||||
class infoflow
|
||||
class infoflow2
|
||||
class infoflow3
|
||||
class infoflow4
|
||||
class infoflow5
|
||||
class infoflow6
|
||||
class infoflow7
|
||||
|
||||
sid kernel
|
||||
sid security
|
||||
|
||||
common infoflow
|
||||
{
|
||||
low_w
|
||||
med_w
|
||||
hi_w
|
||||
low_r
|
||||
med_r
|
||||
hi_r
|
||||
}
|
||||
|
||||
class infoflow
|
||||
inherits infoflow
|
||||
|
||||
class infoflow2
|
||||
inherits infoflow
|
||||
{
|
||||
super_w
|
||||
super_r
|
||||
}
|
||||
|
||||
class infoflow3
|
||||
{
|
||||
null
|
||||
}
|
||||
|
||||
class infoflow4
|
||||
inherits infoflow
|
||||
|
||||
class infoflow5
|
||||
inherits infoflow
|
||||
|
||||
class infoflow6
|
||||
inherits infoflow
|
||||
|
||||
class infoflow7
|
||||
inherits infoflow
|
||||
{
|
||||
super_w
|
||||
super_r
|
||||
super_none
|
||||
super_both
|
||||
super_unmapped
|
||||
}
|
||||
|
||||
sensitivity s0;
|
||||
sensitivity s1;
|
||||
sensitivity s2;
|
||||
|
||||
dominance { s0 s1 s2 }
|
||||
|
||||
category c0;
|
||||
category c1;
|
||||
category c2;
|
||||
category c3;
|
||||
category c4;
|
||||
category c5;
|
||||
category c6;
|
||||
category c7;
|
||||
category c8;
|
||||
category c9;
|
||||
category c10;
|
||||
category c11;
|
||||
category c12;
|
||||
category c13;
|
||||
|
||||
#level decl
|
||||
level s0:c0.c2;
|
||||
level s1:c0.c13;
|
||||
level s2:c0.c13;
|
||||
|
||||
#some constraints
|
||||
mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt));
|
||||
|
||||
attribute mls_exempt;
|
||||
|
||||
type system;
|
||||
role system;
|
||||
role system types system;
|
||||
|
||||
role role20_r;
|
||||
role role21a_r;
|
||||
role role21b_r;
|
||||
role role21c_r;
|
||||
|
||||
role role20_r types system;
|
||||
role role21a_r types system;
|
||||
role role21b_r types system;
|
||||
role role21c_r types system;
|
||||
|
||||
type type30;
|
||||
type type31a;
|
||||
type type31b;
|
||||
type type31c;
|
||||
role system types { type30 type31a type31b type31c };
|
||||
|
||||
allow system self:infoflow hi_w;
|
||||
|
||||
#users
|
||||
user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s2:c0.c4;
|
||||
user user10 roles system level s0 range s0 - s2:c0.c4;
|
||||
user user11a roles system level s0 range s0 - s2:c0.c4;
|
||||
user user11b roles system level s0 range s0 - s2:c0.c4;
|
||||
user user11c roles system level s0 range s0 - s2:c0.c4;
|
||||
|
||||
#normal constraints
|
||||
constrain infoflow hi_w (u1 == u2);
|
||||
|
||||
#isids
|
||||
sid kernel system:system:system:s0
|
||||
sid security system:system:system:s0
|
||||
|
||||
#fs_use
|
||||
fs_use_trans devpts system:object_r:system:s0;
|
||||
fs_use_xattr ext3 system:object_r:system:s0;
|
||||
fs_use_task pipefs system:object_r:system:s0;
|
||||
|
||||
#genfscon
|
||||
genfscon proc / system:object_r:system:s1
|
||||
genfscon proc /sys system:object_r:system:s0
|
||||
genfscon selinuxfs / system:object_r:system:s2:c0.c4
|
||||
portcon tcp 1 system:system:system:s0:c0.c1
|
||||
netifcon eth0 system:object_r:system:s0 system:object_r:system:s0
|
||||
nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0
|
||||
nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0
|
||||
|
97
tests/policyrep/mls.py
Normal file
97
tests/policyrep/mls.py
Normal file
@ -0,0 +1,97 @@
|
||||
# Copyright 2015, Tresys Technology, LLC
|
||||
#
|
||||
# This file is part of SETools.
|
||||
#
|
||||
# SETools is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# SETools is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with SETools. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
import unittest
|
||||
|
||||
from setools import SELinuxPolicy
|
||||
from setools.policyrep.mls import level_factory, InvalidLevel, range_factory, InvalidRange
|
||||
|
||||
|
||||
class BoolQueryTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.p = SELinuxPolicy("tests/policyrep/mls.conf")
|
||||
|
||||
def test_300_level_lookup_no_cats(self):
|
||||
"""Level lookup with no categories."""
|
||||
levelobj = level_factory(self.p.policy, "s2")
|
||||
self.assertEqual(str(levelobj), "s2")
|
||||
|
||||
def test_301_level_lookup_cat_range(self):
|
||||
"""Level lookup with category range."""
|
||||
levelobj = level_factory(self.p.policy, "s1:c0.c13")
|
||||
self.assertEqual(str(levelobj), "s1:c0.c13")
|
||||
|
||||
def test_302_level_lookup_complex_cats(self):
|
||||
"""Level lookup with complex category set."""
|
||||
levelobj = level_factory(self.p.policy, "s2:c0.c5,c7,c9.c11,c13")
|
||||
self.assertEqual(str(levelobj), "s2:c0.c5,c7,c9.c11,c13")
|
||||
|
||||
def test_303_level_lookup_bad1(self):
|
||||
"""Level lookup with garbage."""
|
||||
self.assertRaises(InvalidLevel, level_factory, self.p.policy, "FAIL")
|
||||
|
||||
def test_304_level_lookup_bad2(self):
|
||||
"""Level lookup with : in garbage."""
|
||||
self.assertRaises(InvalidLevel, level_factory, self.p.policy, "FAIL:BAD")
|
||||
|
||||
def test_305_level_lookup_bad_cat(self):
|
||||
"""Level lookup with invalid category."""
|
||||
self.assertRaises(InvalidLevel, level_factory, self.p.policy, "s0:FAIL")
|
||||
|
||||
def test_306_level_lookup_bad_cat_range(self):
|
||||
"""Level lookup with backwards category range."""
|
||||
self.assertRaises(InvalidLevel, level_factory, self.p.policy, "s0:c4.c0")
|
||||
|
||||
def test_306_level_lookup_cat_not_assoc(self):
|
||||
"""Level lookup with category not associated with sensitivity."""
|
||||
# c4 is not associated with s0.
|
||||
self.assertRaises(InvalidLevel, level_factory, self.p.policy, "s0:c0,c4")
|
||||
|
||||
def test_400_range_lookup_single_level(self):
|
||||
"""Range lookup with single-level range."""
|
||||
rangeobj = range_factory(self.p.policy, "s0")
|
||||
self.assertEqual(str(rangeobj), "s0")
|
||||
|
||||
def test_401_range_lookup_single_level_redundant(self):
|
||||
"""Range lookup with single-level range (same range listed twice)."""
|
||||
rangeobj = range_factory(self.p.policy, "s1-s1")
|
||||
self.assertEqual(str(rangeobj), "s1")
|
||||
|
||||
def test_402_range_lookup_simple(self):
|
||||
"""Range lookup with simple range."""
|
||||
rangeobj = range_factory(self.p.policy, "s0-s1:c0.c10")
|
||||
self.assertEqual(str(rangeobj), "s0 - s1:c0.c10")
|
||||
|
||||
def test_403_range_lookup_no_cats(self):
|
||||
"""Range lookup with no categories."""
|
||||
rangeobj = range_factory(self.p.policy, "s0-s1")
|
||||
self.assertEqual(str(rangeobj), "s0 - s1")
|
||||
|
||||
def test_404_range_lookup_complex(self):
|
||||
"""Range lookup with complex category set."""
|
||||
rangeobj = range_factory(self.p.policy, "s0:c0.c2-s2:c0.c5,c7,c9.c11,c13")
|
||||
self.assertEqual(str(rangeobj), "s0:c0.c2 - s2:c0.c5,c7,c9.c11,c13")
|
||||
|
||||
def test_405_range_lookup_non_dom(self):
|
||||
"""Range lookup with non-dominating high level."""
|
||||
self.assertRaises(InvalidRange, range_factory, self.p.policy, "s1-s0")
|
||||
|
||||
def test_406_range_lookup_invalid_range(self):
|
||||
"""Range lookup with an invalid range (low)."""
|
||||
# c13 is not associated with s0.
|
||||
self.assertRaises(InvalidRange, range_factory, self.p.policy, "s0:c13-s2:c13")
|
Loading…
Reference in New Issue
Block a user