conditional.c:391:4: warning: Value stored to 'i' is never read [deadcode.DeadStores]
i = 0;
^ ~
conditional.c:718:2: warning: Value stored to 'len' is never read [deadcode.DeadStores]
len = 0;
^ ~
conditional.c:772:2: warning: Value stored to 'len' is never read [deadcode.DeadStores]
len = 0;
^ ~
services.c:89:10: warning: Value stored to 'new_stack' during its initialization is never read [deadcode.DeadStores]
char **new_stack = stack;
^~~~~~~~~ ~~~~~
services.c:440:11: warning: Value stored to 'new_expr_list' during its initialization is never read [deadcode.DeadStores]
char **new_expr_list = expr_list;
^~~~~~~~~~~~~ ~~~~~~~~~
../cil/src/cil_binary.c:2230:24: warning: Value stored to 'cb_node' during its initialization is never read [deadcode.DeadStores]
struct cil_tree_node *cb_node = node->cl_head;
^~~~~~~ ~~~~~~~~~~~~~
Found by clang-analyzer
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Follow the project style of no declaration after statement.
Found by the gcc warning -Wdeclaration-after-statement
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Follow the project style of no declaration after statement.
Found by the gcc warning -Wdeclaration-after-statement
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Unsigned integer overflow is well-defined and not undefined behavior.
But it is still useful to enable undefined behavior sanitizer checks on
unsigned arithmetic to detect possible issues on counters or variables
with similar purpose.
Use a spaceship operator like comparison instead of subtraction.
Modern compilers will generate a single comparison instruction instead
of actually perform the subtraction.
policydb.c:826:17: runtime error: unsigned integer overflow: 24 - 1699 cannot be represented in type 'unsigned int'
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
The functions `role_set_get_role`, `sepol_validate_transition` and
`sepol_sidtab_remove` seem to be unused since the initial import.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Declare the functions as static or include the corresponding header
file.
assertion.c:294:5: error: no previous prototype for function 'report_assertion_failures' [-Werror,-Wmissing-prototypes]
int report_assertion_failures(sepol_handle_t *handle, policydb_t *p, avrule_t *avrule)
^
context.c:23:5: error: no previous prototype for function 'sepol_check_context' [-Werror,-Wmissing-prototypes]
int sepol_check_context(const char *context)
^
expand.c:3377:5: error: no previous prototype for function 'expand_cond_av_node' [-Werror,-Wmissing-prototypes]
int expand_cond_av_node(policydb_t * p,
^
policydb.c:638:6: error: no previous prototype for function 'role_trans_rule_destroy' [-Werror,-Wmissing-prototypes]
void role_trans_rule_destroy(role_trans_rule_t * x)
^
policydb.c:1169:5: error: no previous prototype for function 'policydb_index_decls' [-Werror,-Wmissing-prototypes]
int policydb_index_decls(sepol_handle_t * handle, policydb_t * p)
^
policydb.c:1429:6: error: no previous prototype for function 'ocontext_selinux_free' [-Werror,-Wmissing-prototypes]
void ocontext_selinux_free(ocontext_t **ocontexts)
^
policydb.c:1451:6: error: no previous prototype for function 'ocontext_xen_free' [-Werror,-Wmissing-prototypes]
void ocontext_xen_free(ocontext_t **ocontexts)
^
policydb.c:1750:5: error: no previous prototype for function 'type_set_or' [-Werror,-Wmissing-prototypes]
int type_set_or(type_set_t * dst, type_set_t * a, type_set_t * b)
^
policydb.c:2524:5: error: no previous prototype for function 'role_trans_read' [-Werror,-Wmissing-prototypes]
int role_trans_read(policydb_t *p, struct policy_file *fp)
^
policydb.c:2567:5: error: no previous prototype for function 'role_allow_read' [-Werror,-Wmissing-prototypes]
int role_allow_read(role_allow_t ** r, struct policy_file *fp)
^
policydb.c:2842:5: error: no previous prototype for function 'filename_trans_read' [-Werror,-Wmissing-prototypes]
int filename_trans_read(policydb_t *p, struct policy_file *fp)
^
services.c:1027:5: error: no previous prototype for function 'sepol_validate_transition' [-Werror,-Wmissing-prototypes]
int sepol_validate_transition(sepol_security_id_t oldsid,
^
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Christian Göttsche <cgzones@googlemail.com> submitted a similar patch
to quote paths when generating CIL policy from a binary policy.
Since genfscon and devicetreecon rules have paths which are allowed
to contain spaces, always quote the path when writing out these rules.
Signed-off-by: James Carter <jwcart2@gmail.com>
Acked-by: Petr Lautrbach <plautrba@redhat.com>
It is possible for anonymous category sets to be in a category
expression if the expression has a macro parameter in it.
Unfortunately, anonymous category sets are not looked for when
resolving category expressions and a segfault will occur during
later processing if there was one.
As an example, consider the following portion of a policy.
(macro m1 ((categoryset cs))
(userlevel USER (s0 (cs)))
)
(call m1 ((c0 c1)))
This policy will cause a segault, because the categoryset datum
for the parameter cs is not seen as a categoryset and is treated
as a plain category.
When resolving an expression, check whether or not the datum that
is found is actually an anonymous category set associated with a
macro parameter. If it is, then resolve the category set if it
has not already been resolved and treat its categories as a sub
expression.
Signed-off-by: James Carter <jwcart2@gmail.com>
Acked-by: Nicolas Iooss <nicolas.iooss@m4x.org>
A named IP address (using an ipaddr rule) could be passed as an
argument, but trying to pass an actual IP address caused an error.
As an exmample, consider the following portion of a policy.
(macro m4 ((ipaddr ip)(ipaddr nm))
(nodecon ip nm (USER ROLE TYPE ((s0) (s0))))
)
(ipaddr nm1 255.255.255.0)
(ipaddr ip1 1.2.3.4)
(call m4 (ip1 nm1)) ; This works
(call m4 (1.2.3.4 255.255.255.0)) ; This doesn't
Allow actual IP addresses to be passed as a call argument. Now the
second call works as well.
Signed-off-by: James Carter <jwcart2@gmail.com>
Acked-by: Nicolas Iooss <nicolas.iooss@m4x.org>
When generating CIL policy from kernel or module policy quote paths,
which are allowed to contain spaces, in the statements `genfscon` and
`devicetreecon`.
Reported by LuK1337 while building policy for Android via IRC.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Anonymous levels can be passed as call arguments and they can
appear in anonymous levelranges as well.
Anonymous call arguments are resolved when they are used in a rule.
If more than one rule uses the anonymous level, then a memory leak
will occur when a new list for the category datum expression is
created without destroying the old one.
When resolving a level, check if the sensitivity datum has already
been resolved. If it has, then the categories have been as well.
Signed-off-by: James Carter <jwcart2@gmail.com>
Set the pointer to the sensitivity in levels, the pointers to the low
and high levels in levelranges, the pointer to the level in userlevels,
the pointer to the range in userranges, and the pointers to contexts
in ocontexts to NULL.
Signed-off-by: James Carter <jwcart2@gmail.com>
Anonymous class permission sets can be passed as call arguments.
Anonymous call arguments are resolved when they are used in a
rule. [This is because all the information might not be present
(like common permissions being added to a class) when the call
itself is resolved.] If there is more than one rule using an
anonymous class permission set, then a memory leak will occur
when a new list for the permission datum expression is created
without destroying the old one.
When resolving the class and permissions, check if the class has
already been resolved. If it has, then the permissions have been
as well.
This bug was found by the secilc-fuzzer.
Signed-off-by: James Carter <jwcart2@gmail.com>
When parsing a CIL policy, the number of open parenthesis is tracked
to verify that each has a matching close parenthesis. If there are
too many open parenthesis, a stack overflow could occur during later
processing.
Exit with an error if the number of open parenthesis exceeds 4096
(which should be enough for any policy.)
This bug was found by the secilc-fuzzer.
Signed-off-by: James Carter <jwcart2@gmail.com>
When exiting with an error because a class or common has too many
permissions, destroy the permission nodes.
This bug was found by the secilc-fuzzer.
Signed-off-by: James Carter <jwcart2@gmail.com>
A failed tunable resolution in a tunableif can cause an optional
to be disabled before the CIL_PASS_CALL1 phase. If this occurs, the
optional block and its subtree should be destroyed, but no reset
will be required since tunables are not allowed inside an optional
block.
Anytime there are optional blocks in the disabled_optionals list
(changed == 1), destroy the optional block and its subtree even if
in a pass before CIL_PASS_CALL1.
This bug was found by the secilc-fuzzer.
Signed-off-by: James Carter <jwcart2@gmail.com>
Lorenzo Ceragioli <lorenzo.ceragioli@phd.unipi.it> noted that the
following policy:
(type a)
(block A
(macro m ((type x))
(type a)
(allow x x (file (read))))
)
(block B
(call A.m(a))
)
results in the allow rule (allow B.a B.a (file(read))). This makes
no sense because the "a" being passed as an argument has to be the
global "a" and not the "a" defined in the macro.
This behavior occurs because the call arguments are resolved AFTER
the macro body has been copied and the declaration of "a" in the
macro has been added to block B's namespace, so this is the "a"
that the call argument resolves to, rather than the one in the
global namespace.
When resolving call arguments, check if the datum found belongs to
a declaration in the call. If it does, then remove the datum from
the symbol table, re-resolve the argument, and add the datum back
into the symbol table.
Signed-off-by: James Carter <jwcart2@gmail.com>
Rename cil_resolve_call1() as cil resolve_call() and rename
cil_resolve_call2() as cil_resolve_call_args() to make it clearer
what is being done in each function.
Move code to build call arguments out of cil_resolve_call() and into
the new function called cil_build_call_args() so that the logic of
cil_resolve_call() can be seen.
Exit cil_resolve_call() immediately if the call has already been
copied.
In __cil_resolve_ast_node(), only resolve calls outside of macros.
This results in more calls to cil_copy_ast(), but slightly less
rules copied overall (since no rules are copied into a macro). This
also means that the CIL_PASS_MACRO pass is not needed and can be
eliminated.
Signed-off-by: James Carter <jwcart2@gmail.com>
Allow inserting a key without providing a node.
This will make it easier to properly resolve call arguments where
a key might need to be temporarily removed to search for a datum
that is not declared within the call. Since the node is already
in the node list, re-inserting the key without this option would
add another link to the node and cause problems.
Also, do not add the node to the datum's node list if the result
of the call to hashtab_insert() is SEPOL_EEXIST because the datum
is a duplicate and will be destroyed.
Signed-off-by: James Carter <jwcart2@gmail.com>
The CIL Reference Guide specifies how name resolution is suppose
to work within an expanded macro.
1. Items defined inside the macro
2. Items passed into the macro as arguments
3. Items defined in the same namespace of the macro
4. Items defined in the caller's namespace
5. Items defined in the global namespace
But Lorenzo Ceragioli <lorenzo.ceragioli@phd.unipi.it> found
that the first step is not done.
So the following policy:
(block A
(type a)
(macro m ()
(type a)
(allow a self (CLASS (PERM)))
)
)
(block B
(call A.m)
)
will result in:
(allow A.a self (CLASS (PERM)))
instead of the expected:
(allow B.a self (CLASS (PERM)))
Now when an expanded call is found, the macro's namespace is
checked first. If the name is found, then the name was declared
in the macro and it is declared in the expanded call, so only the
namespace of the call up to and including the global namespace
will be searched. If the name is not found in the macro's namespace
then name resolution continues with steps 2-5 above.
Signed-off-by: James Carter <jwcart2@gmail.com>
When resolving a name in a block that has been inherited. First,
a search is done in the parent namespaces (if any) of the
blockinherit rule with the exception of the global namespace. If
the name is not found, then a search is done in the namespaces of
the original block (starting with that block's namespace) with
the exception of the global namespace. Finally, if it still has
not been found, the global namespace is searched.
This does not work if a declaration is in the block being
inherited.
For example:
(block b
(typeattribute a)
(allow a self (CLASS (PERM)))
)
(blockinherit b)
This will result in a policy with the following identical allow
rules:
(allow b.a self (CLASS (PERM)))
(allow b.a self (CLASS (PERM)))
rather than the expected:
(allow b.a self (CLASS (PERM)))
(allow a self (CLASS (PERM)))
This is because when the typeattribute is copied while resolving
the inheritance, the new datum is added to the global namespace
and, since that is searched last, the typeattribute in block b is
found first.
This behavior means that no declaration that is inherited into the
global namespace will actually be used.
Instead, if the name is not found in the parent namespaces (if any)
where the blockinherit is located with the exception of the global
namespace, start the next search in the namespace of the parent of
the original block (instead of the original block itself). Now if
a declaration is inherited from the original block, the new
declaration will be used. This behavior seems to be the originally
intended behavior because there is a comment in the code that says,
"Continue search in original block's parent".
This issue was found by secilc-fuzzer. If the original block
is made to be abstract, then the type attribute declaration
in the original block is not in the policy and a segfault
occurs when creating the binary because the copied allow rule
refers to a non-existent type attribute.
Signed-off-by: James Carter <jwcart2@gmail.com>
Use one of the policy config bits to tell the kernel to start using
the nlmsg_readneigh on RTM_GETNEIGH and RTM_GETNEIGHTBL messages instead
of the previous behavior of using nlmsg_read.
Bug: 171572148
Test: atest NetworkInterfaceTest
Test: atest bionic-unit-tests-static
Test: atest CtsSelinuxTargetSdkCurrentTestCases
Test: On Cuttlefish, run combinations of:
- Policy bit set or omitted
- App having nlmsg_readneigh permission or not
Verify that only the combination of the policy bit being set + the app
not having the nlmsg_readneigh permission prevents the app from
sending RTM_GETNEIGH messages.
Change-Id: I8598662b795feaeaeb8b0a7e676b684022861c37
The secilc-fuzzer found a self-referential loop using category sets.
Any set declaration in CIL that allows sets in it is susceptible to
the creation of a self-referential loop. There is a check, but only
for the name of the set being declared being used in the set
declaration.
Check for self-refential loops in user, role, and type attributes
and in category sets. Since all of the sets need to be declared,
this check has to be done when verifying the CIL db before doing
the post phase.
Signed-off-by: James Carter <jwcart2@gmail.com>
Return an error if a call argument fails to resolve so that
the resolution phase stops and returns an error.
This problem was found by the secilc-fuzzer.
Signed-off-by: James Carter <jwcart2@gmail.com>
The secilc-fuzzer found an out of bounds memory access occurs
when building the binary policy if a map class is included in a
classorder statement.
The order statements in CIL (sidorder, classorder, categoryorder,
and sensitivityorder) are used to specify an ordering for sids,
classes, categories, and sensitivities. When the order statments
are resolved and merged, only in the case of the category order
list is the datum resolved checked to see if it is the expected
flavor.
When resolving the sid, class, and sensitivity order statements,
check that each name resolved to a datum of the expected flavor
and return an error if it does not.
Signed-off-by: James Carter <jwcart2@gmail.com>
A CIL policy with inheritance of the form
...
(blockinherit ba)
(block ba
(block b1
(blockinherit bb)
)
(block bb
(block b2
(blockinherit bc)
)
(block bc
(block b3
(blockinherit bd)
)
(block bd
(block b4
(blockinherit be)
)
(block be
...
will require creating 2^depth copies of the block at the bottom of
the inheritance chain. This pattern can quickly consume all the
memory of the system compiling this policy.
The depth of the inheritance chain can be found be walking the
tree up through the parents and noting how many of the parent
blocks have been inherited. The number of times a block will be
copied is found by counting the list of nodes in the "bi_nodes"
list of the block. To minimize legitimate policies from being
falsely detected as being degenerate, both the depth and breadth
(number of copies) are checked and an error is given only if both
exceed the limits (depth >= 12 and breadth >= 4096).
This problem was found by the secilc-fuzzer.
Signed-off-by: James Carter <jwcart2@gmail.com>
There are six instances when the CIL policy is being built or
resolved where an error can be detected, but SEPOL_OK is returned
instead of SEPOL_ERR. This causes the policy compiler to continue
when it should exit with an error.
Return SEPOL_ERR in these cases, so the compiler exits with an
error.
Two of the instances were found by the secilc-fuzzer.
Signed-off-by: James Carter <jwcart2@gmail.com>
In struct cil_classperms_set, the "set" field is a pointer to a
struct cil_classpermission. Normally the classpermission is created
in a classpermissionset rule with a name declared in a
classpermission rule and stored in a symbol table. Commit c49a8ea0
("libsepol/cil: cil_reset_classperms_set() should not reset
classpermission") fixed the resetting of classperms sets by setting
the "set" field to NULL rather than resetting the classpermission
that it pointed to.
But this fix mixed the special case where an anonymous classperm
set is passed as an argument to a call. In this case the
classpermission is not named and not stored in a symtab, it is
created just for the classperms set and its classperms list needs
to be reset.
Reset the classperms list if the classperms set is anonymous (which
is when the datum name is NULL).
Signed-off-by: James Carter <jwcart2@gmail.com>
Add the functions cil_write_parse_ast(), cil_write_build_ast(),
and cil_write_resolve_ast() that can be used outside of libsepol.
These functions take a FILE pointer and CIL db, do the CIL build
through the desired phase, and then call cil_write_ast() to write
the CIL AST at that point.
Signed-off-by: James Carter <jwcart2@gmail.com>
The function cil_print_tree() has existed in cil_tree.c since the
beginning of the development of CIL and secilc. Unfortunately, it
used cil_log() at log level CIL_INFO to print out the AST and
has suffered greatly from bit rot.
Move the functions to write the CIL AST to cil_write_ast.c, update
the functions, and write the AST to the FILE pointer passed in as
an argument.
The function cil_write_ast() supports writing the CIL AST at three
different phases of the compiling a CIL policy. After parsing has
been done and the parse tree has been created, after the CIL AST
has been built, and after the CIL AST has been resolved.
Signed-off-by: James Carter <jwcart2@gmail.com>
In cil_compile(), CIL_INFO is being used as the priority for
error messages. This can make it difficult to tell when the error
occurred.
Instead, use CIL_ERR as the priority for the error messages in
cil_compile().
Signed-off-by: James Carter <jwcart2@gmail.com>
Use a consistent style for the error messages when an invalid
statement is found within tunableif, in-statement, block, macro,
optional, and booleanif blocks.
Signed-off-by: James Carter <jwcart2@gmail.com>
Since tunableifs are resolved before in-statements, do not allow
tuanble declarations in in-statements.
Since in-statements are the first flavor of statement that causes
part of the AST to be copied to another part, there is no need to
check the in-statements when resolving the AST.
Signed-off-by: James Carter <jwcart2@gmail.com>
When resolving the AST, tunable and in-statements are not considered
to be invalid in macros. This is inconsistent with the checks when
building the AST.
Add checks to make tunable and in-statments invalid in macros when
resolving the AST.
Signed-off-by: James Carter <jwcart2@gmail.com>
While there are some checks for invalid statements in an optional
block when resolving the AST, there are no checks when building the
AST.
OSS-Fuzz found the following policy which caused a null dereference
in cil_tree_get_next_path().
(blockinherit b3)
(sid SID)
(sidorder(SID))
(optional o
(ibpkeycon :(1 0)s)
(block b3
(filecon""block())
(filecon""block())))
The problem is that the blockinherit copies block b3 before
the optional block is disabled. When the optional is disabled,
block b3 is deleted along with everything else in the optional.
Later, when filecon statements with the same path are found an
error message is produced and in trying to find out where the block
was copied from, the reference to the deleted block is used. The
error handling code assumes (rightly) that if something was copied
from a block then that block should still exist.
It is clear that in-statements, blocks, and macros cannot be in an
optional, because that allows nodes to be copied from the optional
block to somewhere outside even though the optional could be disabled
later. When optionals are disabled the AST is reset and the
resolution is restarted at the point of resolving macro calls, so
anything resolved before macro calls will never be re-resolved.
This includes tunableifs, in-statements, blockinherits,
blockabstracts, and macro definitions. Tunable declarations also
cannot be in an optional block because they are needed to resolve
tunableifs. It should be fine to allow blockinherit statements in
an optional, because that is copying nodes from outside the optional
to the optional and if the optional is later disabled, everything
will be deleted anyway.
Check and quit with an error if a tunable declaration, in-statement,
block, blockabstract, or macro definition is found within an
optional when either building or resolving the AST.
Signed-off-by: James Carter <jwcart2@gmail.com>
When building the AST, typemember rules in a booleanif block will
be incorrectly called invalid. They are allowed in the kernel
policy and should be allowed in CIL.
When resolving the AST, if a neverallow rule is copied into a
booleanif block, it will not be considered an invalid rule, even
though this is not allowed in the kernel policy.
Update the booleanif checks to allow typemember rules and to not
allow neverallow rules in booleanifs. Also use the same form of
conditional for the checks when building and resolving the AST.
Signed-off-by: James Carter <jwcart2@gmail.com>
Reorder checks for invalid rules in the blocks of tunableifs,
in-statements, macros, and booleanifs when resolving the AST for
consistency.
Order the checks in the same order the blocks will be resolved in,
so tuanbleif, in-statement, macro, booleanif, and then non-block
rules.
Signed-off-by: James Carter <jwcart2@gmail.com>
When resolving the AST, block and optional stacks are used to
determine if the current rule being resolved is in a block or
an optional. There is no need to do this since the parent node
pointers can be used when exiting a block or an optional to
determine if resolution is still within a block or an optional.
When entering either a block or an optional, update the appropriate
tree node pointer. When finished with the last child of a block or
optional, set the appropriate pointer to NULL. If a parent of the
same kind is found when the parent node pointers are followed back
to the root node, then set the pointer to that tree node.
Signed-off-by: James Carter <jwcart2@gmail.com>
In order to find statements not allowed in tunableifs, in-statements,
macros, and booleanifs, there are tree node pointers that point to
each of these kinds of statements when its block is being parsed.
If the pointer is non-NULL, then the rule being parsed is in the block
of that kind of statement.
The tree node pointers were being updated at the wrong point which
prevented an invalid statement from being found if it was the first
statement in the block of a tunableif, in-statement, macro, or
booleanif.
Create a first child helper function for walking the parse tree and
in that function set the appropriate tree node pointer if the
current AST node is a tunableif, in-statement, macro, or booleanif.
This also makes the code symmetrical with the last child helper
where the tree node pointers are set to NULL.
Signed-off-by: James Carter <jwcart2@gmail.com>
Since parse_current, finished, and extra_args can never be NULL,
remove the useless check and directly assign local variables from
extra_args.
Signed-off-by: James Carter <jwcart2@gmail.com>
Reorder checks for invalid rules in the blocks of tunableifs,
in-statements, macros, and booleanifs when building the AST for
consistency.
Order the checks in the same order the blocks will be resolved in,
so tuanbleif, in-statement, macro, booleanif, and then non-block
rules.
Signed-off-by: James Carter <jwcart2@gmail.com>
In cil_gen_node(), after the declaration is added to the symbol
table, if the parent is a macro, then a check is made to ensure
the declaration does not shadow any of the macro's parameters.
This check also needs to be done when copying the AST.
Move the check for the shadowing of macro parameters to its own
function, cil_verify_decl_does_not_shadow_macro_parameter(), and
refactor cil_gen_node() and __cil_copy_node_helper() to use the
new function.
Signed-off-by: James Carter <jwcart2@gmail.com>
The functionality of adding a declaration to a symbol table is also
needed in __cil_copy_node_helper() and not just cil_gen_node().
Create a new function called cil_add_decl_to_symtab() to add a
declaration to a symtab and refactor cil_gen_node() and
__cil_copy_node_helper() to use the new function.
By using the new function, __cil_copy_node_helper() will now allow
duplicate declarations when appropriate.
Signed-off-by: James Carter <jwcart2@gmail.com>
Change the name of cil_is_datum_multiple_decl() to
cil_allow_multiple_decls() and make it static. The new function
takes the CIL db and the flavors of the old and new datum as
arguments. Also, put all of the logic of determining if multiple
declarations are allowed into the new function. Finally, update
the call from cil_gen_node().
Signed-off-by: James Carter <jwcart2@gmail.com>
The following policy will cause a segfault:
(class CLASS (PERM))
(class C (P1 P2 P3))
(classorder (CLASS C))
(sid SID)
(sidorder (SID))
(user USER)
(role ROLE)
(type TYPE)
(category CAT)
(categoryorder (CAT))
(sensitivity SENS)
(sensitivityorder (SENS))
(sensitivitycategory SENS (CAT))
(allow TYPE self (CLASS (PERM)))
(roletype ROLE TYPE)
(userrole USER ROLE)
(userlevel USER (SENS))
(userrange USER ((SENS)(SENS (CAT))))
(sidcontext SID (USER ROLE TYPE ((SENS)(SENS))))
(classmap CM (PM1 PM2 PM3))
(classmapping CM PM1 (C (P1)))
(classmapping CM PM2 (C (P2)))
(classmapping CM PM3 (C (P3)))
(allow TYPE self (CM (and (all) (not PM2))))
The problem is that, while permission expressions are allowed for
normal classes, map classes are expected to only have permission
lists and no check is done to verify that only a permission list
is being used.
When the above policy is parsed, the "and" and "all" are seen as
expression operators, but when the map permissions are converted to
normal class and permissions, the permission expression is assumed
to be a list of datums and since the operators are not datums a
segfault is the result.
There is no reason to limit map classes to only using a list of
permissions and, in fact, it would be better to be able to use them
in the same way normal classes are used.
Allow permissions expressions to be used for map classes by first
evaluating the permission expression and then converting the
resulting list to normal classes and permissions.
Signed-off-by: James Carter <jwcart2@gmail.com>
When CIL parses sets or conditional expressions, any identifier that
matches an operator name will always be taken as an operator. If a
declaration has the same name as an operator, then there is the
possibility of causing either confusion or a syntax error if it is
used in an expression. The potential for problems is much greater
than any possible advantage in allowing a declaration to share the
name of a reserved word.
Create a new function, __cil_is_reserved_name() that is called when
an identifier is declared and its name is being validated. In this
function, check if the declaration has the same name as a reserved
word for an expression operator that can be used with the identifer's
flavor and exit with an error if it does.
Also, move the check for types, type aliases, and type attributes
matching the reserved word "self" to this new function.
Finally, change the name of the function __cil_verify_name() to
cil_verify_name(), since this function is neither static nor a
helper function.
Signed-off-by: James Carter <jwcart2@gmail.com>
In constraint expressions u1, u3, r1, r3, t1, and t3 are never
allowed on the right side of an expression, but there were no checks
to verify that they were not used on the right side. The result was
that the expression "(eq t1 t1)" would be silently turned into
"(eq t1 t2)" when the binary policy was created.
Verify that u1, u3, r1, r3, t1, and t3 are not used on the right
side of a constraint expression.
Signed-off-by: James Carter <jwcart2@gmail.com>
The class field of a struct cil_classperms points to the class looked
up in the symbol table, so that field should be set to NULL when
the cil_classperms is reset.
Set the class field to NULL when resetting the struct cil_classperms.
Signed-off-by: James Carter <jwcart2@gmail.com>
In struct cil_classperms_set, the set field is a pointer to a
struct cil_classpermission which is looked up in the symbol table.
Since the cil_classperms_set does not create the cil_classpermission,
it should not reset it.
Set the set field to NULL instead of resetting the classpermission
that it points to.
Signed-off-by: James Carter <jwcart2@gmail.com>
Map perms share the same struct as regular perms, but only the
map perms use the classperms field. This field is a pointer to a
list of classperms that is created and added to when resolving
classmapping rules, so the map permission doesn't own any of the
data in the list and this list should be destroyed when the AST is
reset.
When resetting a perm, destroy the classperms list without destroying
the data in the list.
Signed-off-by: James Carter <jwcart2@gmail.com>
Nicolas Iooss reports:
A few months ago, OSS-Fuzz found a crash in the CIL compiler, which
got reported as
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28648 (the title
is misleading, or is caused by another issue that conflicts with the
one I report in this message). Here is a minimized CIL policy which
reproduces the issue:
(class CLASS (PERM))
(classorder (CLASS))
(sid SID)
(sidorder (SID))
(user USER)
(role ROLE)
(type TYPE)
(category CAT)
(categoryorder (CAT))
(sensitivity SENS)
(sensitivityorder (SENS))
(sensitivitycategory SENS (CAT))
(allow TYPE self (CLASS (PERM)))
(roletype ROLE TYPE)
(userrole USER ROLE)
(userlevel USER (SENS))
(userrange USER ((SENS)(SENS (CAT))))
(sidcontext SID (USER ROLE TYPE ((SENS)(SENS))))
(classpermission CLAPERM)
(optional OPT
(roletype nonexistingrole nonexistingtype)
(classpermissionset CLAPERM (CLASS (PERM)))
)
The CIL policy fuzzer (which mimics secilc built with clang Address
Sanitizer) reports:
==36541==ERROR: AddressSanitizer: heap-use-after-free on address
0x603000004f98 at pc 0x56445134c842 bp 0x7ffe2a256590 sp
0x7ffe2a256588
READ of size 8 at 0x603000004f98 thread T0
#0 0x56445134c841 in __cil_verify_classperms
/selinux/libsepol/src/../cil/src/cil_verify.c:1620:8
#1 0x56445134a43e in __cil_verify_classpermission
/selinux/libsepol/src/../cil/src/cil_verify.c:1650:9
#2 0x56445134a43e in __cil_pre_verify_helper
/selinux/libsepol/src/../cil/src/cil_verify.c:1715:8
#3 0x5644513225ac in cil_tree_walk_core
/selinux/libsepol/src/../cil/src/cil_tree.c:272:9
#4 0x564451322ab1 in cil_tree_walk
/selinux/libsepol/src/../cil/src/cil_tree.c:316:7
#5 0x5644513226af in cil_tree_walk_core
/selinux/libsepol/src/../cil/src/cil_tree.c:284:9
#6 0x564451322ab1 in cil_tree_walk
/selinux/libsepol/src/../cil/src/cil_tree.c:316:7
#7 0x5644512b88fd in cil_pre_verify
/selinux/libsepol/src/../cil/src/cil_post.c:2510:7
#8 0x5644512b88fd in cil_post_process
/selinux/libsepol/src/../cil/src/cil_post.c:2524:7
#9 0x5644511856ff in cil_compile
/selinux/libsepol/src/../cil/src/cil.c:564:7
The classperms list of a classpermission rule is created and filled
in when classpermissionset rules are processed, so it doesn't own any
part of the list and shouldn't retain any of it when it is reset.
Destroy the classperms list (without destroying the data in it) when
resetting a classpermission rule.
Reported-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Signed-off-by: James Carter <jwcart2@gmail.com>
Based on patch by Nicolas Iooss, who writes:
OSS-Fuzz found a Heap-buffer-overflow in the CIL compiler when trying
to compile the following policy:
(sid SID)
(sidorder(SID))
(filecon "\" any ())
(filecon "" any ())
When cil_post_fc_fill_data() processes "\", it goes beyond the NUL
terminator of the string. Fix this by returning when '\0' is read
after a backslash.
To be consistent with the function compute_diffdata() in
refpolicy/support/fc_sort.py, also increment str_len in this case.
Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28484
Reported-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Signed-off-by: James Carter <jwcart2@gmail.com>
In CIL, blocks, optionals, and macros share the same symbol table so
that the targets of "in" statements can be located. Because of this,
they cannot have the same name in the same namespace, but, because
they do not show up in the final policy, they can have the same name
as long as they are in different namespaces. Unfortunately, when
copying from one namespace to another, no check was being done to see
if there was a conflict.
When copying blocks, optionals, and macros, if a datum is found in
the destination namespace, then there is a conflict with a previously
declared block, optional, or macro, so exit with an error.
Reported-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Reported-by: Evgeny Vereshchagin <evvers@ya.ru>
Signed-off-by: James Carter <jwcart2@gmail.com>
If a role or user attribute with nothing associated with it is used
in a constraint expression, then the bitmap will be empty. This is
not a problem for the kernel, but does cause problems when converting
a kernel policy or module to CIL.
When creating a CIL policy from a kernel policy or module, if an
empty bitmap is encountered, use the string "NO_IDENTIFIER". An
error will occur if an attempt is made to compile the resulting
policy, but a valid policy was not being produced before anyway.
Treat types the same way even though empty bitmaps are not expected.
Signed-off-by: James Carter <jwcart2@gmail.com>
When writing CIL policy from a kernel policy or module, if there are
multiple users, roles, or types, then the list needs to be enclosed
by "(" and ")".
When writing a constraint expression, check to see if there are
multiple identifiers in the names string and enclose the list with
"(" and ")" if there are.
Signed-off-by: James Carter <jwcart2@gmail.com>
The expectation in CIL was to use user, role, or type attributes in
constraint expressions. The problem is that neither user nor role
attributes are part of the kernel binary policy, so when converting
from a kernel policy to CIL, that would require the creation of a
role or user attribute. The better solution is to just allow a list
to be used. In fact, the only thing preventing a list to be used
is a check in cil_verify_constraint_leaf_expr_syntax().
Remove the check and allow lists in constraint expressions.
The following is now allowed:
(constrain (CLASS1 (PERM1)) (eq r1 (ROLE1 ROLE2 ROLE_ATTR3)))
Signed-off-by: James Carter <jwcart2@gmail.com>
When writing a policy.conf from a kernel policy, if there are
multiple users, roles, or types, then the list needs to be enclosed
by "{" and "}".
When writing a constraint expression, check to see if there are
multiple identifiers in the names string and enclose the list
with "{" and "}" if there are.
Signed-off-by: James Carter <jwcart2@gmail.com>
If a role attribute with no roles associated with it is used in a
constraint expression, then the role bitmap will be empty. This is
not a problem for the kernel, but does cause problems when
converting a kernel policy to policy.conf.
When creating a policy.conf from a kernel policy, if an empty bitmap
is encountered, use the string "NO_IDENTIFIER". An error will occur
if an attempt is made to compile the resulting policy, but this is
better than exiting with an error without creating a policy.conf.
Signed-off-by: James Carter <jwcart2@gmail.com>
Using signed integer to represent counts can troube some gcc
optimisation passes, for example in
https://github.com/fishilico/selinux/runs/2125501324?check_suite_focus=true#step:9:107
In function ‘name_list_to_string’,
inlined from ‘constraint_expr_to_string’ at module_to_cil.c:1799:11:
module_to_cil.c:1156:8: error: argument 1 range
[18446744071562067968, 18446744073709551615] exceeds maximum
object size 9223372036854775807 [-Werror=alloc-size-larger-than=]
1156 | str = malloc(len);
| ^~~~~~~~~~~
In file included from module_to_cil.c:39:
module_to_cil.c: In function ‘constraint_expr_to_string’:
/usr/include/stdlib.h:539:14: note: in a call to allocation
function ‘malloc’ declared here
539 | extern void *malloc (size_t __size) __THROW __attribute_malloc__
| ^~~~~~
The wide range (from 18446744071562067968 = 0xffffffff80000000 to
18446744073709551615 = 0xffffffffffffffff) was caused by num_names being
a signed int used in "len += num_names;", even though it should always
be non-negative.
Prevent such issues from occurring by using "unsigned int" where
appropriate.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
OSS-Fuzz found a Null-dereference in __cil_insert_name when trying to
compile the following policy:
(macro MACRO ()
(classmap CLASS (PERM))
(type TYPE)
(typetransition TYPE TYPE CLASS "name" TYPE)
)
(call MACRO)
When using a macro with no argument, macro->params is NULL and
cil_list_for_each(item, macro->params) dereferenced a NULL pointer.
Fix this by checking that macro->params is not NULL before using it.
Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28565
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
All functions of the CIL compiler use cil_log or cil_tree_log to report
errors, but in two places which still uses printf. Replace these printf
invocation with cil_tree_log.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
printf("%i\n", node->flavor); looks very much like a statement which was
added for debugging purpose and was unintentionally left.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
cil_post_fc_fill_data() is not used outside of cil_post.c, and is not
exported in libsepol.so. Make it static, in order to ease the analysis
of static analyzers.
While at it, make its path argument "const char*" and the fields of
"struct fc_data" "unsigned int" or "size_t", in order to make the types
better match the values.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
For policy versions between 20 and 23, attributes exist in the
policy, but only in the type_attr_map. This means that there are
gaps in both the type_val_to_struct and p_type_val_to_name arrays
and policy rules can refer to those gaps which can lead to NULL
dereferences when using sepol_kernel_policydb_to_conf() and
sepol_kernel_policydb_to_cil().
This can be seen with the following policy:
class CLASS1
sid SID1
class CLASS1 { PERM1 }
attribute TYPE_ATTR1;
type TYPE1;
typeattribute TYPE1 TYPE_ATTR1;
allow TYPE_ATTR1 self : CLASS1 PERM1;
role ROLE1;
role ROLE1 types TYPE1;
user USER1 roles ROLE1;
sid SID1 USER1:ROLE1:TYPE1
Compile the policy:
checkpolicy -c 23 -o policy.bin policy.conf
Converting back to a policy.conf causes a segfault:
checkpolicy -F -b -o policy.bin.conf policy.bin
Have both sepol_kernel_policydb_to_conf() and
sepol_kernel_policydb_to_cil() exit with an error if the kernel
policy version is between 20 and 23.
Acked-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Signed-off-by: James Carter <jwcart2@gmail.com>
At one point link_modules() might have needed this initial copying,
but now it serves no purpose, so remove it.
Signed-off-by: James Carter <jwcart2@gmail.com>
Types associated to role attributes in optional blocks are not
associated with the roles that have that attribute. The problem
is that role_fix_callback is called before the avrule_decls are
walked.
Example/
class CLASS1
sid kernel
class CLASS1 { PERM1 }
type TYPE1;
type TYPE1A;
allow TYPE1 self : CLASS1 PERM1;
attribute_role ROLE_ATTR1A;
role ROLE1;
role ROLE1A;
roleattribute ROLE1A ROLE_ATTR1A;
role ROLE1 types TYPE1;
optional {
require {
class CLASS1 PERM1;
}
role ROLE_ATTR1A types TYPE1A;
}
user USER1 roles ROLE1;
sid kernel USER1:ROLE1:TYPE1
In this example ROLE1A will not have TYPE1A associated to it.
Call role_fix_callback() after the avrule_decls are walked.
Signed-off-by: James Carter <jwcart2@gmail.com>
When creating the kernel binary policy, role attributes in constraint
expressions are not expanded. This causes the constraint expression
to refer to a non-existent role in the kernel policy. This can lead
to a segfault when converting the binary policy back to conf or CIL
source or when using policy tools such as seinfo.
Expand role attributes in constraint expressions when creating the
kernel binary policy.
Reported-by: Christian Göttsche <cgzones@googlemail.com>
Signed-off-by: James Carter <jwcart2@gmail.com>
Facebook's Infer static analyzer warns about a use-after-free issue in
libsemanage:
int semanage_direct_mls_enabled(semanage_handle_t * sh)
{
sepol_policydb_t *p = NULL;
int retval;
retval = sepol_policydb_create(&p);
if (retval < 0)
goto cleanup;
/* ... */
cleanup:
sepol_policydb_free(p);
return retval;
}
When sepol_policydb_create() is called, p is allocated and
policydb_init() is called. If this second call fails, p is freed
andsepol_policydb_create() returns -1, but p still stores a pointer to
freed memory. This pointer is then freed again in the cleanup part of
semanage_direct_mls_enabled().
Fix this by setting p to NULL in sepol_policydb_create() after freeing
it.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
CIL permits not assigning a context to a SID, e.g. to an unused initial
SID, e.g. 'any_socket'.
When using the example policy from the SELinux Notebook,
https://github.com/SELinuxProject/selinux-notebook/blob/main/src/notebook-examples/cil-policy/cil-policy.cil,
secilc logs:
No context assigned to SID any_socket, omitting from policy at cil-policy.cil:166
But secil2conf segfaults when writing the policy.conf:
../cil/src/cil_policy.c:274:2: runtime error: member access within null pointer of type 'struct cil_context'
Only print the sid context statement if a context was actually assigned.
The sid declaration is still included via cil_sid_decls_to_policy().
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
Nicolas Iooss reports that fuzzing /usr/libexec/hll/pp with the
American Fuzzy Lop revealed that inconsistent policy modules could be
created that caused NULL dereferences and other problems.
When reading in a binary modular or kernel policy, check values in the
policydb to verify consistency. When reading in the data for commons,
classes, roles, types, users, booleans, sensitivities, and categories
verify that their value is between 1 and the number of primary
identifiers (value-1 is used to index the sym_val_to_name array for
all of these and the val_to_struct array for classes, roles, users,
and types.) Next all references in policy rules are checked to ensure
that they refer to a valid value.
It is possible for the type and role struct and name arrays to have
gaps in them. For roles, there will be gaps in the case of a kernel
policy created from a policy with role attributes, but nothing in the
policy will refer to any of the gaps. For types, there will be gaps
for any kernel policy with a version from 20 to 23, but, unfortunately,
there will be references to the gaps. This is because, while attributes
exist in these policies, they only exist in the type_attr_map. For
policies with versions between 20 and 23, it must be assumed that all
of the gaps and any references to them are valid. To check for
references to gaps, bitmaps are created to map where the gaps are and
all values are verified to be within the proper range and not within a
gap.
Reported-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Signed-off-by: James Carter <jwcart2@gmail.com>
Create the function ebitmap_highest_set_bit() which returns the position
of the highest bit set in the ebitmap.
The return value is valid only if the ebitmap is not empty. An empty
ebitmap will return 0.
Signed-off-by: James Carter <jwcart2@gmail.com>
Nicolas Iooss reports:
I am continuing to investigate OSS-Fuzz crashes and the following one
is quite complex. Here is a CIL policy which triggers a
heap-use-after-free error in the CIL compiler:
(class CLASS (PERM2))
(classorder (CLASS))
(classpermission CLSPRM)
(optional o
(mlsvalidatetrans x (domby l1 h1))
(common CLSCOMMON (PERM1))
(classcommon CLASS CLSCOMMON)
)
(classpermissionset CLSPRM (CLASS (PERM1)))
The issue is that the mlsvalidatetrans fails to resolve in pass
CIL_PASS_MISC3, which comes after the resolution of classcommon (in
pass CIL_PASS_MISC2). So:
* In pass CIL_PASS_MISC2, the optional block still exists, the
classcommon is resolved and class CLASS is linked with common
CLSCOMMON.
* In pass CIL_PASS_MISC3, the optional block is destroyed, including
the common CLSCOMMON.
* When classpermissionset is resolved, function cil_resolve_classperms
uses "common_symtab = &class->common->perms;", which has been freed.
The use-after-free issue occurs in __cil_resolve_perms (in
libsepol/cil/src/cil_resolve_ast.c):
// common_symtab was freed
rc = cil_symtab_get_datum(common_symtab, curr->data, &perm_datum);
The fundamental problem here is that when the optional block is
disabled it is immediately destroyed in the middle of the pass, so
the class has not been reset and still refers to the now destroyed
common when the classpermissionset is resolved later in the same pass.
Added a list, disabled_optionals, to struct cil_args_resolve which is
passed when resolving the tree. When optionals are disabled, they are
now added to this list and then are destroyed after the tree has been
reset between passes.
Reported-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Signed-off-by: James Carter <jwcart2@gmail.com>
Acked-by: Nicolas Iooss <nicolas.iooss@m4x.org>
clang 11.0.0 reports the following warning several times (when building
with "make CC=clang" from libsepol directory, in the default
configuration of the git repository):
../cil/src/cil_binary.c:1980:8: error: cast to smaller integer type
'enum cil_flavor' from 'void *' [-Werror,-Wvoid-pointer-to-enum-cast]
op = (enum cil_flavor)curr->data;
^~~~~~~~~~~~~~~~~~~~~~~~~~~
Silence this warning by casting the pointer to an integer the cast to
enum cil_flavor.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
OSS-Fuzz found a Null-dereference READ in the CIL compiler when trying
to compile the following policy:
(<src_info>)
In cil_gen_src_info(), parse_current->next is NULL even though the code
expects that both parse_current->next and parse_current->next->next
exists.
Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28457
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
OSS-Fuzz found a Null-dereference READ in the CIL compiler when trying
to compile the following policy:
(macro m((name n))) (call m(()))
When calling the macro, the name (in variable "pc") is NULL, which
triggers a NULL pointer dereference when using it as a key in
__cil_insert_name(). The stack trace is:
#0 0x7f4662655a85 in __strlen_avx2 (/usr/lib/libc.so.6+0x162a85)
#1 0x556d0b6d150c in __interceptor_strlen.part.0 (/selinux/libsepol/fuzz/fuzz-secilc+0x44850c)
#2 0x556d0ba74ed6 in symhash /selinux/libsepol/src/symtab.c:22:9
#3 0x556d0b9ef50d in hashtab_search /selinux/libsepol/src/hashtab.c:186:11
#4 0x556d0b928e1f in cil_symtab_get_datum /selinux/libsepol/src/../cil/src/cil_symtab.c:121:37
#5 0x556d0b8f28f4 in __cil_insert_name /selinux/libsepol/src/../cil/src/cil_resolve_ast.c:96:2
#6 0x556d0b908184 in cil_resolve_call1 /selinux/libsepol/src/../cil/src/cil_resolve_ast.c:2835:12
#7 0x556d0b91b404 in __cil_resolve_ast_node /selinux/libsepol/src/../cil/src/cil_resolve_ast.c
#8 0x556d0b91380f in __cil_resolve_ast_node_helper /selinux/libsepol/src/../cil/src/cil_resolve_ast.c:3773:7
#9 0x556d0b932230 in cil_tree_walk_core /selinux/libsepol/src/../cil/src/cil_tree.c:263:9
#10 0x556d0b932230 in cil_tree_walk /selinux/libsepol/src/../cil/src/cil_tree.c:307:7
#11 0x556d0b932326 in cil_tree_walk_core /selinux/libsepol/src/../cil/src/cil_tree.c:275:9
#12 0x556d0b932326 in cil_tree_walk /selinux/libsepol/src/../cil/src/cil_tree.c:307:7
#13 0x556d0b911189 in cil_resolve_ast /selinux/libsepol/src/../cil/src/cil_resolve_ast.c:3941:8
#14 0x556d0b798729 in cil_compile /selinux/libsepol/src/../cil/src/cil.c:550:7
Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28544
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Nicolas Iooss reports:
OSS-Fuzz found an integer overflow when compiling the following
(empty) CIL policy:
;;*lms 2147483647 a
; (empty line)
Change hll_lineno to uint32_t which is the type of the field hll_line
in struct cil_tree_node where the line number will be stored eventually.
Read the line number into an unsigned long variable using strtoul()
instead of strtol(). On systems where ULONG_MAX > UINT32_MAX, return
an error if the value is larger than UINT32_MAX.
Also change hll_expand to uint32_t, since its value will be either
0 or 1 and there is no need for it to be signed.
Reported-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Signed-off-by: James Carter <jwcart2@gmail.com>
It is good practise in C to include the header file that specifies the
prototype of functions which are defined in the source file. Otherwise,
the function prototypes which be different, which could cause unexpected
issues.
Add the include directives to do this.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
In libsepol/src/mls.c, functions sepol_mls_contains and sepol_mls_check
used "sepol_policydb_t * policydb" even though
libsepol/include/sepol/context.h used "const sepol_policydb_t *
policydb".
Add const qualifiers in mls.c in order to match the header file. Detect
such mismatching error at compile time by including the header file in
mls.c.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
libsepol/src/roles.c contains functions which do not match its header
file libsepol/include/sepol/roles.h:
// In roles.c
int sepol_role_exists(sepol_handle_t * handle __attribute__ ((unused)),
sepol_policydb_t * p, const char *role, int *response)
// In roles.h
extern int sepol_role_exists(const sepol_policydb_t * policydb,
const char *role, int *response);
and:
// In roles.c
int sepol_role_list(sepol_handle_t * handle,
sepol_policydb_t * p, char ***roles, unsigned int *nroles)
// In roles.h
extern int sepol_role_list(const sepol_policydb_t * policydb,
char ***roles, unsigned int *nroles);
Instead of fixing the parameter type (using sepol_handle_t or
sepol_policydb_t but not different ones), remove these functions, as
they appear not to be used. They are not exported in libsepol.so.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
This is based on a patch by Nicolas Iooss. He writes:
When secilc compiles the following policy:
(block b1
(optional o1
(blockinherit b1)
(blockinherit x)
)
)
it disables the optional block at pass 3 (CIL_PASS_BLKIN_LINK)
because the block "x" does not exist.
__cil_resolve_ast_last_child_helper() calls
cil_tree_children_destroy() on the optional block, which destroys
the two blockinherit statements. But the (blockinherit b1) node
was referenced inside (block b1) node, in its block->bi_nodes list.
Therefore, when this list is used at pass 4 (CIL_PASS_BLKIN_COPY),
it contains a node which was freed: this triggers a use-after-free
issue
Fix this issue by removing blockinherit nodes from their lists of
nodes block->bi_nodes when they are being destroyed. As
cil_destroy_blockinherit() does not have a reference to the node
containing the blockinherit data, implement this new logic in
cil_tree_node_destroy().
This issue was found while investigating a testcase from an OSS-Fuzz
issue which seems unrelated (a Null-dereference READ in
cil_symtab_get_datum,
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=29861).
Reported-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Signed-off-by: James Carter <jwcart2@gmail.com>
Acked-by: Nicolas Iooss <nicolas.iooss@m4x.org>
The following CIL policy triggers a heap use-after-free in secilc
because when the blockinherit node is destroyed, the block node was
already destroyed:
(block b2a)
(blockinherit b2a)
Fix this by setting blockinherit->block to NULL when destroying block.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Acked-by: James Carter <jwcart2@gmail.com>
When __cil_validate_constrain_expr() fails,
cil_constrain_to_policydb_helper() does not destroy the constraint
expression. This leads to a memory leak reported by OSS-Fuzz with the
following CIL policy:
(class CLASS (PERM))
(classorder (CLASS))
(sid SID)
(sidorder (SID))
(user USER)
(role ROLE)
(type TYPE)
(category CAT)
(categoryorder (CAT))
(sensitivity SENS)
(sensitivityorder (SENS))
(sensitivitycategory SENS (CAT))
(allow TYPE self (CLASS (PERM)))
(roletype ROLE TYPE)
(userrole USER ROLE)
(userlevel USER (SENS))
(userrange USER ((SENS)(SENS (CAT))))
(sidcontext SID (USER ROLE TYPE ((SENS)(SENS))))
(constrain
(CLASS (PERM))
(or
(eq t1 TYPE)
(or
(eq t1 TYPE)
(or
(eq t1 TYPE)
(or
(eq t1 TYPE)
(or
(eq t1 TYPE)
(eq t1 TYPE)
)
)
)
)
)
)
Add constraint_expr_destroy(sepol_expr) to destroy the expression.
Moreover constraint_expr_destroy() was not freeing all items of an
expression. Code in libsepol/src and checkpolicy contained while loop to
free all the items of a constraint expression, but not the one in
libsepol/cil. As freeing only the first item of an expression is
misleading, change the semantic of constraint_expr_destroy() to iterate
the list of constraint_expr_t and to free all items.
Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28938
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Acked-by: James Carter <jwcart2@gmail.com>
Nicolas Iooss reports:
A few weeks ago, OSS-Fuzz got configured in order to fuzz the CIL
policy compiler (cf.
https://github.com/SELinuxProject/selinux/issues/215 and
https://github.com/google/oss-fuzz/pull/4790). It reported a bunch of
simple issues, for which I will submit patches. There are also more
subtle bugs, like the one triggered by this CIL policy:
(class CLASS (PERM))
(classorder (CLASS))
(sid SID)
(sidorder (SID))
(sensitivity SENS)
(sensitivityorder (SENS))
(type TYPE)
(allow TYPE self (CLASS (PERM)))
(block b
(optional o
(sensitivitycategory SENS (C)) ; Non-existing category
triggers disabling the optional
(common COMMON (PERM1))
(classcommon CLASS COMMON)
(allow TYPE self (CLASS (PERM1)))
)
)
On my computer, secilc manages to build this policy fine, but when
clang's Address Sanitizer is enabled, running secilc leads to the
following report:
$ make -C libsepol/src CC=clang CFLAGS='-g -fsanitize=address' libsepol.a
$ clang -g -fsanitize=address secilc/secilc.c libsepol/src/libsepol.a
-o my_secilc
$ ./my_secilc -vv testcase.cil
Parsing testcase.cil
Building AST from Parse Tree
Destroying Parse Tree
Resolving AST
Failed to resolve sensitivitycategory statement at testcase.cil:12
Disabling optional 'o' at testcase.cil:11
Resetting declarations
=================================================================
==181743==ERROR: AddressSanitizer: heap-use-after-free on address
0x6070000000c0 at pc 0x55ff7e445d24 bp 0x7ffe7eecfba0 sp
0x7ffe7eecfb98
READ of size 4 at 0x6070000000c0 thread T0
#0 0x55ff7e445d23 in __class_reset_perm_values
/git/selinux-userspace/libsepol/src/../cil/src/cil_reset_ast.c:17:17
The problem is that the optional branch is destroyed when it is disabled,
so the common has already been destroyed when the reset code tries to
access the number of common permissions, so that it can change the
value of the class permissions back to their original values.
The solution is to count the number of class permissions and then
calculate the number of common permissions.
Reported-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Signed-off-by: James Carter <jwcart2@gmail.com>
This field is suppose to be used to track the number of primary names in
the symtab. It was not being updated or used.
Increment the nprim field when a new datum is added to the symtab and
decrement the field when a datum is removed.
Signed-off-by: James Carter <jwcart2@gmail.com>
OSS-Fuzz found a direct memory leak in policydb_filetrans_insert()
because filenametr_destroy() does not fully destroy the list associated
with a typetransition.
More precisely, let's consider this (minimized) CIL policy:
(class CLASS (PERM))
(classorder (CLASS))
(sid SID)
(sidorder (SID))
(user USER)
(role ROLE)
(type TYPE) ; "type 1" in libsepol internal structures
(type TYPE2) ; "type 2" in libsepol internal structures
(type TYPE3) ; "type 3" in libsepol internal structures
(category CAT)
(categoryorder (CAT))
(sensitivity SENS)
(sensitivityorder (SENS))
(sensitivitycategory SENS (CAT))
(allow TYPE self (CLASS (PERM)))
(roletype ROLE TYPE)
(userrole USER ROLE)
(userlevel USER (SENS))
(userrange USER ((SENS)(SENS (CAT))))
(sidcontext SID (USER ROLE TYPE ((SENS)(SENS))))
(typetransition TYPE2 TYPE CLASS "some_file" TYPE2)
(typetransition TYPE3 TYPE CLASS "some_file" TYPE3)
The two typetransition statements make policydb_filetrans_insert()
insert an item with key {ttype=1, tclass=1, name="some_file"} in the
hashmap p->filename_trans. This item contains a linked list of two
filename_trans_datum_t elements:
* The first one uses {otype=2, stypes=bitmap containing 2}
* The second one uses {otype=3, stypes=bitmap containing 3}
Nevertheless filenametr_destroy() (called by
hashtab_map(p->filename_trans, filenametr_destroy, NULL);) only frees
the first element. Fix this memory leak by freeing all elements.
This issue was introduced by commit 42ae834a74 ("libsepol,checkpolicy:
optimize storage of filename transitions") and was never present in the
kernel, as filenametr_destroy() was modified appropriately in commit
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c3a276111ea2572399281988b3129683e2a6b60b
Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=29138
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Acked-by: Ondrej Mosnacek <omosnace@redhat.com>
OSS-Fuzz found a NULL pointer dereference when the CIL compiler tries to
compile a policy with an invalid integer:
$ echo '(ioportcon(2())n)' > tmp.cil
$ secilc tmp.cil
Segmentation fault (core dumped)
This is because strtol() is called with a NULL pointer, in
cil_fill_integer().
Fix this by checking that int_node->data is not NULL. While at it, use
strtoul() instead of strtol() to parse an unsigned integer.
When using "val > UINT32_MAX" with "unsigned long val;", it is expected
that some compilers emit a warning when the size of "unsigned long" is
32 bits. In theory gcc could be such a compiler (with warning
-Wtype-limits, which is included in -Wextra). Nevertheless this is
currently broken, according to
https://gcc.gnu.org/pipermail/gcc-help/2021-January/139755.html and
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89126 (this bug was
opened in January 2019).
In order to prevent this warning from appearing, introduce some
preprocessor macros around the bound check.
Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28456
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Acked-by: James Carter <jwcart2@gmail.com>
When __cil_resolve_perms fails, it does not destroy perm_datums, which
leads to a memory leak reported by OSS-Fuzz with the following CIL
policy:
(class cl01())
(classorder(cl01))
(type at02)
(type tpr3)
(allow at02 tpr3(cl01((s))))
Calling cil_list_destroy() fixes the issue.
Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28466
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
OSS-Fuzz found a heap buffer overflow (out-of-bound reads) when the CIL
compiler tries to report a recursive blockinherit with an optional
block:
$ echo '(block b (optional o (blockinherit b)))' > tmp.cil
$ secilc tmp.cil
Segmentation fault (core dumped)
This is because cil_print_recursive_blockinherit() assumes that all
nodes are either CIL_BLOCK or CIL_BLOCKINHERIT. Add support for other
block kinds, using cil_node_to_string() to show them.
Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28462
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Function cil_add_file() copies its input into a newly-allocated buffer,
and does not modify "name". State these properties in the types of
parameters by adding "const" qualifiers.
This enables using LibFuzzer directly on cil_add_file(), without a
warning about discarding "const" qualifier:
fuzz-secilc.c: In function ‘LLVMFuzzerTestOneInput’:
fuzz-secilc.c:57:31: warning: passing argument 3 of ‘cil_add_file’
discards ‘const’ qualifier from pointer target type
[-Wdiscarded-qualifiers]
57 | if (cil_add_file(db, "fuzz", data, size) != SEPOL_OK)
| ^~~~
In file included from fuzz-secilc.c:26:
/usr/include/sepol/cil/cil.h:45:57: note: expected ‘char *’ but
argument is of type ‘const uint8_t *’ {aka ‘const unsigned char *’}
45 | extern int cil_add_file(cil_db_t *db, char *name, char *data, size_t size);
| ~~~~~~^~~~
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
OSS-Fuzz found a Null-dereference READ in the CIL compiler when trying
to compile the following policy:
(optional o (validatetrans x (eq t3 (a ()))))
With some logs, secilc reports:
Invalid syntax
Destroying Parse Tree
Resolving AST
Failed to resolve validatetrans statement at fuzz:1
Disabling optional 'o' at tmp.cil:1
So there is an "Invalid syntax" error, but the compilation continues.
Fix this issue by stopping the compilation when cil_fill_list() reports
an error:
Invalid syntax
Bad expression tree for constraint
Bad validatetrans declaration at tmp.cil:1
Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=29061
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
OSS-Fuzz found a heap use-after-free when the CIL compiler destroys its
database after failing to compile the following policy:
(validatetrans x (eq t3 (a)))
This is caused by the fact that the validatetrans AST object references
a stack variable local to __cil_fill_constraint_leaf_expr, when parsing
the list "(a)":
struct cil_list *sub_list;
cil_fill_list(current->next->next->cl_head, leaf_expr_flavor, &sub_list);
cil_list_append(*leaf_expr, CIL_LIST, &sub_list);
Drop the & sign to really add the list like it is supposed to be.
Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28507
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
OSS-Fuzz found a NULL pointer dereference when the CIL compiler tries to
compile a policy where a categoryalias references an unused
categoryalias:
$ echo '(categoryalias c0)(categoryalias c1)(categoryaliasactual c0 c1)' > tmp.cil
$ secil tmp.cil
Segmentation fault (core dumped)
In such a case, a1 can become NULL in cil_resolve_alias_to_actual().
Add a check to report an error when this occurs. Now the error message
is:
Alias c0 references an unused alias c1 at tmp.cil:1
Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28471
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
cil_copy_expandtypeattribute prints "cil_copy_expandtypeattribute 656"
which is quite annoying. Remove the fprintf statement responsible for
this.
While at it, remove another one in cil_tree_print_node()
Fixes: https://lore.kernel.org/selinux/3c2ab876-b0b7-42eb-573d-e5b450a7125a@gmail.com/T/#u
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
It was found in https://github.com/google/oss-fuzz/pull/4790:
```
Invalid token '' at line 2 of fuzz
NEW_FUNC[1/2]: 0x67fff0 in yy_get_previous_state /src/selinux/libsepol/src/../cil/src/cil_lexer.c:1143
NEW_FUNC[2/2]: 0x6803e0 in yy_try_NUL_trans /src/selinux/libsepol/src/../cil/src/cil_lexer.c:1176
=================================================================
==12==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000007992 at pc 0x000000681800 bp 0x7ffccddee530 sp 0x7ffccddee528
WRITE of size 1 at 0x602000007992 thread T0
SCARINESS: 41 (1-byte-write-heap-use-after-free)
#0 0x6817ff in cil_yy_switch_to_buffer /src/selinux/libsepol/src/../cil/src/cil_lexer.c:1315:17
#1 0x6820cc in cil_yy_scan_buffer /src/selinux/libsepol/src/../cil/src/cil_lexer.c:1571:2
#2 0x682662 in cil_lexer_setup /src/selinux/libsepol/src/../cil/src/cil_lexer.l:73:6
#3 0x5cf2ae in cil_parser /src/selinux/libsepol/src/../cil/src/cil_parser.c:220:2
#4 0x56d5e2 in cil_add_file /src/selinux/libsepol/src/../cil/src/cil.c:514:7
#5 0x556e91 in LLVMFuzzerTestOneInput /src/secilc-fuzzer.c:434:7
#6 0x459ab1 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:599:15
#7 0x45a755 in fuzzer::Fuzzer::TryDetectingAMemoryLeak(unsigned char const*, unsigned long, bool) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:675:3
#8 0x45acd9 in fuzzer::Fuzzer::MutateAndTestOne() /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:747:5
#9 0x45b875 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:883:5
#10 0x4499fb in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:906:6
#11 0x473a32 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
#12 0x7f982296d83f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2083f)
#13 0x41e758 in _start (/out/secilc-fuzzer+0x41e758)
DEDUP_TOKEN: cil_yy_switch_to_buffer--cil_yy_scan_buffer--cil_lexer_setup
0x602000007992 is located 2 bytes inside of 4-byte region [0x602000007990,0x602000007994)
freed by thread T0 here:
#0 0x521ef2 in free /src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:127:3
#1 0x56d630 in cil_add_file /src/selinux/libsepol/src/../cil/src/cil.c:526:2
#2 0x556e91 in LLVMFuzzerTestOneInput /src/secilc-fuzzer.c:434:7
#3 0x459ab1 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:599:15
#4 0x458fba in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:505:3
#5 0x45acc7 in fuzzer::Fuzzer::MutateAndTestOne() /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:745:19
#6 0x45b875 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:883:5
#7 0x4499fb in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:906:6
#8 0x473a32 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
#9 0x7f982296d83f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2083f)
DEDUP_TOKEN: free--cil_add_file--LLVMFuzzerTestOneInput
previously allocated by thread T0 here:
#0 0x52215d in malloc /src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:145:3
#1 0x5cecb8 in cil_malloc /src/selinux/libsepol/src/../cil/src/cil_mem.c:39:14
#2 0x56d584 in cil_add_file /src/selinux/libsepol/src/../cil/src/cil.c:510:11
#3 0x556e91 in LLVMFuzzerTestOneInput /src/secilc-fuzzer.c:434:7
#4 0x459ab1 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:599:15
#5 0x458fba in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:505:3
#6 0x45acc7 in fuzzer::Fuzzer::MutateAndTestOne() /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:745:19
#7 0x45b875 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:883:5
#8 0x4499fb in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:906:6
#9 0x473a32 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
#10 0x7f982296d83f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2083f)
DEDUP_TOKEN: malloc--cil_malloc--cil_add_file
SUMMARY: AddressSanitizer: heap-use-after-free /src/selinux/libsepol/src/../cil/src/cil_lexer.c:1315:17 in cil_yy_switch_to_buffer
Shadow bytes around the buggy address:
0x0c047fff8ee0: fa fa fd fa fa fa fd fd fa fa fd fa fa fa fd fd
0x0c047fff8ef0: fa fa fd fa fa fa fd fd fa fa fd fa fa fa fd fd
0x0c047fff8f00: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fd
0x0c047fff8f10: fa fa fd fa fa fa fd fd fa fa fd fa fa fa fd fd
0x0c047fff8f20: fa fa fd fa fa fa fd fd fa fa fd fa fa fa fd fa
=>0x0c047fff8f30: fa fa[fd]fa fa fa fd fa fa fa fd fa fa fa fd fa
0x0c047fff8f40: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
0x0c047fff8f50: fa fa fd fa fa fa fd fd fa fa fd fa fa fa fd fa
0x0c047fff8f60: fa fa fd fd fa fa fd fa fa fa fd fd fa fa fd fa
0x0c047fff8f70: fa fa 00 00 fa fa 02 fa fa fa 02 fa fa fa 00 fa
0x0c047fff8f80: fa fa 03 fa fa fa 00 fa fa fa 03 fa fa fa 00 fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==12==ABORTING
```
Signed-off-by: Evgeny Vereshchagin <evvers@ya.ru>
Acked-by: Nicolas Iooss <nicolas.iooss@m4x.org>
In cil_symtab.h, the macro FLAVOR() is defined. It refers to the
flavor of the first node in the list of nodes that declare the datum.
(The flavors of every node should be the same.) While the macro was
used in many places, it was not used everywhere that it could be.
Change all the remaining places to use FLAVOR().
Signed-off-by: James Carter <jwcart2@gmail.com>
In cil_symtab.h, the macro NODE() is defined. It refers to the first
node in the list of nodes that declare that datum. (It is rare for
a datum to have more than one node in this list.) While the macro was
used in many places, it was not used everywhere that it could be.
Change all the remaining places to use NODE().
Signed-off-by: James Carter <jwcart2@gmail.com>
Block, macro, and optional names are all in stored in a block symtab. A
declarations fully-qualified name includes all of the block names from
the root node to the declaration separated by dots. Macro and optional
names are only used when trying to determine the block referred to by
an "in" block. An optional block name might be stored in a macro's
symtab, but optional blocks have no symtab and (*datum)->symtab just
refers to the symtab of the datum which would be the current symtab.
Since the assignment is not needed, remove it so the code is clearer.
Signed-off-by: James Carter <jwcart2@gmail.com>
When resolving names, the struct cil_args_resolve is passed to the
various resolve functions. The field last_resolved_name is not used.
Remove the last_resolved_name field from struct cil_args_resolve.
Signed-off-by: James Carter <jwcart2@gmail.com>
Since cil_gen_node() is only called from declarations, the check to
determine if the node is a declaration is not needed, so remove it.
Signed-off-by: James Carter <jwcart2@gmail.com>
The function cil_tree_walk() has an argument that can be used by
the process_node helper function to tell cil_tree_walk() to skip
the node's sub-tree or the rest of the current branch. The constants
CIL_TREE_SKIP_NOTHING, CIL_TREE_SKIP_NEXT and CIL_TREE_SKIP_HEAD are
defined to be used by that argument.
Fixed two instances in the function __cil_build_ast_node_helper()
where the value 1 is used instead of the more informative
CIL_TREE_SKIP_NEXT.
Signed-off-by: James Carter <jwcart2@gmail.com>
In get_class_info(), if realloc(class_buf, new_class_buf_len) fails to
grow the memory, the function returns NULL without freeing class_buf.
This leads to a memory leak which is reported by clang's static
analyzer:
https://580-118970575-gh.circle-artifacts.com/0/output-scan-build/2020-11-11-194150-6152-1/report-42a899.html#EndPath
Fix the memory leak by calling free(class_buf).
While at it, use size_t insted of int to store the size of the buffer
which is growing.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Both tunableif and booleanif use conditional blocks (either true or
false). No ordering is imposed, so a false block can be first (or even
the only) block. Checks are made to ensure that the first and second
(if it exists) blocks are either true or false, but no checks are made
to ensure that there is only one true and/or one false block. If there
are more than one true or false block, only the first will be used and
the other will be ignored.
Create a function, cil_verify_conditional_blocks(), that gives an error
along with a message if more than one true or false block is specified
and call that function when building tunableif and booleanif blocks in
the AST.
Signed-off-by: James Carter <jwcart2@gmail.com>
Acked-by: Ondrej Mosnacek <omosnace@redhat.com>
Previous commits removed some symbols and broke ABI, therefore we need to change
SONAME.
See the following quotes from distribution guidelines:
https://www.debian.org/doc/debian-policy/ch-sharedlibs.html#run-time-shared-libraries
Every time the shared library ABI changes in a way that may break
binaries linked against older versions of the shared library, the SONAME
of the library and the corresponding name for the binary package
containing the runtime shared library should change.
https://docs.fedoraproject.org/en-US/packaging-guidelines/#_downstream_so_name_versioning
When new versions of the library are released, you should use an ABI
comparison tool to check for ABI differences in the built shared
libraries. If it detects any incompatibilities, bump the n number by
one.
Signed-off-by: Petr Lautrbach <plautrba@redhat.com>
These functions were converted to no-op by commit
c3f9492d7f ("selinux: Remove legacy local boolean and user code") and
left in libsepol/src/deprecated_functions.c to preserve API/ABI. As we
change libsepol ABI dropping duplicate symbols it's time to drop these
functions too.
Signed-off-by: Petr Lautrbach <plautrba@redhat.com>
Versioned duplicate symbols cause problems for LTO. These symbols were
introduced during the CIL integration several releases ago and were only
consumed by other SELinux userspace components.
Fixes: https://github.com/SELinuxProject/selinux/issues/245
Signed-off-by: Petr Lautrbach <plautrba@redhat.com>
When find_avtab_node() is called with key->specified & AVTAB_XPERMS and
xperms=NULL, xperms is being dereferenced. This is detected as a
"NULL pointer dereference issue" by static analyzers.
Even though it does not make much sense to call find_avtab_node() in a
way which triggers the NULL pointer dereference issue, static analyzers
have a hard time with calls such as:
node = find_avtab_node(handle, avtab, &avkey, cond, NULL);
... where xperms=NULL.
So, make the function report an error instead of crashing.
Here is an example of report from clang's static analyzer:
https://558-118970575-gh.circle-artifacts.com/0/output-scan-build/2020-10-02-065849-6375-1/report-d86a57.html#EndPath
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Contrary to Linux kernel, BUG_ON() does not halt the execution, in
libsepol/src/services.c. Instead it displays an error message and
continues the execution.
This means that this code does not prevent an out-of-bound write from
happening:
case CEXPR_AND:
BUG_ON(sp < 1);
sp--;
s[sp] &= s[sp + 1];
Use if(...){BUG();rc=-EINVAL;goto out;} constructions instead, to make
sure that the array access is always in-bound.
This issue has been found using clang's static analyzer:
https://558-118970575-gh.circle-artifacts.com/0/output-scan-build/2020-10-02-065849-6375-1/report-50a861.html#EndPath
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
When compiling SELinux userspace tools with -ftrapv (this option
generates traps for signed overflow on addition, subtraction,
multiplication operations, instead of silently wrapping around),
semodule crashes when running the tests from
scripts/ci/fedora-test-runner.sh in a Fedora 32 virtual machine:
[root@localhost selinux-testsuite]# make test
make -C policy load
make[1]: Entering directory '/root/selinux-testsuite/policy'
# Test for "expand-check = 0" in /etc/selinux/semanage.conf
# General policy build
make[2]: Entering directory '/root/selinux-testsuite/policy/test_policy'
Compiling targeted test_policy module
Creating targeted test_policy.pp policy package
rm tmp/test_policy.mod.fc
make[2]: Leaving directory '/root/selinux-testsuite/policy/test_policy'
# General policy load
domain_fd_use --> off
/usr/sbin/semodule -i test_policy/test_policy.pp test_mlsconstrain.cil test_overlay_defaultrange.cil test_add_levels.cil test_glblub.cil
make[1]: *** [Makefile:174: load] Aborted (core dumped)
Using "coredumpctl gdb" leads to the following strack trace:
(gdb) bt
#0 0x00007f608fe4fa25 in raise () from /lib64/libc.so.6
#1 0x00007f608fe38895 in abort () from /lib64/libc.so.6
#2 0x00007f6090028aca in __addvsi3.cold () from /lib64/libsepol.so.1
#3 0x00007f6090096f59 in __avrule_xperm_setrangebits (low=30, high=30, xperms=0x8b9eea0)
at ../cil/src/cil_binary.c:1551
#4 0x00007f60900970dd in __cil_permx_bitmap_to_sepol_xperms_list (xperms=0xb650a30, xperms_list=0x7ffce2653b18)
at ../cil/src/cil_binary.c:1596
#5 0x00007f6090097286 in __cil_avrulex_ioctl_to_policydb (k=0xb8ec200 "@\023\214\022\006", datum=0xb650a30,
args=0x239a640) at ../cil/src/cil_binary.c:1649
#6 0x00007f609003f1e5 in hashtab_map (h=0x41f8710, apply=0x7f60900971da <__cil_avrulex_ioctl_to_policydb>,
args=0x239a640) at hashtab.c:234
#7 0x00007f609009ea19 in cil_binary_create_allocated_pdb (db=0x2394f10, policydb=0x239a640)
at ../cil/src/cil_binary.c:4969
#8 0x00007f609009d19d in cil_binary_create (db=0x2394f10, policydb=0x7ffce2653d30) at ../cil/src/cil_binary.c:4329
#9 0x00007f609008ec23 in cil_build_policydb_create_pdb (db=0x2394f10, sepol_db=0x7ffce2653d30)
at ../cil/src/cil.c:631
#10 0x00007f608fff4bf3 in semanage_direct_commit () from /lib64/libsemanage.so.1
#11 0x00007f608fff9fae in semanage_commit () from /lib64/libsemanage.so.1
#12 0x0000000000403e2b in main (argc=7, argv=0x7ffce2655058) at semodule.c:753
(gdb) f 3
#3 0x00007f6090096f59 in __avrule_xperm_setrangebits (low=30, high=30, xperms=0x8b9eea0)
at ../cil/src/cil_binary.c:1551
1551 xperms->perms[i] |= XPERM_SETBITS(h) - XPERM_SETBITS(low);
A signed integer overflow therefore occurs in XPERM_SETBITS(h):
#define XPERM_SETBITS(x) ((1 << (x & 0x1f)) - 1)
This macro is expanded with h=31, so "(1 << 31) - 1" is computed:
* (1 << 31) = -0x80000000 is the lowest signed 32-bit integer value
* (1 << 31) - 1 overflows the capacity of a signed 32-bit integer and
results in 0x7fffffff (which is unsigned)
Using unsigned integers (with "1U") fixes the crash, as
(1U << 31) = 0x80000000U has no overflowing issues.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Acked-by: Petr Lautrbach <plautrba@redhat.com>
When classmaps used in a neverallow were being expanded during CIL
neverallow checking, an empty classmapping in the list of
classmappings for a classmap would cause the classmap expansion to
stop and the rest of the classmapping of the classmap to be ignored.
This would mean that not all of the classes and permissions associated
with the classmap would be used to check for a neverallow violation.
Do not end the expansion of a classmap when one classmapping is empty.
Reported-by: Jonathan Hettwer <j2468h@gmail.com>
Signed-off-by: James Carter <jwcart2@gmail.com>
Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com>
CIL was not correctly determining the depth of conditional expressions
which prevented it from giving an error when the max depth was exceeded.
This allowed invalid policy binaries to be created.
Validate the conditional expression using the same logic that is used
when evaluating a conditional expression. This includes checking the
depth of the expression.
Signed-off-by: James Carter <jwcart2@gmail.com>
Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com>
CIL was not correctly determining the depth of constraint expressions
which prevented it from giving an error when the max depth was exceeded.
This allowed invalid policy binaries with constraint expressions exceeding
the max depth to be created.
Validate the constraint expression using the same logic that is used
when reading the binary policy. This includes checking the depth of the
the expression.
Reported-by: Jonathan Hettwer <j2468h@gmail.com>
Signed-off-by: James Carter <jwcart2@gmail.com>
Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Implement a new, more space-efficient form of storing filename
transitions in the binary policy. The internal structures have already
been converted to this new representation; this patch just implements
reading/writing an equivalent representation from/to the binary policy.
This new format reduces the size of Fedora policy from 7.6 MB to only
3.3 MB (with policy optimization enabled in both cases). With the
unconfined module disabled, the size is reduced from 3.3 MB to 2.4 MB.
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
In preparation to support a new policy format with a more optimal
representation of filename transition rules, this patch applies an
equivalent change from kernel commit c3a276111ea2 ("selinux: optimize
storage of filename transitions").
See the kernel commit's description [1] for the rationale behind this
representation. This change doesn't bring any measurable difference of
policy build performance (semodule -B) on Fedora.
[1] https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git/commit/?id=c3a276111ea2572399281988b3129683e2a6b60b
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
The comparison function, portcon_data_cmp(), only made use of the
protocol to put tcp before udp, dccp, and sctp. Rules that have
the same port range, but with different protocols would be considered
equal unless one of the protocols was tcp. When generating a CIL or
conf source policy from a binary or using the "-S" option in
checkpolicy the non-tcp portcon rules with the same port range would
not be consistently sorted.
Changed portcon_data_cmp() to sort portcon rules like the CIL function
cil_post_portcon_compare().
Reported-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Signed-off-by: James Carter <jwcart2@gmail.com>
Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Improves writing of CIL category rules when converting MLS kernel
policy to CIL. No changes to functionality, but eliminate useless
checks for category aliases when using the p_cat_val_to_name array,
find the actual number of aliases before allocating memory, and
skip the category alias rules if there are no aliases.
Signed-off-by: James Carter <jwcart2@gmail.com>
Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Improves writing of CIL sensitivity rules when converting MLS kernel
policy to CIL. No changes to functionality, but eliminate useless
checks for sensitivity aliases when using the p_sens_val_to_name
array, find the actual number of aliases before allocating memory,
and skip the sensitivity alias rules if there are no aliases.
Signed-off-by: James Carter <jwcart2@gmail.com>
When converting a non-MLS kernel binary policy to CIL, write the CIL
default MLS rules (since CIL requires at least one sensitivity,
and sensitivityorder statements) on separate lines.
This improves the readability of the resulting CIL policy.
Signed-off-by: James Carter <jwcart2@gmail.com>
Type alias rules are not written out when converting a binary kernel
policy to a policy.conf. The problem is that type aliases are not in
the type_val_to_struct array and that is what is being used to find
the aliases.
Since type aliases are only in the types hashtable, walk that to
find the type aliases.
Fixed the syntax of the typalias rule which requires "alias" to come
between the type and the aliases (ex/ typealias TYPE alias ALIAS;).
Fixes: 0a08fd1e69 ("libsepol: Add ability to convert binary
policy to policy.conf file")
Signed-off-by: James Carter <jwcart2@gmail.com>
Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Type alias rules are not written out when converting a binary kernel
policy to CIL. The problem is that type aliases are not in the
type_val_to_struct array and that is what is being used to find the
aliases.
Since type aliases are only in the types hashtable, walk that to
find the type aliases.
Fixes: 70a480bfcd ("libsepol: Add ability to convert binary
policy to CIL")
Signed-off-by: James Carter <jwcart2@gmail.com>
CIL allows a type to be redeclared when using the multiple declarations
option ("-m" or "--muliple-decls"), but make it an error for an identifier
to be declared as both a type and an attribute.
Change the error message so that it always gives the location and flavor
of both declarations. The flavors will be the same in all other cases,
but in this case they explain why there is an error even if multiple
declartions are allowed.
Fixes: Commit fafe4c212b ("libsepol: cil: Add ability to redeclare types[attributes]")
Reported-by: Topi Miettinen <toiwoton@gmail.com>
Signed-off-by: James Carter <jwcart2@gmail.com>
Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Initialize the multiple_decls field when intializing the structure
cil_db.
Fixes: fafe4c212b ("libsepol: cil: Add ability to redeclare types[attributes]")
Reported-by: Topi Miettinen <toiwoton@gmail.com
Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Signed-off-by: James Carter <jwcart2@gmail.com>
As per the issue below, libsepol segfaults on loading old kernel policies
that contain duplicate filename transition rules. The segfault is due to
the fact that the val_to_name arrays have not yet been populated at this
point in the policydb_read() processing. Since this warning apparently
never worked since it was first introduced, drop it and just silently
discard the duplicate like the kernel does. I was not able to produce a
policy with such duplicates using the current policy toolchain, either
via CIL or via binary modules with manual semodule_link/expand.
Fixes: https://github.com/SELinuxProject/selinux/issues/239
Fixes: 8fdb225521 ("libsepol,checkpolicy: convert rangetrans and filenametrans to hashtabs")
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Acked-by: Ondrej Mosnacek <omosnace@redhat.com>
This reverts commit 692716fc5f.
Other parts of the SELinux userspace depend on certain attributes,
such as node_type, exisiting and this change breaks those parts.
Before this patch can be reapplied, we need to identify the attributes
that must never be expanded and create a CIL module with the needed
expandtypeattribute statements (or something similar).
Signed-off-by: James Carter <jwcarter@gmail.com>
Fix issues like:
<inline asm>:1:1: error: unknown directive
.symver cil_build_policydb_pdb, cil_build_policydb@LIBSEPOL_1.0
Which was caused by the DISABLE_SYMVER define not being defined
for static, Mac or Android builds.
Acked-by: Joshua Brindle <joshua.brindle@crunchydata.com>
Signed-off-by: William Roberts <william.c.roberts@intel.com>
Currently a constraint `t1 == t2` gets converted to the invalid cil syntax `(mlsconstrain (class_name (perm_name)) (eq t1 ))` and fails to be loaded into the kernel.
Fixes: 893851c0a1 ("policycoreutils: add a HLL compiler to convert policy packages (.pp) to CIL")
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
The iteration over the set ebitmap bits is not implemented very
efficiently in libsepol. It is slowing down the policy optimization
quite significantly, so convert the type_map from an array of ebitmaps
to an array of simple ordered vectors, which can be traveresed more
easily. The worse space efficiency of the vectors is less important than
the speed in this case.
After this change the duration of semodule -BN decreased from 6.4s to
5.5s on Fedora Rawhide x86_64 (and from 6.1s to 5.6s with the unconfined
module disabled).
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Only attributes can be a superset of another attribute, so we can skip
non-attributes right away.
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com>
I copy-pasted it from a different part of the code, which had to deal
with policydb that isn't final yet. Since we only deal with the final
kernel policy here, we can skip the check for the type datum being NULL.
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com>
With the old hidden_def and hidden_proto DSO infrastructure removed,
correctness of the map file becomes paramount, as it is what filters out
public API. Because of this, the wild cards should not be used, as it
lets some functions through that should not be made public API. Thus
remove the wild cards, and sort the list.
Additionally, verify that nothing changed in external symbols as well:
This was checked by generating an old export map (from master):
nm --defined-only -g ./src/libsepol.so | cut -d' ' -f 3-3 | grep -v '^_' > old.map
Then creating a new one for this library after this patch is applied:
nm --defined-only -g ./src/libsepol.so | cut -d' ' -f 3-3 | grep -v '^_' > new.map
And diffing them:
diff old.map new.map
Fixes: #165Fixes: #204
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: William Roberts <william.c.roberts@intel.com>
Add -fno-semantic-interposition to CFLAGS. This will restore
the DSO infrastructures protections to insure internal callers
of exported symbols call into libselinux and not something loading first
in the library list.
Clang has this enabled by default.
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: William Roberts <william.c.roberts@intel.com>
libsepol already has a linker script controlling it's exports, so this
patch has a net 0 affect, with the exception that internal callers of
external routines, which there could be 0 of, could potentially call a
non-libsepol routine depending on library load order.
NOTE A FEW SYMBOLS ARE EXPORTED THAT NORMALLY WOULDN'T BE
- sepol_context_to_sid
- sepol_ibendport_sid
- sepol_ibpkey_sid
- sepol_msg_default_handler
- sepol_node_sid
- sepol_port_sid
A subsequent map update will follow.
This list was generated by generating an old export map (from master):
nm --defined-only -g ./src/libsepol.so | cut -d' ' -f 3-3 | grep -v '^_' > old.map
Then creating a new one for this library after this patch is applied:
nm --defined-only -g ./src/libsepol.so | cut -d' ' -f 3-3 | grep -v '^_' > new.map
And diffing them:
diff old.map new.map
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: William Roberts <william.c.roberts@intel.com>
libsepol carried its own (outdated) copy of flask.h with the generated
security class and initial SID values for use by the policy
compiler and the forked copy of the security server code
leveraged by tools such as audit2why. Convert libsepol and
checkpolicy entirely to looking up class values from the policy,
remove the SECCLASS_* definitions from its flask.h header, and move
the header with its remaining initial SID definitions private to
libsepol. While we are here, fix the sepol_compute_sid() logic to
properly support features long since added to the policy and kernel,
although there are no users of it other than checkpolicy -d (debug)
and it is not exported to users of the shared library. There
are still some residual differences between the kernel logic and
libsepol.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Acked-by: Petr Lautrbach <plautrba@redhat.com>
The value attrs_expand_size == 1 removes all empty attributes, but it
also makes sense to expand all attributes that have only one type. This
removes some redundant rules (there is sometimes the same rule for the
type and the attribute) and reduces the number of attributes that the
kernel has to go through when looking up rules.
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Acked-by: James Carter <jwcart2@gmail.com>
A parameter of a macro was only considered to be a duplicate if it
matched both the name and flavor of another parameter. While it is
true that CIL is able to differentiate between those two parameters,
there is no reason to use the same name for two macro parameters and
it is better to return an error for what is probably an error.
Remove the check of the flavors when checking for duplicate parameters.
Signed-off-by: James Carter <jwcart2@gmail.com>
Acked-by: Ondrej Mosnacek <omosnace@redhat.com>
Type transition file names are stored in a symbol table. Before the
name is added, the symbol table is searched to see if the name had
already been inserted. If it has, then the already existing datum is
returned. If it has not, then the name is added if either the
typetransition rule does not occur in a macro or the name is not one
of the macro parameters.
Checking for a previous insertion before checking if the name is a
macro parameter can cause a macro parameter to be treated as the
actual name if a previous type transition file name is the same as
the parameter.
Now check the name to see if it a macro paramter before checking for
its existence in the symbol table.
Signed-off-by: James Carter <jwcart2@gmail.com>
Acked-by: Ondrej Mosnacek <omosnace@redhat.com>
This reverts commit 542e878690.
After 6968ea9775 ("libsepol: make ebitmap_cardinality() of linear
complexity"), the caching only saves ~0.06 % of total semodule -BN
running time (on x86_64 without using the POPCNT instruction), so it's
no longer worth the added complexity.
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Create the macro ebitmap_is_empty() to check if an ebitmap is empty.
Use ebitmap_is_empty(), instead of ebitmap_cardinality() or
ebitmap_length(), to check whether or not an ebitmap is empty.
Signed-off-by: James Carter <jwcart2@gmail.com>
Acked-by: Ondrej Mosnacek <omosnace@redhat.com>
As ebitmap_get_bit() complexity is linear in the size of the bitmap, the
complexity of ebitmap_cardinality() is quadratic. This can be optimized
by browsing the nodes of the bitmap directly in ebitmap_cardinality().
While at it, use built-in function __builtin_popcountll() to count the
ones in the 64-bit value n->map for each bitmap node. This seems better
suited than "count++". This seems to work on gcc and clang on x86,
x86_64, ARM and ARM64 but if it causes compatibility issues with some
compilers or architectures (or with older versions of gcc or clang),
the use of __builtin_popcountll() can be replaced by a C implementation
of a popcount algorithm.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Detect when the hashtab's load factor gets too high and try to grow it
and rehash it in such case. If the reallocation fails, just keep the
hashtab at its current size, since this is not a fatal error (it will
just be slower).
This speeds up semodule -BN on Fedora from ~8.9s to ~7.2s (1.7 seconds
saved).
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
hashtab_replace() and hashtab_map_remove_on_error() aren't used
anywhere, no need to keep them around...
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
According to profiling of semodule -BN, ebitmap_cardinality() is called
quite often and contributes a lot to the total runtime. Cache its result
in the ebitmap struct to reduce this overhead. The cached value is
invalidated on most modifying operations, but ebitmap_cardinality() is
usually called once the ebitmap doesn't change any more.
After this patch, the time to do 'semodule -BN' on Fedora Rawhide has
decreased from ~10.9s to ~8.9s (2s saved).
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
[sds@tycho.nsa.gov: correct times per follow-up on list]
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Followed the following steps:
# In repo client
cd external/selinux
repo sync .
repo start mymerge .
git merge aosp/upstream-master --no-ff # resolve any conflicts
lunch && make -j
repo upload .
Test: compiles and boots
Change-Id: I45fd32fb9bfe2291ef32afcc86f26eb2b24e03e8
The filename_- and range_trans_table ancillary hash tables in
cil_binary.c just duplicate the final policydb content and can be simply
removed.
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Use one of the policy config bits to tell the kernel to start using
the nlmsg_readpriv on RTM_GETLINK messages instead of the previous
hehavior of using nlmsg_read.
Bug: 141455849
Test: CtsSelinuxTargetSdkCurrentTestCases
Change-Id: I581af58247afe021d906f60153d5971cfaf14ab6
The classperms associated with each map class permission and with each
classpermissionset are verified in __cil_verify_classperms() which had
multiple problems with how it did the verification.
1) Verification was short-circuited when the first normal class is found.
The second classpermissionset statement below would not have been
verified.
(classpermission cp1)
(classpermissionset cp1 (CLASS (PERM)))
(classpermissionset cp1 cp2)
2) The classperms of a map class permission and classpermissionset were
not checked for being NULL before the function recursively called itself.
This would result in a segfault if the missing map or set was referred to
before the classmap or classpermission occured. This error was reported by
Dominick Grift (dominick.grift@defensec.nl).
These rules would cause a segfault.
(classmap cm1 (mp1))
(classmapping cm1 mp1 (cm2 (mp2)))
(classmap cm2 (mp2))
But an error would be produced for these rules.
(classmap cm1 (mp1))
(classmap cm2 (mp2))
(classmapping cm2 mp2 (cm1 (mp1)))
3) The loop detection logic was incomplete and could only detect a loop
with a certain statement ordering.
These rules would cause a stack overflow.
(classmap cm1 (mp1))
(classmapping cm1 mp1 (cm2 (mp2)))
(classmap cm2 (mp2))
(classmapping cm2 mp2 (cm3 (mp3)))
(classmap cm3 (mp3))
(classmapping cm3 mp3 (cm2 (mp2)))
Rewrote __cil_verify_classperms() to fix these errors.
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
Add support for new SELinux policy capability genfs_seclabel_symlinks.
With this capability enabled symlinks on kernel filesystems will receive
contexts based on genfscon statements, like directories and files,
and not be restricted to the respective filesystem root sid.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
The merge from upstream deleted and created some files.
Update the Android.bp file to incorporate those changes.
Test: compiles
Test: treehugger
Change-Id: I52d797cb43b96e5fa6e1237153d6000cc286405d
Incorporate the latest upstream SELinux changes into the Android
build tree.
% git merge aosp/upstream-master --no-ff
A followup commit will make Android specific changes to allow
this code to compile.
- Known issue: -
Multiple implementations of partial directory match digesting.
To fix bug 62302954 ("Investigate restorecon() / selabel_lookup()
performance"), Android implemented a number of patches, including
7d4a56f84d
The upstream SELinux community ended up writing their own variant of
Android's patch, which accomplishes the same thing. This patch is at
e016502c0a
This merge has the effect of having both patches in the tree at the same
time, which could be confusing. However, the new upstream code isn't
used by Android, so there's no impact (other than code bloat and
duplication).
Change-Id: I2bb804b71763c0c3ba77fe48d42787298f85a9d7
Test: treehugger
Remove restrictions in libsepol and checkpolicy that required all
declared initial SIDs to be assigned a context. With this patch,
it is possible to build and load a policy that drops the sid <sidname>
<context> declarations for the unused initial SIDs. It is still
required to retain the sid <sidname> declarations (in the flask
definitions) in order to preserve the initial SID ordering/values.
The unused initial SIDs can be renamed, e.g. to add an unused_
prefix or similar, if desired, since the names used in the policy
are not stored in the kernel binary policy.
In CIL policies, the (sid ...) and (sidorder (...)) statements
must be left intact for compatibility but the (sidcontext ...)
statements for the unused initial SIDs can be omitted after this change.
With current kernels, if one removes an unused initial SID context
from policy, builds policy with this change applied and loads the
policy into the kernel, cat /sys/fs/selinux/initial_contexts/<sidname>
will show the unlabeled context. With the kernel patch to remove unused
initial SIDs, the /sys/fs/selinux/initial_contexts/<sidname>
file will not be created for unused initial SIDs in the first place.
NB If an unused initial SID was assigned a context different from
the unlabeled context in existing policy, then it is not safe to
remove that initial SID context from policy and reload policy on
the running kernel that was booted with the original policy. This
is because that kernel may have assigned that SID to various kernel
objects already and those objects will then be treated as having
the unlabeled context after the removal. In refpolicy, examples
of such initial SIDs are the "fs" SID and the "sysctl" SID. Even
though these initial SIDs are not directly used (in code) by the current
kernel, their contexts are being applied to filesystems and sysctl files by
policy and therefore the SIDs are being assigned to objects.
NB The "sysctl" SID was in use by the kernel up until
commit 8e6c96935fcc1ed3dbebc96fddfef3f2f2395afc ("security/selinux:
fix /proc/sys/ labeling) circa v2.6.39. Removing its context from
policy will cause sysctl(2) or /proc/sys accesses to end up
performing permission checks against the unlabeled context and
likely encounter denials for kernels < 2.6.39.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Commit 4459d635b8 ("libsepol: Remove cil_mem_error_handler() function
pointer") replaced cil_mem_error_handler usage with inline contents of
the default handler. However, it left over the header declaration and
two callers. Convert these as well and remove the header declaration.
This also fixes a build failure with -fno-common.
Fixes: 4459d635b8 ("libsepol: Remove cil_mem_error_handler() function pointer")
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
GCC 10 comes with -fno-common enabled by default - fix the CIL_KEY_*
global variables to be defined only once in cil.c and declared in the
header file correctly with the 'extern' keyword, so that other units
including the file don't generate duplicate definitions.
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
When copying an avrule with extended permissions (permx) in
cil_copy_avrule(), the check for a named permx checks the new permx
instead of the old one, so the check will always fail. This leads to a
segfault when trying to copy a named permx because there will be an
attempt to copy the nonexistent permx struct instead of the name of
the named permx.
Check whether the original is a named permx instead of the new one.
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
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>
Followed the following steps:
# In repo client
cd external/selinux
repo sync .
repo start mymerge .
git merge aosp/upstream-master --no-ff # resolve any conflicts
lunch && make -j
repo upload .
Test: compiles and boots
Change-Id: Ia2dbf92e3127aa779bec3c46f171d3ef6c1cbfe5
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>
Followed the following steps:
# In repo client
cd external/selinux
repo sync .
repo start mymerge .
git merge aosp/upstream-master --no-ff # resolve any conflicts
lunch && make -j
repo upload .
Test: compiles and boots
Change-Id: I75ccf5307012a2517c0fdf13bea806e10b8b8595
Additionally, resolve build time errors due to
c19395d722
libselinux: selinux_set_mapping: fix handling of unknown classes/perm
Followed the following steps:
# In repo client
cd external/selinux
repo sync .
repo start mymerge .
git merge aosp/upstream-master --no-ff # resolve any conflicts
lunch && make -j
repo upload .
Test: device boots and no obvious problems.
Change-Id: Ib3a6c086ceadaeaaaf35498d53b2b3e3ad5b8945
Fix compile time error in Android specific code.
../cil/src/cil_write_ast.c: In function ‘__cil_write_node_helper’:
../cil/src/cil_write_ast.c:1156:17: error: variable ‘db’ set but not used [-Werror=unused-but-set-variable]
struct cil_db *db = NULL;
^~
../cil/src/cil_write_ast.c: In function ‘__cil_write_last_child_helper’:
../cil/src/cil_write_ast.c:1465:17: error: variable ‘db’ set but not used [-Werror=unused-but-set-variable]
struct cil_db *db = NULL;
^~
Test: compiles
Change-Id: I0af0e896ba1591ef43726dbee9906d581390e1f3
Followed the following steps:
# In repo client
cd external/selinux
repo sync .
repo start mymerge .
git merge aosp/upstream-master --no-ff # resolve any conflicts
repo upload .
Test: device compiles and boots
Change-Id: If92a0b5e99e69ac0434197fa848b736b9cf0bf77
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>
Followed the following steps:
# In repo client
cd external/selinux
repo sync .
repo start mymerge .
git merge aosp/upstream-master --no-ff # resolve any conflicts
repo upload .
Test: device boots and no obvious problems.
Change-Id: I6beff804808e92d1002ead226c7d5c702f373cdc
Followed the following steps:
# In repo client
cd external/selinux
repo sync .
repo start mymerge .
git merge aosp/upstream-master --no-ff # resolve any conflicts
repo upload .
Test: android compiles and boots and no observed problems.
Change-Id: Ic353353e43d9f90921ea39087289fcd5b98521d6
Followed the following steps:
# In repo client
cd external/selinux
repo sync .
repo start mymerge .
git merge aosp/upstream-master --no-ff # resolve any conflicts
repo upload .
Test: android compiles and boots and no observed problems.
Change-Id: Ibdc3617c75af6ba0d93756cec1ad5ae229e3d5e2
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>
In particular, pulls in
3f99b14939
which is needed for b/118685852
Followed the following steps:
# In repo client
cd external/selinux
repo sync .
repo start mymerge .
git merge aosp/upstream-master --no-ff # resolve any conflicts
repo upload .
Bug: 118685852
Test: Android compiles and no obvious problems.
Change-Id: Ic8f1bb2b573a1491b733732653afd7dbe494c85f
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: 9fbb311276 ("libsepol: Add ibpkey ocontext handling")
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Followed the following steps:
# In repo client
cd external/selinux
repo sync .
repo start mymerge .
git merge aosp/upstream-master --no-ff # resolve any conflicts
repo upload .
Test: Android compiles and no obvious problems.
Change-Id: I526e8c09eb7cb7f73fe771fd1295bb406514589b
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>
Followed the following steps:
# In repo client
cd external/selinux
repo sync .
repo start mymerge .
git merge aosp/upstream-master --no-ff # resolve any conflicts
repo upload .
Test: Android compiles and no obvious problems.
Change-Id: I88fac5bcf4a6493672ba95daf8fd982c7b3548b5
Followed the following steps:
# In repo client
cd external/selinux
repo sync .
repo start mymerge .
git merge aosp/upstream-master --no-ff # resolve any conflicts
repo upload .
Test: compiles/boots no problems.
Change-Id: I4cd9f73fbbb818ef7fa07ff8dd183f8a7e892345
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>
sepol_ppfile_to_module_package() does not use its variable "FILE *f =
NULL;" but to fclose() it. This variable has been unneeded since the
introduction of function ppfile_to_module_package() in commit
893851c0a1 ("policycoreutils: add a HLL compiler to convert policy
packages (.pp) to CIL").
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
clang's static analyzer reports that ebitmap_to_names() can call
malloc(0) when the bitmap is empty. If malloc() returns NULL, this
triggers a misleading "Out of memory" error.
Work around this by treating empty bitmaps as appropriate.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
clang's static analyzer warns about dead assignments to local variables.
In module_to_cil.c, there are some which are quite straightforward to
review. Remove them.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
When list_prepend() returns an error, it always means it failed to
allocate some memory and does not hold any reference to its argument
data. This argument needs to be freed by the caller in order to prevent
a memory leak.
While reviewing list_prepend() callers, I spend quite some time
understanding why typealiases_gather_map() does not need to strdup(key)
or free(key) when calling list_prepend(..., key) even though "key" comes
from pdb->p_types.table: because typealias_list_destroy() does not free
the inserted items. Add a comment to make this clearer in the code.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
In cil_tree_print_expr(), "rc < 0" is equivalent to "rc != 0" but
clang's static analyzer does not know about this. Help it.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Fix the following build warning:
policydb.c: In function ‘get_symtab_destroy_func’:
policydb.c:1581:9: error: cast between incompatible function types from ‘int (*)(char *, void *, void *)’ to ‘void (*)(char *, void *, void *)’ [-Werror=cast-function-type]
return (hashtab_destroy_func_t) destroy_f[sym_num];
^
It turns out that this function and type are long unused in libsepol
and are not exported APIs for the shared library, so just remove them.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
When load_users() parses an invalid line with an empty level context
(ie. nothing between "level" and "range" keywords), it allocates memory
with malloc(0) and uses it. The behavior of malloc() in this case is
an unspecified behavior: it might return NULL, which would lead to a
segmentation fault.
Fix this issue by reporting the invalid entry instead. While at it,
ensure that the character before "range" is a space, and change the
logic slightly in order to avoid using "--p; ... p++;".
This issue is reported by clang's static analyzer with the following
message:
genusers.c:222:11: warning: Use of zero-allocated memory
*r++ = *s;
^
genusers.c:225:7: warning: Use of zero-allocated memory
*r = 0;
^
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
In cond_expr_to_cil(), when stack_init() fails to allocate a stack, the
function calls stack_pop() with stack = NULL. Then stack_pop()
dereferences the pointer ("if (stack->pos == -1) {"), which is NULL.
Fix this by moving the stack cleaning loop in a "if (stack != NULL)"
block.
This issue is reported by clang's static analyzer with the following
message:
module_to_cil.c:463:6: warning: Access to field 'pos' results in a
dereference of a null pointer (loaded from variable 'stack')
if (stack->pos == -1) {
^~~~~~~~~~
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Improve the processing of netifcon, genfscon, ibpkeycon, ibendportcon,
portcon, nodecon, fsuse, filecon, iomemcon, ioportcon, pcidevicecon,
and devicetreecon rules.
If the multiple-decls option is not used then report errors if duplicate
context rules are found. If it is used then remove duplicate context rules
and report errors when two rules are identical except for the context.
This also changes the ordering of portcon and filecon rules. The protocol
of portcon rules will be compared if the port numbers are the same and the
path strings of filecon rules will be compared if the number of meta
characters, the stem length, string length and file types are the same.
Based on an initial patch by Pierre-Hugues Husson (phh@phh.me)
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
This commit resolves conflicts in values of expandattribute statements
in policy language and expandtypeattribute in CIL.
For example, these statements resolve to false in policy language:
expandattribute hal_audio true;
expandattribute hal_audio false;
Similarly, in CIL these also resolve to false.
(expandtypeattribute (hal_audio) true)
(expandtypeattribute (hal_audio) false)
A warning will be issued on this conflict.
Motivation
When Android combines multiple .cil files from system.img and vendor.img
it's possible to have conflicting expandattribute statements.
This change deals with this scenario by resolving the value of the
corresponding expandtypeattribute to false. The rationale behind this
override is that true is used for reduce run-time lookups, while
false is used for tests which must pass.
Signed-off-by: Tri Vo <trong@android.com>
Acked-by: Jeff Vander Stoep <jeffv@google.com>
Acked-by: William Roberts <william.c.roberts@intel.com>
Acked-by: James Carter <jwcart2@tycho.nsa.gov>
Nicolas Iooss reports:
In sepol_ibendport_key_create(), if sepol_ibendport_alloc_ibdev_name()
fails to allocate tmp_key->ibdev_name, sepol_ibendport_key_free() is
called to free the memory associated with tmp_key, which results in
free() being called on uninitialized tmp_key->ibdev_name.
This issue is reported by clang's static analyzer with the following
message:
ibendport_record.c:115:2: warning: 1st function call argument is an
uninitialized value
free(key->ibdev_name);
^~~~~~~~~~~~~~~~~~~~~
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
Export the sepol_polcap_getnum/name() functions to users of
the shared library. This will enable SETools to stop depending
on the static library.
Note that we may want to move polcaps.h up one level since
the convention is that headers directly under include/sepol are
shared library APIs while headers under include/sepol/policydb
are limited to static users. However, this will unnecessarily
break the build for existing static users so it is deferred.
Suggested-by: Chris PeBenito <pebenito@ieee.org>
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
cil_tree_print_expr() calls cil_expr_to_string() in order to compute a
string expression into expr_str. If this function fails, expr_str is
left unitialized but its value is dereferenced with:
cil_log(CIL_INFO, "%s)", expr_str);
Prevent such an issue by checking cil_expr_to_string()'s return value
before using expr_str.
This issue has been found with clang's static analyzer.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
This patch solves the following issues:
- The pkg-config files generates odd paths when using DESTDIR without PREFIX
- DESTDIR is needed during compile time to compute library and header paths which it should not.
- Installing with both DESTDIR and PREFIX set gives us odd paths
- Make usage of DESTDIR and PREFIX more standard
Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
Daniel Cashman <dcashman@android.com> discovered the following:
When using cil_db multiple_decls, the different cil_attribute nodes
all point to the same underlying cil_attribute struct. This leads
to problems, though, when modifying the used value in the struct.
__cil_post_db_attr() changes the value of the field to based on
the output of cil_typeattribute_used(), for use later in
cil_typeattribute_to_policydb and cil_typeattribute_to_bitmap, but
due to the multiple declarations, cil_typeattribute_used() could be
called again by a second node. In this second call, the value used
is the modifed value of CIL_TRUE or CIL_FALSE, not the flags actually
needed. This could result in the field being reset again, to an
incorrect CIL_FALSE value.
Add the field "keep" to struct cil_typeattributeset, set its value
using cil_typeattribute_used(), and use it when determining whether
the attribute is to be kept or if it should be expanded.
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
When reading policy, ibendport device names are allocated in
ocontext_read_selinux() but they are not freed when calling
sepol_policydb_free();
Fix this by freeing them in ocontext_selinux_free().
Signed-off-by: Jan Zarsky <jzarsky@redhat.com>
cil_android_attributize() uses a source policy to identify types and
attributes to be versioned according to the given version number, and
then proceeds to modify the provided target policy to provide this
versioning. Previously, the versioned policy relied on a base policy
for the declarations of these type[attribute]s, but with multiple_decl
support added, the declarations can be made in both places. This will
make the policy more robust and allow for greater flexibility and the
types of base policy used.
Bug: 37915794
Test: Builds 'n' boots. non_plat_sepolicy.cil now contains the public
type[attribute] declarations.
Change-Id: Iaa084211a9e2774a7ed391888fb21c4c0cf955db
Followed the following steps:
# In repo client
cd external/selinux
repo sync .
repo start mymerge .
git merge aosp/upstream-master --no-ff # resolve any conflicts
repo upload .
Test: compiles/boots no problems.
Change-Id: I4e7ee3fddfe021d128ebd70a663374367914b825
Public types get versioned for Treble compatibility. The versioned
attribute is declared in vendor policy. Then a mapping between the
newer system policy occurs on the system partition. This causes
on-device compilation to fail in AOSP because the vendor image stays
static and thus the mapping file references undeclared typeattributes.
This can be solved by declaring, or redeclaring all versioned types
in the mapping file. Support for this was added to secilc in commit
fafe4c212b 'libsepol: cil: Add ability
to redeclare types[attributes]'
Bug: 67092827
Bug: 37915794
Test: build and boot aosp_sailfish with new type declared in public
policy
Change-Id: I04a884db6d0eaf42ee189b0669833dd0860b626f
* Use -Wno-error= to keep existing warnings to fix later.
Bug: 66996870
Test: build with WITH_TIDY=1
Change-Id: I0e84d5fb2ae2ae68a687a0b6b81eb64a983db57c
Cutting down on the number of attributes associated with each type
speeds up policy lookup times when there is an access vector cache
miss.
This commit reduces the number of attributes in the policy binary from
607 to 159.
(cherry-pick of commit: 574926fe67)
Bug: 36508258
Test: build and boot Marlin
Change-Id: I42c778fe9e760abf62d4ec1f7b7e748e28ac5497
When sepol_bool_query() returns NULL response, variable name is not
freed. Fix this by calling free() before returning.
Signed-off-by: Jan Zarsky <jzarsky@redhat.com>
cil_gen_node() has been using its argument "db" since commit
fafe4c212b ("libsepol: cil: Add ability to redeclare
types[attributes]"). Drop attribute "unused" on this argument.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
cil_defaults_to_policy() defines its third argument as non-const "char
*kind" even though it is called with literal strings. This makes gcc
report the following warning when compiling with -Wwrite-strings:
../cil/src/cil_policy.c: In function ‘cil_gen_policy’:
../cil/src/cil_policy.c:1931:60: error: passing argument 3 of
‘cil_defaults_to_policy’ discards ‘const’ qualifier from pointer
target type [-Werror=discarded-qualifiers]
cil_defaults_to_policy(out, lists[CIL_LIST_DEFAULT_USER],
"default_user");
^~~~~~~~~~~~~~
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Since commit 67b410e80f ("libsepol/cil: Keep attributes used by
generated attributes in neverallow rules") gcc reports the following
warning when building libsepol:
../cil/src/cil_post.c: In function
‘__cil_post_db_neverallow_attr_helper’:
../cil/src/cil_post.c:1322:17: error: unused variable ‘db’
[-Werror=unused-variable]
struct cil_db *db = extra_args;
^~
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
When compiling libsepol with clang and some warning flags, the compiler
complains about the way IPv6 addresses are initialized:
kernel_to_cil.c:2795:35: error: suggest braces around initialization
of subobject [-Werror,-Wmissing-braces]
struct in6_addr subnet_prefix = {0};
^
{}
When replacing the initializer as suggested, gcc 4.8.4 complains:
kernel_to_cil.c: In function ‘write_selinux_ibpkey_rules_to_cil’:
kernel_to_cil.c:2795:9: error: missing initializer for field
‘__in6_u’ of ‘struct in6_addr’ [-Werror=missing-field-initializers]
struct in6_addr subnet_prefix = {};
^
Thankfully netinet/in.h provides a macro to initialize struct in6_addr
variables:
#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
Both clang and gcc no longer report warnings when using this macro.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
libsepol is entirely C, so it doesn't need libc++. On the host,
libsepolwrap loads libsepol into the system python, which does not have
the sanitizer runtime.
Test: SANITIZE_HOST=true m treble_sepolicy_tests
Test: mmma external/selinux
Change-Id: If22a6b3d492170871bdb70e71bba8148c607af01
In order to reduce policy size, CIL removes attributes that are not used
by a policy rule in the generated binary policy. However, CIL keeps
attributes used by neverallow rules (which are checked at compile time
and not in the binary policy) even if the attribute is not used anywhere
else in the policy. This behavior is useful to Google who pulls neverallow
rules out of the original policy.conf for compatibility testing, but
converts the policy.conf to CIL and uses the CIL compiler to generate
policy. Without this behavior, the generated binary policy might not have
an attribute referred to by one of the neverallow rules used for testing.
The one exception to this behavior is for attributes generated in
module_to_cil (these have an "_typeattr_" in the middle of their name).
Since these attributes are only created because CIL does not allow a
type expression in an AV rule, they are removed if they only appear in
a neverallow rule (which is the case for most of them) or if the
option to expand generated attributes (-G or --expand-generated) is
specified for secilc when compiling the policy.
Removing generated attributes causes a problem, however, if the type
expression that the generated attribute is replacing uses an attribute
that is removed. In this case, the original neverallow rule will refer
to an attribute that does not exist in the generated binary policy.
Now any non-generated attribute used in a typeattributeset rule for a
generated attribute which is used in a neverallow rule will be treated
like it was used in a neverallow rule.
This does not change the behavior of an expandtypeattribute rule for
the attribute. That rule, if it exists, will take precedence.
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
Modify cil_gen_node() to check to see if the cil_db supports multiple
declarations, and if so, to check whether or not the
repeated symbol is eligible to share the existing, already-stored datum. The
only types considered so far are CIL_TYPE and CIL_TYPEATTRIBUTE, both of
which intall empty datums during AST building, so they automatically return
true.
Test: Build policy with multilpe type and attribute declarations, and
without. Policies are binary-identical.
Signed-off-by: Dan Cashman <dcashman@android.com>
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
In cil_strpool_destroy(), cil_strpool_tab is freed but it is not reset to NULL.
When cil_strpool_init() is called again it assumes that cil_strpool_tab was
already initialized. Other functions then work with invalid data.
Signed-off-by: Jan Zarsky <jzarsky@redhat.com>
Define the nnp_nosuid_transition policy capability used to enable
SELinux domain transitions under NNP or nosuid if the
nnp_transition permission or nosuid_transition permission is
allowed between the old and new contexts. When this capability is not
enabled, such transitions remain limited to bounded transitions as they
were prior to the introduction of this capability.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
A build toolchain may override CPPFLAGS on the command line of "make".
Doing so currently breaks libsepol/tests compilation, as it requires
"-I../include/ -I$(CHECKPOLICY)" to be provided in gcc's arguments.
This completes commit 15f2740733 ("Makefiles: override *FLAGS and
*LIBS").
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
There were several places in the makefiles where LDLIBS or CFLAGS were
supposed to include options to build. They were missing the override
keyword so would be skipped if these vars were set on the make cmdline.
Add the override directive to fix this.
Signed-off-by: Jason Zaman <jason@perfinion.com>
While most header files already use the common pattern of `extern "C"`
declarations to enable compiling in a C++ project, some header files in
libsepol instead use the macros `__BEGIN_DECLS` and `__END_DECLS`. These
macros are defined in the "sys/cdefs.h" header file, which provides
some non-standard extensions for glibc.
Convert usage of these declarations with the standard `extern "C"`
pattern. This improves compatibility with other libc implementations,
e.g. musl libc.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
The typebounds rules should end with a ";".
The netifcon and nodecon rules should not end with a ";".
The default rules are missing a "_". They should be "default_user",
"default_role" and "default_type".
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
Commit 9e6840e refactored neverallow checking. In the process a bug
was introduced that causes enabled conditional rules to be skipped.
The bug is that the avtab key is checked by comparing the specified
field of the key to the value AVTAB_ALLOWED. Since enabled conditional
rules have an additional bit set as well, these rules are not
considered to match.
The fix is to use a bitwise AND (&) to only check the desired bit.
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
In mls_semantic_range_expand(), when a call to
mls_semantic_level_expand() fails, the function destroys the semantic
level instead of the expanded one. This leads to a use-after-free which
is reported by gcc's Address Sanitizer:
libsepol.mls_semantic_level_expand: mls_semantic_level_expand: invalid sensitivity level found 128/0.
libsepol.sepol_module_package_read: invalid module in module package (at section 0)
Failed to read policy package
=================================================================
==24456==ERROR: AddressSanitizer: heap-use-after-free on address 0x60200000ee58 at pc 0x7fe6c4fb96b4 bp 0x7fffa5ea6b70 sp 0x7fffa5ea6b60
READ of size 8 at 0x60200000ee58 thread T0
#0 0x7fe6c4fb96b3 in mls_semantic_level_destroy /usr/src/selinux/libsepol/src/mls.c:755
#1 0x7fe6c4fb9b88 in mls_semantic_range_destroy /usr/src/selinux/libsepol/src/mls.c:802
#2 0x7fe6c500e8ab in user_datum_destroy /usr/src/selinux/libsepol/src/policydb.c:535
#3 0x7fe6c500e980 in user_destroy /usr/src/selinux/libsepol/src/policydb.c:1390
#4 0x7fe6c4f36c48 in hashtab_map /usr/src/selinux/libsepol/src/hashtab.c:235
#5 0x7fe6c50152da in symtabs_destroy /usr/src/selinux/libsepol/src/policydb.c:1595
#6 0x7fe6c5015433 in policydb_destroy /usr/src/selinux/libsepol/src/policydb.c:1503
#7 0x7fe6c5040e0d in sepol_policydb_free /usr/src/selinux/libsepol/src/policydb_public.c:82
#8 0x7fe6c4fbc503 in sepol_module_package_free /usr/src/selinux/libsepol/src/module.c:143
#9 0x7fe6c4fefefb in sepol_ppfile_to_module_package /usr/src/selinux/libsepol/src/module_to_cil.c:4293
#10 0x401e51 in main /usr/src/selinux/policycoreutils/hll/pp/pp.c:124
#11 0x7fe6c4add510 in __libc_start_main (/usr/lib/libc.so.6+0x20510)
#12 0x402589 in _start (/usr/src/selinux/DESTDIR/usr/libexec/selinux/hll/pp+0x402589)
0x60200000ee58 is located 8 bytes inside of 16-byte region [0x60200000ee50,0x60200000ee60)
freed by thread T0 here:
#0 0x7fe6c5537ae0 in __interceptor_free /build/gcc-multilib/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:45
#1 0x7fe6c4fb969b in mls_semantic_level_destroy /usr/src/selinux/libsepol/src/mls.c:757
#2 0x7fe6c4f02a57 in mls_semantic_range_expand /usr/src/selinux/libsepol/src/expand.c:948
#3 0x7fe6c5007a98 in policydb_user_cache /usr/src/selinux/libsepol/src/policydb.c:939
#4 0x7fe6c4f36c48 in hashtab_map /usr/src/selinux/libsepol/src/hashtab.c:235
#5 0x7fe6c5013859 in policydb_index_others /usr/src/selinux/libsepol/src/policydb.c:1286
#6 0x7fe6c5020b65 in policydb_read /usr/src/selinux/libsepol/src/policydb.c:4342
#7 0x7fe6c4fc0cdb in sepol_module_package_read /usr/src/selinux/libsepol/src/module.c:618
#8 0x7fe6c4ff008d in sepol_ppfile_to_module_package /usr/src/selinux/libsepol/src/module_to_cil.c:4276
#9 0x401e51 in main /usr/src/selinux/policycoreutils/hll/pp/pp.c:124
#10 0x7fe6c4add510 in __libc_start_main (/usr/lib/libc.so.6+0x20510)
previously allocated by thread T0 here:
#0 0x7fe6c5537e40 in __interceptor_malloc /build/gcc-multilib/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:62
#1 0x7fe6c5004efc in mls_read_semantic_level_helper /usr/src/selinux/libsepol/src/policydb.c:1976
#2 0x7fe6c500f596 in mls_read_semantic_range_helper /usr/src/selinux/libsepol/src/policydb.c:2010
#3 0x7fe6c500f596 in user_read /usr/src/selinux/libsepol/src/policydb.c:3258
#4 0x7fe6c502055b in policydb_read /usr/src/selinux/libsepol/src/policydb.c:4286
#5 0x7fe6c4fc0cdb in sepol_module_package_read /usr/src/selinux/libsepol/src/module.c:618
#6 0x7fe6c4ff008d in sepol_ppfile_to_module_package /usr/src/selinux/libsepol/src/module_to_cil.c:4276
#7 0x401e51 in main /usr/src/selinux/policycoreutils/hll/pp/pp.c:124
#8 0x7fe6c4add510 in __libc_start_main (/usr/lib/libc.so.6+0x20510)
SUMMARY: AddressSanitizer: heap-use-after-free /usr/src/selinux/libsepol/src/mls.c:755 in mls_semantic_level_destroy
Shadow bytes around the buggy address:
0x0c047fff9d70: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff9d80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff9d90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff9da0: fa fa fa fa fa fa fa fa fa fa 01 fa fa fa 01 fa
0x0c047fff9db0: fa fa 01 fa fa fa 01 fa fa fa 01 fa fa fa 01 fa
=>0x0c047fff9dc0: fa fa 00 00 fa fa 00 00 fa fa fd[fd]fa fa fd fd
0x0c047fff9dd0: fa fa fd fd fa fa fd fd fa fa fd fa fa fa fd fd
0x0c047fff9de0: fa fa 04 fa fa fa 00 01 fa fa fd fd fa fa fd fd
0x0c047fff9df0: fa fa fd fd fa fa fd fd fa fa 00 00 fa fa fd fd
0x0c047fff9e00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff9e10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap right redzone: fb
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==24456==ABORTING
This issue has been found while fuzzing hll/pp with the American Fuzzy
Lop.
Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Commit 1089665e31 (Add attribute
expansion options) adds an expandattribute rule to the policy.conf
language which sets a type_datum flag. Currently the flag is used
only when writing out CIL policy from a policy.conf.
Make use of the flag when expanding policy to expand policy rules
and remove all type associations for an attribute that has
TYPE_FLAGS_EXPAND_ATTR_TRUE set. (The attribute will remain in the
policy, but have no types associated with it.)
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
Nicolas Iooss <nicolas.iooss@m4x.org> discovered with clang's static
analyzer that cil_reset_ibpkeycon() was checking that ibpkeycon->context
was NULL and then passing the NULL value to cil_reset_context() which
expected a non-NULL argument.
Instead, cil_reset_ibpkeycon() should check if ibpkeycon->context_str
is NULL. If it is non-NULL then the context field points to a named
context that was created elsewhere and it will be reset there, but if
the context_str field is NULL, then the context is not named and needs
to be reset.
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
This prevented cil_resolve_name() from returning an actual thing when a
name resolved to an alias. This appears to have only affected resolution
dealing with sensitivity and category aliases. Type aliases were not
affected since places that dealt with types handled type aliases
specifically and did not rely on this behavior from cil_resolve_name().
Signed-off-by: Steve Lawrence <slawrence@tresys.com>
when building packages (e.g. for openSUSE Linux)
(random) filesystem order of input files
influences ordering of functions in the output,
thus without the patch, builds (in disposable VMs) would usually differ.
See https://reproducible-builds.org/ for why this matters.
Fixes the following warning from gcc 7:
In function ‘name_list_to_string’,
inlined from ‘constraint_expr_to_string’ at module_to_cil.c:1790:8:
module_to_cil.c:1135:6: warning: argument 1 range [18446744071562067968, 18446744073709551615] exceeds maximum object size 9223372036854775807 [-Walloc-size-larger-than=]
str = malloc(len);
~~~~^~~~~~~~~~~~~
In file included from module_to_cil.c:36:0:
module_to_cil.c: In function ‘constraint_expr_to_string’:
/usr/include/stdlib.h:443:14: note: in a call to allocation function ‘malloc’ declared here
extern void *malloc (size_t __size) __THROW __attribute_malloc__ __wur;
^~~~~~
While we are here, fix a few other issues too.
The usage of snprintf was wrong and unnecessary; we just allocated
the string to be the right size, so we should just fill it.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
https://developers.redhat.com/blog/2017/03/10/wimplicit-fallthrough-in-gcc-7/
Fixes the following warnings by annotating with a /* FALLTHRU */ comment.
Unfortunately, the __attribute__ ((fallthrough)); approach does not appear
to work with older compilers.
../cil/src/cil_parser.c: In function ‘cil_parser’:
../cil/src/cil_parser.c:253:14: warning: this statement may fall through [-Wimplicit-fallthrough=]
tok.value = tok.value+1;
~~~~~~~~~~^~~~~~~~~~~~~
../cil/src/cil_parser.c:254:3: note: here
case SYMBOL:
^~~~
../cil/src/cil_parser.c:275:7: warning: this statement may fall through [-Wimplicit-fallthrough=]
if (tok.type != END_OF_FILE) {
^
../cil/src/cil_parser.c:279:3: note: here
case END_OF_FILE:
^~~~
../cil/src/cil_post.c: In function ‘cil_post_fc_fill_data’:
../cil/src/cil_post.c:104:5: warning: this statement may fall through [-Wimplicit-fallthrough=]
c++;
~^~
../cil/src/cil_post.c:105:3: note: here
default:
^~~~~~~
regex.c: In function ‘regex_format_error’:
regex.c:541:10: warning: this statement may fall through [-Wimplicit-fallthrough=]
*ptr++ = '.';
~~~~~~~^~~~~
regex.c:542:2: note: here
case 3:
^~~~
regex.c:543:10: warning: this statement may fall through [-Wimplicit-fallthrough=]
*ptr++ = '.';
~~~~~~~^~~~~
regex.c:544:2: note: here
case 2:
^~~~
regex.c:545:10: warning: this statement may fall through [-Wimplicit-fallthrough=]
*ptr++ = '.';
~~~~~~~^~~~~
regex.c:546:2: note: here
case 1:
^~~~
regex.c: In function ‘regex_format_error’:
regex.c:541:10: warning: this statement may fall through [-Wimplicit-fallthrough=]
*ptr++ = '.';
~~~~~~~^~~~~
regex.c:542:2: note: here
case 3:
^~~~
regex.c:543:10: warning: this statement may fall through [-Wimplicit-fallthrough=]
*ptr++ = '.';
~~~~~~~^~~~~
regex.c:544:2: note: here
case 2:
^~~~
regex.c:545:10: warning: this statement may fall through [-Wimplicit-fallthrough=]
*ptr++ = '.';
~~~~~~~^~~~~
regex.c:546:2: note: here
case 1:
^~~~
modules.c: In function ‘semanage_module_get_path’:
modules.c:602:7: warning: this statement may fall through [-Wimplicit-fallthrough=]
if (file == NULL) file = "hll";
^
modules.c:603:3: note: here
case SEMANAGE_MODULE_PATH_CIL:
^~~~
modules.c:604:7: warning: this statement may fall through [-Wimplicit-fallthrough=]
if (file == NULL) file = "cil";
^
modules.c:605:3: note: here
case SEMANAGE_MODULE_PATH_LANG_EXT:
^~~~
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Type aliases present a problem for module_to_cil because they are not
in the sym_val_to_name table that it uses to write declarations. Type
aliases are gathered by going through the decl_ids list and then
the alias declaration is written out when the block with that scope
id is handled. This doesn't work if a type alias appears in a require
block, since the require cannot be distinguished from the declaration.
The result is two declarations of the alias and an error when secilc
compiles the policy.
Because of the work cleaning up scope handling, the alias declaration
will always be at the end of the decl_ids list, so now only gather
the last scope id.
Also, when an alias is used in a module it is required as a type and
it will appear in the sym_val_to_name table. When that occurs, just
skip the alias when writing out types.
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
Currently, when checking if an identifier is enabled, each scope in
the decl_ids list is checked. This means that if any block that
requires the identifier is enabled, then the identifier will be treated
as being declared.
Now, declarations will be kept at the end of the decl_ids list and
when checking if an identifier is enabled, only the last scope will
be checked (Except for roles and users which allow multiple declarations,
they will have to keep the old behavior.)
Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>