platform_external_selinux/libsepol/tests/test-deps.c
Nicolas Iooss 120681c1a3 libsepol, libsemanage: add a macro to silence static analyzer warnings in tests
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>
2019-09-30 08:43:41 -04:00

306 lines
10 KiB
C

/*
* Author: Karl MacMillan <kmacmillan@tresys.com>
*
* Copyright (C) 2006 Tresys Technology, LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "test-deps.h"
#include "parse_util.h"
#include "helpers.h"
#include <sepol/policydb/policydb.h>
#include <sepol/policydb/link.h>
#include <stdlib.h>
/* Tests for dependency checking / handling, specifically:
*
* 1 type in module global.
* 2 attribute in module global.
* 3 object class / perm in module global.
* 4 boolean in module global.
* 5 role in module global.
*
* 6 type in module optional.
* 7 attribute in module optional.
* 8 object class / perm in module optional.
* 9 boolean in module optional.
* 10 role in module optional.
*
* 11 type in base optional.
* 12 attribute in base optional.
* 13 object class / perm in base optional.
* 14 boolean in base optional.
* 15 role in base optional.
*
* Each of these tests are done with the dependency met and not
* met. Additionally, each of the required symbols is used in the
* scope it is required.
*
* In addition to the simple tests, we have test with more complex
* modules that test:
*
* 17 mutual dependencies between two modules.
* 18 circular dependency between three modules.
* 19 large number of dependencies in a module with a more complex base.
* 20 nested optionals with requires.
*
* Again, each of these tests is done with the requirements met and not
* met.
*/
#include <sepol/debug.h>
#include <sepol/handle.h>
#include "helpers.h"
#define BASE_MODREQ_TYPE_GLOBAL 0
#define BASE_MODREQ_ATTR_GLOBAL 1
#define BASE_MODREQ_OBJ_GLOBAL 2
#define BASE_MODREQ_BOOL_GLOBAL 3
#define BASE_MODREQ_ROLE_GLOBAL 4
#define BASE_MODREQ_PERM_GLOBAL 5
#define BASE_MODREQ_TYPE_OPT 6
#define BASE_MODREQ_ATTR_OPT 7
#define BASE_MODREQ_OBJ_OPT 8
#define BASE_MODREQ_BOOL_OPT 9
#define BASE_MODREQ_ROLE_OPT 10
#define BASE_MODREQ_PERM_OPT 11
#define NUM_BASES 12
static policydb_t bases_met[NUM_BASES];
static policydb_t bases_notmet[NUM_BASES];
extern int mls;
int deps_test_init(void)
{
int i;
/* To test linking we need 1 base per link test and in
* order to load them in the init function we have
* to keep them all around. Not ideal, but it shouldn't
* matter too much.
*/
for (i = 0; i < NUM_BASES; i++) {
if (test_load_policy(&bases_met[i], POLICY_BASE, mls, "test-deps", "base-metreq.conf"))
return -1;
}
for (i = 0; i < NUM_BASES; i++) {
if (test_load_policy(&bases_notmet[i], POLICY_BASE, mls, "test-deps", "base-notmetreq.conf"))
return -1;
}
return 0;
}
int deps_test_cleanup(void)
{
int i;
for (i = 0; i < NUM_BASES; i++) {
policydb_destroy(&bases_met[i]);
}
for (i = 0; i < NUM_BASES; i++) {
policydb_destroy(&bases_notmet[i]);
}
return 0;
}
/* This function performs testing of the dependency handles for module global
* symbols. It is capable of testing 2 scenarios - the dependencies are met
* and the dependencies are not met.
*
* Parameters:
* req_met boolean indicating whether the base policy meets the
* requirements for the modules global block.
* b index of the base policy in the global bases_met array.
*
* policy name of the policy module to load for this test.
* decl_type name of the unique type found in the module's global
* section is to find that avrule_decl.
*/
static void do_deps_modreq_global(int req_met, int b, const char *policy, const char *decl_type)
{
policydb_t *base;
policydb_t mod;
policydb_t *mods[] = { &mod };
avrule_decl_t *decl;
int ret, link_ret;
sepol_handle_t *h;
/* suppress error reporting - this is because we know that we
* are going to get errors and don't want libsepol complaining
* about it constantly. */
h = sepol_handle_create();
CU_ASSERT_FATAL(h != NULL);
sepol_msg_set_callback(h, NULL, NULL);
if (req_met) {
base = &bases_met[b];
link_ret = 0;
} else {
base = &bases_notmet[b];
link_ret = -3;
}
CU_ASSERT_FATAL(test_load_policy(&mod, POLICY_MOD, mls, "test-deps", policy) == 0);
/* link the modules and check for the correct return value.
*/
ret = link_modules(h, base, mods, 1, 0);
CU_ASSERT_FATAL(ret == link_ret);
policydb_destroy(&mod);
sepol_handle_destroy(h);
if (!req_met)
return;
decl = test_find_decl_by_sym(base, SYM_TYPES, decl_type);
CU_ASSERT_FATAL(decl != NULL);
CU_ASSERT(decl->enabled == 1);
}
/* Test that symbol require statements in the global scope of a module
* work correctly. This will cover tests 1 - 5 (described above).
*
* Each of these policies will require as few symbols as possible to
* use the required symbol in addition requiring (for example, the type
* test also requires an object class for an allow rule).
*/
static void deps_modreq_global(void)
{
/* object classes */
do_deps_modreq_global(1, BASE_MODREQ_OBJ_GLOBAL, "modreq-obj-global.conf", "mod_global_t");
do_deps_modreq_global(0, BASE_MODREQ_OBJ_GLOBAL, "modreq-obj-global.conf", "mod_global_t");
/* types */
do_deps_modreq_global(1, BASE_MODREQ_TYPE_GLOBAL, "modreq-type-global.conf", "mod_global_t");
do_deps_modreq_global(0, BASE_MODREQ_TYPE_GLOBAL, "modreq-type-global.conf", "mod_global_t");
/* attributes */
do_deps_modreq_global(1, BASE_MODREQ_ATTR_GLOBAL, "modreq-attr-global.conf", "mod_global_t");
do_deps_modreq_global(0, BASE_MODREQ_ATTR_GLOBAL, "modreq-attr-global.conf", "mod_global_t");
/* booleans */
do_deps_modreq_global(1, BASE_MODREQ_BOOL_GLOBAL, "modreq-bool-global.conf", "mod_global_t");
do_deps_modreq_global(0, BASE_MODREQ_BOOL_GLOBAL, "modreq-bool-global.conf", "mod_global_t");
/* roles */
do_deps_modreq_global(1, BASE_MODREQ_ROLE_GLOBAL, "modreq-role-global.conf", "mod_global_t");
do_deps_modreq_global(0, BASE_MODREQ_ROLE_GLOBAL, "modreq-role-global.conf", "mod_global_t");
do_deps_modreq_global(1, BASE_MODREQ_PERM_GLOBAL, "modreq-perm-global.conf", "mod_global_t");
do_deps_modreq_global(0, BASE_MODREQ_PERM_GLOBAL, "modreq-perm-global.conf", "mod_global_t");
}
/* This function performs testing of the dependency handles for module optional
* symbols. It is capable of testing 2 scenarios - the dependencies are met
* and the dependencies are not met.
*
* Parameters:
* req_met boolean indicating whether the base policy meets the
* requirements for the modules global block.
* b index of the base policy in the global bases_met array.
*
* policy name of the policy module to load for this test.
* decl_type name of the unique type found in the module's global
* section is to find that avrule_decl.
*/
static void do_deps_modreq_opt(int req_met, int ret_val, int b, const char *policy, const char *decl_type)
{
policydb_t *base;
policydb_t mod;
policydb_t *mods[] = { &mod };
avrule_decl_t *decl;
int ret;
sepol_handle_t *h;
/* suppress error reporting - this is because we know that we
* are going to get errors and don't want libsepol complaining
* about it constantly. */
h = sepol_handle_create();
CU_ASSERT_FATAL(h != NULL);
sepol_msg_set_callback(h, NULL, NULL);
if (req_met) {
base = &bases_met[b];
} else {
base = &bases_notmet[b];
}
CU_ASSERT_FATAL(test_load_policy(&mod, POLICY_MOD, mls, "test-deps", policy) == 0);
/* link the modules and check for the correct return value.
*/
ret = link_modules(h, base, mods, 1, 0);
CU_ASSERT_FATAL(ret == ret_val);
policydb_destroy(&mod);
sepol_handle_destroy(h);
if (ret_val < 0)
return;
decl = test_find_decl_by_sym(base, SYM_TYPES, decl_type);
CU_ASSERT_FATAL(decl != NULL);
if (req_met) {
CU_ASSERT(decl->enabled == 1);
} else {
CU_ASSERT(decl->enabled == 0);
}
}
/* Test that symbol require statements in the global scope of a module
* work correctly. This will cover tests 6 - 10 (described above).
*
* Each of these policies will require as few symbols as possible to
* use the required symbol in addition requiring (for example, the type
* test also requires an object class for an allow rule).
*/
static void deps_modreq_opt(void)
{
/* object classes */
do_deps_modreq_opt(1, 0, BASE_MODREQ_OBJ_OPT, "modreq-obj-opt.conf", "mod_opt_t");
do_deps_modreq_opt(0, 0, BASE_MODREQ_OBJ_OPT, "modreq-obj-opt.conf", "mod_opt_t");
/* types */
do_deps_modreq_opt(1, 0, BASE_MODREQ_TYPE_OPT, "modreq-type-opt.conf", "mod_opt_t");
do_deps_modreq_opt(0, 0, BASE_MODREQ_TYPE_OPT, "modreq-type-opt.conf", "mod_opt_t");
/* attributes */
do_deps_modreq_opt(1, 0, BASE_MODREQ_ATTR_OPT, "modreq-attr-opt.conf", "mod_opt_t");
do_deps_modreq_opt(0, 0, BASE_MODREQ_ATTR_OPT, "modreq-attr-opt.conf", "mod_opt_t");
/* booleans */
do_deps_modreq_opt(1, 0, BASE_MODREQ_BOOL_OPT, "modreq-bool-opt.conf", "mod_opt_t");
do_deps_modreq_opt(0, 0, BASE_MODREQ_BOOL_OPT, "modreq-bool-opt.conf", "mod_opt_t");
/* roles */
do_deps_modreq_opt(1, 0, BASE_MODREQ_ROLE_OPT, "modreq-role-opt.conf", "mod_opt_t");
do_deps_modreq_opt(0, 0, BASE_MODREQ_ROLE_OPT, "modreq-role-opt.conf", "mod_opt_t");
/* permissions */
do_deps_modreq_opt(1, 0, BASE_MODREQ_PERM_OPT, "modreq-perm-opt.conf", "mod_opt_t");
do_deps_modreq_opt(0, -3, BASE_MODREQ_PERM_OPT, "modreq-perm-opt.conf", "mod_opt_t");
}
int deps_add_tests(CU_pSuite suite)
{
if (NULL == CU_add_test(suite, "deps_modreq_global", deps_modreq_global)) {
return CU_get_error();
}
if (NULL == CU_add_test(suite, "deps_modreq_opt", deps_modreq_opt)) {
return CU_get_error();
}
return 0;
}