Since failing to resolve a statement in an optional block is normal,
only display messages about the statement failing to resolve and the
optional block being disabled at the highest verbosity level.
These messages are now only at log level CIL_INFO instead of CIL_WARN.
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
There's a typo in commit b8213acff8 ("libsepol: add a function to optimize
kernel policy") which added new function sepol_policydb_optimize(), but there's
sepol_optimize_policy in libsepol.map.
LIBSEPOL_3.0 is used to follow the next release version libsepol-3.0
Signed-off-by: Petr Lautrbach <plautrba@redhat.com>
Acked-by: Ondrej Mosnacek <omosnace@redhat.com>
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
This improves commit b8213acf (libsepol: add a function to optimize
kernel policy) by Ondrej Mosnacek <omosnace@redhat.com> by always
removing redundant conditional rules which have an identical rule
in the unconditional policy.
Add a flag called not_cond to is_avrule_redundant(). When checking
unconditional rules against the avtab (which stores the unconditional
rules) we need to skip the actual rule that we are checking (otherwise
a rule would be determined to be redundant with itself and bad things
would happen), but when checking a conditional rule against the avtab
we do not want to skip an identical rule (which is what currently
happens), we want to remove the redundant permissions in the conditional
rule.
A couple of examples to illustrate when redundant condtional rules
are not removed.
Example 1
allow t1 t2:class1 perm1;
if (bool1) {
allow t1 t2:class1 perm1;
}
The conditional rule is clearly redundant, but without this change it
will not be removed, because of the check for an identical rule.
Example 2
typeattribute t1 a1;
allow t1 t2:class1 perm1;
allow a1 t2:class1 perm1;
if (bool1) {
allow t1 t2:class1 perm1;
}
The conditional rule is again clearly redundant, but now the order of
processing during the optimization will determine whether or not the
rule is removed. Because a1 contains only t1, a1 and t1 are considered
to be supersets of each other. If the rule with the attribute is
processed first, then it will be determined to be redundant and
removed, so the conditional rule will not be removed. But if the rule
with the type is processed first, then it will be removed and the
conditional rule will be determined to be redundant with the rule with
the attribute and removed as well.
The change reduces the size of policy a bit more than the original
optimization. Looking at the change in number of allow rules, there is
about a 10% improvement over the old optimization.
orig old new
Refpolicy 113284 82467 78053
Fedora 106410 64015 60008
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
Several static analyzers (clang's one, Facebook Infer, etc.) warn about
NULL pointer dereferences after a call to CU_ASSERT_PTR_NOT_NULL_FATAL()
in the test code written using CUnit framework. This is because this
CUnit macro is too complex for them to understand that the pointer
cannot be NULL: it is translated to a call to CU_assertImplementation()
with an argument as TRUE in order to mean that the call is fatal if the
asserted condition failed (cf.
http://cunit.sourceforge.net/doxdocs/group__Framework.html).
A possible solution could consist in replacing the
CU_ASSERT_..._FATAL() calls by assert() ones, as most static analyzers
know about assert(). Nevertheless this seems to go against CUnit's API.
An alternative solution consists in overriding CU_ASSERT_..._FATAL()
macros in order to expand to assert() after a call to the matching
CU_ASSERT_...() non-fatal macro. This appears to work fine and to remove
many false-positive warnings from various static analyzers.
As this substitution should only occur when using static analyzer, put
it under #ifdef __CHECKER__, which is the macro used by sparse when
analyzing the Linux kernel.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Use codespell (https://github.com/codespell-project/codespell) in order
to find many common misspellings that are present in English texts.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
In test_attr_types, the pointer decl is allowed to be NULL in the
beginning, but is dereferenced to produce a helpful message right before
a CU_ASSERT_FATAL. Make this derefence not happen if the pointer is
NULL.
This issue has been found using clang's static analyzer.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
semodule-utils/semodule_link/semodule_link.c contains:
static sepol_module_package_t *load_module(char *filename)
{
/* ... */
if (sepol_module_package_create(&p)) {
/* ... */
goto bad;
/* ... */
bad:
sepol_module_package_free(p);
When sepol_module_package_create() fails while having successfully
allocated p, it currently frees p without setting it back to NULL. This
causes a use-after-free in load_module().
Prevent this use-after-free by setting sepol_module_package_create's
argument back to NULL when an error happens.
This issue has been found using Infer static analyzer.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Doing this looks wrong:
len = scope->decl_ids_len;
if (scope == NULL) {
/* ... */
Move the dereferencing of scope after the NULL check.
This issue has been found using Infer static analyzer.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
When strs_stack_init(&stack) fails to allocate memory and stack is still
NULL, it should not be dereferenced with strs_stack_pop(stack).
This issue has been found using Infer static analyzer.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
As reported by Nicolas Iooss (nicolas.iooss@m4x.org), static analyzers
have problems understanding that the default memory error handler does
not return since it is called through the cil_mem_error_handler()
function pointer. This results in a number of false positive warnings
about null pointer dereferencing.
Since the ability to set the cil_mem_error_handler() is only through
the function cil_set_mem_error_handler() which is never used and whose
definition is not in any header file, remove that function, remove the
use of cil_mem_error_handler() and directly in-line the contents of
the default handler, cil_default_mem_error_handler().
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
This patch is loosely based on a patch by Yuli Khodorkovskiy
<yuli@crunchydata.com> from June 13th, 2019.
Since any permission used in the policy should be defined, CIL
should return an error if it cannot resolve a permission used
in a policy. This was the original behavior of CIL.
The behavior was changed over three commits from July to November
2016 (See commits 46e157b47, da51020d6, and 2eefb20d8). The change
was motivated by Fedora trying to remove permissions from its
policy that were never upstreamed (ex/ process ptrace_child and
capability2 compromise_kernel). Local or third party modules
compiled with those permissions would break policy updates.
After three years it seems unlikely that we need to worry about
those local and third party modules and it is time for CIL to
give an error like it should.
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
Policy developers can set a default_range default to glblub and
computed contexts will be the intersection of the ranges of the
source and target contexts. This can be used by MLS userspace
object managers to find the range of clearances that two contexts
have in common. An example usage is computing a transition between
the network context and the context of a user logging into an MLS
application.
For example, one can add a default with
this cil:
(defaultrange db_table glblub)
or in te (base module only):
default_range db_table glblub;
and then test using the compute_create utility:
$ ./compute_create system_u:system_r:kernel_t:s0:c1,c2,c5-s0:c1.c20 system_u:system_r:kernel_t:s0:c0.c20-s0:c0.c36 db_table
system_u:object_r:kernel_t:s0:c1,c2,c5-s0:c1.c20
Some example range transitions are:
User Permitted Range | Network Device Label | Computed Label
---------------------|----------------------|----------------
s0-s1:c0.c12 | s0 | s0
s0-s1:c0.c12 | s0-s1:c0.c1023 | s0-s1:c0.c12
s0-s4:c0.c512 | s1-s1:c0.c1023 | s1-s1:c0.c512
s0-s15:c0,c2 | s4-s6:c0.c128 | s4-s6:c0,c2
s0-s4 | s2-s6 | s2-s4
s0-s4 | s5-s8 | INVALID
s5-s8 | s0-s4 | INVALID
Signed-off-by: Joshua Brindle <joshua.brindle@crunchydata.com>
Remove legacy local boolean and user code, and to preserve API/ABI
compatibility the following functions int values should be set to '0'
as they are no longer used:
selinux_mkload_policy(int preservebools)
security_set_boolean_list(.... int permanent)
and the following are now no-op and return '-1':
security_load_booleans()
sepol_genusers()
sepol_set_delusers()
sepol_genbools()
sepol_genbools_array()
and these still return their paths for compatibility, however they are
marked as deprecated:
selinux_booleans_path()
selinux_users_path()
These have been removed as they are local functions only:
sepol_genusers_policydb()
sepol_genbools_policydb()
Also "SETLOCALDEFS" removed from SELinux config file and code.
Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
In module_to_cil.c, sepol_ppfile_to_module_package() calls functions
from module.c without including the internal header. This makes building
libsepol with "gcc -flto -fuse-ld=gold" fails when linking libsepol.so:
/tmp/ccHYAKVZ.ltrans21.ltrans.o:<artificial>:function
sepol_ppfile_to_module_package: error: undefined reference to
'sepol_module_package_free'
/tmp/ccHYAKVZ.ltrans21.ltrans.o:<artificial>:function
sepol_ppfile_to_module_package: error: undefined reference to
'sepol_module_package_create'
/tmp/ccHYAKVZ.ltrans21.ltrans.o:<artificial>:function
sepol_ppfile_to_module_package: error: undefined reference to
'sepol_module_package_create'
collect2: error: ld returned 1 exit status
Fixes: https://github.com/SELinuxProject/selinux/issues/165
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Add sepol_policydb_optimize(), which checks a kernel policy for
redundant rules (i.e. those that are covered by an existing more general
rule) and removes them.
Results on Fedora 29 policy:
WITHOUT OPTIMIZATION:
# time semodule -B
real 0m21,280s
user 0m18,636s
sys 0m2,525s
$ wc -c /sys/fs/selinux/policy
8692158 /sys/fs/selinux/policy
$ seinfo (edited)
Allow: 113159
Dontaudit: 10297
Total: 123156
WITH OPTIMIZATION ENABLED:
# time semodule -B
real 0m22,825s
user 0m20,178s
sys 0m2,520s
$ wc -c /sys/fs/selinux/policy
8096158 /sys/fs/selinux/policy
$ seinfo (edited)
Allow: 66334
Dontaudit: 7480
Total: 73814
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Installing a cil module with invalid mlsconstrain syntax currently
results in a segfault. In the following module, the right-hand side of
the second operand of the OR is a list (mlstrustedobject):
$ cat test.cil
(class test (foo) )
(classorder (unordered test))
(mlsconstrain (test (foo))
(or
(dom h1 h2)
(eq t2 (mlstrustedobject))
)
)
$ sudo semodule -i test.cil
zsh: segmentation fault sudo semodule -i test.cil
This syntax is invalid and should error accordingly, rather than
segfaulting. This patch provides this syntax error for the same module:
$ sudo semodule -i test.cil
t1, t2, r1, r2, u1, u2 cannot be used on the left side with a list on the right side
Bad expression tree for constraint
Bad constrain declaration at /var/lib/selinux/mls/tmp/modules/400/test/cil:4
semodule: Failed!
Signed-off-by: Mike Palmiotto <mike.palmiotto@crunchydata.com>
When validatetrans rule is in CIL policy it errors with:
u3, r3, and t3 can only be used with mlsvalidatetrans rules
Will now resolve these examples:
(validatetrans binder (and (and (eq t1 t1_t) (eq t2 t2_t)) (eq t3 t3_t)))
(mlsvalidatetrans file (and (and (eq t1 t1_t) (eq t2 t2_t))
(and (eq t3 t3_t) (domby h1 h2))))
Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
Most of the users of ebitmap_for_each_bit() macro only care for the set
bits, so introduce a new ebitmap_for_each_positive_bit() macro that
skips the unset bits. Replace uses of ebitmap_for_each_bit() with the
new macro where appropriate.
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
clang's static analyze reports a use-after-free in
__cil_expr_to_string(), when __cil_expr_to_string_helper() does not
modify its third parameter (variable s1 here) in this loop:
for (curr = curr->next; curr; curr = curr->next) {
__cil_expr_to_string_helper(curr, flavor, &s1);
cil_asprintf(&c2, "%s %s", c1, s1);
free(c1);
free(s1);
c1 = c2;
}
Silence this warning by making sure s1 is always NULL at the beginning
of every iteration of the loop.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
clang's static analyzer reports a warning when low_bit is used without
having been initialized in statements such as:
low_value = low_bit << 8;
The warning is: "Result of operation is garbage or undefined".
This is caused by low_bit being only initialized when in_range is true.
This issue is not critical because low_value is only used in an
"if (in_range)" block. Silence this warning by moving low_value's
assignment inside this block.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
These were reported by Petr Lautrbach (plautrba@redhat.com) and this
patch was based on his patch with only a few changes.
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
Nicolas Iooss reports:
When using checkpolicy to read a binary policy, permissive types are not
written in the output file. In order to reproduce this issue, a test
policy can be written from minimal.cil with the following commands:
$ cd secilc/test/
$ cp minimum.cil my_policy.cil
$ echo '(typepermissive TYPE)' >> my_policy.cil
$ secilc my_policy.cil
$ checkpolicy -bC -o /dev/stdout policy.31
# There is no "(typepermissive TYPE)" in checkpolicy output.
This is because TYPE_FLAGS_PERMISSIVE is added to typdatum->flags only
when loading a module, which uses the permissive flag in the type
properties. A kernel policy defines permissive types in a dedicated
bitmap, which gets loaded as p->permissive_map before the types are
loaded.
The solution is to use the permissive_map bitmap instead of relying on
the flags field of the struct type_datum when writing out CIL or
policy.conf policy from a binary.
Reported-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
The kernel checks if the port is in the range 1-255 when loading an
ibenportcon rule. Add the same check to libsepol.
Fixes: 118c0cd103 ("libsepol: Add ibendport ocontext handling")
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
We need to convert from little-endian before dong range checks on the
ibpkey port numbers, otherwise we would be checking a wrong value on
big-endian systems.
Fixes: 9fbb3112769a ("libsepol: Add ibpkey ocontext handling")
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Xen uses the initial SIDs domU and domDM in its toolstack, so it makes
sense to add these to xen_sid_to_str[] in kernel_to_common.h
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
When writing CIL from a policy module or when writing CIL or policy.conf
from a kernel binary policy, check that the initial sid index is within
the valid range of the selinux_sid_to_str[] array (or xen_sid_to_str[]
array for a XEN policy). If it is not, then create a unique name
("UNKNOWN"+index) for the initial sid.
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
Since the initial sid strings are defined in kernel_to_common.h,
module_to_cil.c can use those and its initial sid string definitions
can be removed.
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
Want to make use of selinux_sid_to_str[] and xen_sid_to_str[] from
kernel_to_common.h in module_to_cil.c, but stack functions with the
same names exist in module_to_cil.c and kernel_to_common.c (with
the function prototypes in kernel_to_common.h).
Since the stack functions in kernel_to_common.c are less general and
only work with strings, rename those functions from stack_* to
strs_stack_*.
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
Create the function called policydb_sort_ocontexts() that calls
the internal function sort_ocontexts() to sort the ocontexts of
a policydb.
The function sort_ocontexts() is already used by
sepol_kernel_policydb_to_conf() and sepol_kernel_policydb_to_cil()
when converting a binary policy to cil or policy.conf format.
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
When write_binary_policy() fails to open the binary policy, it calls
sepol_handle_destroy(f.handle) but structure f has not been initialized
at this point. Use variable handle instead.
This issue has been found using clang's static analyzer.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
f.handle is never set in read_binary_policy() so there is no need to
call sepol_handle_destroy() on it. Moreover clang's static analyzer
warns about an uninitialized argument value in the first call.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
va_copy()'s manpage [1] states:
Each invocation of va_copy() must be matched by a corresponding
invocation of va_end() in the same function.
create_str_helper() is using va_copy() without va_end(). Add the missing
call.
[1] https://linux.die.net/man/3/va_copy
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>