aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-09 06:02:45 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-09 06:02:45 +0000
commita21e897d34d3177da2e720114dd8cf8572fe63e8 (patch)
tree0ac5f8b919be8431992c69321948d13fdee3ccc6
parentd6993adcbcafa90a5049ca3f62f279b89b1bb802 (diff)
parent7ea0a4df6cb4f6c1afb9922c1c6f8a965774b2c2 (diff)
downloadselinux-android13-frc-extservices-release.tar.gz
Snap for 8558685 from 7ea0a4df6cb4f6c1afb9922c1c6f8a965774b2c2 to tm-frc-extservices-releaset_frc_ext_330443000android13-frc-extservices-release
Change-Id: I60bdd574afaa66ebbf8b8e1a69bd7f77c24f7531
-rw-r--r--.circleci/config.yml2
-rw-r--r--.github/workflows/cifuzz.yml3
-rw-r--r--.github/workflows/run_tests.yml44
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--Makefile4
-rw-r--r--README.md4
-rw-r--r--checkpolicy/module_compiler.c1
-rw-r--r--checkpolicy/parse_util.c1
-rw-r--r--checkpolicy/policy_define.c68
-rw-r--r--checkpolicy/policy_scan.l15
-rw-r--r--libselinux/Android.bp39
-rw-r--r--libselinux/Makefile2
-rw-r--r--libselinux/include/selinux/restorecon.h14
-rw-r--r--libselinux/man/man3/selinux_restorecon.329
-rw-r--r--libselinux/man/man3/selinux_restorecon_parallel.31
-rw-r--r--libselinux/src/Makefile1
-rw-r--r--libselinux/src/android/android_host.c8
-rw-r--r--libselinux/src/android/android_platform.c103
-rw-r--r--libselinux/src/callbacks.c8
-rw-r--r--libselinux/src/callbacks.h13
-rw-r--r--libselinux/src/is_customizable_type.c23
-rw-r--r--libselinux/src/label_file.c15
-rw-r--r--libselinux/src/label_file.h2
-rw-r--r--libselinux/src/libselinux.map5
-rw-r--r--libselinux/src/matchpathcon.c2
-rw-r--r--libselinux/src/procattr.c2
-rw-r--r--libselinux/src/selinux_config.c17
-rw-r--r--libselinux/src/selinux_internal.h16
-rw-r--r--libselinux/src/selinux_restorecon.c458
-rw-r--r--libselinux/src/selinuxswig_python.i6
-rw-r--r--libselinux/src/selinuxswig_python_exception.i8
-rw-r--r--libselinux/src/setrans_client.c2
-rw-r--r--libselinux/utils/Makefile1
-rw-r--r--libsemanage/include/semanage/handle.h5
-rw-r--r--libsemanage/include/semanage/modules.h26
-rw-r--r--libsemanage/man/man5/semanage.conf.52
-rw-r--r--libsemanage/man/ru/man5/semanage.conf.52
-rw-r--r--libsemanage/src/boolean_record.c4
-rw-r--r--libsemanage/src/booleans_file.c2
-rw-r--r--libsemanage/src/compressed_file.c224
-rw-r--r--libsemanage/src/compressed_file.h78
-rw-r--r--libsemanage/src/context_record.c2
-rw-r--r--libsemanage/src/database_join.c12
-rw-r--r--libsemanage/src/direct_api.c541
-rw-r--r--libsemanage/src/direct_api.h4
-rw-r--r--libsemanage/src/fcontexts_file.c6
-rw-r--r--libsemanage/src/handle.c11
-rw-r--r--libsemanage/src/handle.h1
-rw-r--r--libsemanage/src/ibendports_file.c4
-rw-r--r--libsemanage/src/ibpkeys_file.c4
-rw-r--r--libsemanage/src/interfaces_file.c6
-rw-r--r--libsemanage/src/libsemanage.map5
-rw-r--r--libsemanage/src/modules.c60
-rw-r--r--libsemanage/src/modules.h3
-rw-r--r--libsemanage/src/nodes_file.c8
-rw-r--r--libsemanage/src/parse_utils.c6
-rw-r--r--libsemanage/src/parse_utils.h11
-rw-r--r--libsemanage/src/ports_file.c4
-rw-r--r--libsemanage/src/semanage.conf5
-rw-r--r--libsemanage/src/semanage_store.c53
-rw-r--r--libsemanage/src/semanage_store.h1
-rw-r--r--libsemanage/src/semanageswig_python_exception.i8
-rw-r--r--libsemanage/src/seusers_file.c6
-rw-r--r--libsemanage/src/sha256.c294
-rw-r--r--libsemanage/src/sha256.h89
-rw-r--r--libsemanage/src/users_base_file.c7
-rw-r--r--libsemanage/src/users_extra_file.c4
-rw-r--r--libsemanage/src/utilities.c2
-rw-r--r--libsemanage/tests/test_bool.c34
-rw-r--r--libsemanage/tests/test_fcontext.c32
-rw-r--r--libsemanage/tests/test_ibendport.c13
-rw-r--r--libsemanage/tests/test_iface.c24
-rw-r--r--libsemanage/tests/test_node.c29
-rw-r--r--libsemanage/tests/test_other.c6
-rw-r--r--libsemanage/tests/test_port.c24
-rw-r--r--libsemanage/tests/test_user.c17
-rw-r--r--libsemanage/tests/utilities.c5
-rw-r--r--libsemanage/tests/utilities.h2
-rw-r--r--libsepol/Android.bp35
-rw-r--r--libsepol/cil/src/cil.c12
-rw-r--r--libsepol/cil/src/cil_binary.c63
-rw-r--r--libsepol/cil/src/cil_build_ast.c57
-rw-r--r--libsepol/cil/src/cil_copy_ast.c6
-rw-r--r--libsepol/cil/src/cil_internal.h5
-rw-r--r--libsepol/cil/src/cil_log.c5
-rw-r--r--libsepol/cil/src/cil_log.h2
-rw-r--r--libsepol/cil/src/cil_post.c57
-rw-r--r--libsepol/cil/src/cil_resolve_ast.c42
-rw-r--r--libsepol/cil/src/cil_write_ast.c57
-rw-r--r--libsepol/fuzz/binpolicy-fuzzer.c63
-rw-r--r--libsepol/fuzz/policy.binbin0 -> 1552 bytes
-rw-r--r--libsepol/fuzz/secilc-fuzzer.c5
-rw-r--r--libsepol/include/sepol/policydb/polcaps.h19
-rw-r--r--libsepol/src/Makefile6
-rw-r--r--libsepol/src/assertion.c213
-rw-r--r--libsepol/src/avtab.c7
-rw-r--r--libsepol/src/conditional.c55
-rw-r--r--libsepol/src/context_record.c2
-rw-r--r--libsepol/src/ebitmap.c27
-rw-r--r--libsepol/src/expand.c21
-rw-r--r--libsepol/src/hashtab.c7
-rw-r--r--libsepol/src/hierarchy.c2
-rw-r--r--libsepol/src/kernel_to_cil.c87
-rw-r--r--libsepol/src/kernel_to_common.c27
-rw-r--r--libsepol/src/kernel_to_common.h4
-rw-r--r--libsepol/src/kernel_to_conf.c82
-rw-r--r--libsepol/src/link.c24
-rw-r--r--libsepol/src/module.c17
-rw-r--r--libsepol/src/module_to_cil.c62
-rw-r--r--libsepol/src/optimize.c32
-rw-r--r--libsepol/src/polcaps.c19
-rw-r--r--libsepol/src/policydb.c29
-rw-r--r--libsepol/src/policydb_validate.c704
-rw-r--r--libsepol/src/private.h27
-rw-r--r--libsepol/src/services.c16
-rw-r--r--libsepol/src/sidtab.c3
-rw-r--r--libsepol/src/user_record.c8
-rw-r--r--libsepol/src/users.c12
-rw-r--r--libsepol/src/util.c13
-rw-r--r--libsepol/src/write.c2
-rw-r--r--libsepol/tests/Makefile10
-rw-r--r--mcstrans/Makefile6
-rw-r--r--mcstrans/src/Makefile4
-rw-r--r--mcstrans/src/mcscolor.c2
-rw-r--r--mcstrans/src/mcscolor.h8
-rw-r--r--mcstrans/src/mcstrans.c188
-rw-r--r--mcstrans/src/mcstrans.h1
-rw-r--r--mcstrans/src/mcstransd.c13
-rw-r--r--mcstrans/utils/Makefile6
-rw-r--r--policycoreutils/man/man5/selinux_config.52
-rw-r--r--policycoreutils/man/ru/man5/selinux_config.52
-rw-r--r--policycoreutils/newrole/Makefile13
-rw-r--r--policycoreutils/newrole/hashtab.c9
-rw-r--r--policycoreutils/newrole/newrole.c40
-rw-r--r--policycoreutils/run_init/open_init_pty.c2
-rw-r--r--policycoreutils/run_init/run_init.c12
-rwxr-xr-xpolicycoreutils/scripts/fixfiles35
-rw-r--r--policycoreutils/scripts/fixfiles.817
-rw-r--r--policycoreutils/secon/secon.c3
-rw-r--r--policycoreutils/semodule/semodule.813
-rw-r--r--policycoreutils/semodule/semodule.c109
-rw-r--r--policycoreutils/sestatus/sestatus.c12
-rw-r--r--policycoreutils/setfiles/Makefile2
-rw-r--r--policycoreutils/setfiles/restore.c9
-rw-r--r--policycoreutils/setfiles/restore.h2
-rw-r--r--policycoreutils/setfiles/restorecon.89
-rw-r--r--policycoreutils/setfiles/setfiles.89
-rw-r--r--policycoreutils/setfiles/setfiles.c38
-rw-r--r--python/audit2allow/sepolgen-ifgen-attr-helper.c6
-rw-r--r--python/semanage/semanage-fcontext.82
-rw-r--r--python/sepolgen/src/sepolgen/refparser.py2
-rw-r--r--sandbox/seunshare.c2
-rwxr-xr-xscripts/ci/fedora-test-runner.sh2
-rwxr-xr-xscripts/oss-fuzz.sh17
-rw-r--r--secilc/docs/cil_file_labeling_statements.md10
155 files changed, 3865 insertions, 1293 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 5d3177da..af20484b 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -13,7 +13,7 @@ jobs:
# Install dependencies
- run: sudo apt-get update -qq
- - run: sudo apt-get install -qq bison clang clang-tools flex gawk gettext libaudit-dev libcap-dev libcap-ng-dev libcunit1-dev libdbus-glib-1-dev libpcre3-dev python3-dev python-dev ruby-dev swig xmlto
+ - run: sudo apt-get install -qq bison clang clang-tools flex gawk gettext libaudit-dev libcap-dev libcap-ng-dev libcunit1-dev libdbus-glib-1-dev libpcre2-dev python3-dev python-dev ruby-dev swig xmlto
- run:
name: Setup environment variables
diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml
index 5c2233a2..92523db4 100644
--- a/.github/workflows/cifuzz.yml
+++ b/.github/workflows/cifuzz.yml
@@ -28,8 +28,9 @@ jobs:
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'selinux'
- fuzz-seconds: 180
+ fuzz-seconds: 600
dry-run: false
+ report-unreproducible-crashes: true
sanitizer: ${{ matrix.sanitizer }}
- name: Upload Crash
uses: actions/upload-artifact@v1
diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml
index ef4be8af..8b7cb720 100644
--- a/.github/workflows/run_tests.yml
+++ b/.github/workflows/run_tests.yml
@@ -29,6 +29,9 @@ jobs:
python-ruby-version: {python: 3.9, ruby: 2.7, other: linker-bfd}
- compiler: clang
python-ruby-version: {python: 3.9, ruby: 2.7, other: linker-gold}
+ include:
+ - compiler: gcc
+ python-ruby-version: {python: 3.9, ruby: 2.7, other: sanitizers}
steps:
- uses: actions/checkout@v2
@@ -57,7 +60,7 @@ jobs:
libcap-ng-dev \
libcunit1-dev \
libdbus-glib-1-dev \
- libpcre3-dev \
+ libpcre2-dev \
python3-dev \
python-dev \
ruby-dev \
@@ -88,6 +91,11 @@ jobs:
elif [ "${{ matrix.python-ruby-version.other }}" = "test-debug" ] ; then
# Test hat debug build works fine
EXPLICIT_MAKE_VARS="DEBUG=1"
+ elif [ "${{ matrix.python-ruby-version.other }}" = "sanitizers" ] ; then
+ sanitizers='-fsanitize=address,undefined'
+ EXPLICIT_MAKE_VARS="CFLAGS='-g -I$DESTDIR/usr/include $sanitizers' LDFLAGS='-L$DESTDIR/usr/lib $sanitizers' LDLIBS= CPPFLAGS= OPT_SUBDIRS="
+ echo "ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1" >> $GITHUB_ENV
+ echo "UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1" >> $GITHUB_ENV
else
EXPLICIT_MAKE_VARS=
fi
@@ -139,18 +147,18 @@ jobs:
- name: Run tests
run: |
echo "::group::make install"
- make -j$(nproc) install $EXPLICIT_MAKE_VARS -k
+ eval make -j$(nproc) install $EXPLICIT_MAKE_VARS -k
echo "::endgroup::"
echo "::group::make install-pywrap"
- make -j$(nproc) install-pywrap $EXPLICIT_MAKE_VARS -k
+ eval make -j$(nproc) install-pywrap $EXPLICIT_MAKE_VARS -k
echo "::endgroup::"
echo "::group::make install-rubywrap"
- make -j$(nproc) install-rubywrap $EXPLICIT_MAKE_VARS -k
+ eval make -j$(nproc) install-rubywrap $EXPLICIT_MAKE_VARS -k
echo "::endgroup::"
# Now that everything is installed, run "make all" to build everything which may have not been built
echo "::group::make all"
- make -j$(nproc) all $EXPLICIT_MAKE_VARS -k
+ eval make -j$(nproc) all $EXPLICIT_MAKE_VARS -k
echo "::endgroup::"
# Set up environment variables for the tests and show variables (to help debugging issues)
@@ -164,19 +172,21 @@ jobs:
# Run tests
echo "::group::make test"
- make test $EXPLICIT_MAKE_VARS
+ eval make test $EXPLICIT_MAKE_VARS
echo "::endgroup::"
- # Test Python and Ruby wrappers
- echo "::group::Test Python and Ruby wrappers"
- $PYTHON -c 'import selinux;import selinux.audit2why;import semanage;print(selinux.is_selinux_enabled())'
- $RUBY -e 'require "selinux";require "semanage";puts Selinux::is_selinux_enabled()'
- echo "::endgroup::"
-
- # Run Python linter, but not on the downloaded refpolicy
- echo "::group::scripts/run-flake8"
- ./scripts/run-flake8
- echo "::endgroup::"
+ if [ "${{ matrix.python-ruby-version.other }}" != "sanitizers" ] ; then
+ # Test Python and Ruby wrappers
+ echo "::group::Test Python and Ruby wrappers"
+ $PYTHON -c 'import selinux;import selinux.audit2why;import semanage;print(selinux.is_selinux_enabled())'
+ $RUBY -e 'require "selinux";require "semanage";puts Selinux::is_selinux_enabled()'
+ echo "::endgroup::"
+
+ # Run Python linter, but not on the downloaded refpolicy
+ echo "::group::scripts/run-flake8"
+ ./scripts/run-flake8
+ echo "::endgroup::"
+ fi
echo "::group::Test .gitignore and make clean distclean"
# Remove every installed files
@@ -184,6 +194,6 @@ jobs:
# Test that "git status" looks clean, or print a clear error message
git status --short | sed -n 's/^??/error: missing .gitignore entry for/p' | (! grep '^')
# Clean up everything and show which file needs to be added to "make clean"
- make clean distclean $EXPLICIT_MAKE_VARS
+ eval make clean distclean $EXPLICIT_MAKE_VARS
git ls-files --ignored --others --exclude-standard | sed 's/^/error: "make clean distclean" did not remove /' | (! grep '^')
echo "::endgroup::"
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a3517cb8..7c548e58 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -26,7 +26,7 @@ using a custom policy please include it as well.
There are a number of dependencies required to build the userspace
tools/libraries. On a Fedora system you can install them with yum:
- # yum install audit-libs-devel bison bzip2-devel dbus-devel dbus-glib-devel flex flex-devel flex-static glib2-devel libcap-devel libcap-ng-devel pam-devel pcre-devel python-devel setools-devel swig ustr-devel
+ # yum install audit-libs-devel bison bzip2-devel dbus-devel dbus-glib-devel flex flex-devel flex-static glib2-devel libcap-devel libcap-ng-devel pam-devel pcre2-devel python-devel setools-devel swig ustr-devel
The tools and libraries can be built and installed under a private directory from the top level with make, e.g.
diff --git a/Makefile b/Makefile
index 298cd2b7..215e313e 100644
--- a/Makefile
+++ b/Makefile
@@ -9,8 +9,12 @@ ifeq ($(DEBUG),1)
export LDFLAGS = -g
else
export CFLAGS ?= -O2 -Werror -Wall -Wextra \
+ -Wfloat-equal \
+ -Wformat=2 \
+ -Winit-self \
-Wmissing-format-attribute \
-Wmissing-noreturn \
+ -Wnull-dereference \
-Wpointer-arith \
-Wshadow \
-Wstrict-prototypes \
diff --git a/README.md b/README.md
index e1c2fe64..74b0a0c3 100644
--- a/README.md
+++ b/README.md
@@ -51,7 +51,7 @@ dnf install \
libcap-devel \
libcap-ng-devel \
pam-devel \
- pcre-devel \
+ pcre2-devel \
xmlto
# For Python and Ruby bindings
@@ -78,7 +78,7 @@ apt-get install --no-install-recommends --no-install-suggests \
libcap-ng-dev \
libcunit1-dev \
libglib2.0-dev \
- libpcre3-dev \
+ libpcre2-dev \
pkgconf \
python3 \
python3-distutils \
diff --git a/checkpolicy/module_compiler.c b/checkpolicy/module_compiler.c
index 5f5b0b19..129650fa 100644
--- a/checkpolicy/module_compiler.c
+++ b/checkpolicy/module_compiler.c
@@ -99,6 +99,7 @@ int define_policy(int pass, int module_header_given)
yyerror("no module name");
return -1;
}
+ free(policydbp->name);
policydbp->name = id;
if ((policydbp->version =
queue_remove(id_queue)) == NULL) {
diff --git a/checkpolicy/parse_util.c b/checkpolicy/parse_util.c
index 8c1f393c..f2d1e04d 100644
--- a/checkpolicy/parse_util.c
+++ b/checkpolicy/parse_util.c
@@ -47,6 +47,7 @@ int read_source_policy(policydb_t * p, const char *file, const char *progname)
}
policydbp = p;
+ policydbp->name = strdup(file);
mlspol = p->mls;
init_parser(1);
diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c
index d3eb6111..16b78346 100644
--- a/checkpolicy/policy_define.c
+++ b/checkpolicy/policy_define.c
@@ -3477,6 +3477,8 @@ static constraint_expr_t *constraint_expr_clone(const constraint_expr_t * expr)
return NULL;
}
+#define PERMISSION_MASK(nprim) ((nprim) == PERM_SYMTAB_SIZE ? (~UINT32_C(0)) : ((UINT32_C(1) << (nprim)) - 1))
+
int define_constraint(constraint_expr_t * expr)
{
struct constraint_node *node;
@@ -3590,6 +3592,22 @@ int define_constraint(constraint_expr_t * expr)
cladatum = policydbp->class_val_to_struct[i];
node = cladatum->constraints;
+ if (strcmp(id, "*") == 0) {
+ node->permissions = PERMISSION_MASK(cladatum->permissions.nprim);
+ continue;
+ }
+
+ if (strcmp(id, "~") == 0) {
+ node->permissions = ~node->permissions & PERMISSION_MASK(cladatum->permissions.nprim);
+ if (node->permissions == 0) {
+ yywarn("omitting constraint with no permission set");
+ cladatum->constraints = node->next;
+ constraint_expr_destroy(node->expr);
+ free(node);
+ }
+ continue;
+ }
+
perdatum =
(perm_datum_t *) hashtab_search(cladatum->
permissions.
@@ -5290,6 +5308,14 @@ int define_ipv4_node_context()
goto out;
}
+ if (mask.s_addr != 0 && ((~mask.s_addr + 1) & ~mask.s_addr) != 0) {
+ yywarn("ipv4 mask is not contiguous");
+ }
+
+ if ((~mask.s_addr & addr.s_addr) != 0) {
+ yywarn("host bits in ipv4 address set");
+ }
+
newc = malloc(sizeof(ocontext_t));
if (!newc) {
yyerror("out of memory");
@@ -5325,6 +5351,40 @@ out:
return rc;
}
+static int ipv6_is_mask_contiguous(const struct in6_addr *mask)
+{
+ int filled = 1;
+ unsigned i;
+
+ for (i = 0; i < 16; i++) {
+ if ((((~mask->s6_addr[i] & 0xFF) + 1) & (~mask->s6_addr[i] & 0xFF)) != 0) {
+ return 0;
+ }
+ if (!filled && mask->s6_addr[i] != 0) {
+ return 0;
+ }
+
+ if (filled && mask->s6_addr[i] != 0xFF) {
+ filled = 0;
+ }
+ }
+
+ return 1;
+}
+
+static int ipv6_has_host_bits_set(const struct in6_addr *addr, const struct in6_addr *mask)
+{
+ unsigned i;
+
+ for (i = 0; i < 16; i++) {
+ if ((addr->s6_addr[i] & ~mask->s6_addr[i]) != 0) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
int define_ipv6_node_context(void)
{
char *id;
@@ -5376,6 +5436,14 @@ int define_ipv6_node_context(void)
goto out;
}
+ if (!ipv6_is_mask_contiguous(&mask)) {
+ yywarn("ipv6 mask is not contiguous");
+ }
+
+ if (ipv6_has_host_bits_set(&addr, &mask)) {
+ yywarn("host bits in ipv6 address set");
+ }
+
newc = malloc(sizeof(ocontext_t));
if (!newc) {
yyerror("out of memory");
diff --git a/checkpolicy/policy_scan.l b/checkpolicy/policy_scan.l
index 129a8a2a..9fefea7b 100644
--- a/checkpolicy/policy_scan.l
+++ b/checkpolicy/policy_scan.l
@@ -60,7 +60,14 @@ hexval [0-9A-Fa-f]
%%
\n.* {
+#if defined(__GNUC__) && __GNUC__ >= 8
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstringop-truncation"
+#endif
strncpy(linebuf[lno], yytext+1, 255);
+#if defined(__GNUC__) && __GNUC__ >= 8
+#pragma GCC diagnostic pop
+#endif
linebuf[lno][254] = 0;
lno = 1 - lno;
policydb_lineno++;
@@ -308,11 +315,11 @@ GLBLUB { return(GLBLUB); }
int yyerror(const char *msg)
{
if (source_file[0])
- fprintf(stderr, "%s:%ld:",
+ fprintf(stderr, "%s:%lu:",
source_file, source_lineno);
else
fprintf(stderr, "(unknown source)::");
- fprintf(stderr, "ERROR '%s' at token '%s' on line %ld:\n%s\n%s\n",
+ fprintf(stderr, "ERROR '%s' at token '%s' on line %lu:\n%s\n%s\n",
msg,
yytext,
policydb_lineno,
@@ -327,11 +334,11 @@ int yywarn(const char *msg)
return yyerror(msg);
if (source_file[0])
- fprintf(stderr, "%s:%ld:",
+ fprintf(stderr, "%s:%lu:",
source_file, source_lineno);
else
fprintf(stderr, "(unknown source)::");
- fprintf(stderr, "WARNING '%s' at token '%s' on line %ld:\n%s\n%s\n",
+ fprintf(stderr, "WARNING '%s' at token '%s' on line %lu:\n%s\n%s\n",
msg,
yytext,
policydb_lineno,
diff --git a/libselinux/Android.bp b/libselinux/Android.bp
index 6275b410..fab05ba0 100644
--- a/libselinux/Android.bp
+++ b/libselinux/Android.bp
@@ -150,9 +150,8 @@ cc_library {
],
target: {
- linux_glibc: {
+ host_linux: {
srcs: [
- "src/android/android_host.c",
"src/avc.c",
"src/avc_internal.c",
"src/avc_sidtab.c",
@@ -162,50 +161,30 @@ cc_library {
"src/context.c",
"src/deny_unknown.c",
"src/enabled.c",
- "src/fgetfilecon.c",
"src/getenforce.c",
"src/getfilecon.c",
"src/get_initial_context.c",
"src/init.c",
- "src/lgetfilecon.c",
"src/load_policy.c",
- "src/lsetfilecon.c",
"src/mapping.c",
"src/procattr.c",
"src/reject_unknown.c",
"src/sestatus.c",
- "src/setenforce.c",
"src/setexecfilecon.c",
- "src/setfilecon.c",
"src/stringrep.c",
],
},
- linux_bionic: {
- enabled: true,
+ linux_glibc: {
srcs: [
- "src/android/android_host.c",
- "src/avc.c",
- "src/avc_internal.c",
- "src/avc_sidtab.c",
- "src/compute_av.c",
- "src/compute_create.c",
- "src/compute_member.c",
- "src/context.c",
- "src/deny_unknown.c",
- "src/enabled.c",
- "src/getenforce.c",
- "src/getfilecon.c",
- "src/get_initial_context.c",
- "src/init.c",
- "src/load_policy.c",
- "src/mapping.c",
- "src/procattr.c",
- "src/reject_unknown.c",
- "src/sestatus.c",
- "src/setexecfilecon.c",
- "src/stringrep.c",
+ "src/fgetfilecon.c",
+ "src/lgetfilecon.c",
+ "src/lsetfilecon.c",
+ "src/setfilecon.c",
],
},
+ linux_bionic: {
+ enabled: true,
+ },
android: {
srcs: [
diff --git a/libselinux/Makefile b/libselinux/Makefile
index 439bc6a9..6d9e2736 100644
--- a/libselinux/Makefile
+++ b/libselinux/Makefile
@@ -23,7 +23,7 @@ ifeq ($(DISABLE_X11),y)
endif
export DISABLE_SETRANS DISABLE_RPM DISABLE_FLAGS ANDROID_HOST DISABLE_X11 LABEL_BACKEND_ANDROID
-USE_PCRE2 ?= n
+USE_PCRE2 ?= y
ifeq ($(USE_PCRE2),y)
PCRE_MODULE := libpcre2-8
PCRE_CFLAGS := -DUSE_PCRE2 -DPCRE2_CODE_UNIT_WIDTH=8
diff --git a/libselinux/include/selinux/restorecon.h b/libselinux/include/selinux/restorecon.h
index 466de39a..1821a3dc 100644
--- a/libselinux/include/selinux/restorecon.h
+++ b/libselinux/include/selinux/restorecon.h
@@ -2,6 +2,7 @@
#define _RESTORECON_H_
#include <sys/types.h>
+#include <stddef.h>
#include <stdarg.h>
#ifdef __cplusplus
@@ -23,6 +24,19 @@ extern "C" {
*/
extern int selinux_restorecon(const char *pathname,
unsigned int restorecon_flags);
+/**
+ * selinux_restorecon_parallel - Relabel files, optionally use more threads.
+ * @pathname: specifies file/directory to relabel.
+ * @restorecon_flags: specifies the actions to be performed when relabeling.
+ * @nthreads: specifies the number of threads to use (0 = use number of CPUs
+ * currently online)
+ *
+ * Same as selinux_restorecon(3), but allows to use multiple threads to do
+ * the work.
+ */
+extern int selinux_restorecon_parallel(const char *pathname,
+ unsigned int restorecon_flags,
+ size_t nthreads);
/*
* restorecon_flags options
*/
diff --git a/libselinux/man/man3/selinux_restorecon.3 b/libselinux/man/man3/selinux_restorecon.3
index ad637406..334d2930 100644
--- a/libselinux/man/man3/selinux_restorecon.3
+++ b/libselinux/man/man3/selinux_restorecon.3
@@ -11,6 +11,14 @@ selinux_restorecon \- restore file(s) default SELinux security contexts
.br
.BI "unsigned int " restorecon_flags ");"
.in
+.sp
+.BI "int selinux_restorecon_parallel(const char *" pathname ,
+.in +\w'int selinux_restorecon_parallel('u
+.br
+.BI "unsigned int " restorecon_flags ","
+.br
+.BI "size_t " nthreads ");"
+.in
.
.SH "DESCRIPTION"
.BR selinux_restorecon ()
@@ -187,6 +195,27 @@ unless the
.B SELINUX_RESTORECON_IGNORE_MOUNTS
flag has been set.
.RE
+.sp
+.BR selinux_restorecon_parallel()
+is similar to
+.BR selinux_restorecon (3),
+but accepts another parameter that allows to run relabeling over multiple
+threads:
+.sp
+.RS
+.IR nthreads
+specifies the number of threads to use during relabeling. When set to 1,
+the behavior is the same as calling
+.BR selinux_restorecon (3).
+When set to 0, the function will try to use as many threads as there are
+online CPU cores. When set to any other number, the function will try to use
+the given number of threads.
+.sp
+Note that to use the parallel relabeling capability, the calling process
+must be linked with the
+.B libpthread
+library (either at compile time or dynamically at run time). Otherwise the
+function will print a warning and fall back to the single threaded mode.
.
.SH "RETURN VALUE"
On success, zero is returned. On error, \-1 is returned and
diff --git a/libselinux/man/man3/selinux_restorecon_parallel.3 b/libselinux/man/man3/selinux_restorecon_parallel.3
new file mode 100644
index 00000000..092d8412
--- /dev/null
+++ b/libselinux/man/man3/selinux_restorecon_parallel.3
@@ -0,0 +1 @@
+.so man3/selinux_restorecon.3
diff --git a/libselinux/src/Makefile b/libselinux/src/Makefile
index 52c40f01..04bf4f24 100644
--- a/libselinux/src/Makefile
+++ b/libselinux/src/Makefile
@@ -98,7 +98,6 @@ override LDFLAGS += -L/opt/local/lib -undefined dynamic_lookup
LD_SONAME_FLAGS=-install_name,$(LIBSO)
endif
-PCRE_LDLIBS ?= -lpcre
# override with -lfts when building on Musl libc to use fts-standalone
FTS_LDLIBS ?=
diff --git a/libselinux/src/android/android_host.c b/libselinux/src/android/android_host.c
deleted file mode 100644
index 8b55aa78..00000000
--- a/libselinux/src/android/android_host.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include <stdlib.h>
-
-// HACK: placeholder for a library the python bindings expect.
-// Delete after b/33170640 is fixed.
-const char *selinux_openssh_contexts_path(void)
-{
- abort();
-}
diff --git a/libselinux/src/android/android_platform.c b/libselinux/src/android/android_platform.c
index 2516c091..05c923bc 100644
--- a/libselinux/src/android/android_platform.c
+++ b/libselinux/src/android/android_platform.c
@@ -806,9 +806,12 @@ static int seapp_context_lookup(enum seapp_kind kind,
username = pwd->pw_name;
- } else if (appid < AID_ISOLATED_START) {
+ } else if (appid < AID_SDK_SANDBOX_PROCESS_START) {
username = "_app";
appid -= AID_APP;
+ } else if (appid < AID_ISOLATED_START) {
+ username = "_sdksandbox";
+ appid -= AID_SDK_SANDBOX_PROCESS_START;
} else {
username = "_isolated";
appid -= AID_ISOLATED_START;
@@ -1119,20 +1122,49 @@ struct pkg_info *package_info_lookup(const char *name)
* credentials are presented (filenames inside are mangled), so we need
* to delay restorecon of those until vold explicitly requests it. */
// NOTE: these paths need to be kept in sync with vold
-#define DATA_SYSTEM_CE_PREFIX "/data/system_ce"
-#define DATA_VENDOR_CE_PREFIX "/data/vendor_ce"
-#define DATA_MISC_CE_PREFIX "/data/misc_ce"
+#define DATA_SYSTEM_CE_PATH "/data/system_ce"
+#define DATA_VENDOR_CE_PATH "/data/vendor_ce"
+#define DATA_MISC_CE_PATH "/data/misc_ce"
+#define DATA_MISC_DE_PATH "/data/misc_de"
/* The path prefixes of package data directories. */
#define DATA_DATA_PATH "/data/data"
#define DATA_USER_PATH "/data/user"
#define DATA_USER_DE_PATH "/data/user_de"
-#define EXPAND_USER_PATH "/mnt/expand/\?\?\?\?\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?\?\?\?\?\?\?\?\?/user"
-#define EXPAND_USER_DE_PATH "/mnt/expand/\?\?\?\?\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?\?\?\?\?\?\?\?\?/user_de"
#define USER_PROFILE_PATH "/data/misc/profiles/cur/*"
+#define SDK_SANDBOX_DATA_CE_PATH "/data/misc_ce/*/sdksandbox"
+#define SDK_SANDBOX_DATA_DE_PATH "/data/misc_de/*/sdksandbox"
+
+#define EXPAND_MNT_PATH "/mnt/expand/\?\?\?\?\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?\?\?\?\?\?\?\?\?"
+#define EXPAND_USER_PATH EXPAND_MNT_PATH "/user"
+#define EXPAND_USER_DE_PATH EXPAND_MNT_PATH "/user_de"
+#define EXPAND_SDK_CE_PATH EXPAND_MNT_PATH "/misc_ce/*/sdksandbox"
+#define EXPAND_SDK_DE_PATH EXPAND_MNT_PATH "/misc_de/*/sdksandbox"
+
#define DATA_DATA_PREFIX DATA_DATA_PATH "/"
#define DATA_USER_PREFIX DATA_USER_PATH "/"
#define DATA_USER_DE_PREFIX DATA_USER_DE_PATH "/"
+#define DATA_MISC_CE_PREFIX DATA_MISC_CE_PATH "/"
+#define DATA_MISC_DE_PREFIX DATA_MISC_DE_PATH "/"
+#define EXPAND_MNT_PATH_PREFIX EXPAND_MNT_PATH "/"
+
+/*
+ * This method helps in identifying paths that refer to users' app data. Labeling for app data is
+ * based on seapp_contexts and seinfo assignments rather than file_contexts and is managed by
+ * installd rather than by init.
+ */
+static bool is_app_data_path(const char *pathname) {
+ int flags = FNM_LEADING_DIR|FNM_PATHNAME;
+ return (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) ||
+ !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1) ||
+ !strncmp(pathname, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1) ||
+ !fnmatch(EXPAND_USER_PATH, pathname, flags) ||
+ !fnmatch(EXPAND_USER_DE_PATH, pathname, flags) ||
+ !fnmatch(SDK_SANDBOX_DATA_CE_PATH, pathname, flags) ||
+ !fnmatch(SDK_SANDBOX_DATA_DE_PATH, pathname, flags) ||
+ !fnmatch(EXPAND_SDK_CE_PATH, pathname, flags) ||
+ !fnmatch(EXPAND_SDK_DE_PATH, pathname, flags));
+}
static int pkgdir_selabel_lookup(const char *pathname,
const char *seinfo,
@@ -1180,6 +1212,40 @@ static int pkgdir_selabel_lookup(const char *pathname,
pathname++;
else
return 0;
+ } else if (!strncmp(pathname, DATA_MISC_CE_PREFIX, sizeof(DATA_MISC_CE_PREFIX)-1)) {
+ pathname += sizeof(DATA_MISC_CE_PREFIX) - 1;
+ while (isdigit(*pathname))
+ pathname++;
+ if (!strncmp(pathname, "/sdksandbox/", sizeof("/sdksandbox/")-1)) {
+ pathname += sizeof("/sdksandbox/") - 1;
+ } else
+ return 0;
+ } else if (!strncmp(pathname, DATA_MISC_DE_PREFIX, sizeof(DATA_MISC_DE_PREFIX)-1)) {
+ pathname += sizeof(DATA_MISC_DE_PREFIX) - 1;
+ while (isdigit(*pathname))
+ pathname++;
+ if (!strncmp(pathname, "/sdksandbox/", sizeof("/sdksandbox/")-1)) {
+ pathname += sizeof("/sdksandbox/") - 1;
+ } else
+ return 0;
+ } else if (!fnmatch(EXPAND_SDK_CE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) {
+ pathname += sizeof(EXPAND_MNT_PATH_PREFIX) - 1;
+ pathname += sizeof("misc_ce/") - 1;
+ while (isdigit(*pathname))
+ pathname++;
+ if (!strncmp(pathname, "/sdksandbox/", sizeof("/sdksandbox/")-1)) {
+ pathname += sizeof("/sdksandbox/") - 1;
+ } else
+ return 0;
+ } else if (!fnmatch(EXPAND_SDK_DE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) {
+ pathname += sizeof(EXPAND_MNT_PATH_PREFIX) - 1;
+ pathname += sizeof("misc_de/") - 1;
+ while (isdigit(*pathname))
+ pathname++;
+ if (!strncmp(pathname, "/sdksandbox/", sizeof("/sdksandbox/")-1)) {
+ pathname += sizeof("/sdksandbox/") - 1;
+ } else
+ return 0;
} else
return 0;
@@ -1268,11 +1334,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
* have different labeling rules, based off of /seapp_contexts, and
* installd is responsible for managing these labels instead of init.
*/
- if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) ||
- !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1) ||
- !strncmp(pathname, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1) ||
- !fnmatch(EXPAND_USER_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME) ||
- !fnmatch(EXPAND_USER_DE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) {
+ if (is_app_data_path(pathname)) {
if (pkgdir_selabel_lookup(pathname, seinfo, uid, &secontext) < 0)
goto err;
}
@@ -1435,11 +1497,7 @@ static int selinux_android_restorecon_common(const char* pathname_orig,
* assignments rather than file_contexts and is managed by
* installd rather than init.
*/
- if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) ||
- !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1) ||
- !strncmp(pathname, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1) ||
- !fnmatch(EXPAND_USER_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME) ||
- !fnmatch(EXPAND_USER_DE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME))
+ if (is_app_data_path(pathname))
setrestoreconlast = false;
/* Also ignore on /sys since it is regenerated on each boot regardless. */
@@ -1516,20 +1574,15 @@ static int selinux_android_restorecon_common(const char* pathname_orig,
}
if (skipce &&
- (!strncmp(ftsent->fts_path, DATA_SYSTEM_CE_PREFIX, sizeof(DATA_SYSTEM_CE_PREFIX)-1) ||
- !strncmp(ftsent->fts_path, DATA_MISC_CE_PREFIX, sizeof(DATA_MISC_CE_PREFIX)-1) ||
- !strncmp(ftsent->fts_path, DATA_VENDOR_CE_PREFIX, sizeof(DATA_VENDOR_CE_PREFIX)-1))) {
+ (!strncmp(ftsent->fts_path, DATA_SYSTEM_CE_PATH, sizeof(DATA_SYSTEM_CE_PATH)-1) ||
+ !strncmp(ftsent->fts_path, DATA_MISC_CE_PATH, sizeof(DATA_MISC_CE_PATH)-1) ||
+ !strncmp(ftsent->fts_path, DATA_VENDOR_CE_PATH, sizeof(DATA_VENDOR_CE_PATH)-1))) {
// Don't label anything below this directory.
fts_set(fts, ftsent, FTS_SKIP);
// but fall through and make sure we label the directory itself
}
- if (!datadata &&
- (!strcmp(ftsent->fts_path, DATA_DATA_PATH) ||
- !strncmp(ftsent->fts_path, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1) ||
- !strncmp(ftsent->fts_path, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1) ||
- !fnmatch(EXPAND_USER_PATH, ftsent->fts_path, FNM_LEADING_DIR|FNM_PATHNAME) ||
- !fnmatch(EXPAND_USER_DE_PATH, ftsent->fts_path, FNM_LEADING_DIR|FNM_PATHNAME))) {
+ if (!datadata && is_app_data_path(ftsent->fts_path)) {
// Don't label anything below this directory.
fts_set(fts, ftsent, FTS_SKIP);
// but fall through and make sure we label the directory itself
diff --git a/libselinux/src/callbacks.c b/libselinux/src/callbacks.c
index c18ccc54..469c4055 100644
--- a/libselinux/src/callbacks.c
+++ b/libselinux/src/callbacks.c
@@ -10,6 +10,8 @@
#include <selinux/selinux.h>
#include "callbacks.h"
+pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
+
/* default implementations */
static int __attribute__ ((format(printf, 2, 3)))
default_selinux_log(int type __attribute__((unused)), const char *fmt, ...)
@@ -56,7 +58,7 @@ default_selinux_policyload(int seqno __attribute__((unused)))
/* callback pointers */
int __attribute__ ((format(printf, 2, 3)))
-(*selinux_log)(int, const char *, ...) =
+(*selinux_log_direct)(int, const char *, ...) =
default_selinux_log;
int
@@ -81,7 +83,7 @@ selinux_set_callback(int type, union selinux_callback cb)
{
switch (type) {
case SELINUX_CB_LOG:
- selinux_log = cb.func_log;
+ selinux_log_direct = cb.func_log;
break;
case SELINUX_CB_AUDIT:
selinux_audit = cb.func_audit;
@@ -106,7 +108,7 @@ selinux_get_callback(int type)
switch (type) {
case SELINUX_CB_LOG:
- cb.func_log = selinux_log;
+ cb.func_log = selinux_log_direct;
break;
case SELINUX_CB_AUDIT:
cb.func_audit = selinux_audit;
diff --git a/libselinux/src/callbacks.h b/libselinux/src/callbacks.h
index 03d87f0c..f4dab157 100644
--- a/libselinux/src/callbacks.h
+++ b/libselinux/src/callbacks.h
@@ -10,9 +10,11 @@
#include <string.h>
#include <selinux/selinux.h>
+#include "selinux_internal.h"
+
/* callback pointers */
extern int __attribute__ ((format(printf, 2, 3)))
-(*selinux_log) (int type, const char *, ...) ;
+(*selinux_log_direct) (int type, const char *, ...) ;
extern int
(*selinux_audit) (void *, security_class_t, char *, size_t) ;
@@ -26,4 +28,13 @@ extern int
extern int
(*selinux_netlink_policyload) (int seqno) ;
+/* Thread-safe selinux_log() function */
+extern pthread_mutex_t log_mutex;
+
+#define selinux_log(type, ...) do { \
+ __pthread_mutex_lock(&log_mutex); \
+ selinux_log_direct(type, __VA_ARGS__); \
+ __pthread_mutex_unlock(&log_mutex); \
+} while(0)
+
#endif /* _SELINUX_CALLBACKS_H_ */
diff --git a/libselinux/src/is_customizable_type.c b/libselinux/src/is_customizable_type.c
index 1b17860c..f83e1e83 100644
--- a/libselinux/src/is_customizable_type.c
+++ b/libselinux/src/is_customizable_type.c
@@ -9,7 +9,10 @@
#include "selinux_internal.h"
#include "context_internal.h"
-static int get_customizable_type_list(char *** retlist)
+static char **customizable_list = NULL;
+static pthread_once_t customizable_once = PTHREAD_ONCE_INIT;
+
+static void customizable_init(void)
{
FILE *fp;
char *buf;
@@ -18,12 +21,12 @@ static int get_customizable_type_list(char *** retlist)
fp = fopen(selinux_customizable_types_path(), "re");
if (!fp)
- return -1;
+ return;
buf = malloc(selinux_page_size);
if (!buf) {
fclose(fp);
- return -1;
+ return;
}
while (fgets_unlocked(buf, selinux_page_size, fp) && ctr < UINT_MAX) {
ctr++;
@@ -54,23 +57,19 @@ static int get_customizable_type_list(char *** retlist)
fclose(fp);
free(buf);
if (!list)
- return -1;
- *retlist = list;
- return 0;
+ return;
+ customizable_list = list;
}
-static char **customizable_list = NULL;
-
int is_context_customizable(const char * scontext)
{
int i;
const char *type;
context_t c;
- if (!customizable_list) {
- if (get_customizable_type_list(&customizable_list) != 0)
- return -1;
- }
+ __selinux_once(customizable_once, customizable_init);
+ if (!customizable_list)
+ return -1;
c = context_new(scontext);
if (!c)
diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c
index 70ea86fa..695d6a9e 100644
--- a/libselinux/src/label_file.c
+++ b/libselinux/src/label_file.c
@@ -997,7 +997,12 @@ static struct spec **lookup_all(struct selabel_handle *rec,
rc = regex_match(spec->regex, key, partial);
if (rc == REGEX_MATCH || (partial && rc == REGEX_MATCH_PARTIAL)) {
if (rc == REGEX_MATCH) {
- spec->matches++;
+#ifdef __ATOMIC_RELAXED
+ __atomic_store_n(&spec->any_matches,
+ true, __ATOMIC_RELAXED);
+#else
+#error "Please use a compiler that supports __atomic builtins"
+#endif
}
if (strcmp(spec_arr[i].lr.ctx_raw, "<<none>>") == 0) {
@@ -1295,9 +1300,15 @@ static void stats(struct selabel_handle *rec)
struct saved_data *data = (struct saved_data *)rec->data;
unsigned int i, nspec = data->nspec;
struct spec *spec_arr = data->spec_arr;
+ bool any_matches;
for (i = 0; i < nspec; i++) {
- if (spec_arr[i].matches == 0) {
+#ifdef __ATOMIC_RELAXED
+ any_matches = __atomic_load_n(&spec_arr[i].any_matches, __ATOMIC_RELAXED);
+#else
+#error "Please use a compiler that supports __atomic builtins"
+#endif
+ if (!any_matches) {
if (spec_arr[i].type_str) {
COMPAT_LOG(SELINUX_WARNING,
"Warning! No matches for (%s, %s, %s)\n",
diff --git a/libselinux/src/label_file.h b/libselinux/src/label_file.h
index 343ffc70..b453e13f 100644
--- a/libselinux/src/label_file.h
+++ b/libselinux/src/label_file.h
@@ -51,7 +51,7 @@ struct spec {
bool regex_compiled; /* bool to indicate if the regex is compiled */
pthread_mutex_t regex_lock; /* lock for lazy compilation of regex */
mode_t mode; /* mode format value */
- int matches; /* number of matching pathnames */
+ bool any_matches; /* did any pathname match? */
int stem_id; /* indicates which stem-compression item */
char hasMetaChars; /* regular expression has meta-chars */
char from_mmap; /* this spec is from an mmap of the data */
diff --git a/libselinux/src/libselinux.map b/libselinux/src/libselinux.map
index 2a368e93..4acf1caa 100644
--- a/libselinux/src/libselinux.map
+++ b/libselinux/src/libselinux.map
@@ -240,3 +240,8 @@ LIBSELINUX_1.0 {
local:
*;
};
+
+LIBSELINUX_3.4 {
+ global:
+ selinux_restorecon_parallel;
+} LIBSELINUX_1.0;
diff --git a/libselinux/src/matchpathcon.c b/libselinux/src/matchpathcon.c
index 1e7f8890..ea78a23e 100644
--- a/libselinux/src/matchpathcon.c
+++ b/libselinux/src/matchpathcon.c
@@ -356,7 +356,7 @@ int matchpathcon_init_prefix(const char *path, const char *subset)
mycanoncon = default_canoncon;
__selinux_once(once, matchpathcon_init_once);
- __selinux_setspecific(destructor_key, (void *)1);
+ __selinux_setspecific(destructor_key, /* some valid address to please GCC */ &selinux_page_size);
options[SELABEL_OPT_SUBSET].type = SELABEL_OPT_SUBSET;
options[SELABEL_OPT_SUBSET].value = subset;
diff --git a/libselinux/src/procattr.c b/libselinux/src/procattr.c
index 6552ee01..142fbf3a 100644
--- a/libselinux/src/procattr.c
+++ b/libselinux/src/procattr.c
@@ -68,7 +68,7 @@ void __attribute__((destructor)) procattr_destructor(void)
static inline void init_thread_destructor(void)
{
if (destructor_initialized == 0) {
- __selinux_setspecific(destructor_key, (void *)1);
+ __selinux_setspecific(destructor_key, /* some valid address to please GCC */ &selinux_page_size);
destructor_initialized = 1;
}
}
diff --git a/libselinux/src/selinux_config.c b/libselinux/src/selinux_config.c
index 97f81a8b..d2e49ee1 100644
--- a/libselinux/src/selinux_config.c
+++ b/libselinux/src/selinux_config.c
@@ -92,6 +92,7 @@ int selinux_getenforcemode(int *enforce)
FILE *cfg = fopen(SELINUXCONFIG, "re");
if (cfg) {
char *buf;
+ char *tag;
int len = sizeof(SELINUXTAG) - 1;
buf = malloc(selinux_page_size);
if (!buf) {
@@ -101,21 +102,24 @@ int selinux_getenforcemode(int *enforce)
while (fgets_unlocked(buf, selinux_page_size, cfg)) {
if (strncmp(buf, SELINUXTAG, len))
continue;
+ tag = buf+len;
+ while (isspace(*tag))
+ tag++;
if (!strncasecmp
- (buf + len, "enforcing", sizeof("enforcing") - 1)) {
+ (tag, "enforcing", sizeof("enforcing") - 1)) {
*enforce = 1;
ret = 0;
break;
} else
if (!strncasecmp
- (buf + len, "permissive",
+ (tag, "permissive",
sizeof("permissive") - 1)) {
*enforce = 0;
ret = 0;
break;
} else
if (!strncasecmp
- (buf + len, "disabled",
+ (tag, "disabled",
sizeof("disabled") - 1)) {
*enforce = -1;
ret = 0;
@@ -176,7 +180,10 @@ static void init_selinux_config(void)
if (!strncasecmp(buf_p, SELINUXTYPETAG,
sizeof(SELINUXTYPETAG) - 1)) {
- type = strdup(buf_p + sizeof(SELINUXTYPETAG) - 1);
+ buf_p += sizeof(SELINUXTYPETAG) - 1;
+ while (isspace(*buf_p))
+ buf_p++;
+ type = strdup(buf_p);
if (!type) {
free(line_buf);
fclose(fp);
@@ -199,6 +206,8 @@ static void init_selinux_config(void)
} else if (!strncmp(buf_p, REQUIRESEUSERS,
sizeof(REQUIRESEUSERS) - 1)) {
value = buf_p + sizeof(REQUIRESEUSERS) - 1;
+ while (isspace(*value))
+ value++;
intptr = &require_seusers;
} else {
continue;
diff --git a/libselinux/src/selinux_internal.h b/libselinux/src/selinux_internal.h
index 27e9ac53..297dcf26 100644
--- a/libselinux/src/selinux_internal.h
+++ b/libselinux/src/selinux_internal.h
@@ -69,6 +69,22 @@ extern int selinux_page_size ;
pthread_mutex_unlock(LOCK); \
} while (0)
+#pragma weak pthread_create
+#pragma weak pthread_join
+#pragma weak pthread_cond_init
+#pragma weak pthread_cond_signal
+#pragma weak pthread_cond_destroy
+#pragma weak pthread_cond_wait
+
+/* check if all functions needed to do parallel operations are available */
+#define __pthread_supported ( \
+ pthread_create && \
+ pthread_join && \
+ pthread_cond_init && \
+ pthread_cond_destroy && \
+ pthread_cond_signal && \
+ pthread_cond_wait \
+)
#define SELINUXDIR "/etc/selinux/"
#define SELINUXCONFIG SELINUXDIR "config"
diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c
index 04d95650..72f4fb46 100644
--- a/libselinux/src/selinux_restorecon.c
+++ b/libselinux/src/selinux_restorecon.c
@@ -60,6 +60,7 @@ static int exclude_count = 0;
static struct edir *exclude_lst = NULL;
static uint64_t fc_count = 0; /* Number of files processed so far */
static uint64_t efile_count; /* Estimated total number of files */
+static pthread_mutex_t progress_mutex = PTHREAD_MUTEX_INITIALIZER;
/* Store information on directories with xattr's. */
static struct dir_xattr *dir_xattr_list;
@@ -411,6 +412,7 @@ typedef struct file_spec {
} file_spec_t;
static file_spec_t *fl_head;
+static pthread_mutex_t fl_mutex = PTHREAD_MUTEX_INITIALIZER;
/*
* Try to add an association between an inode and a context. If there is a
@@ -424,11 +426,12 @@ static int filespec_add(ino_t ino, const char *con, const char *file,
int h, ret;
struct stat64 sb;
+ __pthread_mutex_lock(&fl_mutex);
+
if (!fl_head) {
- fl_head = malloc(sizeof(file_spec_t) * HASH_BUCKETS);
+ fl_head = calloc(HASH_BUCKETS, sizeof(file_spec_t));
if (!fl_head)
goto oom;
- memset(fl_head, 0, sizeof(file_spec_t) * HASH_BUCKETS);
}
h = (ino + (ino >> HASH_BITS)) & HASH_MASK;
@@ -445,11 +448,11 @@ static int filespec_add(ino_t ino, const char *con, const char *file,
fl->con = strdup(con);
if (!fl->con)
goto oom;
- return 1;
+ goto unlock_1;
}
if (strcmp(fl->con, con) == 0)
- return 1;
+ goto unlock_1;
selinux_log(SELINUX_ERROR,
"conflicting specifications for %s and %s, using %s.\n",
@@ -458,6 +461,9 @@ static int filespec_add(ino_t ino, const char *con, const char *file,
fl->file = strdup(file);
if (!fl->file)
goto oom;
+
+ __pthread_mutex_unlock(&fl_mutex);
+
if (flags->conflicterror) {
selinux_log(SELINUX_ERROR,
"treating conflicting specifications as an error.\n");
@@ -482,13 +488,19 @@ static int filespec_add(ino_t ino, const char *con, const char *file,
goto oom_freefl;
fl->next = prevfl->next;
prevfl->next = fl;
+
+ __pthread_mutex_unlock(&fl_mutex);
return 0;
oom_freefl:
free(fl);
oom:
+ __pthread_mutex_unlock(&fl_mutex);
selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__);
return -1;
+unlock_1:
+ __pthread_mutex_unlock(&fl_mutex);
+ return 1;
}
/*
@@ -598,7 +610,7 @@ out:
}
static int restorecon_sb(const char *pathname, const struct stat *sb,
- struct rest_flags *flags)
+ struct rest_flags *flags, bool first)
{
char *newcon = NULL;
char *curcon = NULL;
@@ -627,7 +639,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
sb->st_mode);
if (rc < 0) {
- if (errno == ENOENT && flags->warnonnomatch)
+ if (errno == ENOENT && flags->warnonnomatch && first)
selinux_log(SELINUX_INFO,
"Warning no default label for %s\n",
lookup_path);
@@ -636,6 +648,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
}
if (flags->progress) {
+ __pthread_mutex_lock(&progress_mutex);
fc_count++;
if (fc_count % STAR_COUNT == 0) {
if (flags->mass_relabel && efile_count > 0) {
@@ -647,6 +660,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
}
fflush(stdout);
}
+ __pthread_mutex_unlock(&progress_mutex);
}
if (flags->add_assoc) {
@@ -800,66 +814,215 @@ oom:
goto free;
}
+struct rest_state {
+ struct rest_flags flags;
+ dev_t dev_num;
+ struct statfs sfsb;
+ bool ignore_digest;
+ bool setrestorecondigest;
+ bool parallel;
-/*
- * Public API
- */
+ FTS *fts;
+ FTSENT *ftsent_first;
+ struct dir_hash_node *head, *current;
+ bool abort;
+ int error;
+ int saved_errno;
+ pthread_mutex_t mutex;
+};
-/* selinux_restorecon(3) - Main function that is responsible for labeling */
-int selinux_restorecon(const char *pathname_orig,
- unsigned int restorecon_flags)
+static void *selinux_restorecon_thread(void *arg)
{
- struct rest_flags flags;
+ struct rest_state *state = arg;
+ FTS *fts = state->fts;
+ FTSENT *ftsent;
+ int error;
+ char ent_path[PATH_MAX];
+ struct stat ent_st;
+ bool first = false;
+
+ if (state->parallel)
+ pthread_mutex_lock(&state->mutex);
+
+ if (state->ftsent_first) {
+ ftsent = state->ftsent_first;
+ state->ftsent_first = NULL;
+ first = true;
+ goto loop_body;
+ }
+
+ while (((void)(errno = 0), ftsent = fts_read(fts)) != NULL) {
+loop_body:
+ /* If the FTS_XDEV flag is set and the device is different */
+ if (state->flags.set_xdev &&
+ ftsent->fts_statp->st_dev != state->dev_num)
+ continue;
- flags.nochange = (restorecon_flags &
+ switch (ftsent->fts_info) {
+ case FTS_DC:
+ selinux_log(SELINUX_ERROR,
+ "Directory cycle on %s.\n",
+ ftsent->fts_path);
+ errno = ELOOP;
+ state->error = -1;
+ state->abort = true;
+ goto finish;
+ case FTS_DP:
+ continue;
+ case FTS_DNR:
+ error = errno;
+ errno = ftsent->fts_errno;
+ selinux_log(SELINUX_ERROR,
+ "Could not read %s: %m.\n",
+ ftsent->fts_path);
+ errno = error;
+ fts_set(fts, ftsent, FTS_SKIP);
+ continue;
+ case FTS_NS:
+ error = errno;
+ errno = ftsent->fts_errno;
+ selinux_log(SELINUX_ERROR,
+ "Could not stat %s: %m.\n",
+ ftsent->fts_path);
+ errno = error;
+ fts_set(fts, ftsent, FTS_SKIP);
+ continue;
+ case FTS_ERR:
+ error = errno;
+ errno = ftsent->fts_errno;
+ selinux_log(SELINUX_ERROR,
+ "Error on %s: %m.\n",
+ ftsent->fts_path);
+ errno = error;
+ fts_set(fts, ftsent, FTS_SKIP);
+ continue;
+ case FTS_D:
+ if (state->sfsb.f_type == SYSFS_MAGIC &&
+ !selabel_partial_match(fc_sehandle,
+ ftsent->fts_path)) {
+ fts_set(fts, ftsent, FTS_SKIP);
+ continue;
+ }
+
+ if (check_excluded(ftsent->fts_path)) {
+ fts_set(fts, ftsent, FTS_SKIP);
+ continue;
+ }
+
+ if (state->setrestorecondigest) {
+ struct dir_hash_node *new_node = NULL;
+
+ if (check_context_match_for_dir(ftsent->fts_path,
+ &new_node,
+ state->error) &&
+ !state->ignore_digest) {
+ selinux_log(SELINUX_INFO,
+ "Skipping restorecon on directory(%s)\n",
+ ftsent->fts_path);
+ fts_set(fts, ftsent, FTS_SKIP);
+ continue;
+ }
+
+ if (new_node && !state->error) {
+ if (!state->current) {
+ state->current = new_node;
+ state->head = state->current;
+ } else {
+ state->current->next = new_node;
+ state->current = new_node;
+ }
+ }
+ }
+ /* fall through */
+ default:
+ strcpy(ent_path, ftsent->fts_path);
+ ent_st = *ftsent->fts_statp;
+ if (state->parallel)
+ pthread_mutex_unlock(&state->mutex);
+
+ error = restorecon_sb(ent_path, &ent_st, &state->flags,
+ first);
+
+ if (state->parallel) {
+ pthread_mutex_lock(&state->mutex);
+ if (state->abort)
+ goto unlock;
+ }
+
+ state->error |= error;
+ first = false;
+ if (error && state->flags.abort_on_error) {
+ state->abort = true;
+ goto finish;
+ }
+ break;
+ }
+ }
+
+finish:
+ if (!state->saved_errno)
+ state->saved_errno = errno;
+unlock:
+ if (state->parallel)
+ pthread_mutex_unlock(&state->mutex);
+ return NULL;
+}
+
+static int selinux_restorecon_common(const char *pathname_orig,
+ unsigned int restorecon_flags,
+ size_t nthreads)
+{
+ struct rest_state state;
+
+ state.flags.nochange = (restorecon_flags &
SELINUX_RESTORECON_NOCHANGE) ? true : false;
- flags.verbose = (restorecon_flags &
+ state.flags.verbose = (restorecon_flags &
SELINUX_RESTORECON_VERBOSE) ? true : false;
- flags.progress = (restorecon_flags &
+ state.flags.progress = (restorecon_flags &
SELINUX_RESTORECON_PROGRESS) ? true : false;
- flags.mass_relabel = (restorecon_flags &
+ state.flags.mass_relabel = (restorecon_flags &
SELINUX_RESTORECON_MASS_RELABEL) ? true : false;
- flags.recurse = (restorecon_flags &
+ state.flags.recurse = (restorecon_flags &
SELINUX_RESTORECON_RECURSE) ? true : false;
- flags.set_specctx = (restorecon_flags &
+ state.flags.set_specctx = (restorecon_flags &
SELINUX_RESTORECON_SET_SPECFILE_CTX) ? true : false;
- flags.userealpath = (restorecon_flags &
+ state.flags.userealpath = (restorecon_flags &
SELINUX_RESTORECON_REALPATH) ? true : false;
- flags.set_xdev = (restorecon_flags &
+ state.flags.set_xdev = (restorecon_flags &
SELINUX_RESTORECON_XDEV) ? true : false;
- flags.add_assoc = (restorecon_flags &
+ state.flags.add_assoc = (restorecon_flags &
SELINUX_RESTORECON_ADD_ASSOC) ? true : false;
- flags.abort_on_error = (restorecon_flags &
+ state.flags.abort_on_error = (restorecon_flags &
SELINUX_RESTORECON_ABORT_ON_ERROR) ? true : false;
- flags.syslog_changes = (restorecon_flags &
+ state.flags.syslog_changes = (restorecon_flags &
SELINUX_RESTORECON_SYSLOG_CHANGES) ? true : false;
- flags.log_matches = (restorecon_flags &
+ state.flags.log_matches = (restorecon_flags &
SELINUX_RESTORECON_LOG_MATCHES) ? true : false;
- flags.ignore_noent = (restorecon_flags &
+ state.flags.ignore_noent = (restorecon_flags &
SELINUX_RESTORECON_IGNORE_NOENTRY) ? true : false;
- flags.warnonnomatch = true;
- flags.conflicterror = (restorecon_flags &
+ state.flags.warnonnomatch = true;
+ state.flags.conflicterror = (restorecon_flags &
SELINUX_RESTORECON_CONFLICT_ERROR) ? true : false;
ignore_mounts = (restorecon_flags &
SELINUX_RESTORECON_IGNORE_MOUNTS) ? true : false;
- bool ignore_digest = (restorecon_flags &
+ state.ignore_digest = (restorecon_flags &
SELINUX_RESTORECON_IGNORE_DIGEST) ? true : false;
- bool setrestorecondigest = true;
+ state.setrestorecondigest = true;
+
+ state.head = NULL;
+ state.current = NULL;
+ state.abort = false;
+ state.error = 0;
+ state.saved_errno = 0;
struct stat sb;
- struct statfs sfsb;
- FTS *fts;
- FTSENT *ftsent;
char *pathname = NULL, *pathdnamer = NULL, *pathdname, *pathbname;
char *paths[2] = { NULL, NULL };
int fts_flags, error, sverrno;
- dev_t dev_num = 0;
struct dir_hash_node *current = NULL;
- struct dir_hash_node *head = NULL;
- int errno_tmp;
- if (flags.verbose && flags.progress)
- flags.verbose = false;
+ if (state.flags.verbose && state.flags.progress)
+ state.flags.verbose = false;
__selinux_once(fc_once, restorecon_init);
@@ -872,13 +1035,31 @@ int selinux_restorecon(const char *pathname_orig,
*/
if (selabel_no_digest ||
(restorecon_flags & SELINUX_RESTORECON_SKIP_DIGEST))
- setrestorecondigest = false;
+ state.setrestorecondigest = false;
+
+ if (!__pthread_supported) {
+ if (nthreads != 1) {
+ nthreads = 1;
+ selinux_log(SELINUX_WARNING,
+ "Threading functionality not available, falling back to 1 thread.");
+ }
+ } else if (nthreads == 0) {
+ long nproc = sysconf(_SC_NPROCESSORS_ONLN);
+
+ if (nproc > 0) {
+ nthreads = nproc;
+ } else {
+ nthreads = 1;
+ selinux_log(SELINUX_WARNING,
+ "Unable to detect CPU count, falling back to 1 thread.");
+ }
+ }
/*
* Convert passed-in pathname to canonical pathname by resolving
* realpath of containing dir, then appending last component name.
*/
- if (flags.userealpath) {
+ if (state.flags.userealpath) {
char *basename_cpy = strdup(pathname_orig);
if (!basename_cpy)
goto realpatherr;
@@ -923,7 +1104,7 @@ int selinux_restorecon(const char *pathname_orig,
paths[0] = pathname;
if (lstat(pathname, &sb) < 0) {
- if (flags.ignore_noent && errno == ENOENT) {
+ if (state.flags.ignore_noent && errno == ENOENT) {
free(pathdnamer);
free(pathname);
return 0;
@@ -938,21 +1119,21 @@ int selinux_restorecon(const char *pathname_orig,
/* Skip digest if not a directory */
if (!S_ISDIR(sb.st_mode))
- setrestorecondigest = false;
+ state.setrestorecondigest = false;
- if (!flags.recurse) {
+ if (!state.flags.recurse) {
if (check_excluded(pathname)) {
error = 0;
goto cleanup;
}
- error = restorecon_sb(pathname, &sb, &flags);
+ error = restorecon_sb(pathname, &sb, &state.flags, true);
goto cleanup;
}
/* Obtain fs type */
- memset(&sfsb, 0, sizeof sfsb);
- if (!S_ISLNK(sb.st_mode) && statfs(pathname, &sfsb) < 0) {
+ memset(&state.sfsb, 0, sizeof(state.sfsb));
+ if (!S_ISLNK(sb.st_mode) && statfs(pathname, &state.sfsb) < 0) {
selinux_log(SELINUX_ERROR,
"statfs(%s) failed: %m\n",
pathname);
@@ -961,21 +1142,21 @@ int selinux_restorecon(const char *pathname_orig,
}
/* Skip digest on in-memory filesystems and /sys */
- if (sfsb.f_type == RAMFS_MAGIC || sfsb.f_type == TMPFS_MAGIC ||
- sfsb.f_type == SYSFS_MAGIC)
- setrestorecondigest = false;
+ if (state.sfsb.f_type == RAMFS_MAGIC || state.sfsb.f_type == TMPFS_MAGIC ||
+ state.sfsb.f_type == SYSFS_MAGIC)
+ state.setrestorecondigest = false;
- if (flags.set_xdev)
+ if (state.flags.set_xdev)
fts_flags = FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV;
else
fts_flags = FTS_PHYSICAL | FTS_NOCHDIR;
- fts = fts_open(paths, fts_flags, NULL);
- if (!fts)
+ state.fts = fts_open(paths, fts_flags, NULL);
+ if (!state.fts)
goto fts_err;
- ftsent = fts_read(fts);
- if (!ftsent)
+ state.ftsent_first = fts_read(state.fts);
+ if (!state.ftsent_first)
goto fts_err;
/*
@@ -987,106 +1168,66 @@ int selinux_restorecon(const char *pathname_orig,
* directories with a different device number when the FTS_XDEV flag
* is set (from http://marc.info/?l=selinux&m=124688830500777&w=2).
*/
- dev_num = ftsent->fts_statp->st_dev;
+ state.dev_num = state.ftsent_first->fts_statp->st_dev;
- error = 0;
- do {
- /* If the FTS_XDEV flag is set and the device is different */
- if (flags.set_xdev && ftsent->fts_statp->st_dev != dev_num)
- continue;
+ if (nthreads == 1) {
+ state.parallel = false;
+ selinux_restorecon_thread(&state);
+ } else {
+ size_t i;
+ pthread_t self = pthread_self();
+ pthread_t *threads = NULL;
- switch (ftsent->fts_info) {
- case FTS_DC:
- selinux_log(SELINUX_ERROR,
- "Directory cycle on %s.\n",
- ftsent->fts_path);
- errno = ELOOP;
- error = -1;
- goto out;
- case FTS_DP:
- continue;
- case FTS_DNR:
- errno_tmp = errno;
- errno = ftsent->fts_errno;
- selinux_log(SELINUX_ERROR,
- "Could not read %s: %m.\n",
- ftsent->fts_path);
- errno = errno_tmp;
- fts_set(fts, ftsent, FTS_SKIP);
- continue;
- case FTS_NS:
- errno_tmp = errno;
- errno = ftsent->fts_errno;
- selinux_log(SELINUX_ERROR,
- "Could not stat %s: %m.\n",
- ftsent->fts_path);
- errno = errno_tmp;
- fts_set(fts, ftsent, FTS_SKIP);
- continue;
- case FTS_ERR:
- errno_tmp = errno;
- errno = ftsent->fts_errno;
- selinux_log(SELINUX_ERROR,
- "Error on %s: %m.\n",
- ftsent->fts_path);
- errno = errno_tmp;
- fts_set(fts, ftsent, FTS_SKIP);
- continue;
- case FTS_D:
- if (sfsb.f_type == SYSFS_MAGIC &&
- !selabel_partial_match(fc_sehandle,
- ftsent->fts_path)) {
- fts_set(fts, ftsent, FTS_SKIP);
- continue;
- }
+ pthread_mutex_init(&state.mutex, NULL);
- if (check_excluded(ftsent->fts_path)) {
- fts_set(fts, ftsent, FTS_SKIP);
- continue;
+ threads = calloc(nthreads - 1, sizeof(*threads));
+ if (!threads)
+ goto oom;
+
+ state.parallel = true;
+ /*
+ * Start (nthreads - 1) threads - the main thread is going to
+ * take part, too.
+ */
+ for (i = 0; i < nthreads - 1; i++) {
+ if (pthread_create(&threads[i], NULL,
+ selinux_restorecon_thread, &state)) {
+ /*
+ * If any thread fails to be created, just mark
+ * it as such and let the successfully created
+ * threads do the job. In the worst case the
+ * main thread will do everything, but that's
+ * still better than to give up.
+ */
+ threads[i] = self;
}
+ }
- if (setrestorecondigest) {
- struct dir_hash_node *new_node = NULL;
+ /* Let's join in on the fun! */
+ selinux_restorecon_thread(&state);
- if (check_context_match_for_dir(ftsent->fts_path,
- &new_node,
- error) &&
- !ignore_digest) {
- selinux_log(SELINUX_INFO,
- "Skipping restorecon on directory(%s)\n",
- ftsent->fts_path);
- fts_set(fts, ftsent, FTS_SKIP);
- continue;
- }
-
- if (new_node && !error) {
- if (!current) {
- current = new_node;
- head = current;
- } else {
- current->next = new_node;
- current = current->next;
- }
- }
- }
- /* fall through */
- default:
- error |= restorecon_sb(ftsent->fts_path,
- ftsent->fts_statp, &flags);
- if (flags.warnonnomatch)
- flags.warnonnomatch = false;
- if (error && flags.abort_on_error)
- goto out;
- break;
+ /* Now wait for all threads to finish. */
+ for (i = 0; i < nthreads - 1; i++) {
+ /* Skip threads that failed to be created. */
+ if (pthread_equal(threads[i], self))
+ continue;
+ pthread_join(threads[i], NULL);
}
- } while ((ftsent = fts_read(fts)) != NULL);
+ free(threads);
+
+ pthread_mutex_destroy(&state.mutex);
+ }
+
+ error = state.error;
+ if (state.saved_errno)
+ goto out;
/*
* Labeling successful. Write partial match digests for subdirectories.
* TODO: Write digest upon FTS_DP if no error occurs in its descents.
*/
- if (setrestorecondigest && !flags.nochange && !error) {
- current = head;
+ if (state.setrestorecondigest && !state.flags.nochange && !error) {
+ current = state.head;
while (current != NULL) {
if (setxattr(current->path,
RESTORECON_PARTIAL_MATCH_DIGEST,
@@ -1101,22 +1242,21 @@ int selinux_restorecon(const char *pathname_orig,
}
out:
- if (flags.progress && flags.mass_relabel)
+ if (state.flags.progress && state.flags.mass_relabel)
fprintf(stdout, "\r%s 100.0%%\n", pathname);
- sverrno = errno;
- (void) fts_close(fts);
- errno = sverrno;
+ (void) fts_close(state.fts);
+ errno = state.saved_errno;
cleanup:
- if (flags.add_assoc) {
- if (flags.verbose)
+ if (state.flags.add_assoc) {
+ if (state.flags.verbose)
filespec_eval();
filespec_destroy();
}
free(pathdnamer);
free(pathname);
- current = head;
+ current = state.head;
while (current != NULL) {
struct dir_hash_node *next = current->next;
@@ -1150,6 +1290,26 @@ fts_err:
goto cleanup;
}
+
+/*
+ * Public API
+ */
+
+/* selinux_restorecon(3) - Main function that is responsible for labeling */
+int selinux_restorecon(const char *pathname_orig,
+ unsigned int restorecon_flags)
+{
+ return selinux_restorecon_common(pathname_orig, restorecon_flags, 1);
+}
+
+/* selinux_restorecon_parallel(3) - Parallel version of selinux_restorecon(3) */
+int selinux_restorecon_parallel(const char *pathname_orig,
+ unsigned int restorecon_flags,
+ size_t nthreads)
+{
+ return selinux_restorecon_common(pathname_orig, restorecon_flags, nthreads);
+}
+
/* selinux_restorecon_set_sehandle(3) is called to set the global fc handle */
void selinux_restorecon_set_sehandle(struct selabel_handle *hndl)
{
diff --git a/libselinux/src/selinuxswig_python.i b/libselinux/src/selinuxswig_python.i
index 4c73bf92..17e03b9e 100644
--- a/libselinux/src/selinuxswig_python.i
+++ b/libselinux/src/selinuxswig_python.i
@@ -20,7 +20,7 @@ DISABLED = -1
PERMISSIVE = 0
ENFORCING = 1
-def restorecon(path, recursive=False, verbose=False, force=False):
+def restorecon(path, recursive=False, verbose=False, force=False, nthreads=1):
""" Restore SELinux context on a given path
Arguments:
@@ -32,6 +32,8 @@ def restorecon(path, recursive=False, verbose=False, force=False):
force -- Force reset of context to match file_context for customizable files,
and the default file context, changing the user, role, range portion as well
as the type (default False)
+ nthreads -- The number of threads to use during relabeling, or 0 to use as many
+ threads as there are online CPU cores (default 1)
"""
restorecon_flags = SELINUX_RESTORECON_IGNORE_DIGEST | SELINUX_RESTORECON_REALPATH
@@ -41,7 +43,7 @@ def restorecon(path, recursive=False, verbose=False, force=False):
restorecon_flags |= SELINUX_RESTORECON_VERBOSE
if force:
restorecon_flags |= SELINUX_RESTORECON_SET_SPECFILE_CTX
- selinux_restorecon(os.path.expanduser(path), restorecon_flags)
+ selinux_restorecon_parallel(os.path.expanduser(path), restorecon_flags, nthreads)
def chcon(path, context, recursive=False):
""" Set the SELinux context on a given path """
diff --git a/libselinux/src/selinuxswig_python_exception.i b/libselinux/src/selinuxswig_python_exception.i
index 237ea69a..a02f4923 100644
--- a/libselinux/src/selinuxswig_python_exception.i
+++ b/libselinux/src/selinuxswig_python_exception.i
@@ -1183,6 +1183,14 @@
}
}
+%exception selinux_restorecon_parallel {
+ $action
+ if (result < 0) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ SWIG_fail;
+ }
+}
+
%exception selinux_restorecon_set_alt_rootpath {
$action
if (result < 0) {
diff --git a/libselinux/src/setrans_client.c b/libselinux/src/setrans_client.c
index 52a8ba78..faa12681 100644
--- a/libselinux/src/setrans_client.c
+++ b/libselinux/src/setrans_client.c
@@ -272,7 +272,7 @@ static inline void init_thread_destructor(void)
if (!has_setrans)
return;
if (destructor_initialized == 0) {
- __selinux_setspecific(destructor_key, (void *)1);
+ __selinux_setspecific(destructor_key, /* some valid address to please GCC */ &selinux_page_size);
destructor_initialized = 1;
}
}
diff --git a/libselinux/utils/Makefile b/libselinux/utils/Makefile
index 36816155..801066cb 100644
--- a/libselinux/utils/Makefile
+++ b/libselinux/utils/Makefile
@@ -44,7 +44,6 @@ endif
override CFLAGS += -I../include -D_GNU_SOURCE $(DISABLE_FLAGS) $(PCRE_CFLAGS)
override LDFLAGS += -L../src
override LDLIBS += -lselinux $(FTS_LDLIBS)
-PCRE_LDLIBS ?= -lpcre
ifeq ($(ANDROID_HOST),y)
TARGETS=sefcontext_compile
diff --git a/libsemanage/include/semanage/handle.h b/libsemanage/include/semanage/handle.h
index 946d69bc..0157be4f 100644
--- a/libsemanage/include/semanage/handle.h
+++ b/libsemanage/include/semanage/handle.h
@@ -66,6 +66,11 @@ extern void semanage_set_reload(semanage_handle_t * handle, int do_reload);
* 1 for yes, 0 for no (default) */
extern void semanage_set_rebuild(semanage_handle_t * handle, int do_rebuild);
+/* set whether to rebuild the policy on commit when potential changes
+ * to module files since last rebuild are detected,
+ * 1 for yes (default), 0 for no */
+extern void semanage_set_check_ext_changes(semanage_handle_t * handle, int do_check);
+
/* Fills *compiler_path with the location of the hll compiler sh->conf->compiler_directory_path
* corresponding to lang_ext.
* Upon success returns 0, -1 on error. */
diff --git a/libsemanage/include/semanage/modules.h b/libsemanage/include/semanage/modules.h
index b51f61f0..14666f6d 100644
--- a/libsemanage/include/semanage/modules.h
+++ b/libsemanage/include/semanage/modules.h
@@ -282,4 +282,30 @@ extern int semanage_module_get_enabled(semanage_handle_t *sh,
const semanage_module_key_t *modkey,
int *enabled);
+/* Compute checksum for @modkey module contents.
+ *
+ * If @checksum is NULL, the function will just return the length of the
+ * checksum string in @checksum_len (checksum strings are guaranteed to
+ * have a fixed length for a given libsemanage binary). @modkey and @cil
+ * are ignored in this case and should be set to NULL and 0 (respectively).
+ *
+ * If @checksum is non-NULL, on success, @checksum will point to a buffer
+ * containing the checksum string and @checksum_len will point to the
+ * length of the string (without the null terminator). The semantics of
+ * @cil are the same as for @extract_cil in semanage_module_extract().
+ *
+ * The caller is responsible to free the buffer returned in @checksum (using
+ * free(3)).
+ *
+ * Callers may assume that if the checksum strings for two modules match,
+ * the module content is the same (collisions are theoretically possible,
+ * yet extremely unlikely).
+ *
+ * Returns 0 on success and -1 on error.
+ */
+extern int semanage_module_compute_checksum(semanage_handle_t *sh,
+ semanage_module_key_t *modkey,
+ int cil, char **checksum,
+ size_t *checksum_len);
+
#endif
diff --git a/libsemanage/man/man5/semanage.conf.5 b/libsemanage/man/man5/semanage.conf.5
index 7d6f2fef..380b58be 100644
--- a/libsemanage/man/man5/semanage.conf.5
+++ b/libsemanage/man/man5/semanage.conf.5
@@ -23,7 +23,7 @@ Management library writes to the SELinux policy module store directly (this is t
Otherwise a socket path or a server name can be used for the argument.
If the argument begins with "/" (as in "/foo/bar"), it represents the path to a named socket that should be used to connect the policy management
server.
-If the argument does not begin with a "/" (as in "foo.com:4242"), it should be interpreted as the name of a remote policy management server
+If the argument does not begin with a "/" (as in "example.com:4242"), it should be interpreted as the name of a remote policy management server
to be used through a TCP connection (default port is 4242 unless a different one is specified after the server name using the colon to separate
the two fields).
diff --git a/libsemanage/man/ru/man5/semanage.conf.5 b/libsemanage/man/ru/man5/semanage.conf.5
index cf65b3e6..548aa58d 100644
--- a/libsemanage/man/ru/man5/semanage.conf.5
+++ b/libsemanage/man/ru/man5/semanage.conf.5
@@ -19,7 +19,7 @@ semanage.conf \- глобальный файл конфигурации для
Указать, как библиотека управления SELinux должна взаимодействовать с хранилищем политики SELinux. Если установлено "direct", библиотека управления SELinux выполняет запись напрямую в хранилище модулей политики SELinux (это значение по умолчанию).
В ином случае в качестве аргумента может использоваться путь к сокету или имя сервера.
Если аргумент начинается с "/" (как в "/foo/bar"), он представляет собой путь к именованному сокету, который следует использовать для подключения сервера управления политикой.
-Если аргумент не начинается с "/" (как в "foo.com:4242"), он должен интерпретироваться как имя удалённого сервера управления политикой, который следует использовать через TCP-подключение (порт по умолчанию 4242, если только после имени сервера через двоеточие, разделяющее два поля, не указан другой порт).
+Если аргумент не начинается с "/" (как в "example.com:4242"), он должен интерпретироваться как имя удалённого сервера управления политикой, который следует использовать через TCP-подключение (порт по умолчанию 4242, если только после имени сервера через двоеточие, разделяющее два поля, не указан другой порт).
.TP
.B root
diff --git a/libsemanage/src/boolean_record.c b/libsemanage/src/boolean_record.c
index 95f3a862..40dc6545 100644
--- a/libsemanage/src/boolean_record.c
+++ b/libsemanage/src/boolean_record.c
@@ -7,6 +7,9 @@
*/
#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
#include <sepol/boolean_record.h>
typedef sepol_bool_t semanage_bool_t;
@@ -20,7 +23,6 @@ typedef semanage_bool_key_t record_key_t;
#include "boolean_internal.h"
#include "handle.h"
#include "database.h"
-#include <stdlib.h>
#include <selinux/selinux.h>
/* Key */
diff --git a/libsemanage/src/booleans_file.c b/libsemanage/src/booleans_file.c
index f79d0b44..6d600bbc 100644
--- a/libsemanage/src/booleans_file.c
+++ b/libsemanage/src/booleans_file.c
@@ -48,7 +48,7 @@ static int bool_parse(semanage_handle_t * handle,
goto last;
/* Extract name */
- if (parse_fetch_string(handle, info, &str, '=') < 0)
+ if (parse_fetch_string(handle, info, &str, '=', 0) < 0)
goto err;
if (semanage_bool_set_name(handle, boolean, str) < 0)
diff --git a/libsemanage/src/compressed_file.c b/libsemanage/src/compressed_file.c
new file mode 100644
index 00000000..5546b830
--- /dev/null
+++ b/libsemanage/src/compressed_file.c
@@ -0,0 +1,224 @@
+/* Author: Jason Tang <jtang@tresys.com>
+ * Christopher Ashworth <cashworth@tresys.com>
+ * Ondrej Mosnacek <omosnacek@gmail.com>
+ *
+ * Copyright (C) 2004-2006 Tresys Technology, LLC
+ * Copyright (C) 2005-2021 Red Hat, Inc.
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <bzlib.h>
+
+#include "compressed_file.h"
+
+#include "debug.h"
+
+#define BZ2_MAGICSTR "BZh"
+#define BZ2_MAGICLEN (sizeof(BZ2_MAGICSTR)-1)
+
+/* bzip() a data to a file, returning the total number of compressed bytes
+ * in the file. Returns -1 if file could not be compressed. */
+static int bzip(semanage_handle_t *sh, const char *filename, void *data,
+ size_t num_bytes)
+{
+ BZFILE* b;
+ size_t size = 1<<16;
+ int bzerror;
+ size_t total = 0;
+ size_t len = 0;
+ FILE *f;
+
+ if ((f = fopen(filename, "wb")) == NULL) {
+ return -1;
+ }
+
+ if (!sh->conf->bzip_blocksize) {
+ if (fwrite(data, 1, num_bytes, f) < num_bytes) {
+ fclose(f);
+ return -1;
+ }
+ fclose(f);
+ return 0;
+ }
+
+ b = BZ2_bzWriteOpen( &bzerror, f, sh->conf->bzip_blocksize, 0, 0);
+ if (bzerror != BZ_OK) {
+ BZ2_bzWriteClose ( &bzerror, b, 1, 0, 0 );
+ fclose(f);
+ return -1;
+ }
+
+ while ( num_bytes > total ) {
+ if (num_bytes - total > size) {
+ len = size;
+ } else {
+ len = num_bytes - total;
+ }
+ BZ2_bzWrite ( &bzerror, b, (uint8_t *)data + total, len );
+ if (bzerror == BZ_IO_ERROR) {
+ BZ2_bzWriteClose ( &bzerror, b, 1, 0, 0 );
+ fclose(f);
+ return -1;
+ }
+ total += len;
+ }
+
+ BZ2_bzWriteClose ( &bzerror, b, 0, 0, 0 );
+ fclose(f);
+ if (bzerror == BZ_IO_ERROR) {
+ return -1;
+ }
+ return 0;
+}
+
+/* bunzip() a file to '*data', returning the total number of uncompressed bytes
+ * in the file. Returns -1 if file could not be decompressed. */
+static ssize_t bunzip(semanage_handle_t *sh, FILE *f, void **data)
+{
+ BZFILE* b = NULL;
+ size_t nBuf;
+ uint8_t* buf = NULL;
+ size_t size = 1<<18;
+ size_t bufsize = size;
+ int bzerror;
+ size_t total = 0;
+ uint8_t* uncompress = NULL;
+ uint8_t* tmpalloc = NULL;
+ int ret = -1;
+
+ buf = malloc(bufsize);
+ if (buf == NULL) {
+ ERR(sh, "Failure allocating memory.");
+ goto exit;
+ }
+
+ /* Check if the file is bzipped */
+ bzerror = fread(buf, 1, BZ2_MAGICLEN, f);
+ rewind(f);
+ if ((bzerror != BZ2_MAGICLEN) || memcmp(buf, BZ2_MAGICSTR, BZ2_MAGICLEN)) {
+ goto exit;
+ }
+
+ b = BZ2_bzReadOpen ( &bzerror, f, 0, sh->conf->bzip_small, NULL, 0 );
+ if ( bzerror != BZ_OK ) {
+ ERR(sh, "Failure opening bz2 archive.");
+ goto exit;
+ }
+
+ uncompress = malloc(size);
+ if (uncompress == NULL) {
+ ERR(sh, "Failure allocating memory.");
+ goto exit;
+ }
+
+ while ( bzerror == BZ_OK) {
+ nBuf = BZ2_bzRead ( &bzerror, b, buf, bufsize);
+ if (( bzerror == BZ_OK ) || ( bzerror == BZ_STREAM_END )) {
+ if (total + nBuf > size) {
+ size *= 2;
+ tmpalloc = realloc(uncompress, size);
+ if (tmpalloc == NULL) {
+ ERR(sh, "Failure allocating memory.");
+ goto exit;
+ }
+ uncompress = tmpalloc;
+ }
+ memcpy(&uncompress[total], buf, nBuf);
+ total += nBuf;
+ }
+ }
+ if ( bzerror != BZ_STREAM_END ) {
+ ERR(sh, "Failure reading bz2 archive.");
+ goto exit;
+ }
+
+ ret = total;
+ *data = uncompress;
+
+exit:
+ BZ2_bzReadClose ( &bzerror, b );
+ free(buf);
+ if ( ret < 0 ) {
+ free(uncompress);
+ }
+ return ret;
+}
+
+int map_compressed_file(semanage_handle_t *sh, const char *path,
+ struct file_contents *contents)
+{
+ ssize_t size = -1;
+ void *uncompress;
+ int ret = 0, fd = -1;
+ FILE *file = NULL;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ ERR(sh, "Unable to open %s\n", path);
+ return -1;
+ }
+
+ file = fdopen(fd, "r");
+ if (file == NULL) {
+ ERR(sh, "Unable to open %s\n", path);
+ close(fd);
+ return -1;
+ }
+
+ if ((size = bunzip(sh, file, &uncompress)) >= 0) {
+ contents->data = uncompress;
+ contents->len = size;
+ contents->compressed = 1;
+ } else {
+ struct stat sb;
+ if (fstat(fd, &sb) == -1 ||
+ (uncompress = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) ==
+ MAP_FAILED) {
+ ret = -1;
+ } else {
+ contents->data = uncompress;
+ contents->len = sb.st_size;
+ contents->compressed = 0;
+ }
+ }
+ fclose(file);
+ return ret;
+}
+
+void unmap_compressed_file(struct file_contents *contents)
+{
+ if (!contents->data)
+ return;
+
+ if (contents->compressed) {
+ free(contents->data);
+ } else {
+ munmap(contents->data, contents->len);
+ }
+}
+
+int write_compressed_file(semanage_handle_t *sh, const char *path,
+ void *data, size_t len)
+{
+ return bzip(sh, path, data, len);
+}
diff --git a/libsemanage/src/compressed_file.h b/libsemanage/src/compressed_file.h
new file mode 100644
index 00000000..96cfb4b6
--- /dev/null
+++ b/libsemanage/src/compressed_file.h
@@ -0,0 +1,78 @@
+/* Author: Jason Tang <jtang@tresys.com>
+ * Christopher Ashworth <cashworth@tresys.com>
+ * Ondrej Mosnacek <omosnacek@gmail.com>
+ *
+ * Copyright (C) 2004-2006 Tresys Technology, LLC
+ * Copyright (C) 2005-2021 Red Hat, Inc.
+ *
+ * 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
+ */
+
+#ifndef _SEMANAGE_CIL_FILE_H_
+#define _SEMANAGE_CIL_FILE_H_
+
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include "handle.h"
+
+struct file_contents {
+ void *data; /** file contents (uncompressed) */
+ size_t len; /** length of contents */
+ int compressed; /** whether file was compressed */
+};
+
+/**
+ * Map/read a possibly-compressed file into memory.
+ *
+ * If the file is bzip compressed map_file will uncompress the file into
+ * @p contents. The caller is responsible for calling
+ * @ref unmap_compressed_file on @p contents on success.
+ *
+ * @param sh semanage handle
+ * @param path path to the file
+ * @param contents pointer to struct file_contents, which will be
+ * populated with data pointer, size, and an indication whether
+ * the file was compressed or not
+ *
+ * @return 0 on success, -1 otherwise.
+ */
+int map_compressed_file(semanage_handle_t *sh, const char *path,
+ struct file_contents *contents);
+
+/**
+ * Destroy a previously mapped possibly-compressed file.
+ *
+ * If all fields of @p contents are zero/NULL, the function is
+ * guaranteed to do nothing.
+ *
+ * @param contents pointer to struct file_contents to destroy
+ */
+void unmap_compressed_file(struct file_contents *contents);
+
+/**
+ * Write bytes into a file, using compression if configured.
+ *
+ * @param sh semanage handle
+ * @param path path to the file
+ * @param data pointer to the data
+ * @param len length of the data
+ *
+ * @return 0 on success, -1 otherwise.
+ */
+int write_compressed_file(semanage_handle_t *sh, const char *path,
+ void *data, size_t len);
+
+#endif
diff --git a/libsemanage/src/context_record.c b/libsemanage/src/context_record.c
index 16ba518e..dafb90fc 100644
--- a/libsemanage/src/context_record.c
+++ b/libsemanage/src/context_record.c
@@ -7,6 +7,8 @@ typedef sepol_context_t semanage_context_t;
#define _SEMANAGE_CONTEXT_DEFINED_
+#include <semanage/context_record.h>
+
/* User */
const char *semanage_context_get_user(const semanage_context_t * con)
{
diff --git a/libsemanage/src/database_join.c b/libsemanage/src/database_join.c
index b9b35a61..a49a6226 100644
--- a/libsemanage/src/database_join.c
+++ b/libsemanage/src/database_join.c
@@ -77,10 +77,14 @@ static int dbase_join_cache(semanage_handle_t * handle, dbase_join_t * dbase)
goto err;
/* Sort for quicker merge later */
- qsort(records1, rcount1, sizeof(record1_t *),
- (int (*)(const void *, const void *))rtable1->compare2_qsort);
- qsort(records2, rcount2, sizeof(record2_t *),
- (int (*)(const void *, const void *))rtable2->compare2_qsort);
+ if (rcount1 > 0) {
+ qsort(records1, rcount1, sizeof(record1_t *),
+ (int (*)(const void *, const void *))rtable1->compare2_qsort);
+ }
+ if (rcount2 > 0) {
+ qsort(records2, rcount2, sizeof(record2_t *),
+ (int (*)(const void *, const void *))rtable2->compare2_qsort);
+ }
/* Now merge into this dbase */
while (i < rcount1 || j < rcount2) {
diff --git a/libsemanage/src/direct_api.c b/libsemanage/src/direct_api.c
index f0e2300a..d83941b0 100644
--- a/libsemanage/src/direct_api.c
+++ b/libsemanage/src/direct_api.c
@@ -33,6 +33,8 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
#include <limits.h>
#include <errno.h>
#include <dirent.h>
@@ -50,13 +52,13 @@
#include "debug.h"
#include "handle.h"
+#include "compressed_file.h"
#include "modules.h"
#include "direct_api.h"
#include "semanage_store.h"
#include "database_policydb.h"
#include "policy.h"
-#include <sys/mman.h>
-#include <sys/wait.h>
+#include "sha256.h"
#define PIPE_READ 0
#define PIPE_WRITE 1
@@ -446,198 +448,10 @@ static int parse_module_headers(semanage_handle_t * sh, char *module_data,
return 0;
}
-#include <stdlib.h>
-#include <bzlib.h>
-#include <string.h>
-#include <sys/sendfile.h>
-
-/* bzip() a data to a file, returning the total number of compressed bytes
- * in the file. Returns -1 if file could not be compressed. */
-static ssize_t bzip(semanage_handle_t *sh, const char *filename, char *data,
- size_t num_bytes)
-{
- BZFILE* b;
- size_t size = 1<<16;
- int bzerror;
- size_t total = 0;
- size_t len = 0;
- FILE *f;
-
- if ((f = fopen(filename, "wb")) == NULL) {
- return -1;
- }
-
- if (!sh->conf->bzip_blocksize) {
- if (fwrite(data, 1, num_bytes, f) < num_bytes) {
- fclose(f);
- return -1;
- }
- fclose(f);
- return num_bytes;
- }
-
- b = BZ2_bzWriteOpen( &bzerror, f, sh->conf->bzip_blocksize, 0, 0);
- if (bzerror != BZ_OK) {
- BZ2_bzWriteClose ( &bzerror, b, 1, 0, 0 );
- return -1;
- }
-
- while ( num_bytes > total ) {
- if (num_bytes - total > size) {
- len = size;
- } else {
- len = num_bytes - total;
- }
- BZ2_bzWrite ( &bzerror, b, &data[total], len );
- if (bzerror == BZ_IO_ERROR) {
- BZ2_bzWriteClose ( &bzerror, b, 1, 0, 0 );
- return -1;
- }
- total += len;
- }
-
- BZ2_bzWriteClose ( &bzerror, b, 0, 0, 0 );
- fclose(f);
- if (bzerror == BZ_IO_ERROR) {
- return -1;
- }
- return total;
-}
-
-#define BZ2_MAGICSTR "BZh"
-#define BZ2_MAGICLEN (sizeof(BZ2_MAGICSTR)-1)
-
-/* bunzip() a file to '*data', returning the total number of uncompressed bytes
- * in the file. Returns -1 if file could not be decompressed. */
-ssize_t bunzip(semanage_handle_t *sh, FILE *f, char **data)
-{
- BZFILE* b = NULL;
- size_t nBuf;
- char* buf = NULL;
- size_t size = 1<<18;
- size_t bufsize = size;
- int bzerror;
- size_t total = 0;
- char* uncompress = NULL;
- char* tmpalloc = NULL;
- int ret = -1;
-
- buf = malloc(bufsize);
- if (buf == NULL) {
- ERR(sh, "Failure allocating memory.");
- goto exit;
- }
-
- /* Check if the file is bzipped */
- bzerror = fread(buf, 1, BZ2_MAGICLEN, f);
- rewind(f);
- if ((bzerror != BZ2_MAGICLEN) || memcmp(buf, BZ2_MAGICSTR, BZ2_MAGICLEN)) {
- goto exit;
- }
-
- b = BZ2_bzReadOpen ( &bzerror, f, 0, sh->conf->bzip_small, NULL, 0 );
- if ( bzerror != BZ_OK ) {
- ERR(sh, "Failure opening bz2 archive.");
- goto exit;
- }
-
- uncompress = malloc(size);
- if (uncompress == NULL) {
- ERR(sh, "Failure allocating memory.");
- goto exit;
- }
-
- while ( bzerror == BZ_OK) {
- nBuf = BZ2_bzRead ( &bzerror, b, buf, bufsize);
- if (( bzerror == BZ_OK ) || ( bzerror == BZ_STREAM_END )) {
- if (total + nBuf > size) {
- size *= 2;
- tmpalloc = realloc(uncompress, size);
- if (tmpalloc == NULL) {
- ERR(sh, "Failure allocating memory.");
- goto exit;
- }
- uncompress = tmpalloc;
- }
- memcpy(&uncompress[total], buf, nBuf);
- total += nBuf;
- }
- }
- if ( bzerror != BZ_STREAM_END ) {
- ERR(sh, "Failure reading bz2 archive.");
- goto exit;
- }
-
- ret = total;
- *data = uncompress;
-
-exit:
- BZ2_bzReadClose ( &bzerror, b );
- free(buf);
- if ( ret < 0 ) {
- free(uncompress);
- }
- return ret;
-}
-
-/* mmap() a file to '*data',
- * If the file is bzip compressed map_file will uncompress
- * the file into '*data'.
- * Returns the total number of bytes in memory .
- * Returns -1 if file could not be opened or mapped. */
-static ssize_t map_file(semanage_handle_t *sh, const char *path, char **data,
- int *compressed)
-{
- ssize_t size = -1;
- char *uncompress;
- int fd = -1;
- FILE *file = NULL;
-
- fd = open(path, O_RDONLY);
- if (fd == -1) {
- ERR(sh, "Unable to open %s\n", path);
- return -1;
- }
-
- file = fdopen(fd, "r");
- if (file == NULL) {
- ERR(sh, "Unable to open %s\n", path);
- close(fd);
- return -1;
- }
-
- if ((size = bunzip(sh, file, &uncompress)) > 0) {
- *data = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
- if (*data == MAP_FAILED) {
- free(uncompress);
- fclose(file);
- return -1;
- } else {
- memcpy(*data, uncompress, size);
- }
- free(uncompress);
- *compressed = 1;
- } else {
- struct stat sb;
- if (fstat(fd, &sb) == -1 ||
- (*data = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) ==
- MAP_FAILED) {
- size = -1;
- } else {
- size = sb.st_size;
- }
- *compressed = 0;
- }
-
- fclose(file);
-
- return size;
-}
-
/* Writes a block of data to a file. Returns 0 on success, -1 on
* error. */
static int write_file(semanage_handle_t * sh,
- const char *filename, char *data, size_t num_bytes)
+ const char *filename, const char *data, size_t num_bytes)
{
int out;
@@ -1037,23 +851,33 @@ cleanup:
return ret;
}
+static void update_checksum_with_len(Sha256Context *context, size_t s)
+{
+ int i;
+ uint8_t buffer[8];
+
+ for (i = 0; i < 8; i++) {
+ buffer[i] = s & 0xff;
+ s >>= 8;
+ }
+ Sha256Update(context, buffer, 8);
+}
+
static int semanage_compile_module(semanage_handle_t *sh,
- semanage_module_info_t *modinfo)
+ semanage_module_info_t *modinfo,
+ Sha256Context *context)
{
char cil_path[PATH_MAX];
char hll_path[PATH_MAX];
char *compiler_path = NULL;
char *cil_data = NULL;
char *err_data = NULL;
- char *hll_data = NULL;
char *start = NULL;
char *end = NULL;
- ssize_t hll_data_len = 0;
- ssize_t bzip_status;
int status = 0;
- int compressed;
size_t cil_data_len = 0;
size_t err_data_len = 0;
+ struct file_contents hll_contents = {};
if (!strcasecmp(modinfo->lang_ext, "cil")) {
goto cleanup;
@@ -1084,13 +908,15 @@ static int semanage_compile_module(semanage_handle_t *sh,
goto cleanup;
}
- if ((hll_data_len = map_file(sh, hll_path, &hll_data, &compressed)) <= 0) {
+ status = map_compressed_file(sh, hll_path, &hll_contents);
+ if (status < 0) {
ERR(sh, "Unable to read file %s\n", hll_path);
- status = -1;
goto cleanup;
}
- status = semanage_pipe_data(sh, compiler_path, hll_data, (size_t)hll_data_len, &cil_data, &cil_data_len, &err_data, &err_data_len);
+ status = semanage_pipe_data(sh, compiler_path, hll_contents.data,
+ hll_contents.len, &cil_data, &cil_data_len,
+ &err_data, &err_data_len);
if (err_data_len > 0) {
for (start = end = err_data; end < err_data + err_data_len; end++) {
if (*end == '\n') {
@@ -1110,10 +936,14 @@ static int semanage_compile_module(semanage_handle_t *sh,
goto cleanup;
}
- bzip_status = bzip(sh, cil_path, cil_data, cil_data_len);
- if (bzip_status == -1) {
- ERR(sh, "Failed to bzip %s\n", cil_path);
- status = -1;
+ if (context) {
+ update_checksum_with_len(context, cil_data_len);
+ Sha256Update(context, cil_data, cil_data_len);
+ }
+
+ status = write_compressed_file(sh, cil_path, cil_data, cil_data_len);
+ if (status == -1) {
+ ERR(sh, "Failed to write %s\n", cil_path);
goto cleanup;
}
@@ -1131,9 +961,7 @@ static int semanage_compile_module(semanage_handle_t *sh,
}
cleanup:
- if (hll_data_len > 0) {
- munmap(hll_data, hll_data_len);
- }
+ unmap_compressed_file(&hll_contents);
free(cil_data);
free(err_data);
free(compiler_path);
@@ -1141,18 +969,40 @@ cleanup:
return status;
}
+static int modinfo_cmp(const void *a, const void *b)
+{
+ const semanage_module_info_t *ma = a;
+ const semanage_module_info_t *mb = b;
+
+ return strcmp(ma->name, mb->name);
+}
+
static int semanage_compile_hll_modules(semanage_handle_t *sh,
- semanage_module_info_t *modinfos,
- int num_modinfos)
+ semanage_module_info_t *modinfos,
+ int num_modinfos,
+ char *cil_checksum)
{
- int status = 0;
- int i;
+ /* to be incremented when checksum input data format changes */
+ static const size_t CHECKSUM_EPOCH = 1;
+
+ int i, status = 0;
char cil_path[PATH_MAX];
struct stat sb;
+ Sha256Context context;
+ SHA256_HASH hash;
+ struct file_contents contents = {};
assert(sh);
assert(modinfos);
+ /* Sort modules by name to get consistent ordering. */
+ qsort(modinfos, num_modinfos, sizeof(*modinfos), &modinfo_cmp);
+
+ Sha256Initialise(&context);
+ update_checksum_with_len(&context, CHECKSUM_EPOCH);
+
+ /* prefix with module count to avoid collisions */
+ update_checksum_with_len(&context, num_modinfos);
for (i = 0; i < num_modinfos; i++) {
status = semanage_module_get_path(
sh,
@@ -1160,31 +1010,103 @@ static int semanage_compile_hll_modules(semanage_handle_t *sh,
SEMANAGE_MODULE_PATH_CIL,
cil_path,
sizeof(cil_path));
- if (status != 0) {
- goto cleanup;
- }
+ if (status != 0)
+ return -1;
- if (semanage_get_ignore_module_cache(sh) == 0 &&
- (status = stat(cil_path, &sb)) == 0) {
- continue;
- }
- if (status != 0 && errno != ENOENT) {
- ERR(sh, "Unable to access %s: %s\n", cil_path, strerror(errno));
- goto cleanup; //an error in the "stat" call
+ if (!semanage_get_ignore_module_cache(sh)) {
+ status = stat(cil_path, &sb);
+ if (status == 0) {
+ status = map_compressed_file(sh, cil_path, &contents);
+ if (status < 0) {
+ ERR(sh, "Error mapping file: %s", cil_path);
+ return -1;
+ }
+
+ /* prefix with length to avoid collisions */
+ update_checksum_with_len(&context, contents.len);
+ Sha256Update(&context, contents.data, contents.len);
+
+ unmap_compressed_file(&contents);
+ continue;
+ } else if (errno != ENOENT) {
+ ERR(sh, "Unable to access %s: %s\n", cil_path,
+ strerror(errno));
+ return -1; //an error in the "stat" call
+ }
}
- status = semanage_compile_module(sh, &modinfos[i]);
- if (status < 0) {
- goto cleanup;
+ status = semanage_compile_module(sh, &modinfos[i], &context);
+ if (status < 0)
+ return -1;
+ }
+ Sha256Finalise(&context, &hash);
+
+ semanage_hash_to_checksum_string(hash.bytes, cil_checksum);
+ return 0;
+}
+
+static int semanage_compare_checksum(semanage_handle_t *sh, const char *reference)
+{
+ const char *path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES_CHECKSUM);
+ struct stat sb;
+ int fd, retval;
+ char *data;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ if (errno != ENOENT) {
+ ERR(sh, "Unable to open %s: %s\n", path, strerror(errno));
+ return -1;
}
+ /* Checksum file not present - force a rebuild. */
+ return 1;
}
- status = 0;
+ if (fstat(fd, &sb) == -1) {
+ ERR(sh, "Unable to stat %s\n", path);
+ retval = -1;
+ goto out_close;
+ }
-cleanup:
- return status;
+ if (sb.st_size != (off_t)CHECKSUM_CONTENT_SIZE) {
+ /* Incompatible/invalid hash type - just force a rebuild. */
+ WARN(sh, "Module checksum invalid - forcing a rebuild\n");
+ retval = 1;
+ goto out_close;
+ }
+
+ data = mmap(NULL, CHECKSUM_CONTENT_SIZE, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (data == MAP_FAILED) {
+ ERR(sh, "Unable to mmap %s\n", path);
+ retval = -1;
+ goto out_close;
+ }
+
+ retval = memcmp(data, reference, CHECKSUM_CONTENT_SIZE) != 0;
+ munmap(data, sb.st_size);
+out_close:
+ close(fd);
+ return retval;
+}
+
+static int semanage_write_modules_checksum(semanage_handle_t *sh,
+ const char *checksum)
+{
+ const char *path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES_CHECKSUM);
+
+ return write_file(sh, path, checksum, CHECKSUM_CONTENT_SIZE);
}
+/* Files that must exist in order to skip policy rebuild. */
+static const int semanage_computed_files[] = {
+ SEMANAGE_STORE_KERNEL,
+ SEMANAGE_STORE_FC,
+ SEMANAGE_STORE_SEUSERS,
+ SEMANAGE_LINKED,
+ SEMANAGE_SEUSERS_LINKED,
+ SEMANAGE_USERS_EXTRA_LINKED
+};
+
/* Copies a file from src to dst. If dst already exists then
* overwrite it. If source doesn't exist then return success.
* Returns 0 on success, -1 on error. */
@@ -1211,6 +1133,7 @@ static int semanage_direct_commit(semanage_handle_t * sh)
semanage_module_info_t *modinfos = NULL;
mode_t mask = umask(0077);
struct stat sb;
+ char modules_checksum[CHECKSUM_CONTENT_SIZE + 1 /* '\0' */];
int do_rebuild, do_write_kernel, do_install;
int fcontexts_modified, ports_modified, seusers_modified,
@@ -1244,6 +1167,14 @@ static int semanage_direct_commit(semanage_handle_t * sh)
seusers_modified = seusers->dtable->is_modified(seusers->dbase);
fcontexts_modified = fcontexts->dtable->is_modified(fcontexts->dbase);
+ /* Before we do anything else, flush the join to its component parts.
+ * This *does not* flush to disk automatically */
+ if (users->dtable->is_modified(users->dbase)) {
+ retval = users->dtable->flush(sh, users->dbase);
+ if (retval < 0)
+ goto cleanup;
+ }
+
/* Rebuild if explicitly requested or any module changes occurred. */
do_rebuild = sh->do_rebuild | sh->modules_modified;
@@ -1310,14 +1241,6 @@ static int semanage_direct_commit(semanage_handle_t * sh)
}
}
- /* Before we do anything else, flush the join to its component parts.
- * This *does not* flush to disk automatically */
- if (users->dtable->is_modified(users->dbase)) {
- retval = users->dtable->flush(sh, users->dbase);
- if (retval < 0)
- goto cleanup;
- }
-
/*
* This is for systems that have already migrated with an older version
* of semanage_migrate_store. The older version did not copy
@@ -1326,70 +1249,59 @@ static int semanage_direct_commit(semanage_handle_t * sh)
* in order to skip re-linking are present; otherwise, we force
* a rebuild.
*/
- if (!do_rebuild) {
- int files[] = {SEMANAGE_STORE_KERNEL,
- SEMANAGE_STORE_FC,
- SEMANAGE_STORE_SEUSERS,
- SEMANAGE_LINKED,
- SEMANAGE_SEUSERS_LINKED,
- SEMANAGE_USERS_EXTRA_LINKED};
-
- for (i = 0; i < (int) ARRAY_SIZE(files); i++) {
- path = semanage_path(SEMANAGE_TMP, files[i]);
- if (stat(path, &sb) != 0) {
- if (errno != ENOENT) {
- ERR(sh, "Unable to access %s: %s\n", path, strerror(errno));
- retval = -1;
- goto cleanup;
- }
-
- do_rebuild = 1;
- goto rebuild;
+ for (i = 0; !do_rebuild && i < (int)ARRAY_SIZE(semanage_computed_files); i++) {
+ path = semanage_path(SEMANAGE_TMP, semanage_computed_files[i]);
+ if (stat(path, &sb) != 0) {
+ if (errno != ENOENT) {
+ ERR(sh, "Unable to access %s: %s\n", path, strerror(errno));
+ retval = -1;
+ goto cleanup;
}
+
+ do_rebuild = 1;
+ break;
}
}
-rebuild:
- /*
- * Now that we know whether or not a rebuild is required,
- * we can determine what else needs to be done.
- * We need to write the kernel policy if we are rebuilding
- * or if any other policy component that lives in the kernel
- * policy has been modified.
- * We need to install the policy files if any of the managed files
- * that live under /etc/selinux (kernel policy, seusers, file contexts)
- * will be modified.
- */
- do_write_kernel = do_rebuild | ports_modified | ibpkeys_modified |
- ibendports_modified |
- bools->dtable->is_modified(bools->dbase) |
- ifaces->dtable->is_modified(ifaces->dbase) |
- nodes->dtable->is_modified(nodes->dbase) |
- users->dtable->is_modified(users_base->dbase);
- do_install = do_write_kernel | seusers_modified | fcontexts_modified;
-
- /*
- * If there were policy changes, or explicitly requested, or
- * any required files are missing, rebuild the policy.
- */
- if (do_rebuild) {
- /* =================== Module expansion =============== */
-
+ if (do_rebuild || sh->check_ext_changes) {
retval = semanage_get_active_modules(sh, &modinfos, &num_modinfos);
if (retval < 0) {
goto cleanup;
}
+ /* No modules - nothing to rebuild. */
if (num_modinfos == 0) {
goto cleanup;
}
- retval = semanage_compile_hll_modules(sh, modinfos, num_modinfos);
+ retval = semanage_compile_hll_modules(sh, modinfos, num_modinfos,
+ modules_checksum);
if (retval < 0) {
ERR(sh, "Failed to compile hll files into cil files.\n");
goto cleanup;
}
+ if (!do_rebuild && sh->check_ext_changes) {
+ retval = semanage_compare_checksum(sh, modules_checksum);
+ if (retval < 0)
+ goto cleanup;
+ do_rebuild = retval;
+ }
+
+ retval = semanage_write_modules_checksum(sh, modules_checksum);
+ if (retval < 0) {
+ ERR(sh, "Failed to write module checksum file.\n");
+ goto cleanup;
+ }
+ }
+
+ /*
+ * If there were policy changes, or explicitly requested, or
+ * any required files are missing, rebuild the policy.
+ */
+ if (do_rebuild) {
+ /* =================== Module expansion =============== */
+
retval = semanage_get_cil_paths(sh, modinfos, num_modinfos, &mod_filenames);
if (retval < 0)
goto cleanup;
@@ -1521,6 +1433,23 @@ rebuild:
}
}
+ /*
+ * Determine what else needs to be done.
+ * We need to write the kernel policy if we are rebuilding
+ * or if any other policy component that lives in the kernel
+ * policy has been modified.
+ * We need to install the policy files if any of the managed files
+ * that live under /etc/selinux (kernel policy, seusers, file contexts)
+ * will be modified.
+ */
+ do_write_kernel = do_rebuild | ports_modified | ibpkeys_modified |
+ ibendports_modified |
+ bools->dtable->is_modified(bools->dbase) |
+ ifaces->dtable->is_modified(ifaces->dbase) |
+ nodes->dtable->is_modified(nodes->dbase) |
+ users->dtable->is_modified(users_base->dbase);
+ do_install = do_write_kernel | seusers_modified | fcontexts_modified;
+
/* Attach our databases to the policydb we just created or loaded. */
dbase_policydb_attach((dbase_policydb_t *) pusers_base->dbase, out);
dbase_policydb_attach((dbase_policydb_t *) pports->dbase, out);
@@ -1756,19 +1685,17 @@ static int semanage_direct_install_file(semanage_handle_t * sh,
{
int retval = -1;
- char *data = NULL;
- ssize_t data_len = 0;
- int compressed = 0;
char *path = NULL;
char *filename;
char *lang_ext = NULL;
char *module_name = NULL;
char *separator;
char *version = NULL;
+ struct file_contents contents = {};
- if ((data_len = map_file(sh, install_filename, &data, &compressed)) <= 0) {
+ retval = map_compressed_file(sh, install_filename, &contents);
+ if (retval < 0) {
ERR(sh, "Unable to read file %s\n", install_filename);
- retval = -1;
goto cleanup;
}
@@ -1781,7 +1708,7 @@ static int semanage_direct_install_file(semanage_handle_t * sh,
filename = basename(path);
- if (compressed) {
+ if (contents.compressed) {
separator = strrchr(filename, '.');
if (separator == NULL) {
ERR(sh, "Compressed module does not have a valid extension.");
@@ -1805,7 +1732,8 @@ static int semanage_direct_install_file(semanage_handle_t * sh,
}
if (strcmp(lang_ext, "pp") == 0) {
- retval = parse_module_headers(sh, data, data_len, &module_name, &version);
+ retval = parse_module_headers(sh, contents.data, contents.len,
+ &module_name, &version);
free(version);
if (retval != 0)
goto cleanup;
@@ -1822,10 +1750,11 @@ static int semanage_direct_install_file(semanage_handle_t * sh,
fprintf(stderr, "Warning: SELinux userspace will refer to the module from %s as %s rather than %s\n", install_filename, module_name, filename);
}
- retval = semanage_direct_install(sh, data, data_len, module_name, lang_ext);
+ retval = semanage_direct_install(sh, contents.data, contents.len,
+ module_name, lang_ext);
cleanup:
- if (data_len > 0) munmap(data, data_len);
+ unmap_compressed_file(&contents);
free(module_name);
free(path);
@@ -1844,10 +1773,8 @@ static int semanage_direct_extract(semanage_handle_t * sh,
enum semanage_module_path_type file_type;
int rc = -1;
semanage_module_info_t *_modinfo = NULL;
- ssize_t _data_len;
- char *_data;
- int compressed;
struct stat sb;
+ struct file_contents contents = {};
/* get path of module */
rc = semanage_module_get_path(
@@ -1897,25 +1824,39 @@ static int semanage_direct_extract(semanage_handle_t * sh,
goto cleanup;
}
- rc = semanage_compile_module(sh, _modinfo);
+ rc = semanage_compile_module(sh, _modinfo, NULL);
if (rc < 0) {
goto cleanup;
}
}
- _data_len = map_file(sh, input_file, &_data, &compressed);
- if (_data_len <= 0) {
+ rc = map_compressed_file(sh, input_file, &contents);
+ if (rc < 0) {
ERR(sh, "Error mapping file: %s", input_file);
- rc = -1;
goto cleanup;
}
+ /* The API promises an mmap'ed pointer */
+ if (contents.compressed) {
+ *mapped_data = mmap(NULL, contents.len, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
+ if (*mapped_data == MAP_FAILED) {
+ ERR(sh, "Unable to map memory");
+ rc = -1;
+ goto cleanup;
+ }
+ memcpy(*mapped_data, contents.data, contents.len);
+ free(contents.data);
+ } else {
+ *mapped_data = contents.data;
+ }
+
*modinfo = _modinfo;
- *data_len = (size_t)_data_len;
- *mapped_data = _data;
+ *data_len = contents.len;
cleanup:
if (rc != 0) {
+ unmap_compressed_file(&contents);
semanage_module_info_destroy(sh, _modinfo);
free(_modinfo);
}
@@ -2869,8 +2810,8 @@ static int semanage_direct_install_info(semanage_handle_t *sh,
goto cleanup;
}
- ret = bzip(sh, path, data, data_len);
- if (ret <= 0) {
+ ret = write_compressed_file(sh, path, data, data_len);
+ if (ret < 0) {
ERR(sh, "Error while writing to %s.", path);
status = -3;
goto cleanup;
diff --git a/libsemanage/src/direct_api.h b/libsemanage/src/direct_api.h
index e56107b2..ffd428eb 100644
--- a/libsemanage/src/direct_api.h
+++ b/libsemanage/src/direct_api.h
@@ -39,8 +39,4 @@ int semanage_direct_access_check(struct semanage_handle *sh);
int semanage_direct_mls_enabled(struct semanage_handle *sh);
-#include <stdio.h>
-#include <unistd.h>
-ssize_t bunzip(struct semanage_handle *sh, FILE *f, char **data);
-
#endif
diff --git a/libsemanage/src/fcontexts_file.c b/libsemanage/src/fcontexts_file.c
index 04cd365a..f3579410 100644
--- a/libsemanage/src/fcontexts_file.c
+++ b/libsemanage/src/fcontexts_file.c
@@ -90,7 +90,7 @@ static int fcontext_parse(semanage_handle_t * handle,
goto last;
/* Regexp */
- if (parse_fetch_string(handle, info, &str, ' ') < 0)
+ if (parse_fetch_string(handle, info, &str, ' ', 0) < 0)
goto err;
if (semanage_fcontext_set_expr(handle, fcontext, str) < 0)
goto err;
@@ -100,7 +100,7 @@ static int fcontext_parse(semanage_handle_t * handle,
/* Type */
if (parse_assert_space(handle, info) < 0)
goto err;
- if (parse_fetch_string(handle, info, &str, ' ') < 0)
+ if (parse_fetch_string(handle, info, &str, ' ', 0) < 0)
goto err;
if (!strcasecmp(str, "-s"))
semanage_fcontext_set_type(fcontext, SEMANAGE_FCONTEXT_SOCK);
@@ -124,7 +124,7 @@ static int fcontext_parse(semanage_handle_t * handle,
/* Context */
if (parse_assert_space(handle, info) < 0)
goto err;
- if (parse_fetch_string(handle, info, &str, ' ') < 0)
+ if (parse_fetch_string(handle, info, &str, ' ', 0) < 0)
goto err;
process_context:
diff --git a/libsemanage/src/handle.c b/libsemanage/src/handle.c
index bb1e6140..b2201ee3 100644
--- a/libsemanage/src/handle.c
+++ b/libsemanage/src/handle.c
@@ -116,20 +116,23 @@ semanage_handle_t *semanage_handle_create(void)
void semanage_set_rebuild(semanage_handle_t * sh, int do_rebuild)
{
-
assert(sh != NULL);
sh->do_rebuild = do_rebuild;
- return;
}
void semanage_set_reload(semanage_handle_t * sh, int do_reload)
{
-
assert(sh != NULL);
sh->do_reload = do_reload;
- return;
+}
+
+void semanage_set_check_ext_changes(semanage_handle_t * sh, int do_check)
+{
+ assert(sh != NULL);
+
+ sh->check_ext_changes = do_check;
}
int semanage_get_hll_compiler_path(semanage_handle_t *sh,
diff --git a/libsemanage/src/handle.h b/libsemanage/src/handle.h
index e1ce83ba..4d2aae8f 100644
--- a/libsemanage/src/handle.h
+++ b/libsemanage/src/handle.h
@@ -61,6 +61,7 @@ struct semanage_handle {
int is_in_transaction;
int do_reload; /* whether to reload policy after commit */
int do_rebuild; /* whether to rebuild policy if there were no changes */
+ int check_ext_changes; /* whether to rebuild if external changes are detected via checksum */
int commit_err; /* set by semanage_direct_commit() if there are
* any errors when building or committing the
* sandbox to kernel policy at /etc/selinux
diff --git a/libsemanage/src/ibendports_file.c b/libsemanage/src/ibendports_file.c
index bafa8c1d..2fa2a67c 100644
--- a/libsemanage/src/ibendports_file.c
+++ b/libsemanage/src/ibendports_file.c
@@ -75,7 +75,7 @@ static int ibendport_parse(semanage_handle_t *handle,
goto err;
/* IB Device Name */
- if (parse_fetch_string(handle, info, &str, ' ') < 0)
+ if (parse_fetch_string(handle, info, &str, ' ', 0) < 0)
goto err;
if (semanage_ibendport_set_ibdev_name(handle, ibendport, str) < 0)
goto err;
@@ -92,7 +92,7 @@ static int ibendport_parse(semanage_handle_t *handle,
/* context */
if (parse_assert_space(handle, info) < 0)
goto err;
- if (parse_fetch_string(handle, info, &str, ' ') < 0)
+ if (parse_fetch_string(handle, info, &str, ' ', 0) < 0)
goto err;
if (semanage_context_from_string(handle, str, &con) < 0) {
ERR(handle, "invalid security context \"%s\" (%s: %u)\n%s",
diff --git a/libsemanage/src/ibpkeys_file.c b/libsemanage/src/ibpkeys_file.c
index 929bc31e..edde69f0 100644
--- a/libsemanage/src/ibpkeys_file.c
+++ b/libsemanage/src/ibpkeys_file.c
@@ -80,7 +80,7 @@ static int ibpkey_parse(semanage_handle_t *handle,
goto err;
/* Subnet Prefix */
- if (parse_fetch_string(handle, info, &str, ' ') < 0)
+ if (parse_fetch_string(handle, info, &str, ' ', 0) < 0)
goto err;
if (semanage_ibpkey_set_subnet_prefix(handle, ibpkey, str) < 0)
goto err;
@@ -115,7 +115,7 @@ static int ibpkey_parse(semanage_handle_t *handle,
semanage_ibpkey_set_pkey(ibpkey, low);
}
/* Pkey context */
- if (parse_fetch_string(handle, info, &str, ' ') < 0)
+ if (parse_fetch_string(handle, info, &str, ' ', 0) < 0)
goto err;
if (semanage_context_from_string(handle, str, &con) < 0) {
ERR(handle, "invalid security context \"%s\" (%s: %u)\n%s",
diff --git a/libsemanage/src/interfaces_file.c b/libsemanage/src/interfaces_file.c
index c19c8f94..244f0ae5 100644
--- a/libsemanage/src/interfaces_file.c
+++ b/libsemanage/src/interfaces_file.c
@@ -72,7 +72,7 @@ static int iface_parse(semanage_handle_t * handle,
goto err;
/* Name */
- if (parse_fetch_string(handle, info, &str, ' ') < 0)
+ if (parse_fetch_string(handle, info, &str, ' ', 0) < 0)
goto err;
if (semanage_iface_set_name(handle, iface, str) < 0)
goto err;
@@ -82,7 +82,7 @@ static int iface_parse(semanage_handle_t * handle,
/* Interface context */
if (parse_assert_space(handle, info) < 0)
goto err;
- if (parse_fetch_string(handle, info, &str, ' ') < 0)
+ if (parse_fetch_string(handle, info, &str, ' ', 0) < 0)
goto err;
if (semanage_context_from_string(handle, str, &con) < 0) {
ERR(handle, "invalid security context \"%s\" (%s: %u)\n%s",
@@ -106,7 +106,7 @@ static int iface_parse(semanage_handle_t * handle,
/* Message context */
if (parse_assert_space(handle, info) < 0)
goto err;
- if (parse_fetch_string(handle, info, &str, ' ') < 0)
+ if (parse_fetch_string(handle, info, &str, ' ', 0) < 0)
goto err;
if (semanage_context_from_string(handle, str, &con) < 0) {
ERR(handle, "invalid security context \"%s\" (%s: %u)\n%s",
diff --git a/libsemanage/src/libsemanage.map b/libsemanage/src/libsemanage.map
index 3ea7b60f..c8214b26 100644
--- a/libsemanage/src/libsemanage.map
+++ b/libsemanage/src/libsemanage.map
@@ -345,3 +345,8 @@ LIBSEMANAGE_1.1 {
semanage_module_remove_key;
semanage_set_store_root;
} LIBSEMANAGE_1.0;
+
+LIBSEMANAGE_3.4 {
+ semanage_module_compute_checksum;
+ semanage_set_check_ext_changes;
+} LIBSEMANAGE_1.1;
diff --git a/libsemanage/src/modules.c b/libsemanage/src/modules.c
index b6dd456c..c3bd90ac 100644
--- a/libsemanage/src/modules.c
+++ b/libsemanage/src/modules.c
@@ -35,11 +35,13 @@
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/mman.h>
#include <errno.h>
#include <ctype.h>
#include "handle.h"
#include "modules.h"
+#include "sha256.h"
#include "debug.h"
int semanage_module_install(semanage_handle_t * sh,
@@ -168,6 +170,7 @@ const char *semanage_module_get_name(semanage_module_info_t * modinfo)
/* Legacy function that remains to preserve ABI
* compatibility.
*/
+extern const char *semanage_module_get_version(semanage_module_info_t *);
const char *semanage_module_get_version(semanage_module_info_t * modinfo
__attribute__ ((unused)))
{
@@ -975,3 +978,60 @@ int semanage_module_remove_key(semanage_handle_t *sh,
return sh->funcs->remove_key(sh, modkey);
}
+static const char CHECKSUM_TYPE[] = "sha256";
+const size_t CHECKSUM_CONTENT_SIZE = sizeof(CHECKSUM_TYPE) + 1 + 2 * SHA256_HASH_SIZE;
+
+void semanage_hash_to_checksum_string(const uint8_t *hash, char *checksum)
+{
+ size_t i;
+
+ checksum += sprintf(checksum, "%s:", CHECKSUM_TYPE);
+ for (i = 0; i < SHA256_HASH_SIZE; i++) {
+ checksum += sprintf(checksum, "%02x", (unsigned)hash[i]);
+ }
+}
+
+int semanage_module_compute_checksum(semanage_handle_t *sh,
+ semanage_module_key_t *modkey,
+ int cil, char **checksum,
+ size_t *checksum_len)
+{
+ semanage_module_info_t *extract_info = NULL;
+ Sha256Context context;
+ SHA256_HASH sha256_hash;
+ char *checksum_str;
+ void *data;
+ size_t data_len = 0;
+ int result;
+
+ if (!checksum_len)
+ return -1;
+
+ if (!checksum) {
+ *checksum_len = CHECKSUM_CONTENT_SIZE;
+ return 0;
+ }
+
+ result = semanage_module_extract(sh, modkey, cil, &data, &data_len, &extract_info);
+ if (result != 0)
+ return -1;
+
+ semanage_module_info_destroy(sh, extract_info);
+ free(extract_info);
+
+ Sha256Initialise(&context);
+ Sha256Update(&context, data, data_len);
+ Sha256Finalise(&context, &sha256_hash);
+
+ munmap(data, data_len);
+
+ checksum_str = malloc(CHECKSUM_CONTENT_SIZE + 1 /* '\0' */);
+ if (!checksum_str)
+ return -1;
+
+ semanage_hash_to_checksum_string(sha256_hash.bytes, checksum_str);
+
+ *checksum = checksum_str;
+ *checksum_len = CHECKSUM_CONTENT_SIZE;
+ return 0;
+}
diff --git a/libsemanage/src/modules.h b/libsemanage/src/modules.h
index 64d4a157..cf2432c5 100644
--- a/libsemanage/src/modules.h
+++ b/libsemanage/src/modules.h
@@ -102,4 +102,7 @@ int semanage_module_get_path(semanage_handle_t *sh,
char *path,
size_t len);
+extern const size_t CHECKSUM_CONTENT_SIZE;
+void semanage_hash_to_checksum_string(const uint8_t *hash, char *checksum);
+
#endif
diff --git a/libsemanage/src/nodes_file.c b/libsemanage/src/nodes_file.c
index c3647f2a..2d2b7fe0 100644
--- a/libsemanage/src/nodes_file.c
+++ b/libsemanage/src/nodes_file.c
@@ -77,7 +77,7 @@ static int node_parse(semanage_handle_t * handle,
goto err;
/* Protocol */
- if (parse_fetch_string(handle, info, &str, ' ') < 0)
+ if (parse_fetch_string(handle, info, &str, ' ', 0) < 0)
goto err;
if (!strcasecmp(str, "ipv4"))
proto = SEMANAGE_PROTO_IP4;
@@ -96,7 +96,7 @@ static int node_parse(semanage_handle_t * handle,
/* Address */
if (parse_assert_space(handle, info) < 0)
goto err;
- if (parse_fetch_string(handle, info, &str, ' ') < 0)
+ if (parse_fetch_string(handle, info, &str, ' ', 0) < 0)
goto err;
if (semanage_node_set_addr(handle, node, proto, str) < 0)
goto err;
@@ -106,7 +106,7 @@ static int node_parse(semanage_handle_t * handle,
str = NULL;
/* Netmask */
- if (parse_fetch_string(handle, info, &str, ' ') < 0)
+ if (parse_fetch_string(handle, info, &str, ' ', 0) < 0)
goto err;
if (semanage_node_set_mask(handle, node, proto, str) < 0)
goto err;
@@ -116,7 +116,7 @@ static int node_parse(semanage_handle_t * handle,
str = NULL;
/* Port context */
- if (parse_fetch_string(handle, info, &str, ' ') < 0)
+ if (parse_fetch_string(handle, info, &str, ' ', 0) < 0)
goto err;
if (semanage_context_from_string(handle, str, &con) < 0) {
ERR(handle, "invalid security context \"%s\" (%s: %u)\n%s",
diff --git a/libsemanage/src/parse_utils.c b/libsemanage/src/parse_utils.c
index 4fb54fc3..918dee43 100644
--- a/libsemanage/src/parse_utils.c
+++ b/libsemanage/src/parse_utils.c
@@ -239,7 +239,7 @@ int parse_fetch_int(semanage_handle_t * handle,
char *test = NULL;
int value = 0;
- if (parse_fetch_string(handle, info, &str, delim) < 0)
+ if (parse_fetch_string(handle, info, &str, delim, 0) < 0)
goto err;
if (!isdigit((int)*str)) {
@@ -267,7 +267,7 @@ int parse_fetch_int(semanage_handle_t * handle,
}
int parse_fetch_string(semanage_handle_t * handle,
- parse_info_t * info, char **str, char delim)
+ parse_info_t * info, char **str, char delim, int allow_spaces)
{
char *start = info->ptr;
@@ -277,7 +277,7 @@ int parse_fetch_string(semanage_handle_t * handle,
if (parse_assert_noeof(handle, info) < 0)
goto err;
- while (*(info->ptr) && !isspace(*(info->ptr)) &&
+ while (*(info->ptr) && (allow_spaces || !isspace(*(info->ptr))) &&
(*(info->ptr) != delim)) {
info->ptr++;
len++;
diff --git a/libsemanage/src/parse_utils.h b/libsemanage/src/parse_utils.h
index 0f334860..3e44aca1 100644
--- a/libsemanage/src/parse_utils.h
+++ b/libsemanage/src/parse_utils.h
@@ -71,12 +71,11 @@ extern int parse_optional_str(parse_info_t * info, const char *str);
int parse_fetch_int(semanage_handle_t * hgandle,
parse_info_t * info, int *num, char delim);
-/* Extract the next string (delimited by
- * whitespace), and move the read pointer past it.
- * Stop of the optional character delim is encountered,
- * or if whitespace/eof is encountered. Fail if the
- * string is of length 0. */
+/* Extract the next string and move the read pointer past it.
+ * Stop if the optional character delim (or eof) is encountered,
+ * or if whitespace is encountered and allow_spaces is 0.
+ * Fail if the string is of length 0. */
extern int parse_fetch_string(semanage_handle_t * handle,
- parse_info_t * info, char **str_ptr, char delim);
+ parse_info_t * info, char **str_ptr, char delim, int allow_spaces);
#endif
diff --git a/libsemanage/src/ports_file.c b/libsemanage/src/ports_file.c
index ade4102f..1356021a 100644
--- a/libsemanage/src/ports_file.c
+++ b/libsemanage/src/ports_file.c
@@ -77,7 +77,7 @@ static int port_parse(semanage_handle_t * handle,
goto err;
/* Protocol */
- if (parse_fetch_string(handle, info, &str, ' ') < 0)
+ if (parse_fetch_string(handle, info, &str, ' ', 0) < 0)
goto err;
if (!strcasecmp(str, "tcp"))
semanage_port_set_proto(port, SEMANAGE_PROTO_TCP);
@@ -123,7 +123,7 @@ static int port_parse(semanage_handle_t * handle,
semanage_port_set_port(port, low);
/* Port context */
- if (parse_fetch_string(handle, info, &str, ' ') < 0)
+ if (parse_fetch_string(handle, info, &str, ' ', 0) < 0)
goto err;
if (semanage_context_from_string(handle, str, &con) < 0) {
ERR(handle, "invalid security context \"%s\" (%s: %u)\n%s",
diff --git a/libsemanage/src/semanage.conf b/libsemanage/src/semanage.conf
index dc8d46b8..98d769b5 100644
--- a/libsemanage/src/semanage.conf
+++ b/libsemanage/src/semanage.conf
@@ -24,8 +24,9 @@
# /foo/bar - Write by way of a policy management server, whose
# named socket is at /foo/bar. The path must begin
# with a '/'.
-# foo.com:4242 - Establish a TCP connection to a remote policy
-# management server at foo.com. If there is a colon
+# example.com:4242
+# - Establish a TCP connection to a remote policy
+# management server at example.com. If there is a colon
# then the remainder is interpreted as a port number;
# otherwise default to port 4242.
module-store = direct
diff --git a/libsemanage/src/semanage_store.c b/libsemanage/src/semanage_store.c
index c6a736fe..767f05cb 100644
--- a/libsemanage/src/semanage_store.c
+++ b/libsemanage/src/semanage_store.c
@@ -59,6 +59,7 @@ typedef struct dbase_policydb dbase_t;
#include "debug.h"
#include "utilities.h"
+#include "compressed_file.h"
#define SEMANAGE_CONF_FILE "semanage.conf"
/* relative path names to enum semanage_paths to special files and
@@ -114,6 +115,7 @@ static const char *semanage_sandbox_paths[SEMANAGE_STORE_NUM_PATHS] = {
"/disable_dontaudit",
"/preserve_tunables",
"/modules/disabled",
+ "/modules_checksum",
"/policy.kern",
"/file_contexts.local",
"/file_contexts.homedirs",
@@ -2054,60 +2056,27 @@ int semanage_direct_get_serial(semanage_handle_t * sh)
int semanage_load_files(semanage_handle_t * sh, cil_db_t *cildb, char **filenames, int numfiles)
{
- int retval = 0;
- FILE *fp;
- ssize_t size;
- char *data = NULL;
+ int i, retval = 0;
char *filename;
- int i;
+ struct file_contents contents = {};
for (i = 0; i < numfiles; i++) {
filename = filenames[i];
- if ((fp = fopen(filename, "rb")) == NULL) {
- ERR(sh, "Could not open module file %s for reading.", filename);
- goto cleanup;
- }
-
- if ((size = bunzip(sh, fp, &data)) <= 0) {
- rewind(fp);
- __fsetlocking(fp, FSETLOCKING_BYCALLER);
-
- if (fseek(fp, 0, SEEK_END) != 0) {
- ERR(sh, "Failed to determine size of file %s.", filename);
- goto cleanup;
- }
- size = ftell(fp);
- rewind(fp);
-
- data = malloc(size);
- if (fread(data, size, 1, fp) != 1) {
- ERR(sh, "Failed to read file %s.", filename);
- goto cleanup;
- }
- }
+ retval = map_compressed_file(sh, filename, &contents);
+ if (retval < 0)
+ return -1;
- fclose(fp);
- fp = NULL;
+ retval = cil_add_file(cildb, filename, contents.data, contents.len);
+ unmap_compressed_file(&contents);
- retval = cil_add_file(cildb, filename, data, size);
if (retval != SEPOL_OK) {
ERR(sh, "Error while reading from file %s.", filename);
- goto cleanup;
+ return -1;
}
-
- free(data);
- data = NULL;
}
- return retval;
-
- cleanup:
- if (fp != NULL) {
- fclose(fp);
- }
- free(data);
- return -1;
+ return 0;
}
/*
diff --git a/libsemanage/src/semanage_store.h b/libsemanage/src/semanage_store.h
index b9ec5664..1fc77da8 100644
--- a/libsemanage/src/semanage_store.h
+++ b/libsemanage/src/semanage_store.h
@@ -60,6 +60,7 @@ enum semanage_sandbox_defs {
SEMANAGE_DISABLE_DONTAUDIT,
SEMANAGE_PRESERVE_TUNABLES,
SEMANAGE_MODULES_DISABLED,
+ SEMANAGE_MODULES_CHECKSUM,
SEMANAGE_STORE_KERNEL,
SEMANAGE_STORE_FC_LOCAL,
SEMANAGE_STORE_FC_HOMEDIRS,
diff --git a/libsemanage/src/semanageswig_python_exception.i b/libsemanage/src/semanageswig_python_exception.i
index 372ec948..0df8bbc3 100644
--- a/libsemanage/src/semanageswig_python_exception.i
+++ b/libsemanage/src/semanageswig_python_exception.i
@@ -351,6 +351,14 @@
}
}
+%exception semanage_module_compute_checksum {
+ $action
+ if (result < 0) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ SWIG_fail;
+ }
+}
+
%exception semanage_msg_get_level {
$action
if (result < 0) {
diff --git a/libsemanage/src/seusers_file.c b/libsemanage/src/seusers_file.c
index 910bedf4..21b970ac 100644
--- a/libsemanage/src/seusers_file.c
+++ b/libsemanage/src/seusers_file.c
@@ -53,7 +53,7 @@ static int seuser_parse(semanage_handle_t * handle,
goto last;
/* Extract name */
- if (parse_fetch_string(handle, info, &str, ':') < 0)
+ if (parse_fetch_string(handle, info, &str, ':', 1) < 0)
goto err;
if (semanage_seuser_set_name(handle, seuser, str) < 0)
goto err;
@@ -68,7 +68,7 @@ static int seuser_parse(semanage_handle_t * handle,
goto err;
/* Extract sename */
- if (parse_fetch_string(handle, info, &str, ':') < 0)
+ if (parse_fetch_string(handle, info, &str, ':', 1) < 0)
goto err;
if (semanage_seuser_set_sename(handle, seuser, str) < 0)
goto err;
@@ -83,7 +83,7 @@ static int seuser_parse(semanage_handle_t * handle,
goto err;
/* NOTE: does not allow spaces/multiline */
- if (parse_fetch_string(handle, info, &str, ' ') < 0)
+ if (parse_fetch_string(handle, info, &str, ' ', 0) < 0)
goto err;
if (semanage_seuser_set_mlsrange(handle, seuser, str) < 0)
diff --git a/libsemanage/src/sha256.c b/libsemanage/src/sha256.c
new file mode 100644
index 00000000..fe2aeef0
--- /dev/null
+++ b/libsemanage/src/sha256.c
@@ -0,0 +1,294 @@
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// WjCryptLib_Sha256
+//
+// Implementation of SHA256 hash function.
+// Original author: Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+// Modified by WaterJuice retaining Public Domain license.
+//
+// This is free and unencumbered software released into the public domain - June 2013 waterjuice.org
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// IMPORTS
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include "sha256.h"
+#include <memory.h>
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// MACROS
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#define ror(value, bits) (((value) >> (bits)) | ((value) << (32 - (bits))))
+
+#define MIN(x, y) ( ((x)<(y))?(x):(y) )
+
+#define STORE32H(x, y) \
+ { (y)[0] = (uint8_t)(((x)>>24)&255); (y)[1] = (uint8_t)(((x)>>16)&255); \
+ (y)[2] = (uint8_t)(((x)>>8)&255); (y)[3] = (uint8_t)((x)&255); }
+
+#define LOAD32H(x, y) \
+ { x = ((uint32_t)((y)[0] & 255)<<24) | \
+ ((uint32_t)((y)[1] & 255)<<16) | \
+ ((uint32_t)((y)[2] & 255)<<8) | \
+ ((uint32_t)((y)[3] & 255)); }
+
+#define STORE64H(x, y) \
+ { (y)[0] = (uint8_t)(((x)>>56)&255); (y)[1] = (uint8_t)(((x)>>48)&255); \
+ (y)[2] = (uint8_t)(((x)>>40)&255); (y)[3] = (uint8_t)(((x)>>32)&255); \
+ (y)[4] = (uint8_t)(((x)>>24)&255); (y)[5] = (uint8_t)(((x)>>16)&255); \
+ (y)[6] = (uint8_t)(((x)>>8)&255); (y)[7] = (uint8_t)((x)&255); }
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// CONSTANTS
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// The K array
+static const uint32_t K[64] = {
+ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
+ 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
+ 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
+ 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
+ 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
+ 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
+ 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
+ 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
+ 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
+ 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+
+#define BLOCK_SIZE 64
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// INTERNAL FUNCTIONS
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Various logical functions
+#define Ch( x, y, z ) (z ^ (x & (y ^ z)))
+#define Maj( x, y, z ) (((x | y) & z) | (x & y))
+#define S( x, n ) ror((x),(n))
+#define R( x, n ) (((x)&0xFFFFFFFFUL)>>(n))
+#define Sigma0( x ) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
+#define Sigma1( x ) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
+#define Gamma0( x ) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
+#define Gamma1( x ) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
+
+#define Sha256Round( a, b, c, d, e, f, g, h, i ) \
+ t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
+ t1 = Sigma0(a) + Maj(a, b, c); \
+ d += t0; \
+ h = t0 + t1;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// TransformFunction
+//
+// Compress 512-bits
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static
+void
+ TransformFunction
+ (
+ Sha256Context* Context,
+ uint8_t const* Buffer
+ )
+{
+ uint32_t S[8];
+ uint32_t W[64];
+ uint32_t t0;
+ uint32_t t1;
+ uint32_t t;
+ int i;
+
+ // Copy state into S
+ for( i=0; i<8; i++ )
+ {
+ S[i] = Context->state[i];
+ }
+
+ // Copy the state into 512-bits into W[0..15]
+ for( i=0; i<16; i++ )
+ {
+ LOAD32H( W[i], Buffer + (4*i) );
+ }
+
+ // Fill W[16..63]
+ for( i=16; i<64; i++ )
+ {
+ W[i] = Gamma1( W[i-2]) + W[i-7] + Gamma0( W[i-15] ) + W[i-16];
+ }
+
+ // Compress
+ for( i=0; i<64; i++ )
+ {
+ Sha256Round( S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i );
+ t = S[7];
+ S[7] = S[6];
+ S[6] = S[5];
+ S[5] = S[4];
+ S[4] = S[3];
+ S[3] = S[2];
+ S[2] = S[1];
+ S[1] = S[0];
+ S[0] = t;
+ }
+
+ // Feedback
+ for( i=0; i<8; i++ )
+ {
+ Context->state[i] = Context->state[i] + S[i];
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC FUNCTIONS
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Sha256Initialise
+//
+// Initialises a SHA256 Context. Use this to initialise/reset a context.
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+void
+ Sha256Initialise
+ (
+ Sha256Context* Context // [out]
+ )
+{
+ Context->curlen = 0;
+ Context->length = 0;
+ Context->state[0] = 0x6A09E667UL;
+ Context->state[1] = 0xBB67AE85UL;
+ Context->state[2] = 0x3C6EF372UL;
+ Context->state[3] = 0xA54FF53AUL;
+ Context->state[4] = 0x510E527FUL;
+ Context->state[5] = 0x9B05688CUL;
+ Context->state[6] = 0x1F83D9ABUL;
+ Context->state[7] = 0x5BE0CD19UL;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Sha256Update
+//
+// Adds data to the SHA256 context. This will process the data and update the internal state of the context. Keep on
+// calling this function until all the data has been added. Then call Sha256Finalise to calculate the hash.
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+void
+ Sha256Update
+ (
+ Sha256Context* Context, // [in out]
+ void const* Buffer, // [in]
+ uint32_t BufferSize // [in]
+ )
+{
+ uint32_t n;
+
+ if( Context->curlen > sizeof(Context->buf) )
+ {
+ return;
+ }
+
+ while( BufferSize > 0 )
+ {
+ if( Context->curlen == 0 && BufferSize >= BLOCK_SIZE )
+ {
+ TransformFunction( Context, (uint8_t*)Buffer );
+ Context->length += BLOCK_SIZE * 8;
+ Buffer = (uint8_t*)Buffer + BLOCK_SIZE;
+ BufferSize -= BLOCK_SIZE;
+ }
+ else
+ {
+ n = MIN( BufferSize, (BLOCK_SIZE - Context->curlen) );
+ memcpy( Context->buf + Context->curlen, Buffer, (size_t)n );
+ Context->curlen += n;
+ Buffer = (uint8_t*)Buffer + n;
+ BufferSize -= n;
+ if( Context->curlen == BLOCK_SIZE )
+ {
+ TransformFunction( Context, Context->buf );
+ Context->length += 8*BLOCK_SIZE;
+ Context->curlen = 0;
+ }
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Sha256Finalise
+//
+// Performs the final calculation of the hash and returns the digest (32 byte buffer containing 256bit hash). After
+// calling this, Sha256Initialised must be used to reuse the context.
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+void
+ Sha256Finalise
+ (
+ Sha256Context* Context, // [in out]
+ SHA256_HASH* Digest // [out]
+ )
+{
+ int i;
+
+ if( Context->curlen >= sizeof(Context->buf) )
+ {
+ return;
+ }
+
+ // Increase the length of the message
+ Context->length += Context->curlen * 8;
+
+ // Append the '1' bit
+ Context->buf[Context->curlen++] = (uint8_t)0x80;
+
+ // if the length is currently above 56 bytes we append zeros
+ // then compress. Then we can fall back to padding zeros and length
+ // encoding like normal.
+ if( Context->curlen > 56 )
+ {
+ while( Context->curlen < 64 )
+ {
+ Context->buf[Context->curlen++] = (uint8_t)0;
+ }
+ TransformFunction(Context, Context->buf);
+ Context->curlen = 0;
+ }
+
+ // Pad up to 56 bytes of zeroes
+ while( Context->curlen < 56 )
+ {
+ Context->buf[Context->curlen++] = (uint8_t)0;
+ }
+
+ // Store length
+ STORE64H( Context->length, Context->buf+56 );
+ TransformFunction( Context, Context->buf );
+
+ // Copy output
+ for( i=0; i<8; i++ )
+ {
+ STORE32H( Context->state[i], Digest->bytes+(4*i) );
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Sha256Calculate
+//
+// Combines Sha256Initialise, Sha256Update, and Sha256Finalise into one function. Calculates the SHA256 hash of the
+// buffer.
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+void
+ Sha256Calculate
+ (
+ void const* Buffer, // [in]
+ uint32_t BufferSize, // [in]
+ SHA256_HASH* Digest // [in]
+ )
+{
+ Sha256Context context;
+
+ Sha256Initialise( &context );
+ Sha256Update( &context, Buffer, BufferSize );
+ Sha256Finalise( &context, Digest );
+}
diff --git a/libsemanage/src/sha256.h b/libsemanage/src/sha256.h
new file mode 100644
index 00000000..406ed869
--- /dev/null
+++ b/libsemanage/src/sha256.h
@@ -0,0 +1,89 @@
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// WjCryptLib_Sha256
+//
+// Implementation of SHA256 hash function.
+// Original author: Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+// Modified by WaterJuice retaining Public Domain license.
+//
+// This is free and unencumbered software released into the public domain - June 2013 waterjuice.org
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// IMPORTS
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include <stdint.h>
+#include <stdio.h>
+
+typedef struct
+{
+ uint64_t length;
+ uint32_t state[8];
+ uint32_t curlen;
+ uint8_t buf[64];
+} Sha256Context;
+
+#define SHA256_HASH_SIZE ( 256 / 8 )
+
+typedef struct
+{
+ uint8_t bytes [SHA256_HASH_SIZE];
+} SHA256_HASH;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC FUNCTIONS
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Sha256Initialise
+//
+// Initialises a SHA256 Context. Use this to initialise/reset a context.
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+void
+ Sha256Initialise
+ (
+ Sha256Context* Context // [out]
+ );
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Sha256Update
+//
+// Adds data to the SHA256 context. This will process the data and update the internal state of the context. Keep on
+// calling this function until all the data has been added. Then call Sha256Finalise to calculate the hash.
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+void
+ Sha256Update
+ (
+ Sha256Context* Context, // [in out]
+ void const* Buffer, // [in]
+ uint32_t BufferSize // [in]
+ );
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Sha256Finalise
+//
+// Performs the final calculation of the hash and returns the digest (32 byte buffer containing 256bit hash). After
+// calling this, Sha256Initialised must be used to reuse the context.
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+void
+ Sha256Finalise
+ (
+ Sha256Context* Context, // [in out]
+ SHA256_HASH* Digest // [out]
+ );
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Sha256Calculate
+//
+// Combines Sha256Initialise, Sha256Update, and Sha256Finalise into one function. Calculates the SHA256 hash of the
+// buffer.
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+void
+ Sha256Calculate
+ (
+ void const* Buffer, // [in]
+ uint32_t BufferSize, // [in]
+ SHA256_HASH* Digest // [in]
+ );
diff --git a/libsemanage/src/users_base_file.c b/libsemanage/src/users_base_file.c
index 0f0a8fdb..a0f8cd7e 100644
--- a/libsemanage/src/users_base_file.c
+++ b/libsemanage/src/users_base_file.c
@@ -83,7 +83,7 @@ static int user_base_parse(semanage_handle_t * handle,
goto err;
/* Parse user name */
- if (parse_fetch_string(handle, info, &name_str, ' ') < 0)
+ if (parse_fetch_string(handle, info, &name_str, ' ', 0) < 0)
goto err;
if (semanage_user_base_set_name(handle, user, name_str) < 0) {
@@ -150,7 +150,7 @@ static int user_base_parse(semanage_handle_t * handle,
goto err;
/* NOTE: does not allow spaces/multiline */
- if (parse_fetch_string(handle, info, &str, ' ') < 0)
+ if (parse_fetch_string(handle, info, &str, ' ', 0) < 0)
goto err;
if (semanage_user_base_set_mlslevel(handle, user, str) < 0)
goto err;
@@ -165,8 +165,7 @@ static int user_base_parse(semanage_handle_t * handle,
if (parse_assert_space(handle, info) < 0)
goto err;
- /* NOTE: does not allow spaces/multiline */
- if (parse_fetch_string(handle, info, &str, ';') < 0)
+ if (parse_fetch_string(handle, info, &str, ';', 1) < 0)
goto err;
if (semanage_user_base_set_mlsrange(handle, user, str) < 0)
goto err;
diff --git a/libsemanage/src/users_extra_file.c b/libsemanage/src/users_extra_file.c
index 8f2bebd6..7aa9df3c 100644
--- a/libsemanage/src/users_extra_file.c
+++ b/libsemanage/src/users_extra_file.c
@@ -57,7 +57,7 @@ static int user_extra_parse(semanage_handle_t * handle,
goto err;
/* Extract name */
- if (parse_fetch_string(handle, info, &str, ' ') < 0)
+ if (parse_fetch_string(handle, info, &str, ' ', 0) < 0)
goto err;
if (semanage_user_extra_set_name(handle, user_extra, str) < 0)
goto err;
@@ -73,7 +73,7 @@ static int user_extra_parse(semanage_handle_t * handle,
goto err;
/* Extract prefix */
- if (parse_fetch_string(handle, info, &str, ';') < 0)
+ if (parse_fetch_string(handle, info, &str, ';', 1) < 0)
goto err;
if (semanage_user_extra_set_prefix(handle, user_extra, str) < 0)
goto err;
diff --git a/libsemanage/src/utilities.c b/libsemanage/src/utilities.c
index fc5a6a51..fdbb8ad6 100644
--- a/libsemanage/src/utilities.c
+++ b/libsemanage/src/utilities.c
@@ -292,7 +292,7 @@ char *semanage_str_replace(const char *search, const char *replace,
*
* returns the newly created node or NULL on error
*/
-semanage_list_t *list_addafter_controlmem(semanage_list_t * item, char *data)
+static semanage_list_t *list_addafter_controlmem(semanage_list_t * item, char *data)
{
semanage_list_t *temp = malloc(sizeof(semanage_list_t));
diff --git a/libsemanage/tests/test_bool.c b/libsemanage/tests/test_bool.c
index ae80d448..7bf5225b 100644
--- a/libsemanage/tests/test_bool.c
+++ b/libsemanage/tests/test_bool.c
@@ -132,6 +132,8 @@ semanage_bool_t *get_bool_nth(int idx)
if (i != (unsigned int) idx)
semanage_bool_free(records[i]);
+ free(records);
+
return boolean;
}
@@ -163,6 +165,8 @@ semanage_bool_key_t *get_bool_key_nth(int idx)
CU_ASSERT_FATAL(res >= 0);
CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+ semanage_bool_free(boolean);
+
return key;
}
@@ -196,6 +200,9 @@ void add_local_bool(const char *name)
CU_ASSERT_PTR_NOT_NULL_FATAL(boolean);
CU_ASSERT_FATAL(semanage_bool_modify_local(sh, key, boolean) >= 0);
+
+ semanage_bool_key_free(key);
+ semanage_bool_free(boolean);
}
void delete_local_bool(const char *name)
@@ -208,6 +215,8 @@ void delete_local_bool(const char *name)
CU_ASSERT_PTR_NOT_NULL_FATAL(key);
CU_ASSERT_FATAL(semanage_bool_del_local(sh, key) >= 0);
+
+ semanage_bool_key_free(key);
}
/* Function bool_key_create */
@@ -447,6 +456,8 @@ void helper_bool_create(level_t level)
CU_ASSERT_PTR_NULL(semanage_bool_get_name(boolean));
CU_ASSERT(semanage_bool_get_value(boolean) == 0);
+ semanage_bool_free(boolean);
+
cleanup_handle(level);
}
@@ -483,6 +494,9 @@ void helper_bool_clone(level_t level, int bool_idx)
CU_ASSERT_EQUAL(val, val_clone);
+ semanage_bool_free(boolean_clone);
+ semanage_bool_free(boolean);
+
cleanup_handle(level);
}
@@ -514,6 +528,9 @@ void helper_bool_query(level_t level, const char *bool_str, int exp_res)
CU_ASSERT_PTR_NULL(resp);
}
+ semanage_bool_free(resp);
+ semanage_bool_key_free(key);
+
cleanup_handle(level);
}
@@ -647,6 +664,8 @@ void helper_bool_list(level_t level)
for (unsigned int i = 0; i < count; i++)
semanage_bool_free(records[i]);
+ free(records);
+
cleanup_handle(level);
}
@@ -662,7 +681,7 @@ void helper_bool_modify_del_local(level_t level, const char *name,
int old_val, int exp_res)
{
semanage_bool_t *boolean;
- semanage_bool_t *boolean_local;
+ semanage_bool_t *boolean_local = NULL;
semanage_bool_key_t *key = NULL;
int res;
int new_val;
@@ -696,6 +715,8 @@ void helper_bool_modify_del_local(level_t level, const char *name,
CU_ASSERT(semanage_bool_query_local(sh, key,
&boolean_local) >= 0);
CU_ASSERT(semanage_bool_compare2(boolean_local, boolean) == 0);
+ semanage_bool_free(boolean_local);
+
CU_ASSERT(semanage_bool_del_local(sh, key) >= 0);
CU_ASSERT(semanage_bool_query_local(sh, key,
&boolean_local) < 0);
@@ -734,15 +755,18 @@ void test_bool_query_local(void)
/* transaction */
setup_handle(SH_TRANS);
+ semanage_bool_key_free(key);
CU_ASSERT(semanage_bool_key_create(sh, BOOL1_NAME, &key) >= 0);
CU_ASSERT_PTR_NOT_NULL(key);
CU_ASSERT(semanage_bool_query_local(sh, key, &resp) < 0);
CU_ASSERT_PTR_NULL(resp);
+ semanage_bool_free(resp);
add_local_bool(BOOL1_NAME);
CU_ASSERT(semanage_bool_query_local(sh, key, &resp) >= 0);
CU_ASSERT_PTR_NOT_NULL(resp);
+ semanage_bool_free(resp);
semanage_bool_key_free(key);
CU_ASSERT(semanage_bool_key_create(sh, BOOL2_NAME, &key) >= 0);
@@ -751,8 +775,10 @@ void test_bool_query_local(void)
add_local_bool(BOOL2_NAME);
CU_ASSERT(semanage_bool_query_local(sh, key, &resp) >= 0);
CU_ASSERT_PTR_NOT_NULL(resp);
+ semanage_bool_free(resp);
/* cleanup */
+ semanage_bool_key_free(key);
delete_local_bool(BOOL1_NAME);
delete_local_bool(BOOL2_NAME);
cleanup_handle(SH_TRANS);
@@ -784,6 +810,7 @@ void test_bool_exists_local(void)
CU_ASSERT(resp == 0);
/* cleanup */
+ semanage_bool_key_free(key);
cleanup_handle(SH_TRANS);
}
@@ -918,12 +945,17 @@ void test_bool_list_local(void)
CU_ASSERT(semanage_bool_list_local(sh, &records, &count) >= 0);
CU_ASSERT(count == init_count + 1);
CU_ASSERT_PTR_NOT_NULL(records[0]);
+ semanage_bool_free(records[0]);
+ free(records);
add_local_bool(BOOL2_NAME);
CU_ASSERT(semanage_bool_list_local(sh, &records, &count) >= 0);
CU_ASSERT(count == init_count + 2);
CU_ASSERT_PTR_NOT_NULL(records[0]);
CU_ASSERT_PTR_NOT_NULL(records[1]);
+ semanage_bool_free(records[0]);
+ semanage_bool_free(records[1]);
+ free(records);
/* cleanup */
delete_local_bool(BOOL1_NAME);
diff --git a/libsemanage/tests/test_fcontext.c b/libsemanage/tests/test_fcontext.c
index 62af711f..a5fcf849 100644
--- a/libsemanage/tests/test_fcontext.c
+++ b/libsemanage/tests/test_fcontext.c
@@ -214,6 +214,8 @@ semanage_fcontext_t *get_fcontext_nth(int idx)
if (i != (unsigned int) idx)
semanage_fcontext_free(records[i]);
+ free(records);
+
return fcontext;
}
@@ -230,6 +232,8 @@ semanage_fcontext_key_t *get_fcontext_key_nth(int idx)
CU_ASSERT_FATAL(semanage_fcontext_key_extract(sh, fcontext, &key) >= 0);
CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+ semanage_fcontext_free(fcontext);
+
return key;
}
@@ -246,6 +250,10 @@ void add_local_fcontext(int fcontext_idx)
CU_ASSERT_PTR_NOT_NULL_FATAL(key);
CU_ASSERT_FATAL(semanage_fcontext_modify_local(sh, key, fcontext) >= 0);
+
+ /* cleanup */
+ semanage_fcontext_key_free(key);
+ semanage_fcontext_free(fcontext);
}
void delete_local_fcontext(int fcontext_idx)
@@ -257,6 +265,8 @@ void delete_local_fcontext(int fcontext_idx)
key = get_fcontext_key_nth(fcontext_idx);
CU_ASSERT_FATAL(semanage_fcontext_del_local(sh, key) >= 0);
+
+ semanage_fcontext_key_free(key);
}
semanage_fcontext_key_t *get_fcontext_key_from_str(const char *str, int type)
@@ -477,6 +487,7 @@ void helper_fcontext_get_set_con(level_t level, int fcontext_idx,
}
/* cleanup */
+ semanage_context_free(con);
semanage_fcontext_free(fcontext);
cleanup_handle(level);
}
@@ -587,12 +598,14 @@ void helper_fcontext_query(level_t level, const char *fcontext_expr,
CU_ASSERT(res >= 0);
const char *expr = semanage_fcontext_get_expr(resp);
CU_ASSERT_STRING_EQUAL(expr, fcontext_expr);
+ semanage_fcontext_free(resp);
} else {
CU_ASSERT(res < 0);
CU_ASSERT(resp == (void *) 42);
}
/* cleanup */
+ semanage_fcontext_key_free(key);
cleanup_handle(level);
}
@@ -752,6 +765,8 @@ void helper_fcontext_list(level_t level)
for (unsigned int i = 0; i < count; i++)
semanage_fcontext_free(records[i]);
+ free(records);
+
/* cleanup */
cleanup_handle(level);
}
@@ -768,7 +783,7 @@ void helper_fcontext_modify_del_local(level_t level, int fcontext_idx,
const char *con_str, int exp_res)
{
semanage_fcontext_t *fcontext;
- semanage_fcontext_t *fcontext_local;
+ semanage_fcontext_t *fcontext_local = NULL;
semanage_fcontext_key_t *key = NULL;
semanage_context_t *con = NULL;
int res;
@@ -803,6 +818,8 @@ void helper_fcontext_modify_del_local(level_t level, int fcontext_idx,
&fcontext_local) >= 0);
CU_ASSERT(semanage_fcontext_compare2(fcontext_local,
fcontext) == 0);
+ semanage_fcontext_free(fcontext_local);
+
CU_ASSERT(semanage_fcontext_del_local(sh, key) >= 0);
CU_ASSERT(semanage_fcontext_query_local(sh, key,
&fcontext_local) < 0);
@@ -811,6 +828,7 @@ void helper_fcontext_modify_del_local(level_t level, int fcontext_idx,
}
/* cleanup */
+ semanage_context_free(con);
semanage_fcontext_key_free(key);
semanage_fcontext_free(fcontext);
cleanup_handle(level);
@@ -846,6 +864,7 @@ void test_fcontext_query_local(void)
/* transaction */
setup_handle(SH_TRANS);
+ semanage_fcontext_key_free(key);
key = get_fcontext_key_nth(I_FIRST);
CU_ASSERT(semanage_fcontext_query_local(sh, key, &resp) < 0);
CU_ASSERT_PTR_NULL(resp);
@@ -853,14 +872,19 @@ void test_fcontext_query_local(void)
add_local_fcontext(I_FIRST);
CU_ASSERT(semanage_fcontext_query_local(sh, key, &resp) >= 0);
CU_ASSERT_PTR_NOT_NULL(resp);
+ semanage_fcontext_free(resp);
+ resp = NULL;
semanage_fcontext_key_free(key);
key = get_fcontext_key_nth(I_SECOND);
add_local_fcontext(I_SECOND);
CU_ASSERT(semanage_fcontext_query_local(sh, key, &resp) >= 0);
CU_ASSERT_PTR_NOT_NULL(resp);
+ semanage_fcontext_free(resp);
+ resp = NULL;
/* cleanup */
+ semanage_fcontext_key_free(key);
delete_local_fcontext(I_FIRST);
delete_local_fcontext(I_SECOND);
cleanup_handle(SH_TRANS);
@@ -898,6 +922,7 @@ void test_fcontext_exists_local(void)
CU_ASSERT(resp == 0);
/* cleanup */
+ semanage_fcontext_key_free(key);
cleanup_handle(SH_TRANS);
}
@@ -1031,12 +1056,17 @@ void test_fcontext_list_local(void)
CU_ASSERT(semanage_fcontext_list_local(sh, &records, &count) >= 0);
CU_ASSERT(count == 1);
CU_ASSERT_PTR_NOT_NULL(records[0]);
+ semanage_fcontext_free(records[0]);
+ free(records);
add_local_fcontext(I_SECOND);
CU_ASSERT(semanage_fcontext_list_local(sh, &records, &count) >= 0);
CU_ASSERT(count == 2);
CU_ASSERT_PTR_NOT_NULL(records[0]);
CU_ASSERT_PTR_NOT_NULL(records[1]);
+ semanage_fcontext_free(records[0]);
+ semanage_fcontext_free(records[1]);
+ free(records);
/* cleanup */
delete_local_fcontext(I_FIRST);
diff --git a/libsemanage/tests/test_ibendport.c b/libsemanage/tests/test_ibendport.c
index 79a8e2c8..8addc908 100644
--- a/libsemanage/tests/test_ibendport.c
+++ b/libsemanage/tests/test_ibendport.c
@@ -113,6 +113,8 @@ semanage_ibendport_t *get_ibendport_nth(int idx)
if (i != (unsigned int) idx)
semanage_ibendport_free(records[i]);
+ free(records);
+
return ibendport;
}
@@ -132,6 +134,8 @@ semanage_ibendport_key_t *get_ibendport_key_nth(int idx)
CU_ASSERT_FATAL(res >= 0);
CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+ semanage_ibendport_free(ibendport);
+
return key;
}
@@ -148,6 +152,9 @@ void add_local_ibendport(int idx)
CU_ASSERT_FATAL(semanage_ibendport_modify_local(sh, key,
ibendport) >= 0);
+
+ semanage_ibendport_key_free(key);
+ semanage_ibendport_free(ibendport);
}
void delete_local_ibendport(int idx)
@@ -155,6 +162,8 @@ void delete_local_ibendport(int idx)
semanage_ibendport_key_t *key = NULL;
key = get_ibendport_key_nth(idx);
CU_ASSERT_FATAL(semanage_ibendport_del_local(sh, key) >= 0);
+
+ semanage_ibendport_key_free(key);
}
/* Function semanage_ibendport_query */
@@ -195,7 +204,9 @@ void test_ibendport_query(void)
CU_ASSERT_CONTEXT_EQUAL(con, con_exp);
/* cleanup */
+ free(name_exp);
free(name);
+ semanage_ibendport_key_free(key);
semanage_ibendport_free(ibendport);
semanage_ibendport_free(ibendport_exp);
cleanup_handle(SH_CONNECT);
@@ -356,12 +367,14 @@ void test_ibendport_modify_del_query_local(void)
CU_ASSERT(semanage_ibendport_query_local(sh, key,
&ibendport_local) >= 0);
CU_ASSERT_PTR_NOT_NULL_FATAL(ibendport_local);
+ semanage_ibendport_free(ibendport_local);
CU_ASSERT(semanage_ibendport_del_local(sh, key) >= 0);
CU_ASSERT(semanage_ibendport_query_local(sh, key,
&ibendport_local) < 0);
/* cleanup */
+ semanage_ibendport_key_free(key);
semanage_ibendport_free(ibendport);
cleanup_handle(SH_TRANS);
}
diff --git a/libsemanage/tests/test_iface.c b/libsemanage/tests/test_iface.c
index d5d530a8..434372f8 100644
--- a/libsemanage/tests/test_iface.c
+++ b/libsemanage/tests/test_iface.c
@@ -139,6 +139,8 @@ semanage_iface_t *get_iface_nth(int idx)
if (i != (unsigned int) idx)
semanage_iface_free(records[i]);
+ free(records);
+
return iface;
}
@@ -157,6 +159,9 @@ semanage_iface_key_t *get_iface_key_nth(int idx)
CU_ASSERT_FATAL(res >= 0);
CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+ /* cleanup */
+ semanage_iface_free(iface);
+
return key;
}
@@ -171,6 +176,10 @@ void add_local_iface(int idx)
CU_ASSERT_PTR_NOT_NULL_FATAL(key);
CU_ASSERT_FATAL(semanage_iface_modify_local(sh, key, iface) >= 0);
+
+ /* cleanup */
+ semanage_iface_key_free(key);
+ semanage_iface_free(iface);
}
void delete_local_iface(int idx)
@@ -178,6 +187,9 @@ void delete_local_iface(int idx)
semanage_iface_key_t *key = NULL;
key = get_iface_key_nth(idx);
CU_ASSERT_FATAL(semanage_iface_del_local(sh, key) >= 0);
+
+ /* cleanup */
+ semanage_iface_key_free(key);
}
/* Function semanage_iface_compare */
@@ -309,6 +321,7 @@ void test_iface_get_set_ifcon(void)
CU_ASSERT_CONTEXT_EQUAL(con1, con2);
/* cleanup */
+ semanage_context_free(con1);
semanage_iface_free(iface);
cleanup_handle(SH_CONNECT);
}
@@ -332,6 +345,7 @@ void test_iface_get_set_msgcon(void)
CU_ASSERT_CONTEXT_EQUAL(con1, con2);
/* cleanup */
+ semanage_context_free(con1);
semanage_iface_free(iface);
cleanup_handle(SH_CONNECT);
}
@@ -357,6 +371,8 @@ void test_iface_create(void)
CU_ASSERT(semanage_iface_set_msgcon(sh, iface, msgcon) >= 0);
/* cleanup */
+ semanage_context_free(msgcon);
+ semanage_context_free(ifcon);
semanage_iface_free(iface);
cleanup_handle(SH_CONNECT);
}
@@ -393,6 +409,8 @@ void test_iface_clone(void)
CU_ASSERT_CONTEXT_EQUAL(msgcon, msgcon2);
/* cleanup */
+ semanage_context_free(msgcon);
+ semanage_context_free(ifcon);
semanage_iface_free(iface);
semanage_iface_free(iface_clone);
cleanup_handle(SH_CONNECT);
@@ -426,6 +444,7 @@ void test_iface_query(void)
CU_ASSERT_CONTEXT_EQUAL(con, con_exp);
/* cleanup */
+ semanage_iface_key_free(key);
semanage_iface_free(iface);
semanage_iface_free(iface_exp);
cleanup_handle(SH_CONNECT);
@@ -513,6 +532,8 @@ void test_iface_list(void)
for (unsigned int i = 0; i < count; i++)
semanage_iface_free(records[i]);
+ free(records);
+
/* cleanup */
cleanup_handle(SH_CONNECT);
}
@@ -541,11 +562,13 @@ void test_iface_modify_del_query_local(void)
CU_ASSERT(semanage_iface_query_local(sh, key, &iface_local) >= 0);
CU_ASSERT_PTR_NOT_NULL_FATAL(iface_local);
+ semanage_iface_free(iface_local);
CU_ASSERT(semanage_iface_del_local(sh, key) >= 0);
CU_ASSERT(semanage_iface_query_local(sh, key, &iface_local) < 0);
/* cleanup */
+ semanage_iface_key_free(key);
semanage_iface_free(iface);
cleanup_handle(SH_TRANS);
}
@@ -658,6 +681,7 @@ void test_iface_list_local(void)
/* cleanup */
for (unsigned int i = 0; i < count; i++)
semanage_iface_free(records[i]);
+ free(records);
delete_local_iface(I_FIRST);
delete_local_iface(I_SECOND);
diff --git a/libsemanage/tests/test_node.c b/libsemanage/tests/test_node.c
index 53c2eb69..e49e8c3b 100644
--- a/libsemanage/tests/test_node.c
+++ b/libsemanage/tests/test_node.c
@@ -148,6 +148,8 @@ semanage_node_t *get_node_nth(int idx)
if (i != (unsigned int) idx)
semanage_node_free(records[i]);
+ free(records);
+
return node;
}
@@ -167,6 +169,8 @@ semanage_node_key_t *get_node_key_nth(int idx)
CU_ASSERT_FATAL(res >= 0);
CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+ semanage_node_free(node);
+
return key;
}
@@ -181,6 +185,10 @@ void add_local_node(int idx)
CU_ASSERT_PTR_NOT_NULL_FATAL(key);
CU_ASSERT_FATAL(semanage_node_modify_local(sh, key, node) >= 0);
+
+ /* cleanup */
+ semanage_node_key_free(key);
+ semanage_node_free(node);
}
void delete_local_node(int idx)
@@ -190,6 +198,9 @@ void delete_local_node(int idx)
key = get_node_key_nth(idx);
CU_ASSERT_FATAL(semanage_node_del_local(sh, key) >= 0);
+
+ /* cleanup */
+ semanage_node_key_free(key);
}
/* Function semanage_node_compare */
@@ -305,6 +316,7 @@ void test_node_get_set_addr(void)
CU_ASSERT_STRING_EQUAL(addr, "192.168.0.1");
/* cleanup */
+ free(addr);
semanage_node_free(node);
cleanup_handle(SH_CONNECT);
}
@@ -334,6 +346,7 @@ void test_node_get_set_addr_bytes(void)
CU_ASSERT(addr1[i] == addr2[i]);
/* cleanup */
+ free(addr2);
semanage_node_free(node);
cleanup_handle(SH_CONNECT);
}
@@ -357,6 +370,7 @@ void test_node_get_set_mask(void)
CU_ASSERT_STRING_EQUAL(mask, "255.255.255.0");
/* cleanup */
+ free(mask);
semanage_node_free(node);
cleanup_handle(SH_CONNECT);
}
@@ -386,6 +400,7 @@ void test_node_get_set_mask_bytes(void)
CU_ASSERT(mask1[i] == mask2[i]);
/* cleanup */
+ free(mask2);
semanage_node_free(node);
cleanup_handle(SH_CONNECT);
}
@@ -436,6 +451,7 @@ void test_node_get_set_con(void)
CU_ASSERT_CONTEXT_EQUAL(con1, con2);
/* cleanup */
+ semanage_context_free(con1);
semanage_node_free(node);
cleanup_handle(SH_CONNECT);
}
@@ -461,6 +477,7 @@ void test_node_create(void)
CU_ASSERT(semanage_node_set_con(sh, node, con) >= 0);
/* cleanup */
+ semanage_context_free(con);
semanage_node_free(node);
cleanup_handle(SH_CONNECT);
}
@@ -508,6 +525,9 @@ void test_node_clone(void)
CU_ASSERT_CONTEXT_EQUAL(con, con2);
/* cleanup */
+ free(mask2);
+ free(addr2);
+ semanage_context_free(con);
semanage_node_free(node);
semanage_node_free(node_clone);
cleanup_handle(SH_CONNECT);
@@ -552,6 +572,8 @@ void test_node_query(void)
CU_ASSERT_CONTEXT_EQUAL(con, con_exp);
/* cleanup */
+ semanage_node_key_free(key);
+ semanage_node_free(node_exp);
semanage_node_free(node);
cleanup_handle(SH_CONNECT);
}
@@ -638,6 +660,8 @@ void test_node_list(void)
for (unsigned int i = 0; i < count; i++)
semanage_node_free(records[i]);
+ free(records);
+
/* cleanup */
cleanup_handle(SH_CONNECT);
}
@@ -679,6 +703,7 @@ void test_node_modify_del_query_local(void)
CU_ASSERT(semanage_node_query_local(sh, key, &node_local) >= 0);
CU_ASSERT_PTR_NOT_NULL_FATAL(node_local);
+ semanage_node_free(node_local);
CU_ASSERT(semanage_node_del_local(sh, key) >= 0);
CU_ASSERT(semanage_node_del_local(sh, key_tmp) >= 0);
@@ -686,6 +711,8 @@ void test_node_modify_del_query_local(void)
CU_ASSERT(semanage_node_query_local(sh, key, &node_local) < 0);
/* cleanup */
+ semanage_node_key_free(key_tmp);
+ semanage_node_key_free(key);
semanage_node_free(node);
semanage_node_free(node_tmp);
cleanup_handle(SH_TRANS);
@@ -800,6 +827,8 @@ void test_node_list_local(void)
for (unsigned int i = 0; i < count; i++)
semanage_node_free(records[i]);
+ free(records);
+
delete_local_node(I_FIRST);
delete_local_node(I_SECOND);
delete_local_node(I_THIRD);
diff --git a/libsemanage/tests/test_other.c b/libsemanage/tests/test_other.c
index c4ee0ed8..0a57e247 100644
--- a/libsemanage/tests/test_other.c
+++ b/libsemanage/tests/test_other.c
@@ -81,6 +81,9 @@ void test_semanage_context(void)
assert(str);
CU_ASSERT_STRING_EQUAL(str, "user_u:role_r:type_t:s0");
+ semanage_context_free(con);
+ con = NULL;
+
CU_ASSERT(semanage_context_from_string(sh, "my_u:my_r:my_t:s0",
&con) >= 0);
CU_ASSERT_STRING_EQUAL(semanage_context_get_user(con), "my_u");
@@ -95,6 +98,7 @@ void test_semanage_context(void)
CU_ASSERT_STRING_EQUAL(semanage_context_get_mls(con_clone), "s0");
/* cleanup */
+ free(str);
semanage_context_free(con);
semanage_context_free(con_clone);
cleanup_handle(SH_CONNECT);
@@ -115,6 +119,8 @@ void test_debug(void)
CU_ASSERT(semanage_module_info_set_priority(sh, modinfo, -42) < 0);
/* cleanup */
+ semanage_module_info_destroy(sh, modinfo);
+ free(modinfo);
CU_ASSERT(semanage_disconnect(sh) >= 0);
semanage_handle_destroy(sh);
}
diff --git a/libsemanage/tests/test_port.c b/libsemanage/tests/test_port.c
index 0408be4d..f4c6ec21 100644
--- a/libsemanage/tests/test_port.c
+++ b/libsemanage/tests/test_port.c
@@ -146,6 +146,8 @@ semanage_port_t *get_port_nth(int idx)
if (i != (unsigned int) idx)
semanage_port_free(records[i]);
+ free(records);
+
return port;
}
@@ -165,6 +167,9 @@ semanage_port_key_t *get_port_key_nth(int idx)
CU_ASSERT_FATAL(res >= 0);
CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+ /* cleanup */
+ semanage_port_free(port);
+
return key;
}
@@ -181,6 +186,10 @@ void add_local_port(int port_idx)
CU_ASSERT_PTR_NOT_NULL_FATAL(key);
CU_ASSERT_FATAL(semanage_port_modify_local(sh, key, port) >= 0);
+
+ /* cleanup */
+ semanage_port_key_free(key);
+ semanage_port_free(port);
}
void delete_local_port(int port_idx)
@@ -192,6 +201,8 @@ void delete_local_port(int port_idx)
key = get_port_key_nth(port_idx);
CU_ASSERT_FATAL(semanage_port_del_local(sh, key) >= 0);
+
+ semanage_port_key_free(key);
}
/* Function semanage_port_compare */
@@ -447,6 +458,7 @@ void test_port_clone(void)
CU_ASSERT_CONTEXT_EQUAL(con, con2);
/* cleanup */
+ semanage_context_free(con);
semanage_port_free(port);
semanage_port_free(port_clone);
cleanup_handle(SH_CONNECT);
@@ -480,6 +492,7 @@ void test_port_query(void)
CU_ASSERT_CONTEXT_EQUAL(con, con_exp);
/* cleanup */
+ semanage_port_key_free(key);
semanage_port_free(port);
semanage_port_free(port_exp);
cleanup_handle(SH_CONNECT);
@@ -567,6 +580,8 @@ void test_port_list(void)
for (unsigned int i = 0; i < count; i++)
semanage_port_free(records[i]);
+ free(records);
+
cleanup_handle(SH_CONNECT);
}
@@ -594,11 +609,14 @@ void test_port_modify_del_local(void)
con_local = semanage_port_get_con(port_local);
CU_ASSERT_CONTEXT_EQUAL(con, con_local);
+ semanage_port_free(port_local);
CU_ASSERT(semanage_port_del_local(sh, key) >= 0);
CU_ASSERT(semanage_port_query_local(sh, key, &port_local) < 0);
/* cleanup */
+ semanage_context_free(con);
+ semanage_port_key_free(key);
semanage_port_free(port);
cleanup_handle(SH_TRANS);
}
@@ -633,6 +651,7 @@ void test_port_query_local(void)
/* cleanup */
delete_local_port(I_FIRST);
+ semanage_port_key_free(key);
semanage_port_free(port);
semanage_port_free(port_exp);
cleanup_handle(SH_TRANS);
@@ -747,6 +766,8 @@ void test_port_list_local(void)
for (unsigned int i = 0; i < count; i++)
semanage_port_free(records[i]);
+ free(records);
+
delete_local_port(I_FIRST);
delete_local_port(I_SECOND);
delete_local_port(I_THIRD);
@@ -773,6 +794,7 @@ void helper_port_validate_local_noport(void)
helper_commit();
/* cleanup */
+ semanage_port_key_free(key);
helper_begin_transaction();
delete_local_port(I_FIRST);
cleanup_handle(SH_TRANS);
@@ -832,6 +854,8 @@ void helper_port_validate_local_twoports(void)
helper_begin_transaction();
CU_ASSERT(semanage_port_del_local(sh, key1) >= 0);
CU_ASSERT(semanage_port_del_local(sh, key2) >= 0);
+ semanage_context_free(con2);
+ semanage_context_free(con1);
semanage_port_key_free(key1);
semanage_port_key_free(key2);
semanage_port_free(port1);
diff --git a/libsemanage/tests/test_user.c b/libsemanage/tests/test_user.c
index cd082030..c3835c8d 100644
--- a/libsemanage/tests/test_user.c
+++ b/libsemanage/tests/test_user.c
@@ -130,6 +130,8 @@ semanage_user_t *get_user_nth(int idx)
if (i != (unsigned int) idx)
semanage_user_free(records[i]);
+ free(records);
+
return user;
}
@@ -149,6 +151,8 @@ semanage_user_key_t *get_user_key_nth(int idx)
CU_ASSERT_FATAL(res >= 0);
CU_ASSERT_PTR_NOT_NULL_FATAL(key);
+ semanage_user_free(user);
+
return key;
}
@@ -165,6 +169,9 @@ void add_local_user(int user_idx)
CU_ASSERT_PTR_NOT_NULL_FATAL(key);
CU_ASSERT_FATAL(semanage_user_modify_local(sh, key, user) >= 0);
+
+ semanage_user_key_free(key);
+ semanage_user_free(user);
}
void delete_local_user(int user_idx)
@@ -176,6 +183,8 @@ void delete_local_user(int user_idx)
key = get_user_key_nth(user_idx);
CU_ASSERT_FATAL(semanage_user_del_local(sh, key) >= 0);
+
+ semanage_user_key_free(key);
}
/* Function semanage_user_compare */
@@ -391,6 +400,7 @@ void test_user_roles(void)
CU_ASSERT(semanage_user_get_num_roles(user) == 0);
/* cleanup */
+ free(roles_arr);
semanage_user_free(user);
cleanup_handle(SH_CONNECT);
}
@@ -459,6 +469,7 @@ void test_user_query(void)
CU_ASSERT_PTR_NOT_NULL(user);
/* cleanup */
+ semanage_user_key_free(key);
semanage_user_free(user);
cleanup_handle(SH_CONNECT);
}
@@ -546,6 +557,8 @@ void test_user_list(void)
for (unsigned int i = 0; i < count; i++)
semanage_user_free(records[i]);
+ free(records);
+
cleanup_handle(SH_CONNECT);
}
@@ -573,10 +586,12 @@ void test_user_modify_del_query_local(void)
CU_ASSERT(semanage_user_query_local(sh, key, &user_local) >= 0);
CU_ASSERT_PTR_NOT_NULL_FATAL(user_local);
+ semanage_user_free(user_local);
CU_ASSERT(semanage_user_del_local(sh, key) >= 0);
CU_ASSERT(semanage_user_query_local(sh, key, &user_local) < 0);
/* cleanup */
+ semanage_user_key_free(key);
semanage_user_free(user);
cleanup_handle(SH_TRANS);
}
@@ -683,6 +698,8 @@ void test_user_list_local(void)
for (unsigned int i = 0; i < count; i++)
semanage_user_free(records[i]);
+ free(records);
+
delete_local_user(I_FIRST);
delete_local_user(I_SECOND);
delete_local_user(I_THIRD);
diff --git a/libsemanage/tests/utilities.c b/libsemanage/tests/utilities.c
index 18393215..b28ae155 100644
--- a/libsemanage/tests/utilities.c
+++ b/libsemanage/tests/utilities.c
@@ -99,6 +99,7 @@ int write_test_policy_from_file(const char *filename) {
char *buf = NULL;
size_t len = 0;
FILE *fptr = fopen(filename, "rb");
+ int rc;
if (!fptr) {
perror("fopen");
@@ -120,7 +121,9 @@ int write_test_policy_from_file(const char *filename) {
fread(buf, len, 1, fptr);
fclose(fptr);
- return write_test_policy(buf, len);
+ rc = write_test_policy(buf, len);
+ free(buf);
+ return rc;
}
int write_test_policy_src(unsigned char *data, unsigned int data_len) {
diff --git a/libsemanage/tests/utilities.h b/libsemanage/tests/utilities.h
index db4dabf9..298b3280 100644
--- a/libsemanage/tests/utilities.h
+++ b/libsemanage/tests/utilities.h
@@ -39,6 +39,8 @@
CU_ASSERT(semanage_context_to_string(sh, CON1, &__str) >= 0); \
CU_ASSERT(semanage_context_to_string(sh, CON2, &__str2) >= 0); \
CU_ASSERT_STRING_EQUAL(__str, __str2); \
+ free(__str2); \
+ free(__str); \
} while (0)
diff --git a/libsepol/Android.bp b/libsepol/Android.bp
index 5232a68a..6135745c 100644
--- a/libsepol/Android.bp
+++ b/libsepol/Android.bp
@@ -33,21 +33,32 @@ license {
],
}
-common_CFLAGS = [
- "-D_GNU_SOURCE",
- "-Wall",
- "-Werror",
- "-W",
- "-Wundef",
- "-Wshadow",
- "-Wno-error=missing-noreturn",
- "-Wmissing-format-attribute",
-]
+cc_defaults {
+ name: "libsepol_defaults",
+ cflags: [
+ "-D_GNU_SOURCE",
+ "-Wall",
+ "-Werror",
+ "-W",
+ "-Wundef",
+ "-Wshadow",
+ "-Wno-error=missing-noreturn",
+ "-Wmissing-format-attribute",
+ ],
+ target: {
+ bionic: {
+ cflags: ["-DHAVE_REALLOCARRAY"]
+ },
+ musl: {
+ cflags: ["-DHAVE_REALLOCARRAY"]
+ }
+ }
+}
cc_library {
name: "libsepol",
+ defaults: ["libsepol_defaults"],
host_supported: true,
- cflags: common_CFLAGS,
srcs: [
"src/assertion.c",
"src/avrule_block.c",
@@ -135,7 +146,7 @@ cc_library {
cc_binary_host {
name: "chkcon",
+ defaults: ["libsepol_defaults"],
srcs: ["utils/chkcon.c"],
shared_libs: ["libsepol"],
- cflags: common_CFLAGS,
}
diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c
index 4cc7f87f..38edcf8e 100644
--- a/libsepol/cil/src/cil.c
+++ b/libsepol/cil/src/cil.c
@@ -1456,6 +1456,12 @@ int cil_userprefixes_to_string(struct cil_db *db, char **out, size_t *size)
buf_pos = snprintf(str_tmp, str_len, "user %s prefix %s;\n", user->datum.fqn,
userprefix->prefix_str);
+ if (buf_pos < 0) {
+ free(str_tmp);
+ *size = 0;
+ *out = NULL;
+ goto exit;
+ }
str_len -= buf_pos;
str_tmp += buf_pos;
}
@@ -1765,6 +1771,9 @@ int cil_filecons_to_string(struct cil_db *db, char **out, size_t *size)
str_tmp += buf_pos;
switch(filecon->type) {
+ case CIL_FILECON_ANY:
+ str_type = "";
+ break;
case CIL_FILECON_FILE:
str_type = "\t--";
break;
@@ -2530,7 +2539,7 @@ void cil_filecon_init(struct cil_filecon **filecon)
*filecon = cil_malloc(sizeof(**filecon));
(*filecon)->path_str = NULL;
- (*filecon)->type = 0;
+ (*filecon)->type = CIL_FILECON_ANY;
(*filecon)->context_str = NULL;
(*filecon)->context = NULL;
}
@@ -2574,6 +2583,7 @@ void cil_genfscon_init(struct cil_genfscon **genfscon)
(*genfscon)->fs_str = NULL;
(*genfscon)->path_str = NULL;
+ (*genfscon)->file_type = CIL_FILECON_ANY;
(*genfscon)->context_str = NULL;
(*genfscon)->context = NULL;
}
diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c
index d8aa495a..53017e2d 100644
--- a/libsepol/cil/src/cil_binary.c
+++ b/libsepol/cil/src/cil_binary.c
@@ -2823,6 +2823,12 @@ int cil_constrain_to_policydb_helper(policydb_t *pdb, const struct cil_db *db, s
goto exit;
}
+ if (sepol_constrain->permissions == 0) {
+ /* No permissions, so don't insert rule. */
+ free(sepol_constrain);
+ return SEPOL_OK;
+ }
+
rc = __cil_constrain_expr_to_sepol_expr(pdb, db, expr, &sepol_expr);
if (rc != SEPOL_OK) {
goto exit;
@@ -3462,6 +3468,43 @@ int cil_genfscon_to_policydb(policydb_t *pdb, struct cil_sort *genfscons)
new_ocon->u.name = cil_strdup(cil_genfscon->path_str);
+ if (cil_genfscon->file_type != CIL_FILECON_ANY) {
+ class_datum_t *class_datum;
+ const char *class_name;
+ switch (cil_genfscon->file_type) {
+ case CIL_FILECON_FILE:
+ class_name = "file";
+ break;
+ case CIL_FILECON_DIR:
+ class_name = "dir";
+ break;
+ case CIL_FILECON_CHAR:
+ class_name = "chr_file";
+ break;
+ case CIL_FILECON_BLOCK:
+ class_name = "blk_file";
+ break;
+ case CIL_FILECON_SOCKET:
+ class_name = "sock_file";
+ break;
+ case CIL_FILECON_PIPE:
+ class_name = "fifo_file";
+ break;
+ case CIL_FILECON_SYMLINK:
+ class_name = "lnk_file";
+ break;
+ default:
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ class_datum = hashtab_search(pdb->p_classes.table, class_name);
+ if (!class_datum) {
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ new_ocon->v.sclass = class_datum->s.value;
+ }
+
rc = __cil_context_to_sepol_context(pdb, cil_genfscon->context, &new_ocon->context[0]);
if (rc != SEPOL_OK) {
goto exit;
@@ -4603,6 +4646,9 @@ static int __cil_print_neverallow_failure(const struct cil_db *db, struct cil_tr
char *neverallow_str;
char *allow_str;
enum cil_flavor avrule_flavor;
+ int num_matching = 0;
+ int count_matching = 0;
+ enum cil_log_level log_level = cil_get_log_level();
target.rule_kind = CIL_AVRULE_ALLOWED;
target.is_extended = cil_rule->is_extended;
@@ -4630,10 +4676,18 @@ static int __cil_print_neverallow_failure(const struct cil_db *db, struct cil_tr
}
cil_list_for_each(i2, matching) {
+ num_matching++;
+ }
+ cil_list_for_each(i2, matching) {
n2 = i2->data;
r2 = n2->data;
__cil_print_parents(" ", n2);
__cil_print_rule(" ", allow_str, r2);
+ count_matching++;
+ if (count_matching >= 4 && num_matching > 4 && log_level == CIL_ERR) {
+ cil_log(CIL_ERR, " Only first 4 of %d matching rules shown (use \"-v\" to show all)\n", num_matching);
+ break;
+ }
}
cil_log(CIL_ERR,"\n");
cil_list_destroy(&matching, CIL_FALSE);
@@ -4826,6 +4880,7 @@ static int cil_check_type_bounds(const struct cil_db *db, policydb_t *pdb, void
struct cil_avrule target;
struct cil_tree_node *n1 = NULL;
int count_bad = 0;
+ enum cil_log_level log_level = cil_get_log_level();
*violation = CIL_TRUE;
@@ -4872,16 +4927,16 @@ static int cil_check_type_bounds(const struct cil_db *db, policydb_t *pdb, void
__cil_print_rule(" ", "allow", r2);
}
count_matching++;
- if (count_matching >= 2) {
- cil_log(CIL_ERR, " Only first 2 of %d matching rules shown\n", num_matching);
+ if (count_matching >= 2 && num_matching > 2 && log_level == CIL_ERR) {
+ cil_log(CIL_ERR, " Only first 2 of %d matching rules shown (use \"-v\" to show all)\n", num_matching);
break;
}
}
cil_list_destroy(&matching, CIL_FALSE);
cil_list_destroy(&target.perms.classperms, CIL_TRUE);
count_bad++;
- if (count_bad >= 2) {
- cil_log(CIL_ERR, " Only first 2 of %d bad rules shown\n", numbad);
+ if (count_bad >= 4 && numbad > 4 && log_level == CIL_ERR) {
+ cil_log(CIL_ERR, " Only first 4 of %d bad rules shown (use \"-v\" to show all)\n", numbad);
break;
}
}
diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c
index 9c34be23..5f9392d1 100644
--- a/libsepol/cil/src/cil_build_ast.c
+++ b/libsepol/cil/src/cil_build_ast.c
@@ -4229,7 +4229,9 @@ int cil_gen_filecon(struct cil_db *db, struct cil_tree_node *parse_current, stru
filecon->path_str = parse_current->next->data;
- if (type == CIL_KEY_FILE) {
+ if (type == CIL_KEY_ANY) {
+ filecon->type = CIL_FILECON_ANY;
+ } else if (type == CIL_KEY_FILE) {
filecon->type = CIL_FILECON_FILE;
} else if (type == CIL_KEY_DIR) {
filecon->type = CIL_FILECON_DIR;
@@ -4243,8 +4245,6 @@ int cil_gen_filecon(struct cil_db *db, struct cil_tree_node *parse_current, stru
filecon->type = CIL_FILECON_PIPE;
} else if (type == CIL_KEY_SYMLINK) {
filecon->type = CIL_FILECON_SYMLINK;
- } else if (type == CIL_KEY_ANY) {
- filecon->type = CIL_FILECON_ANY;
} else {
cil_log(CIL_ERR, "Invalid file type\n");
rc = SEPOL_ERR;
@@ -4572,9 +4572,11 @@ int cil_gen_genfscon(struct cil_db *db, struct cil_tree_node *parse_current, str
CIL_SYN_STRING,
CIL_SYN_STRING,
CIL_SYN_STRING | CIL_SYN_LIST,
+ CIL_SYN_STRING | CIL_SYN_LIST | CIL_SYN_END,
CIL_SYN_END
};
size_t syntax_len = sizeof(syntax)/sizeof(*syntax);
+ struct cil_tree_node *context_node;
int rc = SEPOL_ERR;
struct cil_genfscon *genfscon = NULL;
@@ -4592,15 +4594,48 @@ int cil_gen_genfscon(struct cil_db *db, struct cil_tree_node *parse_current, str
genfscon->fs_str = parse_current->next->data;
genfscon->path_str = parse_current->next->next->data;
- if (parse_current->next->next->next->cl_head == NULL ) {
- genfscon->context_str = parse_current->next->next->next->data;
+ if (parse_current->next->next->next->next) {
+ /* (genfscon <FS_STR> <PATH_STR> <FILE_TYPE> ... */
+ char *file_type = parse_current->next->next->next->data;
+ if (file_type == CIL_KEY_ANY) {
+ genfscon->file_type = CIL_FILECON_ANY;
+ } else if (file_type == CIL_KEY_FILE) {
+ genfscon->file_type = CIL_FILECON_FILE;
+ } else if (file_type == CIL_KEY_DIR) {
+ genfscon->file_type = CIL_FILECON_DIR;
+ } else if (file_type == CIL_KEY_CHAR) {
+ genfscon->file_type = CIL_FILECON_CHAR;
+ } else if (file_type == CIL_KEY_BLOCK) {
+ genfscon->file_type = CIL_FILECON_BLOCK;
+ } else if (file_type == CIL_KEY_SOCKET) {
+ genfscon->file_type = CIL_FILECON_SOCKET;
+ } else if (file_type == CIL_KEY_PIPE) {
+ genfscon->file_type = CIL_FILECON_PIPE;
+ } else if (file_type == CIL_KEY_SYMLINK) {
+ genfscon->file_type = CIL_FILECON_SYMLINK;
+ } else {
+ if (parse_current->next->next->next->cl_head) {
+ cil_log(CIL_ERR, "Expecting file type, but found a list\n");
+ } else {
+ cil_log(CIL_ERR, "Invalid file type \"%s\"\n", file_type);
+ }
+ rc = SEPOL_ERR;
+ goto exit;
+ }
+ context_node = parse_current->next->next->next->next;
} else {
- cil_context_init(&genfscon->context);
+ /* (genfscon <FS_STR> <PATH_STR> ... */
+ context_node = parse_current->next->next->next;
+ }
- rc = cil_fill_context(parse_current->next->next->next->cl_head, genfscon->context);
+ if (context_node->cl_head) {
+ cil_context_init(&genfscon->context);
+ rc = cil_fill_context(context_node->cl_head, genfscon->context);
if (rc != SEPOL_OK) {
goto exit;
}
+ } else {
+ genfscon->context_str = context_node->data;
}
ast_node->data = genfscon;
@@ -5668,10 +5703,10 @@ int cil_fill_ipaddr(struct cil_tree_node *addr_node, struct cil_ipaddr *addr)
goto exit;
}
- if (strchr(addr_node->data, '.') != NULL) {
- addr->family = AF_INET;
- } else {
+ if (strchr(addr_node->data, ':') != NULL) {
addr->family = AF_INET6;
+ } else {
+ addr->family = AF_INET;
}
rc = inet_pton(addr->family, addr_node->data, &addr->ip);
@@ -5683,7 +5718,7 @@ int cil_fill_ipaddr(struct cil_tree_node *addr_node, struct cil_ipaddr *addr)
return SEPOL_OK;
exit:
- cil_log(CIL_ERR, "Bad ip address or netmask\n");
+ cil_log(CIL_ERR, "Bad ip address or netmask: %s\n", (addr_node && addr_node->data) ? (const char *)addr_node->data : "n/a");
return rc;
}
diff --git a/libsepol/cil/src/cil_copy_ast.c b/libsepol/cil/src/cil_copy_ast.c
index 2fad972c..a4ead9db 100644
--- a/libsepol/cil/src/cil_copy_ast.c
+++ b/libsepol/cil/src/cil_copy_ast.c
@@ -1725,6 +1725,12 @@ int __cil_copy_node_helper(struct cil_tree_node *orig, uint32_t *finished, void
copy_func = &cil_copy_block;
break;
case CIL_BLOCKABSTRACT:
+ if (args->orig_dest->flavor == CIL_BLOCKINHERIT) {
+ /* When inheriting a block, don't copy any blockabstract
+ * statements. Inheriting a block from a block that was
+ * just inherited never worked. */
+ return SEPOL_OK;
+ }
copy_func = &cil_copy_blockabstract;
break;
case CIL_BLOCKINHERIT:
diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h
index 6f1d3cb5..a7604762 100644
--- a/libsepol/cil/src/cil_internal.h
+++ b/libsepol/cil/src/cil_internal.h
@@ -730,14 +730,14 @@ struct cil_context {
};
enum cil_filecon_types {
- CIL_FILECON_FILE = 1,
+ CIL_FILECON_ANY = 0,
+ CIL_FILECON_FILE,
CIL_FILECON_DIR,
CIL_FILECON_CHAR,
CIL_FILECON_BLOCK,
CIL_FILECON_SOCKET,
CIL_FILECON_PIPE,
CIL_FILECON_SYMLINK,
- CIL_FILECON_ANY
};
struct cil_filecon {
@@ -791,6 +791,7 @@ struct cil_ipaddr {
struct cil_genfscon {
char *fs_str;
char *path_str;
+ enum cil_filecon_types file_type;
char *context_str;
struct cil_context *context;
};
diff --git a/libsepol/cil/src/cil_log.c b/libsepol/cil/src/cil_log.c
index a8e4d2e9..a296929b 100644
--- a/libsepol/cil/src/cil_log.c
+++ b/libsepol/cil/src/cil_log.c
@@ -70,3 +70,8 @@ void cil_set_log_level(enum cil_log_level lvl)
{
cil_log_level = lvl;
}
+
+enum cil_log_level cil_get_log_level(void)
+{
+ return cil_log_level;
+}
diff --git a/libsepol/cil/src/cil_log.h b/libsepol/cil/src/cil_log.h
index 541569be..442781fb 100644
--- a/libsepol/cil/src/cil_log.h
+++ b/libsepol/cil/src/cil_log.h
@@ -38,4 +38,6 @@
__attribute__ ((format(printf, 2, 0))) void cil_vlog(enum cil_log_level lvl, const char *msg, va_list args);
__attribute__ ((format(printf, 2, 3))) void cil_log(enum cil_log_level lvl, const char *msg, ...);
+enum cil_log_level cil_get_log_level(void);
+
#endif // CIL_LOG_H_
diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c
index 7e2c2b9a..09c02af9 100644
--- a/libsepol/cil/src/cil_post.c
+++ b/libsepol/cil/src/cil_post.c
@@ -2280,8 +2280,10 @@ static int __cil_post_report_conflict(struct cil_tree_node *node, uint32_t *fini
static int __cil_post_process_context_rules(struct cil_sort *sort, int (*compar)(const void *, const void *), int (*concompar)(const void *, const void *), struct cil_db *db, enum cil_flavor flavor, const char *flavor_str)
{
uint32_t count = sort->count;
- uint32_t i, j = 0, removed = 0;
+ uint32_t i = 0, j, removed = 0;
+ int conflicting = 0;
int rc = SEPOL_OK;
+ enum cil_log_level log_level = cil_get_log_level();
if (count < 2) {
return SEPOL_OK;
@@ -2289,36 +2291,43 @@ static int __cil_post_process_context_rules(struct cil_sort *sort, int (*compar)
qsort(sort->array, sort->count, sizeof(sort->array), compar);
- for (i=1; i<count; i++) {
+ for (j=1; j<count; j++) {
if (compar(&sort->array[i], &sort->array[j]) != 0) {
- j++;
+ i++;
+ if (conflicting >= 4) {
+ /* 2 rules were written when conflicting == 1 */
+ cil_log(CIL_WARN, " Only first 4 of %d conflicting rules shown\n", conflicting);
+ }
+ conflicting = 0;
} else {
removed++;
- if (!db->multiple_decls ||
- concompar(&sort->array[i], &sort->array[j]) != 0) {
- struct cil_list_item li;
- int rc2;
- cil_log(CIL_WARN, "Found conflicting %s rules\n",
- flavor_str);
- rc = SEPOL_ERR;
- li.flavor = flavor;
- li.data = sort->array[i];
- rc2 = cil_tree_walk(db->ast->root,
- __cil_post_report_conflict,
- NULL, NULL, &li);
- if (rc2 != SEPOL_OK) goto exit;
- li.data = sort->array[j];
- rc2 = cil_tree_walk(db->ast->root,
- __cil_post_report_conflict,
- NULL, NULL, &li);
- if (rc2 != SEPOL_OK) goto exit;
+ if (!db->multiple_decls || concompar(&sort->array[i], &sort->array[j]) != 0) {
+ conflicting++;
+ if (log_level >= CIL_WARN) {
+ struct cil_list_item li;
+ int rc2;
+ li.flavor = flavor;
+ if (conflicting == 1) {
+ cil_log(CIL_WARN, "Found conflicting %s rules\n", flavor_str);
+ rc = SEPOL_ERR;
+ li.data = sort->array[i];
+ rc2 = cil_tree_walk(db->ast->root, __cil_post_report_conflict,
+ NULL, NULL, &li);
+ if (rc2 != SEPOL_OK) goto exit;
+ }
+ if (conflicting < 4 || log_level > CIL_WARN) {
+ li.data = sort->array[j];
+ rc2 = cil_tree_walk(db->ast->root, __cil_post_report_conflict,
+ NULL, NULL, &li);
+ if (rc2 != SEPOL_OK) goto exit;
+ }
+ }
}
}
- if (i != j) {
- sort->array[j] = sort->array[i];
+ if (i != j && !conflicting) {
+ sort->array[i] = sort->array[j];
}
}
-
sort->count = count - removed;
exit:
diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c
index e97a9f46..69a8a2ed 100644
--- a/libsepol/cil/src/cil_resolve_ast.c
+++ b/libsepol/cil/src/cil_resolve_ast.c
@@ -65,6 +65,7 @@ struct cil_args_resolve {
struct cil_list *sensitivityorder_lists;
struct cil_list *in_list_before;
struct cil_list *in_list_after;
+ struct cil_list *abstract_blocks;
};
static struct cil_name * __cil_insert_name(struct cil_db *db, hashtab_key_t key, struct cil_tree_node *ast_node)
@@ -754,6 +755,11 @@ int cil_resolve_classcommon(struct cil_tree_node *current, void *extra_args)
if (rc != SEPOL_OK) {
goto exit;
}
+ if (NODE(class_datum)->flavor != CIL_CLASS) {
+ cil_log(CIL_ERR, "Class %s is not a kernel class and cannot be associated with common %s\n", clscom->class_str, clscom->common_str);
+ rc = SEPOL_ERR;
+ goto exit;
+ }
rc = cil_resolve_name(current, clscom->common_str, CIL_SYM_COMMONS, extra_args, &common_datum);
if (rc != SEPOL_OK) {
@@ -2379,11 +2385,25 @@ exit:
return rc;
}
+static void cil_mark_subtree_abstract(struct cil_tree_node *node)
+{
+ struct cil_block *block = node->data;
+
+ block->is_abstract = CIL_TRUE;
+
+ for (node = node->cl_head; node; node = node->next) {
+ if (node->flavor == CIL_BLOCK) {
+ cil_mark_subtree_abstract(node);
+ }
+ }
+}
+
int cil_resolve_blockabstract(struct cil_tree_node *current, void *extra_args)
{
struct cil_blockabstract *abstract = current->data;
struct cil_symtab_datum *block_datum = NULL;
struct cil_tree_node *block_node = NULL;
+ struct cil_args_resolve *args = extra_args;
int rc = SEPOL_ERR;
rc = cil_resolve_name(current, abstract->block_str, CIL_SYM_BLOCKS, extra_args, &block_datum);
@@ -2398,7 +2418,7 @@ int cil_resolve_blockabstract(struct cil_tree_node *current, void *extra_args)
goto exit;
}
- ((struct cil_block*)block_datum)->is_abstract = CIL_TRUE;
+ cil_list_append(args->abstract_blocks, CIL_NODE, block_node);
return SEPOL_OK;
@@ -4084,6 +4104,7 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current)
extra_args.sensitivityorder_lists = NULL;
extra_args.in_list_before = NULL;
extra_args.in_list_after = NULL;
+ extra_args.abstract_blocks = NULL;
cil_list_init(&extra_args.to_destroy, CIL_NODE);
cil_list_init(&extra_args.sidorder_lists, CIL_LIST_ITEM);
@@ -4093,6 +4114,7 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current)
cil_list_init(&extra_args.sensitivityorder_lists, CIL_LIST_ITEM);
cil_list_init(&extra_args.in_list_before, CIL_IN);
cil_list_init(&extra_args.in_list_after, CIL_IN);
+ cil_list_init(&extra_args.abstract_blocks, CIL_NODE);
for (pass = CIL_PASS_TIF; pass < CIL_PASS_NUM; pass++) {
extra_args.pass = pass;
@@ -4116,6 +4138,13 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current)
cil_list_destroy(&extra_args.in_list_after, CIL_FALSE);
}
+ if (pass == CIL_PASS_BLKABS) {
+ struct cil_list_item *item;
+ cil_list_for_each(item, extra_args.abstract_blocks) {
+ cil_mark_subtree_abstract(item->data);
+ }
+ }
+
if (pass == CIL_PASS_BLKIN_LINK) {
rc = cil_check_for_bad_inheritance(current);
if (rc != SEPOL_OK) {
@@ -4234,6 +4263,7 @@ exit:
cil_list_destroy(&extra_args.to_destroy, CIL_FALSE);
cil_list_destroy(&extra_args.in_list_before, CIL_FALSE);
cil_list_destroy(&extra_args.in_list_after, CIL_FALSE);
+ cil_list_destroy(&extra_args.abstract_blocks, CIL_FALSE);
return rc;
}
@@ -4255,9 +4285,13 @@ static int __cil_resolve_name_with_parents(struct cil_tree_node *node, char *nam
case CIL_ROOT:
goto exit;
break;
- case CIL_BLOCK:
- symtab = &((struct cil_block*)node->data)->symtab[sym_index];
- rc = cil_symtab_get_datum(symtab, name, datum);
+ case CIL_BLOCK: {
+ struct cil_block *block = node->data;
+ if (!block->is_abstract) {
+ symtab = &block->symtab[sym_index];
+ rc = cil_symtab_get_datum(symtab, name, datum);
+ }
+ }
break;
case CIL_BLOCKINHERIT: {
struct cil_blockinherit *inherit = node->data;
diff --git a/libsepol/cil/src/cil_write_ast.c b/libsepol/cil/src/cil_write_ast.c
index 38374f10..c0ee7473 100644
--- a/libsepol/cil/src/cil_write_ast.c
+++ b/libsepol/cil/src/cil_write_ast.c
@@ -1232,24 +1232,34 @@ void cil_write_ast_node(FILE *out, struct cil_tree_node *node)
struct cil_filecon *filecon = node->data;
fprintf(out, "(filecon ");
fprintf(out, "\"%s\" ", filecon->path_str);
- if (filecon->type == CIL_FILECON_FILE)
+ switch (filecon->type) {
+ case CIL_FILECON_ANY:
+ fprintf(out, "%s ", CIL_KEY_ANY);
+ break;
+ case CIL_FILECON_FILE:
fprintf(out, "%s ", CIL_KEY_FILE);
- else if (filecon->type == CIL_FILECON_DIR)
+ break;
+ case CIL_FILECON_DIR:
fprintf(out, "%s ", CIL_KEY_DIR);
- else if (filecon->type == CIL_FILECON_CHAR)
+ break;
+ case CIL_FILECON_CHAR:
fprintf(out, "%s ", CIL_KEY_CHAR);
- else if (filecon->type == CIL_FILECON_BLOCK)
+ break;
+ case CIL_FILECON_BLOCK:
fprintf(out, "%s ", CIL_KEY_BLOCK);
- else if (filecon->type == CIL_FILECON_SOCKET)
+ break;
+ case CIL_FILECON_SOCKET:
fprintf(out, "%s ", CIL_KEY_SOCKET);
- else if (filecon->type == CIL_FILECON_PIPE)
+ break;
+ case CIL_FILECON_PIPE:
fprintf(out, "%s ", CIL_KEY_PIPE);
- else if (filecon->type == CIL_FILECON_SYMLINK)
+ break;
+ case CIL_FILECON_SYMLINK:
fprintf(out, "%s ", CIL_KEY_SYMLINK);
- else if (filecon->type == CIL_FILECON_ANY)
- fprintf(out, "%s ", CIL_KEY_ANY);
- else
+ break;
+ default:
fprintf(out, "<?FILETYPE> ");
+ }
if (filecon->context)
write_context(out, filecon->context, CIL_TRUE);
else if (filecon->context_str)
@@ -1318,6 +1328,33 @@ void cil_write_ast_node(FILE *out, struct cil_tree_node *node)
struct cil_genfscon *genfscon = node->data;
fprintf(out, "(genfscon ");
fprintf(out, "%s \"%s\" ", genfscon->fs_str, genfscon->path_str);
+ if (genfscon->file_type != CIL_FILECON_ANY) {
+ switch (genfscon->file_type) {
+ case CIL_FILECON_FILE:
+ fprintf(out, "%s ", CIL_KEY_FILE);
+ break;
+ case CIL_FILECON_DIR:
+ fprintf(out, "%s ", CIL_KEY_DIR);
+ break;
+ case CIL_FILECON_CHAR:
+ fprintf(out, "%s ", CIL_KEY_CHAR);
+ break;
+ case CIL_FILECON_BLOCK:
+ fprintf(out, "%s ", CIL_KEY_BLOCK);
+ break;
+ case CIL_FILECON_SOCKET:
+ fprintf(out, "%s ", CIL_KEY_SOCKET);
+ break;
+ case CIL_FILECON_PIPE:
+ fprintf(out, "%s ", CIL_KEY_PIPE);
+ break;
+ case CIL_FILECON_SYMLINK:
+ fprintf(out, "%s ", CIL_KEY_SYMLINK);
+ break;
+ default:
+ fprintf(out, "<?FILETYPE> ");
+ }
+ }
if (genfscon->context)
write_context(out, genfscon->context, CIL_TRUE);
else
diff --git a/libsepol/fuzz/binpolicy-fuzzer.c b/libsepol/fuzz/binpolicy-fuzzer.c
new file mode 100644
index 00000000..85c59645
--- /dev/null
+++ b/libsepol/fuzz/binpolicy-fuzzer.c
@@ -0,0 +1,63 @@
+#include <sepol/debug.h>
+#include <sepol/kernel_to_cil.h>
+#include <sepol/kernel_to_conf.h>
+#include <sepol/policydb/policydb.h>
+
+extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+static int write_binary_policy(policydb_t *p, FILE *outfp)
+{
+ struct policy_file pf;
+
+ policy_file_init(&pf);
+ pf.type = PF_USE_STDIO;
+ pf.fp = outfp;
+ return policydb_write(p, &pf);
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ policydb_t policydb = {};
+ sidtab_t sidtab = {};
+ struct policy_file pf;
+ FILE *devnull = NULL;
+
+ sepol_debug(0);
+
+ policy_file_init(&pf);
+ pf.type = PF_USE_MEMORY;
+ pf.data = (char *) data;
+ pf.len = size;
+
+ if (policydb_init(&policydb))
+ goto exit;
+
+ if (policydb_read(&policydb, &pf, /*verbose=*/0))
+ goto exit;
+
+ if (policydb_load_isids(&policydb, &sidtab))
+ goto exit;
+
+ if (policydb.policy_type == POLICY_KERN)
+ (void) policydb_optimize(&policydb);
+
+ devnull = fopen("/dev/null", "w");
+ if (!devnull)
+ goto exit;
+
+ (void) write_binary_policy(&policydb, devnull);
+
+ (void) sepol_kernel_policydb_to_conf(devnull, &policydb);
+
+ (void) sepol_kernel_policydb_to_cil(devnull, &policydb);
+
+exit:
+ if (devnull != NULL)
+ fclose(devnull);
+
+ policydb_destroy(&policydb);
+ sepol_sidtab_destroy(&sidtab);
+
+ /* Non-zero return values are reserved for future use. */
+ return 0;
+}
diff --git a/libsepol/fuzz/policy.bin b/libsepol/fuzz/policy.bin
new file mode 100644
index 00000000..6f977ef3
--- /dev/null
+++ b/libsepol/fuzz/policy.bin
Binary files differ
diff --git a/libsepol/fuzz/secilc-fuzzer.c b/libsepol/fuzz/secilc-fuzzer.c
index 255b3241..9a1a16de 100644
--- a/libsepol/fuzz/secilc-fuzzer.c
+++ b/libsepol/fuzz/secilc-fuzzer.c
@@ -8,6 +8,10 @@
#include <sepol/cil/cil.h>
#include <sepol/policydb.h>
+static void log_handler(__attribute__((unused)) int lvl, __attribute__((unused)) const char *msg) {
+ /* be quiet */
+}
+
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
enum cil_log_level log_level = CIL_ERR;
struct sepol_policy_file *pf = NULL;
@@ -24,6 +28,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
sepol_policydb_t *pdb = NULL;
cil_set_log_level(log_level);
+ cil_set_log_handler(log_handler);
cil_db_init(&db);
cil_set_disable_dontaudit(db, disable_dontaudit);
diff --git a/libsepol/include/sepol/policydb/polcaps.h b/libsepol/include/sepol/policydb/polcaps.h
index 40669fb5..f5e32e60 100644
--- a/libsepol/include/sepol/policydb/polcaps.h
+++ b/libsepol/include/sepol/policydb/polcaps.h
@@ -7,16 +7,17 @@ extern "C" {
/* Policy capabilities */
enum {
- POLICYDB_CAPABILITY_NETPEER,
- POLICYDB_CAPABILITY_OPENPERM,
- POLICYDB_CAPABILITY_EXTSOCKCLASS,
- POLICYDB_CAPABILITY_ALWAYSNETWORK,
- POLICYDB_CAPABILITY_CGROUPSECLABEL,
- POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION,
- POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS,
- __POLICYDB_CAPABILITY_MAX
+ POLICYDB_CAP_NETPEER,
+ POLICYDB_CAP_OPENPERM,
+ POLICYDB_CAP_EXTSOCKCLASS,
+ POLICYDB_CAP_ALWAYSNETWORK,
+ POLICYDB_CAP_CGROUPSECLABEL,
+ POLICYDB_CAP_NNP_NOSUID_TRANSITION,
+ POLICYDB_CAP_GENFS_SECLABEL_SYMLINKS,
+ POLICYDB_CAP_IOCTL_SKIP_CLOEXEC,
+ __POLICYDB_CAP_MAX
};
-#define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
+#define POLICYDB_CAP_MAX (__POLICYDB_CAP_MAX - 1)
/* Convert a capability name to number. */
extern int sepol_polcap_getnum(const char *name);
diff --git a/libsepol/src/Makefile b/libsepol/src/Makefile
index dc8b1773..13410c67 100644
--- a/libsepol/src/Makefile
+++ b/libsepol/src/Makefile
@@ -29,6 +29,12 @@ LOBJS += $(sort $(patsubst %.c,%.lo,$(sort $(wildcard $(CILDIR)/src/*.c)) $(CIL_
override CFLAGS += -I$(CILDIR)/include
endif
+# check for reallocarray(3) availability
+H := \#
+ifeq (yes,$(shell printf '${H}define _GNU_SOURCE\n${H}include <stdlib.h>\nint main(void){void*p=reallocarray(NULL, 1, sizeof(char));return 0;}' | $(CC) -x c -o /dev/null - >/dev/null 2>&1 && echo yes))
+override CFLAGS += -DHAVE_REALLOCARRAY
+endif
+
LD_SONAME_FLAGS=-soname,$(LIBSO),--version-script=$(LIBMAP),-z,defs
LN=ln
diff --git a/libsepol/src/assertion.c b/libsepol/src/assertion.c
index dd2749a0..161874c3 100644
--- a/libsepol/src/assertion.c
+++ b/libsepol/src/assertion.c
@@ -36,13 +36,21 @@ struct avtab_match_args {
unsigned long errors;
};
+static const char* policy_name(policydb_t *p) {
+ const char *policy_file = "policy.conf";
+ if (p->name) {
+ policy_file = p->name;
+ }
+ return policy_file;
+}
+
static void report_failure(sepol_handle_t *handle, policydb_t *p, const avrule_t *avrule,
unsigned int stype, unsigned int ttype,
const class_perm_node_t *curperm, uint32_t perms)
{
if (avrule->source_filename) {
- ERR(handle, "neverallow on line %lu of %s (or line %lu of policy.conf) violated by allow %s %s:%s {%s };",
- avrule->source_line, avrule->source_filename, avrule->line,
+ ERR(handle, "neverallow on line %lu of %s (or line %lu of %s) violated by allow %s %s:%s {%s };",
+ avrule->source_line, avrule->source_filename, avrule->line, policy_name(p),
p->p_type_val_to_name[stype],
p->p_type_val_to_name[ttype],
p->p_class_val_to_name[curperm->tclass - 1],
@@ -65,14 +73,11 @@ static void report_failure(sepol_handle_t *handle, policydb_t *p, const avrule_t
static int match_any_class_permissions(class_perm_node_t *cp, uint32_t class, uint32_t data)
{
for (; cp; cp = cp->next) {
- if ((cp->tclass == class) && (cp->data & data)) {
- break;
- }
+ if ((cp->tclass == class) && (cp->data & data))
+ return 1;
}
- if (!cp)
- return 0;
- return 1;
+ return 0;
}
static int extended_permissions_and(uint32_t *perms1, uint32_t *perms2) {
@@ -151,15 +156,16 @@ static int report_assertion_extended_permissions(sepol_handle_t *handle,
ebitmap_t *tattr = &p->type_attr_map[ttype];
ebitmap_node_t *snode, *tnode;
unsigned int i, j;
- int rc = 1;
- int ret = 0;
+ int rc;
+ int found_xperm = 0;
+ int errors = 0;
memcpy(&tmp_key, k, sizeof(avtab_key_t));
tmp_key.specified = AVTAB_XPERMS_ALLOWED;
ebitmap_for_each_positive_bit(sattr, snode, i) {
+ tmp_key.source_type = i + 1;
ebitmap_for_each_positive_bit(tattr, tnode, j) {
- tmp_key.source_type = i + 1;
tmp_key.target_type = j + 1;
for (node = avtab_search_node(avtab, &tmp_key);
node;
@@ -168,40 +174,39 @@ static int report_assertion_extended_permissions(sepol_handle_t *handle,
if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
&& (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER))
continue;
-
+ found_xperm = 1;
rc = check_extended_permissions(avrule->xperms, xperms);
/* failure on the extended permission check_extended_permissions */
if (rc) {
extended_permissions_violated(&error, avrule->xperms, xperms);
- ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of policy.conf) violated by\n"
+ ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of %s) violated by\n"
"allowxperm %s %s:%s %s;",
- avrule->source_line, avrule->source_filename, avrule->line,
+ avrule->source_line, avrule->source_filename, avrule->line, policy_name(p),
p->p_type_val_to_name[i],
p->p_type_val_to_name[j],
p->p_class_val_to_name[curperm->tclass - 1],
sepol_extended_perms_to_string(&error));
- rc = 0;
- ret++;
+ errors++;
}
}
}
}
/* failure on the regular permissions */
- if (rc) {
- ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of policy.conf) violated by\n"
+ if (!found_xperm) {
+ ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of %s) violated by\n"
"allow %s %s:%s {%s };",
- avrule->source_line, avrule->source_filename, avrule->line,
+ avrule->source_line, avrule->source_filename, avrule->line, policy_name(p),
p->p_type_val_to_name[stype],
p->p_type_val_to_name[ttype],
p->p_class_val_to_name[curperm->tclass - 1],
sepol_av_to_string(p, curperm->tclass, perms));
- ret++;
+ errors++;
}
- return ret;
+ return errors;
}
static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void *args)
@@ -214,9 +219,10 @@ static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void
avrule_t *avrule = a->avrule;
class_perm_node_t *cp;
uint32_t perms;
- ebitmap_t src_matches, tgt_matches, self_matches, matches;
+ ebitmap_t src_matches, tgt_matches, self_matches;
ebitmap_node_t *snode, *tnode;
unsigned int i, j;
+ const int is_avrule_self = (avrule->flags & RULE_SELF) != 0;
if ((k->specified & AVTAB_ALLOWED) == 0)
return 0;
@@ -227,31 +233,27 @@ static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void
ebitmap_init(&src_matches);
ebitmap_init(&tgt_matches);
ebitmap_init(&self_matches);
- ebitmap_init(&matches);
rc = ebitmap_and(&src_matches, &avrule->stypes.types,
&p->attr_type_map[k->source_type - 1]);
- if (rc)
+ if (rc < 0)
goto oom;
if (ebitmap_is_empty(&src_matches))
goto exit;
rc = ebitmap_and(&tgt_matches, &avrule->ttypes.types, &p->attr_type_map[k->target_type -1]);
- if (rc)
+ if (rc < 0)
goto oom;
- if (avrule->flags == RULE_SELF) {
- rc = ebitmap_and(&matches, &p->attr_type_map[k->source_type - 1], &p->attr_type_map[k->target_type - 1]);
- if (rc)
- goto oom;
- rc = ebitmap_and(&self_matches, &avrule->stypes.types, &matches);
- if (rc)
+ if (is_avrule_self) {
+ rc = ebitmap_and(&self_matches, &src_matches, &p->attr_type_map[k->target_type - 1]);
+ if (rc < 0)
goto oom;
if (!ebitmap_is_empty(&self_matches)) {
rc = ebitmap_union(&tgt_matches, &self_matches);
- if (rc)
+ if (rc < 0)
goto oom;
}
}
@@ -268,6 +270,8 @@ static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void
ebitmap_for_each_positive_bit(&src_matches, snode, i) {
ebitmap_for_each_positive_bit(&tgt_matches, tnode, j) {
+ if (is_avrule_self && i != j)
+ continue;
if (avrule->specified == AVRULE_XPERMS_NEVERALLOW) {
a->errors += report_assertion_extended_permissions(handle,p, avrule,
i, j, cp, perms, k, avtab);
@@ -278,16 +282,12 @@ static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void
}
}
}
- goto exit;
oom:
- ERR(NULL, "Out of memory - unable to check neverallows");
-
exit:
ebitmap_destroy(&src_matches);
ebitmap_destroy(&tgt_matches);
ebitmap_destroy(&self_matches);
- ebitmap_destroy(&matches);
return rc;
}
@@ -301,12 +301,14 @@ static int report_assertion_failures(sepol_handle_t *handle, policydb_t *p, avru
args.avrule = avrule;
args.errors = 0;
+ args.avtab = &p->te_avtab;
rc = avtab_map(&p->te_avtab, report_assertion_avtab_matches, &args);
- if (rc)
+ if (rc < 0)
goto oom;
+ args.avtab = &p->te_cond_avtab;
rc = avtab_map(&p->te_cond_avtab, report_assertion_avtab_matches, &args);
- if (rc)
+ if (rc < 0)
goto oom;
return args.errors;
@@ -337,8 +339,8 @@ static int check_assertion_extended_permissions_avtab(avrule_t *avrule, avtab_t
tmp_key.specified = AVTAB_XPERMS_ALLOWED;
ebitmap_for_each_positive_bit(sattr, snode, i) {
+ tmp_key.source_type = i + 1;
ebitmap_for_each_positive_bit(tattr, tnode, j) {
- tmp_key.source_type = i + 1;
tmp_key.target_type = j + 1;
for (node = avtab_search_node(avtab, &tmp_key);
node;
@@ -350,7 +352,7 @@ static int check_assertion_extended_permissions_avtab(avrule_t *avrule, avtab_t
continue;
rc = check_extended_permissions(neverallow_xperms, xperms);
if (rc)
- break;
+ return rc;
}
}
}
@@ -377,125 +379,138 @@ static int check_assertion_extended_permissions_avtab(avrule_t *avrule, avtab_t
static int check_assertion_extended_permissions(avrule_t *avrule, avtab_t *avtab,
avtab_key_t *k, policydb_t *p)
{
- ebitmap_t src_matches, tgt_matches, self_matches, matches;
+ ebitmap_t src_matches, tgt_matches, self_matches;
unsigned int i, j;
ebitmap_node_t *snode, *tnode;
- class_perm_node_t *cp;
+ const int is_avrule_self = (avrule->flags & RULE_SELF) != 0;
int rc;
- int ret = 1;
ebitmap_init(&src_matches);
ebitmap_init(&tgt_matches);
ebitmap_init(&self_matches);
- ebitmap_init(&matches);
rc = ebitmap_and(&src_matches, &avrule->stypes.types,
&p->attr_type_map[k->source_type - 1]);
- if (rc)
+ if (rc < 0)
goto oom;
- if (ebitmap_is_empty(&src_matches))
+ if (ebitmap_is_empty(&src_matches)) {
+ rc = 0;
goto exit;
+ }
rc = ebitmap_and(&tgt_matches, &avrule->ttypes.types,
&p->attr_type_map[k->target_type -1]);
- if (rc)
+ if (rc < 0)
goto oom;
- if (avrule->flags == RULE_SELF) {
- rc = ebitmap_and(&matches, &p->attr_type_map[k->source_type - 1],
- &p->attr_type_map[k->target_type - 1]);
- if (rc)
- goto oom;
- rc = ebitmap_and(&self_matches, &avrule->stypes.types, &matches);
- if (rc)
+ if (is_avrule_self) {
+ rc = ebitmap_and(&self_matches, &src_matches, &p->attr_type_map[k->target_type - 1]);
+ if (rc < 0)
goto oom;
if (!ebitmap_is_empty(&self_matches)) {
rc = ebitmap_union(&tgt_matches, &self_matches);
- if (rc)
+ if (rc < 0)
goto oom;
}
}
- if (ebitmap_is_empty(&tgt_matches))
+ if (ebitmap_is_empty(&tgt_matches)) {
+ rc = 0;
goto exit;
+ }
- for (cp = avrule->perms; cp; cp = cp->next) {
- if (cp->tclass != k->target_class)
- continue;
- ebitmap_for_each_positive_bit(&src_matches, snode, i) {
- ebitmap_for_each_positive_bit(&tgt_matches, tnode, j) {
- ret = check_assertion_extended_permissions_avtab(
- avrule, avtab, i, j, k, p);
- if (ret)
- goto exit;
+ ebitmap_for_each_positive_bit(&src_matches, snode, i) {
+ ebitmap_for_each_positive_bit(&tgt_matches, tnode, j) {
+ if (is_avrule_self && i != j)
+ continue;
+ if (check_assertion_extended_permissions_avtab(avrule, avtab, i, j, k, p)) {
+ rc = 1;
+ goto exit;
}
}
}
- goto exit;
-oom:
- ERR(NULL, "Out of memory - unable to check neverallows");
+ rc = 0;
+oom:
exit:
ebitmap_destroy(&src_matches);
ebitmap_destroy(&tgt_matches);
- ebitmap_destroy(&matches);
- return ret;
+ ebitmap_destroy(&self_matches);
+ return rc;
+}
+
+static int check_assertion_self_match(avtab_key_t *k, avrule_t *avrule, policydb_t *p)
+{
+ ebitmap_t src_matches;
+ int rc;
+
+ /* The key's target must match something in the matches of the avrule's source
+ * and the key's source.
+ */
+
+ rc = ebitmap_and(&src_matches, &avrule->stypes.types, &p->attr_type_map[k->source_type - 1]);
+ if (rc < 0)
+ goto oom;
+
+ if (!ebitmap_match_any(&src_matches, &p->attr_type_map[k->target_type - 1])) {
+ rc = 0;
+ goto nomatch;
+ }
+
+ rc = 1;
+
+oom:
+nomatch:
+ ebitmap_destroy(&src_matches);
+ return rc;
}
static int check_assertion_avtab_match(avtab_key_t *k, avtab_datum_t *d, void *args)
{
- int rc, rc2 = 0;
+ int rc;
struct avtab_match_args *a = (struct avtab_match_args *)args;
policydb_t *p = a->p;
avrule_t *avrule = a->avrule;
avtab_t *avtab = a->avtab;
if ((k->specified & AVTAB_ALLOWED) == 0)
- goto exit;
+ goto nomatch;
if (!match_any_class_permissions(avrule->perms, k->target_class, d->data))
- goto exit;
+ goto nomatch;
- rc = ebitmap_match_any(&avrule->stypes.types, &p->attr_type_map[k->source_type - 1]);
- if (rc == 0)
- goto exit;
+ if (!ebitmap_match_any(&avrule->stypes.types, &p->attr_type_map[k->source_type - 1]))
+ goto nomatch;
- if (avrule->flags == RULE_SELF) {
- /* If the neverallow uses SELF, then it is not enough that the
- * neverallow's source matches the src and tgt of the rule being checked.
- * It must match the same thing in the src and tgt, so AND the source
- * and target together and check for a match on the result.
- */
- ebitmap_t match;
- rc = ebitmap_and(&match, &p->attr_type_map[k->source_type - 1], &p->attr_type_map[k->target_type - 1] );
- if (rc) {
- ebitmap_destroy(&match);
- goto oom;
+ /* neverallow may have tgts even if it uses SELF */
+ if (!ebitmap_match_any(&avrule->ttypes.types, &p->attr_type_map[k->target_type -1])) {
+ if (avrule->flags == RULE_SELF) {
+ rc = check_assertion_self_match(k, avrule, p);
+ if (rc < 0)
+ goto oom;
+ if (rc == 0)
+ goto nomatch;
+ } else {
+ goto nomatch;
}
- rc2 = ebitmap_match_any(&avrule->stypes.types, &match);
- ebitmap_destroy(&match);
}
- /* neverallow may have tgts even if it uses SELF */
- rc = ebitmap_match_any(&avrule->ttypes.types, &p->attr_type_map[k->target_type -1]);
- if (rc == 0 && rc2 == 0)
- goto exit;
-
if (avrule->specified == AVRULE_XPERMS_NEVERALLOW) {
rc = check_assertion_extended_permissions(avrule, avtab, k, p);
+ if (rc < 0)
+ goto oom;
if (rc == 0)
- goto exit;
+ goto nomatch;
}
return 1;
-exit:
+nomatch:
return 0;
oom:
- ERR(NULL, "Out of memory - unable to check neverallows");
return rc;
}
@@ -538,6 +553,10 @@ int check_assertions(sepol_handle_t * handle, policydb_t * p,
if (!(a->specified & (AVRULE_NEVERALLOW | AVRULE_XPERMS_NEVERALLOW)))
continue;
rc = check_assertion(p, a);
+ if (rc < 0) {
+ ERR(handle, "Error occurred while checking neverallows");
+ return -1;
+ }
if (rc) {
rc = report_assertion_failures(handle, p, a);
if (rc < 0) {
diff --git a/libsepol/src/avtab.c b/libsepol/src/avtab.c
index 46e1e75d..7920b60a 100644
--- a/libsepol/src/avtab.c
+++ b/libsepol/src/avtab.c
@@ -503,6 +503,11 @@ int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a,
for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
if (val & spec_order[i]) {
+ if (items >= items2) { /* items is index, items2 is total number */
+ ERR(fp->handle, "entry has too many items (%d/%d)",
+ items + 1, items2);
+ return -1;
+ }
key.specified = spec_order[i] | enabled;
datum.data = le32_to_cpu(buf32[items++]);
rc = insertf(a, &key, &datum, p);
@@ -543,7 +548,7 @@ int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a,
if ((vers < POLICYDB_VERSION_XPERMS_IOCTL) &&
(key.specified & AVTAB_XPERMS)) {
ERR(fp->handle, "policy version %u does not support extended "
- "permissions rules and one was specified\n", vers);
+ "permissions rules and one was specified", vers);
return -1;
} else if (key.specified & AVTAB_XPERMS) {
rc = next_entry(&buf8, fp, sizeof(uint8_t));
diff --git a/libsepol/src/conditional.c b/libsepol/src/conditional.c
index 037dc7e2..f78b38a2 100644
--- a/libsepol/src/conditional.c
+++ b/libsepol/src/conditional.c
@@ -25,6 +25,7 @@
#include <sepol/policydb/conditional.h>
#include "private.h"
+#include "debug.h"
/* move all type rules to top of t/f lists to help kernel on evaluation */
static void cond_optimize(cond_av_list_t ** l)
@@ -314,8 +315,7 @@ static int evaluate_cond_node(policydb_t * p, cond_node_t * node)
if (new_state != node->cur_state) {
node->cur_state = new_state;
if (new_state == -1)
- printf
- ("expression result was undefined - disabling all rules.\n");
+ WARN(NULL, "expression result was undefined - disabling all rules.");
/* turn the rules on or off */
for (cur = node->true_list; cur != NULL; cur = cur->next) {
if (new_state <= 0) {
@@ -368,8 +368,7 @@ int cond_normalize_expr(policydb_t * p, cond_node_t * cn)
if (ne) {
ne->next = NULL;
} else { /* ne should never be NULL */
- printf
- ("Found expr with no bools and only a ! - this should never happen.\n");
+ ERR(NULL, "Found expr with no bools and only a ! - this should never happen.");
return -1;
}
/* swap the true and false lists */
@@ -421,9 +420,8 @@ int cond_normalize_expr(policydb_t * p, cond_node_t * cn)
}
k = cond_evaluate_expr(p, cn->expr);
if (k == -1) {
- printf
- ("While testing expression, expression result "
- "was undefined - this should never happen.\n");
+ ERR(NULL, "While testing expression, expression result "
+ "was undefined - this should never happen.");
return -1;
}
/* set the bit if expression evaluates true */
@@ -524,7 +522,7 @@ int cond_init_bool_indexes(policydb_t * p)
if (p->bool_val_to_struct)
free(p->bool_val_to_struct);
p->bool_val_to_struct = (cond_bool_datum_t **)
- malloc(p->p_bools.nprim * sizeof(cond_bool_datum_t *));
+ mallocarray(p->p_bools.nprim, sizeof(cond_bool_datum_t *));
if (!p->bool_val_to_struct)
return -1;
return 0;
@@ -635,9 +633,8 @@ static int cond_insertf(avtab_t * a
*/
if (k->specified & AVTAB_TYPE) {
if (avtab_search(&p->te_avtab, k)) {
- printf
- ("security: type rule already exists outside of a conditional.");
- goto err;
+ WARN(NULL, "security: type rule already exists outside of a conditional.");
+ return -1;
}
/*
* If we are reading the false list other will be a pointer to
@@ -652,9 +649,8 @@ static int cond_insertf(avtab_t * a
if (node_ptr) {
if (avtab_search_node_next
(node_ptr, k->specified)) {
- printf
- ("security: too many conflicting type rules.");
- goto err;
+ ERR(NULL, "security: too many conflicting type rules.");
+ return -1;
}
found = 0;
for (cur = other; cur != NULL; cur = cur->next) {
@@ -664,30 +660,28 @@ static int cond_insertf(avtab_t * a
}
}
if (!found) {
- printf
- ("security: conflicting type rules.\n");
- goto err;
+ ERR(NULL, "security: conflicting type rules.");
+ return -1;
}
}
} else {
if (avtab_search(&p->te_cond_avtab, k)) {
- printf
- ("security: conflicting type rules when adding type rule for true.\n");
- goto err;
+ ERR(NULL, "security: conflicting type rules when adding type rule for true.");
+ return -1;
}
}
}
node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
if (!node_ptr) {
- printf("security: could not insert rule.");
- goto err;
+ ERR(NULL, "security: could not insert rule.");
+ return -1;
}
node_ptr->parse_context = (void *)1;
list = malloc(sizeof(cond_av_list_t));
if (!list)
- goto err;
+ return -1;
memset(list, 0, sizeof(cond_av_list_t));
list->node = node_ptr;
@@ -697,11 +691,6 @@ static int cond_insertf(avtab_t * a
data->tail->next = list;
data->tail = list;
return 0;
-
- err:
- cond_av_list_destroy(data->head);
- data->head = NULL;
- return -1;
}
static int cond_read_av_list(policydb_t * p, void *fp,
@@ -730,8 +719,10 @@ static int cond_read_av_list(policydb_t * p, void *fp,
for (i = 0; i < len; i++) {
rc = avtab_read_item(fp, p->policyvers, &p->te_cond_avtab,
cond_insertf, &data);
- if (rc)
+ if (rc) {
+ cond_av_list_destroy(data.head);
return rc;
+ }
}
@@ -742,14 +733,12 @@ static int cond_read_av_list(policydb_t * p, void *fp,
static int expr_isvalid(policydb_t * p, cond_expr_t * expr)
{
if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
- printf
- ("security: conditional expressions uses unknown operator.\n");
+ WARN(NULL, "security: conditional expressions uses unknown operator.");
return 0;
}
if (expr->bool > p->p_bools.nprim) {
- printf
- ("security: conditional expressions uses unknown bool.\n");
+ WARN(NULL, "security: conditional expressions uses unknown bool.");
return 0;
}
return 1;
diff --git a/libsepol/src/context_record.c b/libsepol/src/context_record.c
index 435f7880..2bda121b 100644
--- a/libsepol/src/context_record.c
+++ b/libsepol/src/context_record.c
@@ -127,7 +127,7 @@ int sepol_context_create(sepol_handle_t * handle, sepol_context_t ** con_ptr)
(sepol_context_t *) malloc(sizeof(sepol_context_t));
if (!con) {
- ERR(handle, "out of memory, could not " "create context\n");
+ ERR(handle, "out of memory, could not create context");
return STATUS_ERR;
}
diff --git a/libsepol/src/ebitmap.c b/libsepol/src/ebitmap.c
index 1de3816a..bd98c0f8 100644
--- a/libsepol/src/ebitmap.c
+++ b/libsepol/src/ebitmap.c
@@ -406,8 +406,7 @@ int ebitmap_read(ebitmap_t * e, void *fp)
count = le32_to_cpu(buf[2]);
if (mapsize != MAPSIZE) {
- printf
- ("security: ebitmap: map size %d does not match my size %zu (high bit was %d)\n",
+ ERR(NULL, "security: ebitmap: map size %d does not match my size %zu (high bit was %d)",
mapsize, MAPSIZE, e->highbit);
goto bad;
}
@@ -416,8 +415,7 @@ int ebitmap_read(ebitmap_t * e, void *fp)
goto ok;
}
if (e->highbit & (MAPSIZE - 1)) {
- printf
- ("security: ebitmap: high bit (%d) is not a multiple of the map size (%zu)\n",
+ ERR(NULL, "security: ebitmap: high bit (%d) is not a multiple of the map size (%zu)",
e->highbit, MAPSIZE);
goto bad;
}
@@ -429,12 +427,12 @@ int ebitmap_read(ebitmap_t * e, void *fp)
for (i = 0; i < count; i++) {
rc = next_entry(buf, fp, sizeof(uint32_t));
if (rc < 0) {
- printf("security: ebitmap: truncated map\n");
+ ERR(NULL, "security: ebitmap: truncated map");
goto bad;
}
n = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t));
if (!n) {
- printf("security: ebitmap: out of memory\n");
+ ERR(NULL, "security: ebitmap: out of memory");
rc = -ENOMEM;
goto bad;
}
@@ -443,34 +441,30 @@ int ebitmap_read(ebitmap_t * e, void *fp)
n->startbit = le32_to_cpu(buf[0]);
if (n->startbit & (MAPSIZE - 1)) {
- printf
- ("security: ebitmap start bit (%d) is not a multiple of the map size (%zu)\n",
+ ERR(NULL, "security: ebitmap start bit (%d) is not a multiple of the map size (%zu)",
n->startbit, MAPSIZE);
goto bad_free;
}
if (n->startbit > (e->highbit - MAPSIZE)) {
- printf
- ("security: ebitmap start bit (%d) is beyond the end of the bitmap (%zu)\n",
+ ERR(NULL, "security: ebitmap start bit (%d) is beyond the end of the bitmap (%zu)",
n->startbit, (e->highbit - MAPSIZE));
goto bad_free;
}
rc = next_entry(&map, fp, sizeof(uint64_t));
if (rc < 0) {
- printf("security: ebitmap: truncated map\n");
+ ERR(NULL, "security: ebitmap: truncated map");
goto bad_free;
}
n->map = le64_to_cpu(map);
if (!n->map) {
- printf
- ("security: ebitmap: null map in ebitmap (startbit %d)\n",
+ ERR(NULL, "security: ebitmap: null map in ebitmap (startbit %d)",
n->startbit);
goto bad_free;
}
if (l) {
if (n->startbit <= l->startbit) {
- printf
- ("security: ebitmap: start bit %d comes after start bit %d\n",
+ ERR(NULL, "security: ebitmap: start bit %d comes after start bit %d",
n->startbit, l->startbit);
goto bad_free;
}
@@ -481,8 +475,7 @@ int ebitmap_read(ebitmap_t * e, void *fp)
l = n;
}
if (count && l->startbit + MAPSIZE != e->highbit) {
- printf
- ("security: ebitmap: high bit %u has not the expected value %zu\n",
+ ERR(NULL, "security: ebitmap: high bit %u has not the expected value %zu",
e->highbit, l->startbit + MAPSIZE);
goto bad;
}
diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c
index a6a466f7..7da51a40 100644
--- a/libsepol/src/expand.c
+++ b/libsepol/src/expand.c
@@ -166,7 +166,7 @@ static int type_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
if (new_type->flags & TYPE_FLAGS_PERMISSIVE)
if (ebitmap_set_bit(&state->out->permissive_map, new_type->s.value, 1)) {
- ERR(state->handle, "Out of memory!\n");
+ ERR(state->handle, "Out of memory!");
return -1;
}
@@ -929,11 +929,15 @@ int mls_semantic_level_expand(mls_semantic_level_t * sl, mls_level_t * l,
if (!sl->sens)
return 0;
+ /* Invalid sensitivity */
+ if (sl->sens > p->p_levels.nprim || !p->p_sens_val_to_name[sl->sens - 1])
+ return -1;
+
l->sens = sl->sens;
levdatum = (level_datum_t *) hashtab_search(p->p_levels.table,
p->p_sens_val_to_name[l->sens - 1]);
if (!levdatum) {
- ERR(h, "%s: Impossible situation found, nothing in p_levels.table.\n",
+ ERR(h, "%s: Impossible situation found, nothing in p_levels.table.",
__func__);
errno = ENOENT;
return -1;
@@ -1690,7 +1694,7 @@ static int expand_terule_helper(sepol_handle_t * handle,
uint32_t oldtype = 0;
if (!(specified & (AVRULE_TRANSITION|AVRULE_MEMBER|AVRULE_CHANGE))) {
- ERR(handle, "Invalid specification: %"PRIu32"\n", specified);
+ ERR(handle, "Invalid specification: %"PRIu32, specified);
return EXPAND_RULE_ERROR;
}
@@ -1869,7 +1873,7 @@ static int expand_avrule_helper(sepol_handle_t * handle,
return EXPAND_RULE_ERROR;
break;
default:
- ERR(handle, "Unknown specification: %"PRIu32"\n", specified);
+ ERR(handle, "Unknown specification: %"PRIu32, specified);
return EXPAND_RULE_ERROR;
}
@@ -2477,7 +2481,7 @@ int role_set_expand(role_set_t * x, ebitmap_t * r, policydb_t * out, policydb_t
/* if role is to be complimented, invert the entire bitmap here */
if (x->flags & ROLE_COMP) {
- for (i = 0; i < ebitmap_length(r); i++) {
+ for (i = 0; i < p->p_roles.nprim; i++) {
if (ebitmap_get_bit(r, i)) {
if (ebitmap_set_bit(r, i, 0))
return -1;
@@ -2966,6 +2970,9 @@ int expand_module(sepol_handle_t * handle,
state.out->policy_type = POLICY_KERN;
state.out->policyvers = POLICYDB_VERSION_MAX;
+ if (state.base->name) {
+ state.out->name = strdup(state.base->name);
+ }
/* Copy mls state from base to out */
out->mls = base->mls;
@@ -3146,9 +3153,9 @@ int expand_module(sepol_handle_t * handle,
goto cleanup;
/* Build the type<->attribute maps and remove attributes. */
- state.out->attr_type_map = malloc(state.out->p_types.nprim *
+ state.out->attr_type_map = mallocarray(state.out->p_types.nprim,
sizeof(ebitmap_t));
- state.out->type_attr_map = malloc(state.out->p_types.nprim *
+ state.out->type_attr_map = mallocarray(state.out->p_types.nprim,
sizeof(ebitmap_t));
if (!state.out->attr_type_map || !state.out->type_attr_map) {
ERR(handle, "Out of memory!");
diff --git a/libsepol/src/hashtab.c b/libsepol/src/hashtab.c
index 21143b76..3ecaf165 100644
--- a/libsepol/src/hashtab.c
+++ b/libsepol/src/hashtab.c
@@ -32,6 +32,8 @@
#include <string.h>
#include <sepol/policydb/hashtab.h>
+#include "private.h"
+
hashtab_t hashtab_create(unsigned int (*hash_value) (hashtab_t h,
const_hashtab_key_t key),
int (*keycmp) (hashtab_t h,
@@ -52,7 +54,7 @@ hashtab_t hashtab_create(unsigned int (*hash_value) (hashtab_t h,
p->nel = 0;
p->hash_value = hash_value;
p->keycmp = keycmp;
- p->htable = (hashtab_ptr_t *) malloc(sizeof(hashtab_ptr_t) * size);
+ p->htable = (hashtab_ptr_t *) mallocarray(size, sizeof(hashtab_ptr_t));
if (p->htable == NULL) {
free(p);
return NULL;
@@ -222,8 +224,9 @@ int hashtab_map(hashtab_t h,
int (*apply) (hashtab_key_t k,
hashtab_datum_t d, void *args), void *args)
{
- unsigned int i, ret;
+ unsigned int i;
hashtab_ptr_t cur;
+ int ret;
if (!h)
return SEPOL_OK;
diff --git a/libsepol/src/hierarchy.c b/libsepol/src/hierarchy.c
index 8919daa7..350443a8 100644
--- a/libsepol/src/hierarchy.c
+++ b/libsepol/src/hierarchy.c
@@ -237,7 +237,7 @@ oom:
ERR(handle, "Insufficient memory");
exit:
- ERR(handle,"Failed to expand parent rules\n");
+ ERR(handle,"Failed to expand parent rules");
avtab_destroy(global_avtab);
bounds_destroy_cond_info(*cond_info);
*cond_info = NULL;
diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c
index 305567a5..869f6940 100644
--- a/libsepol/src/kernel_to_cil.c
+++ b/libsepol/src/kernel_to_cil.c
@@ -278,10 +278,13 @@ static int class_constraint_rules_to_strs(struct policydb *pdb, char *classkey,
char *expr = NULL;
int is_mls;
char *perms;
- const char *format_str;
+ const char *key_word;
struct strs *strs;
for (curr = constraint_rules; curr != NULL; curr = curr->next) {
+ if (curr->permissions == 0) {
+ continue;
+ }
expr = constraint_expr_to_str(pdb, curr->expr, &is_mls);
if (!expr) {
rc = -1;
@@ -291,14 +294,14 @@ static int class_constraint_rules_to_strs(struct policydb *pdb, char *classkey,
perms = sepol_av_to_string(pdb, class->s.value, curr->permissions);
if (is_mls) {
- format_str = "(mlsconstrain (%s (%s)) %s)";
+ key_word = "mlsconstrain";
strs = mls_list;
} else {
- format_str = "(constrain (%s (%s)) %s)";
+ key_word = "constrain";
strs = non_mls_list;
}
- rc = strs_create_and_add(strs, format_str, 3, classkey, perms+1, expr);
+ rc = strs_create_and_add(strs, "(%s (%s (%s)) %s)", 4, key_word, classkey, perms+1, expr);
free(expr);
if (rc != 0) {
goto exit;
@@ -319,7 +322,7 @@ static int class_validatetrans_rules_to_strs(struct policydb *pdb, char *classke
struct constraint_node *curr;
char *expr = NULL;
int is_mls;
- const char *format_str;
+ const char *key_word;
struct strs *strs;
int rc = 0;
@@ -331,14 +334,14 @@ static int class_validatetrans_rules_to_strs(struct policydb *pdb, char *classke
}
if (is_mls) {
- format_str = "(mlsvalidatetrans %s %s)";
+ key_word = "mlsvalidatetrans";
strs = mls_list;
} else {
- format_str = "(validatetrans %s %s)";
+ key_word = "validatetrans";
strs = non_mls_list;
}
- rc = strs_create_and_add(strs, format_str, 2, classkey, expr);
+ rc = strs_create_and_add(strs, "(%s %s %s)", 3, key_word, classkey, expr);
free(expr);
if (rc != 0) {
goto exit;
@@ -358,6 +361,7 @@ static int constraint_rules_to_strs(struct policydb *pdb, struct strs *mls_strs,
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
if (class->constraints) {
name = pdb->p_class_val_to_name[i];
rc = class_constraint_rules_to_strs(pdb, name, class, class->constraints, mls_strs, non_mls_strs);
@@ -383,6 +387,7 @@ static int validatetrans_rules_to_strs(struct policydb *pdb, struct strs *mls_st
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
if (class->validatetrans) {
name = pdb->p_class_val_to_name[i];
rc = class_validatetrans_rules_to_strs(pdb, name, class->validatetrans, mls_strs, non_mls_strs);
@@ -461,6 +466,7 @@ static int write_class_decl_rules_to_cil(FILE *out, struct policydb *pdb)
/* class */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
name = pdb->p_class_val_to_name[i];
perms = class_or_common_perms_to_str(&class->permissions);
if (perms) {
@@ -488,6 +494,7 @@ static int write_class_decl_rules_to_cil(FILE *out, struct policydb *pdb)
/* classcommon */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
name = pdb->p_class_val_to_name[i];
if (class->comkey != NULL) {
sepol_printf(out, "(classcommon %s %s)\n", name, class->comkey);
@@ -503,6 +510,7 @@ static int write_class_decl_rules_to_cil(FILE *out, struct policydb *pdb)
}
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
name = class->comkey;
if (name != NULL) {
common = hashtab_search(pdb->p_commons.table, name);
@@ -727,6 +735,7 @@ static int write_default_rules_to_cil(FILE *out, struct policydb *pdb)
/* default_user */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
if (class->default_user != 0) {
rc = write_default_user_to_cil(out, pdb->p_class_val_to_name[i], class);
if (rc != 0) {
@@ -738,6 +747,7 @@ static int write_default_rules_to_cil(FILE *out, struct policydb *pdb)
/* default_role */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
if (class->default_role != 0) {
rc = write_default_role_to_cil(out, pdb->p_class_val_to_name[i], class);
if (rc != 0) {
@@ -749,6 +759,7 @@ static int write_default_rules_to_cil(FILE *out, struct policydb *pdb)
/* default_type */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
if (class->default_type != 0) {
rc = write_default_type_to_cil(out, pdb->p_class_val_to_name[i], class);
if (rc != 0) {
@@ -764,6 +775,7 @@ static int write_default_rules_to_cil(FILE *out, struct policydb *pdb)
/* default_range */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
if (class->default_range) {
rc = write_default_range_to_cil(out, pdb->p_class_val_to_name[i], class);
if (rc != 0) {
@@ -1035,7 +1047,6 @@ static char *cats_ebitmap_to_str(struct ebitmap *cats, char **val_to_name)
struct ebitmap_node *node;
uint32_t i, start, range;
char *catsbuf = NULL, *p;
- const char *fmt;
int len, remaining;
remaining = (int)cats_ebitmap_len(cats, val_to_name);
@@ -1063,9 +1074,15 @@ static char *cats_ebitmap_to_str(struct ebitmap *cats, char **val_to_name)
continue;
if (range > 1) {
- fmt = (range == 2) ? "%s %s " : "(range %s %s) ";
- len = snprintf(p, remaining, fmt,
- val_to_name[start], val_to_name[i]);
+ if (range == 2) {
+ len = snprintf(p, remaining, "%s %s ",
+ val_to_name[start],
+ val_to_name[i]);
+ } else {
+ len = snprintf(p, remaining, "(range %s %s) ",
+ val_to_name[start],
+ val_to_name[i]);
+ }
} else {
len = snprintf(p, remaining, "%s ", val_to_name[start]);
}
@@ -1213,7 +1230,7 @@ static int write_type_attributes_to_cil(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type = pdb->type_val_to_struct[i];
- if (type->flavor == TYPE_ATTRIB) {
+ if (type && type->flavor == TYPE_ATTRIB) {
rc = strs_add(strs, pdb->p_type_val_to_name[i]);
if (rc != 0) {
goto exit;
@@ -1343,7 +1360,7 @@ static int write_type_decl_rules_to_cil(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type = pdb->type_val_to_struct[i];
- if (type->flavor == TYPE_TYPE && type->primary) {
+ if (type && type->flavor == TYPE_TYPE && type->primary) {
rc = strs_add(strs, pdb->p_type_val_to_name[i]);
if (rc != 0) {
goto exit;
@@ -1472,7 +1489,7 @@ static int write_type_bounds_rules_to_cil(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type = pdb->type_val_to_struct[i];
- if (type->flavor == TYPE_TYPE) {
+ if (type && type->flavor == TYPE_TYPE) {
if (type->bounds > 0) {
rc = strs_add(strs, pdb->p_type_val_to_name[i]);
if (rc != 0) {
@@ -1526,7 +1543,7 @@ static int write_type_attribute_sets_to_cil(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
attr = pdb->type_val_to_struct[i];
- if (attr->flavor != TYPE_ATTRIB) continue;
+ if (!attr || attr->flavor != TYPE_ATTRIB) continue;
name = pdb->p_type_val_to_name[i];
typemap = &pdb->attr_type_map[i];
if (ebitmap_is_empty(typemap)) continue;
@@ -2259,7 +2276,7 @@ static int write_role_decl_rules_to_cil(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type_datum = pdb->type_val_to_struct[i];
- if (type_datum->flavor == TYPE_TYPE && type_datum->primary) {
+ if (type_datum && type_datum->flavor == TYPE_TYPE && type_datum->primary) {
rc = strs_add(strs, pdb->p_type_val_to_name[i]);
if (rc != 0) {
goto exit;
@@ -2383,6 +2400,7 @@ static int write_user_decl_rules_to_cil(FILE *out, struct policydb *pdb)
}
for (i=0; i < pdb->p_users.nprim; i++) {
+ if (!pdb->p_user_val_to_name[i]) continue;
rc = strs_add(strs, pdb->p_user_val_to_name[i]);
if (rc != 0) {
goto exit;
@@ -2640,6 +2658,8 @@ static int write_genfscon_rules_to_cil(FILE *out, struct policydb *pdb)
struct ocontext *ocon;
struct strs *strs;
char *fstype, *name, *ctx;
+ uint32_t sclass;
+ const char *file_type;
int rc;
rc = strs_init(&strs, 32);
@@ -2652,14 +2672,43 @@ static int write_genfscon_rules_to_cil(FILE *out, struct policydb *pdb)
fstype = genfs->fstype;
name = ocon->u.name;
+ sclass = ocon->v.sclass;
+ file_type = NULL;
+ if (sclass) {
+ const char *class_name = pdb->p_class_val_to_name[sclass-1];
+ if (strcmp(class_name, "file") == 0) {
+ file_type = "file";
+ } else if (strcmp(class_name, "dir") == 0) {
+ file_type = "dir";
+ } else if (strcmp(class_name, "chr_file") == 0) {
+ file_type = "char";
+ } else if (strcmp(class_name, "blk_file") == 0) {
+ file_type = "block";
+ } else if (strcmp(class_name, "sock_file") == 0) {
+ file_type = "socket";
+ } else if (strcmp(class_name, "fifo_file") == 0) {
+ file_type = "pipe";
+ } else if (strcmp(class_name, "lnk_file") == 0) {
+ file_type = "symlink";
+ } else {
+ rc = -1;
+ goto exit;
+ }
+ }
+
ctx = context_to_str(pdb, &ocon->context[0]);
if (!ctx) {
rc = -1;
goto exit;
}
- rc = strs_create_and_add(strs, "(genfscon %s \"%s\" %s)", 3,
- fstype, name, ctx);
+ if (file_type) {
+ rc = strs_create_and_add(strs, "(genfscon %s \"%s\" %s %s)", 4,
+ fstype, name, file_type, ctx);
+ } else {
+ rc = strs_create_and_add(strs, "(genfscon %s \"%s\" %s)", 3,
+ fstype, name, ctx);
+ }
free(ctx);
if (rc != 0) {
goto exit;
diff --git a/libsepol/src/kernel_to_common.c b/libsepol/src/kernel_to_common.c
index a7453d3c..972499ab 100644
--- a/libsepol/src/kernel_to_common.c
+++ b/libsepol/src/kernel_to_common.c
@@ -18,6 +18,7 @@
#include <sepol/policydb/hashtab.h>
#include <sepol/policydb/symtab.h>
+#include "private.h"
#include "kernel_to_common.h"
@@ -57,7 +58,7 @@ static char *create_str_helper(const char *fmt, int num, va_list vargs)
va_list vargs2;
char *str = NULL;
char *s;
- size_t len;
+ size_t len, s_len;
int i, rc;
va_copy(vargs2, vargs);
@@ -66,7 +67,8 @@ static char *create_str_helper(const char *fmt, int num, va_list vargs)
for (i=0; i<num; i++) {
s = va_arg(vargs, char *);
- len += strlen(s) - 2; /* -2 for each %s in fmt */
+ s_len = strlen(s);
+ len += s_len > 1 ? s_len - 2 : 0; /* -2 for each %s in fmt */
}
str = malloc(len);
@@ -106,6 +108,10 @@ int strs_init(struct strs **strs, size_t size)
{
struct strs *new;
+ if (size == 0) {
+ size = 1;
+ }
+
*strs = NULL;
new = malloc(sizeof(struct strs));
@@ -114,7 +120,7 @@ int strs_init(struct strs **strs, size_t size)
return -1;
}
- new->list = calloc(sizeof(char *), size);
+ new->list = calloc(size, sizeof(char *));
if (!new->list) {
sepol_log_err("Out of memory");
free(new);
@@ -159,9 +165,9 @@ int strs_add(struct strs *strs, char *s)
{
if (strs->num + 1 > strs->size) {
char **new;
- unsigned i = strs->size;
+ size_t i = strs->size;
strs->size *= 2;
- new = realloc(strs->list, sizeof(char *)*strs->size);
+ new = reallocarray(strs->list, strs->size, sizeof(char *));
if (!new) {
sepol_log_err("Out of memory");
return -1;
@@ -212,15 +218,15 @@ char *strs_remove_last(struct strs *strs)
return strs->list[strs->num];
}
-int strs_add_at_index(struct strs *strs, char *s, unsigned index)
+int strs_add_at_index(struct strs *strs, char *s, size_t index)
{
if (index >= strs->size) {
char **new;
- unsigned i = strs->size;
+ size_t i = strs->size;
while (index >= strs->size) {
strs->size *= 2;
}
- new = realloc(strs->list, sizeof(char *)*strs->size);
+ new = reallocarray(strs->list, strs->size, sizeof(char *));
if (!new) {
sepol_log_err("Out of memory");
return -1;
@@ -237,7 +243,7 @@ int strs_add_at_index(struct strs *strs, char *s, unsigned index)
return 0;
}
-char *strs_read_at_index(struct strs *strs, unsigned index)
+char *strs_read_at_index(struct strs *strs, size_t index)
{
if (index >= strs->num) {
return NULL;
@@ -361,6 +367,9 @@ int ebitmap_to_strs(struct ebitmap *map, struct strs *strs, char **val_to_name)
int rc;
ebitmap_for_each_positive_bit(map, node, i) {
+ if (!val_to_name[i])
+ continue;
+
rc = strs_add(strs, val_to_name[i]);
if (rc != 0) {
return -1;
diff --git a/libsepol/src/kernel_to_common.h b/libsepol/src/kernel_to_common.h
index 8aa483fa..e9932d30 100644
--- a/libsepol/src/kernel_to_common.h
+++ b/libsepol/src/kernel_to_common.h
@@ -99,8 +99,8 @@ int strs_add(struct strs *strs, char *s);
__attribute__ ((format(printf, 2, 4)))
int strs_create_and_add(struct strs *strs, const char *fmt, int num, ...);
char *strs_remove_last(struct strs *strs);
-int strs_add_at_index(struct strs *strs, char *s, unsigned index);
-char *strs_read_at_index(struct strs *strs, unsigned index);
+int strs_add_at_index(struct strs *strs, char *s, size_t index);
+char *strs_read_at_index(struct strs *strs, size_t index);
void strs_sort(struct strs *strs);
unsigned strs_num_items(struct strs *strs);
size_t strs_len_items(struct strs *strs);
diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c
index eb72e4ac..3544f73d 100644
--- a/libsepol/src/kernel_to_conf.c
+++ b/libsepol/src/kernel_to_conf.c
@@ -271,12 +271,15 @@ static int class_constraint_rules_to_strs(struct policydb *pdb, char *classkey,
{
struct constraint_node *curr;
struct strs *strs;
- const char *format_str, *flavor;
+ const char *flavor, *perm_prefix, *perm_suffix;
char *perms, *expr;
int is_mls;
int rc = 0;
for (curr = constraint_rules; curr != NULL; curr = curr->next) {
+ if (curr->permissions == 0) {
+ continue;
+ }
expr = constraint_expr_to_str(pdb, curr->expr, &is_mls);
if (!expr) {
rc = -1;
@@ -285,9 +288,11 @@ static int class_constraint_rules_to_strs(struct policydb *pdb, char *classkey,
perms = sepol_av_to_string(pdb, class->s.value, curr->permissions);
if (strchr(perms, ' ')) {
- format_str = "%s %s { %s } %s;";
+ perm_prefix = "{ ";
+ perm_suffix = " }";
} else {
- format_str = "%s %s %s %s";
+ perm_prefix = "";
+ perm_suffix = "";
}
if (is_mls) {
flavor = "mlsconstrain";
@@ -297,8 +302,10 @@ static int class_constraint_rules_to_strs(struct policydb *pdb, char *classkey,
strs = non_mls_list;
}
- rc = strs_create_and_add(strs, format_str, 4,
- flavor, classkey, perms+1, expr);
+ rc = strs_create_and_add(strs, "%s %s %s%s%s %s;", 6,
+ flavor, classkey,
+ perm_prefix, perms+1, perm_suffix,
+ expr);
free(expr);
if (rc != 0) {
goto exit;
@@ -358,7 +365,7 @@ static int constraint_rules_to_strs(struct policydb *pdb, struct strs *mls_strs,
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
- if (class->constraints) {
+ if (class && class->constraints) {
name = pdb->p_class_val_to_name[i];
rc = class_constraint_rules_to_strs(pdb, name, class, class->constraints, mls_strs, non_mls_strs);
if (rc != 0) {
@@ -383,7 +390,7 @@ static int validatetrans_rules_to_strs(struct policydb *pdb, struct strs *mls_st
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
- if (class->validatetrans) {
+ if (class && class->validatetrans) {
name = pdb->p_class_val_to_name[i];
rc = class_validatetrans_rules_to_strs(pdb, name, class->validatetrans, mls_strs, non_mls_strs);
if (rc != 0) {
@@ -551,6 +558,7 @@ static int write_class_and_common_rules_to_conf(FILE *out, struct policydb *pdb)
}
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
name = class->comkey;
if (!name) continue;
common = hashtab_search(pdb->p_commons.table, name);
@@ -577,6 +585,7 @@ static int write_class_and_common_rules_to_conf(FILE *out, struct policydb *pdb)
/* class */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
name = pdb->p_class_val_to_name[i];
sepol_printf(out, "class %s", name);
if (class->comkey) {
@@ -702,6 +711,7 @@ static int write_default_rules_to_conf(FILE *out, struct policydb *pdb)
/* default_user */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
if (class->default_user != 0) {
rc = write_default_user_to_conf(out, pdb->p_class_val_to_name[i], class);
if (rc != 0) {
@@ -713,6 +723,7 @@ static int write_default_rules_to_conf(FILE *out, struct policydb *pdb)
/* default_role */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
if (class->default_role != 0) {
rc = write_default_role_to_conf(out, pdb->p_class_val_to_name[i], class);
if (rc != 0) {
@@ -724,6 +735,7 @@ static int write_default_rules_to_conf(FILE *out, struct policydb *pdb)
/* default_type */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
if (class->default_type != 0) {
rc = write_default_type_to_conf(out, pdb->p_class_val_to_name[i], class);
if (rc != 0) {
@@ -739,6 +751,7 @@ static int write_default_rules_to_conf(FILE *out, struct policydb *pdb)
/* default_range */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
if (class->default_range != 0) {
rc = write_default_range_to_conf(out, pdb->p_class_val_to_name[i], class);
if (rc != 0) {
@@ -908,7 +921,7 @@ static int write_category_rules_to_conf(FILE *out, struct policydb *pdb)
unsigned i, j, num;
int rc = 0;
- rc = strs_init(&strs, pdb->p_levels.nprim);
+ rc = strs_init(&strs, pdb->p_cats.nprim);
if (rc != 0) {
goto exit;
}
@@ -1026,7 +1039,6 @@ static char *cats_ebitmap_to_str(struct ebitmap *cats, char **val_to_name)
struct ebitmap_node *node;
uint32_t i, start, range, first;
char *catsbuf = NULL, *p;
- const char *fmt;
char sep;
int len, remaining;
@@ -1054,12 +1066,12 @@ static char *cats_ebitmap_to_str(struct ebitmap *cats, char **val_to_name)
if (range > 1) {
sep = (range == 2) ? ',' : '.';
- fmt = first ? "%s%c%s" : ",%s%c%s";
- len = snprintf(p, remaining, fmt,
+ len = snprintf(p, remaining, "%s%s%c%s",
+ first ? "" : ",",
val_to_name[start], sep, val_to_name[i]);
} else {
- fmt = first ? "%s" : ",%s";
- len = snprintf(p, remaining, fmt, val_to_name[start]);
+ len = snprintf(p, remaining, "%s%s", first ? "" : ",",
+ val_to_name[start]);
}
if (len < 0 || len >= remaining) {
@@ -1201,7 +1213,7 @@ static int write_type_attributes_to_conf(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type = pdb->type_val_to_struct[i];
- if (type->flavor == TYPE_ATTRIB) {
+ if (type && type->flavor == TYPE_ATTRIB) {
rc = strs_add(strs, pdb->p_type_val_to_name[i]);
if (rc != 0) {
goto exit;
@@ -1331,7 +1343,7 @@ static int write_type_decl_rules_to_conf(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type = pdb->type_val_to_struct[i];
- if (type->flavor == TYPE_TYPE && type->primary) {
+ if (type && type->flavor == TYPE_TYPE && type->primary) {
rc = strs_add(strs, pdb->p_type_val_to_name[i]);
if (rc != 0) {
goto exit;
@@ -1451,7 +1463,7 @@ static int write_type_bounds_rules_to_conf(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type = pdb->type_val_to_struct[i];
- if (type->flavor == TYPE_TYPE) {
+ if (type && type->flavor == TYPE_TYPE) {
if (type->bounds > 0) {
rc = strs_add(strs, pdb->p_type_val_to_name[i]);
if (rc != 0) {
@@ -1574,7 +1586,7 @@ static int write_type_attribute_sets_to_conf(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type = pdb->type_val_to_struct[i];
- if (type->flavor != TYPE_TYPE || !type->primary) continue;
+ if (!type || type->flavor != TYPE_TYPE || !type->primary) continue;
if (ebitmap_cardinality(&pdb->type_attr_map[i]) == 1) continue;
rc = ebitmap_cpy(&attrmap, &pdb->type_attr_map[i]);
@@ -2318,6 +2330,7 @@ static int write_user_decl_rules_to_conf(FILE *out, struct policydb *pdb)
}
for (i=0; i < pdb->p_users.nprim; i++) {
+ if (!pdb->p_user_val_to_name[i]) continue;
rc = strs_add(strs, pdb->p_user_val_to_name[i]);
if (rc != 0) {
goto exit;
@@ -2513,6 +2526,8 @@ static int write_genfscon_rules_to_conf(FILE *out, struct policydb *pdb)
struct ocontext *ocon;
struct strs *strs;
char *fstype, *name, *ctx;
+ uint32_t sclass;
+ const char *file_type;
int rc;
rc = strs_init(&strs, 32);
@@ -2525,14 +2540,43 @@ static int write_genfscon_rules_to_conf(FILE *out, struct policydb *pdb)
fstype = genfs->fstype;
name = ocon->u.name;
+ sclass = ocon->v.sclass;
+ file_type = NULL;
+ if (sclass) {
+ const char *class_name = pdb->p_class_val_to_name[sclass-1];
+ if (strcmp(class_name, "file") == 0) {
+ file_type = "--";
+ } else if (strcmp(class_name, "dir") == 0) {
+ file_type = "-d";
+ } else if (strcmp(class_name, "chr_file") == 0) {
+ file_type = "-c";
+ } else if (strcmp(class_name, "blk_file") == 0) {
+ file_type = "-b";
+ } else if (strcmp(class_name, "sock_file") == 0) {
+ file_type = "-s";
+ } else if (strcmp(class_name, "fifo_file") == 0) {
+ file_type = "-p";
+ } else if (strcmp(class_name, "lnk_file") == 0) {
+ file_type = "-l";
+ } else {
+ rc = -1;
+ goto exit;
+ }
+ }
+
ctx = context_to_str(pdb, &ocon->context[0]);
if (!ctx) {
rc = -1;
goto exit;
}
- rc = strs_create_and_add(strs, "genfscon %s \"%s\" %s", 3,
- fstype, name, ctx);
+ if (file_type) {
+ rc = strs_create_and_add(strs, "genfscon %s \"%s\" %s %s", 4,
+ fstype, name, file_type, ctx);
+ } else {
+ rc = strs_create_and_add(strs, "genfscon %s \"%s\" %s", 3,
+ fstype, name, ctx);
+ }
free(ctx);
if (rc != 0) {
goto exit;
diff --git a/libsepol/src/link.c b/libsepol/src/link.c
index 7512a4d9..21a5a935 100644
--- a/libsepol/src/link.c
+++ b/libsepol/src/link.c
@@ -34,6 +34,7 @@
#include <assert.h>
#include "debug.h"
+#include "private.h"
#undef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
@@ -164,7 +165,7 @@ static int permission_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
(hashtab_datum_t) new_perm);
if (ret) {
ERR(state->handle,
- "could not insert permission into class\n");
+ "could not insert permission into class");
goto err;
}
new_perm->s.value = dest_class->permissions.nprim + 1;
@@ -190,8 +191,9 @@ static int permission_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
ERR(state->handle, "Out of memory!");
return -1;
}
- memcpy(newmap, mod->perm_map[sclassi],
- mod->perm_map_len[sclassi] * sizeof(*newmap));
+ if (mod->perm_map_len[sclassi] > 0) {
+ memcpy(newmap, mod->perm_map[sclassi], mod->perm_map_len[sclassi] * sizeof(*newmap));
+ }
free(mod->perm_map[sclassi]);
mod->perm_map[sclassi] = newmap;
mod->perm_map_len[sclassi] = perm->s.value;
@@ -287,7 +289,7 @@ static int class_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
new_class =
(class_datum_t *) calloc(1, sizeof(class_datum_t));
if (new_class == NULL) {
- ERR(state->handle, "Memory error\n");
+ ERR(state->handle, "Memory error");
ret = SEPOL_ERR;
goto err;
}
@@ -298,7 +300,7 @@ static int class_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
}
new_id = strdup(id);
if (new_id == NULL) {
- ERR(state->handle, "Memory error\n");
+ ERR(state->handle, "Memory error");
symtab_destroy(&new_class->permissions);
ret = SEPOL_ERR;
goto err;
@@ -694,7 +696,7 @@ static int sens_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
return SEPOL_ENOTSUP;
} else {
ERR(state->handle,
- "%s: has an unknown scope: %d\n",
+ "%s: has an unknown scope: %d",
state->cur_mod_name, scope->scope);
return SEPOL_ENOTSUP;
}
@@ -736,7 +738,7 @@ static int cat_copy_callback(hashtab_key_t key, hashtab_datum_t datum,
} else {
/* unknown scope? malformed policy? */
ERR(state->handle,
- "%s: has an unknown scope: %d\n",
+ "%s: has an unknown scope: %d",
state->cur_mod_name, scope->scope);
return SEPOL_ENOTSUP;
}
@@ -1679,7 +1681,7 @@ static int copy_scope_index(scope_index_t * src, scope_index_t * dest,
}
/* next copy the enabled permissions data */
- if ((dest->class_perms_map = malloc(largest_mapped_class_value *
+ if ((dest->class_perms_map = mallocarray(largest_mapped_class_value,
sizeof(*dest->class_perms_map))) ==
NULL) {
goto cleanup;
@@ -1779,7 +1781,7 @@ static int copy_avrule_block(link_state_t * state, policy_module_t * module,
if (module->policy->name != NULL) {
new_decl->module_name = strdup(module->policy->name);
if (new_decl->module_name == NULL) {
- ERR(state->handle, "Out of memory\n");
+ ERR(state->handle, "Out of memory");
avrule_decl_destroy(new_decl);
ret = -1;
goto cleanup;
@@ -2206,7 +2208,7 @@ static int enable_avrules(link_state_t * state, policydb_t * pol)
if (state->verbose) {
const char *mod_name = decl->module_name ?
decl->module_name : "BASE";
- INFO(state->handle, "check module %s decl %d\n",
+ INFO(state->handle, "check module %s decl %d",
mod_name, decl->decl_id);
}
rc = is_decl_requires_met(state, decl, &req);
@@ -2552,7 +2554,7 @@ int link_modules(sepol_handle_t * handle,
if (mods[i]->policyvers > b->policyvers) {
WARN(state.handle,
- "Upgrading policy version from %u to %u\n", b->policyvers, mods[i]->policyvers);
+ "Upgrading policy version from %u to %u", b->policyvers, mods[i]->policyvers);
b->policyvers = mods[i]->policyvers;
}
diff --git a/libsepol/src/module.c b/libsepol/src/module.c
index 02a5de2c..d93d08a2 100644
--- a/libsepol/src/module.c
+++ b/libsepol/src/module.c
@@ -293,11 +293,14 @@ static int link_netfilter_contexts(sepol_module_package_t * base,
}
base->netfilter_contexts = base_context;
for (i = 0; i < num_modules; i++) {
- memcpy(base->netfilter_contexts + base->netfilter_contexts_len,
- modules[i]->netfilter_contexts,
- modules[i]->netfilter_contexts_len);
- base->netfilter_contexts_len +=
- modules[i]->netfilter_contexts_len;
+ if (modules[i]->netfilter_contexts_len > 0) {
+ memcpy(base->netfilter_contexts + base->netfilter_contexts_len,
+ modules[i]->netfilter_contexts,
+ modules[i]->netfilter_contexts_len);
+ base->netfilter_contexts_len +=
+ modules[i]->netfilter_contexts_len;
+ }
+
}
return 0;
}
@@ -406,14 +409,14 @@ static int module_package_read_offsets(sepol_module_package_t * mod,
goto err;
}
- off = (size_t *) malloc((nsec + 1) * sizeof(size_t));
+ off = (size_t *) mallocarray(nsec + 1, sizeof(size_t));
if (!off) {
ERR(file->handle, "out of memory");
goto err;
}
free(buf);
- buf = malloc(sizeof(uint32_t) * nsec);
+ buf = mallocarray(nsec, sizeof(uint32_t));
if (!buf) {
ERR(file->handle, "out of memory");
goto err;
diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c
index 16e4004e..c9e88f1e 100644
--- a/libsepol/src/module_to_cil.c
+++ b/libsepol/src/module_to_cil.c
@@ -430,7 +430,7 @@ static int stack_init(struct stack **stack)
goto exit;
}
- s->stack = malloc(sizeof(*s->stack) * STACK_SIZE);
+ s->stack = mallocarray(STACK_SIZE, sizeof(*s->stack));
if (s->stack == NULL) {
goto exit;
}
@@ -453,7 +453,7 @@ static int stack_push(struct stack *stack, void *ptr)
void *new_stack;
if (stack->pos + 1 == stack->size) {
- new_stack = realloc(stack->stack, sizeof(*stack->stack) * (stack->size * 2));
+ new_stack = reallocarray(stack->stack, stack->size * 2, sizeof(*stack->stack));
if (new_stack == NULL) {
goto exit;
}
@@ -1008,7 +1008,7 @@ static int ebitmap_to_names(struct ebitmap *map, char **vals_to_names, char ***n
goto exit;
}
- name_arr = malloc(sizeof(*name_arr) * num);
+ name_arr = mallocarray(num, sizeof(*name_arr));
if (name_arr == NULL) {
log_err("Out of memory");
rc = -1;
@@ -1259,7 +1259,7 @@ static int cond_expr_to_cil(int indent, struct policydb *pdb, struct cond_expr *
char *val2 = NULL;
unsigned int num_params;
const char *op;
- const char *fmt_str;
+ const char *sep;
const char *type;
rc = stack_init(&stack);
@@ -1308,11 +1308,11 @@ static int cond_expr_to_cil(int indent, struct policydb *pdb, struct cond_expr *
rc = -1;
goto exit;
}
- fmt_str = "(%s %s)";
+ sep = "";
} else {
val2 = stack_pop(stack);
val1 = stack_pop(stack);
- fmt_str = "(%s %s %s)";
+ sep = " ";
}
if (val1 == NULL || val2 == NULL) {
@@ -1334,10 +1334,7 @@ static int cond_expr_to_cil(int indent, struct policydb *pdb, struct cond_expr *
goto exit;
}
- // although we always supply val2 and there isn't always a 2nd
- // value, it should only be used when there are actually two values
- // in the format strings
- rlen = snprintf(new_val, len, fmt_str, op, val1, val2);
+ rlen = snprintf(new_val, len, "(%s %s%s%s)", op, val1, sep, val2);
if (rlen < 0 || rlen >= len) {
log_err("Failed to generate conditional expression");
rc = -1;
@@ -1711,7 +1708,7 @@ static int constraint_expr_to_string(struct policydb *pdb, struct constraint_exp
char *val2 = NULL;
uint32_t num_params;
const char *op;
- const char *fmt_str;
+ const char *sep;
const char *attr1;
const char *attr2;
char *names = NULL;
@@ -1849,11 +1846,11 @@ static int constraint_expr_to_string(struct policydb *pdb, struct constraint_exp
rc = -1;
goto exit;
}
- fmt_str = "(%s %s)";
+ sep = "";
} else {
val2 = stack_pop(stack);
val1 = stack_pop(stack);
- fmt_str = "(%s %s %s)";
+ sep = " ";
}
if (val1 == NULL || val2 == NULL) {
@@ -1875,10 +1872,7 @@ static int constraint_expr_to_string(struct policydb *pdb, struct constraint_exp
goto exit;
}
- // although we always supply val2 and there isn't always a 2nd
- // value, it should only be used when there are actually two values
- // in the format strings
- rlen = snprintf(new_val, len, fmt_str, op, val1, val2);
+ rlen = snprintf(new_val, len, "(%s %s%s%s)", op, val1, sep, val2);
if (rlen < 0 || rlen >= len) {
log_err("Failed to generate constraint expression");
rc = -1;
@@ -2961,10 +2955,35 @@ static int genfscon_to_cil(struct policydb *pdb)
{
struct genfs *genfs;
struct ocontext *ocon;
+ uint32_t sclass;
for (genfs = pdb->genfs; genfs != NULL; genfs = genfs->next) {
for (ocon = genfs->head; ocon != NULL; ocon = ocon->next) {
- cil_printf("(genfscon %s \"%s\" ", genfs->fstype, ocon->u.name);
+ sclass = ocon->v.sclass;
+ if (sclass) {
+ const char *file_type;
+ const char *class_name = pdb->p_class_val_to_name[sclass-1];
+ if (strcmp(class_name, "file") == 0) {
+ file_type = "file";
+ } else if (strcmp(class_name, "dir") == 0) {
+ file_type = "dir";
+ } else if (strcmp(class_name, "chr_file") == 0) {
+ file_type = "char";
+ } else if (strcmp(class_name, "blk_file") == 0) {
+ file_type = "block";
+ } else if (strcmp(class_name, "sock_file") == 0) {
+ file_type = "socket";
+ } else if (strcmp(class_name, "fifo_file") == 0) {
+ file_type = "pipe";
+ } else if (strcmp(class_name, "lnk_file") == 0) {
+ file_type = "symlink";
+ } else {
+ return -1;
+ }
+ cil_printf("(genfscon %s \"%s\" %s ", genfs->fstype, ocon->u.name, file_type);
+ } else {
+ cil_printf("(genfscon %s \"%s\" ", genfs->fstype, ocon->u.name);
+ }
context_to_cil(pdb, &ocon->context[0]);
cil_printf(")\n");
}
@@ -4123,7 +4142,7 @@ exit:
static int fp_to_buffer(FILE *fp, char **data, size_t *data_len)
{
int rc = -1;
- char *d = NULL;
+ char *d = NULL, *d_tmp;
size_t d_len = 0;
size_t read_len = 0;
size_t max_len = 1 << 17; // start at 128KB, this is enough to hold about half of all the existing pp files
@@ -4139,12 +4158,13 @@ static int fp_to_buffer(FILE *fp, char **data, size_t *data_len)
d_len += read_len;
if (d_len == max_len) {
max_len *= 2;
- d = realloc(d, max_len);
- if (d == NULL) {
+ d_tmp = realloc(d, max_len);
+ if (d_tmp == NULL) {
log_err("Out of memory");
rc = -1;
goto exit;
}
+ d = d_tmp;
}
}
diff --git a/libsepol/src/optimize.c b/libsepol/src/optimize.c
index 6826155c..93ff2116 100644
--- a/libsepol/src/optimize.c
+++ b/libsepol/src/optimize.c
@@ -31,6 +31,9 @@
#include <sepol/policydb/policydb.h>
#include <sepol/policydb/conditional.h>
+#include "debug.h"
+#include "private.h"
+
#define TYPE_VEC_INIT_SIZE 16
struct type_vec {
@@ -42,7 +45,7 @@ static int type_vec_init(struct type_vec *v)
{
v->capacity = TYPE_VEC_INIT_SIZE;
v->count = 0;
- v->types = malloc(v->capacity * sizeof(*v->types));
+ v->types = mallocarray(v->capacity, sizeof(*v->types));
if (!v->types)
return -1;
return 0;
@@ -57,8 +60,9 @@ static int type_vec_append(struct type_vec *v, uint32_t type)
{
if (v->capacity == v->count) {
unsigned int new_capacity = v->capacity * 2;
- uint32_t *new_types = realloc(v->types,
- new_capacity * sizeof(*v->types));
+ uint32_t *new_types = reallocarray(v->types,
+ new_capacity,
+ sizeof(*v->types));
if (!new_types)
return -1;
@@ -93,7 +97,7 @@ static struct type_vec *build_type_map(const policydb_t *p)
{
unsigned int i, k;
ebitmap_node_t *n;
- struct type_vec *map = malloc(p->p_types.nprim * sizeof(*map));
+ struct type_vec *map = mallocarray(p->p_types.nprim, sizeof(*map));
if (!map)
return NULL;
@@ -101,6 +105,9 @@ static struct type_vec *build_type_map(const policydb_t *p)
if (type_vec_init(&map[i]))
goto err;
+ if (!p->type_val_to_struct[i])
+ continue;
+
if (p->type_val_to_struct[i]->flavor != TYPE_ATTRIB) {
ebitmap_for_each_positive_bit(&p->type_attr_map[i],
n, k) {
@@ -111,11 +118,13 @@ static struct type_vec *build_type_map(const policydb_t *p)
ebitmap_t *types_i = &p->attr_type_map[i];
for (k = 0; k < p->p_types.nprim; k++) {
- ebitmap_t *types_k = &p->attr_type_map[k];
+ const ebitmap_t *types_k;
- if (p->type_val_to_struct[k]->flavor != TYPE_ATTRIB)
+ if (!p->type_val_to_struct[k] || p->type_val_to_struct[k]->flavor != TYPE_ATTRIB)
continue;
+ types_k = &p->attr_type_map[k];
+
if (ebitmap_contains(types_k, types_i)) {
if (type_vec_append(&map[i], k))
goto err;
@@ -435,6 +444,17 @@ int policydb_optimize(policydb_t *p)
if (p->policy_type != POLICY_KERN)
return -1;
+ if (p->policyvers >= POLICYDB_VERSION_AVTAB && p->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
+ /*
+ * 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.
+ */
+ ERR(NULL, "Optimizing policy versions between 20 and 23 is not supported");
+ return -1;
+ }
+
type_map = build_type_map(p);
if (!type_map)
return -1;
diff --git a/libsepol/src/polcaps.c b/libsepol/src/polcaps.c
index 6a74ec7d..687e971c 100644
--- a/libsepol/src/polcaps.c
+++ b/libsepol/src/polcaps.c
@@ -6,13 +6,14 @@
#include <sepol/policydb/polcaps.h>
static const char * const polcap_names[] = {
- "network_peer_controls", /* POLICYDB_CAPABILITY_NETPEER */
- "open_perms", /* POLICYDB_CAPABILITY_OPENPERM */
- "extended_socket_class", /* POLICYDB_CAPABILITY_EXTSOCKCLASS */
- "always_check_network", /* POLICYDB_CAPABILITY_ALWAYSNETWORK */
- "cgroup_seclabel", /* POLICYDB_CAPABILITY_SECLABEL */
- "nnp_nosuid_transition", /* POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION */
- "genfs_seclabel_symlinks", /* POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS */
+ "network_peer_controls", /* POLICYDB_CAP_NETPEER */
+ "open_perms", /* POLICYDB_CAP_OPENPERM */
+ "extended_socket_class", /* POLICYDB_CAP_EXTSOCKCLASS */
+ "always_check_network", /* POLICYDB_CAP_ALWAYSNETWORK */
+ "cgroup_seclabel", /* POLICYDB_CAP_SECLABEL */
+ "nnp_nosuid_transition", /* POLICYDB_CAP_NNP_NOSUID_TRANSITION */
+ "genfs_seclabel_symlinks", /* POLICYDB_CAP_GENFS_SECLABEL_SYMLINKS */
+ "ioctl_skip_cloexec", /* POLICYDB_CAP_IOCTL_SKIP_CLOEXEC */
NULL
};
@@ -20,7 +21,7 @@ int sepol_polcap_getnum(const char *name)
{
int capnum;
- for (capnum = 0; capnum <= POLICYDB_CAPABILITY_MAX; capnum++) {
+ for (capnum = 0; capnum <= POLICYDB_CAP_MAX; capnum++) {
if (polcap_names[capnum] == NULL)
continue;
if (strcasecmp(polcap_names[capnum], name) == 0)
@@ -31,7 +32,7 @@ int sepol_polcap_getnum(const char *name)
const char *sepol_polcap_getname(unsigned int capnum)
{
- if (capnum > POLICYDB_CAPABILITY_MAX)
+ if (capnum > POLICYDB_CAP_MAX)
return NULL;
return polcap_names[capnum];
diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
index 587ba64a..fc71463e 100644
--- a/libsepol/src/policydb.c
+++ b/libsepol/src/policydb.c
@@ -2103,6 +2103,8 @@ static int common_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
if (symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE))
goto bad;
comdatum->permissions.nprim = le32_to_cpu(buf[2]);
+ if (comdatum->permissions.nprim > PERM_SYMTAB_SIZE)
+ goto bad;
nel = le32_to_cpu(buf[3]);
key = malloc(len + 1);
@@ -2251,6 +2253,8 @@ static int class_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
if (symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE))
goto bad;
cladatum->permissions.nprim = le32_to_cpu(buf[3]);
+ if (cladatum->permissions.nprim > PERM_SYMTAB_SIZE)
+ goto bad;
nel = le32_to_cpu(buf[4]);
ncons = le32_to_cpu(buf[5]);
@@ -2679,7 +2683,10 @@ static int filename_trans_read_one_compat(policydb_t *p, struct policy_file *fp)
if (rc < 0)
goto err;
- stype = le32_to_cpu(buf[0]);
+ stype = le32_to_cpu(buf[0]);
+ if (stype == 0)
+ goto err;
+
ttype = le32_to_cpu(buf[1]);
tclass = le32_to_cpu(buf[2]);
otype = le32_to_cpu(buf[3]);
@@ -2773,6 +2780,7 @@ static int filename_trans_read_one(policydb_t *p, struct policy_file *fp)
if (!datum)
goto err;
+ datum->next = NULL;
*dst = datum;
/* ebitmap_read() will at least init the bitmap */
@@ -2790,7 +2798,6 @@ static int filename_trans_read_one(policydb_t *p, struct policy_file *fp)
dst = &datum->next;
}
- *dst = NULL;
if (ndatum > 1 && filename_trans_check_datum(first))
goto err;
@@ -2879,6 +2886,8 @@ static int ocontext_read_xen(const struct policydb_compat_info *info,
if (rc < 0)
return -1;
c->sid[0] = le32_to_cpu(buf[0]);
+ if (is_saturated(c->sid[0]))
+ return -1;
if (context_read_and_validate
(&c->context[0], p, fp))
return -1;
@@ -2990,6 +2999,8 @@ static int ocontext_read_selinux(const struct policydb_compat_info *info,
if (rc < 0)
return -1;
c->sid[0] = le32_to_cpu(buf[0]);
+ if (is_saturated(c->sid[0]))
+ return -1;
if (context_read_and_validate
(&c->context[0], p, fp))
return -1;
@@ -3926,6 +3937,8 @@ static int scope_index_read(scope_index_t * scope_index,
if (rc < 0)
return -1;
scope_index->class_perms_len = le32_to_cpu(buf[0]);
+ if (is_saturated(scope_index->class_perms_len))
+ return -1;
if (scope_index->class_perms_len == 0) {
scope_index->class_perms_map = NULL;
return 0;
@@ -3980,6 +3993,8 @@ static int avrule_decl_read(policydb_t * p, avrule_decl_t * decl,
if (rc < 0)
return -1;
nprim = le32_to_cpu(buf[0]);
+ if (is_saturated(nprim))
+ return -1;
nel = le32_to_cpu(buf[1]);
for (j = 0; j < nel; j++) {
if (read_f[i] (p, decl->symtab[i].table, fp)) {
@@ -4106,12 +4121,12 @@ static int scope_read(policydb_t * p, int symnum, struct policy_file *fp)
goto cleanup;
scope->scope = le32_to_cpu(buf[0]);
scope->decl_ids_len = le32_to_cpu(buf[1]);
- if (scope->decl_ids_len == 0) {
+ if (zero_or_saturated(scope->decl_ids_len)) {
ERR(fp->handle, "invalid scope with no declaration");
goto cleanup;
}
if ((scope->decl_ids =
- malloc(scope->decl_ids_len * sizeof(uint32_t))) == NULL) {
+ mallocarray(scope->decl_ids_len, sizeof(uint32_t))) == NULL) {
goto cleanup;
}
rc = next_entry(scope->decl_ids, fp, sizeof(uint32_t) * scope->decl_ids_len);
@@ -4396,6 +4411,8 @@ int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose)
if (rc < 0)
goto bad;
nprim = le32_to_cpu(buf[0]);
+ if (is_saturated(nprim))
+ goto bad;
nel = le32_to_cpu(buf[1]);
if (nel && !nprim) {
ERR(fp->handle, "unexpected items in symbol table with no symbol");
@@ -4500,8 +4517,8 @@ int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose)
}
if (policy_type == POLICY_KERN) {
- p->type_attr_map = malloc(p->p_types.nprim * sizeof(ebitmap_t));
- p->attr_type_map = malloc(p->p_types.nprim * sizeof(ebitmap_t));
+ p->type_attr_map = mallocarray(p->p_types.nprim, sizeof(ebitmap_t));
+ p->attr_type_map = mallocarray(p->p_types.nprim, sizeof(ebitmap_t));
if (!p->type_attr_map || !p->attr_type_map)
goto bad;
for (i = 0; i < p->p_types.nprim; i++) {
diff --git a/libsepol/src/policydb_validate.c b/libsepol/src/policydb_validate.c
index 5804d247..a2dcebe4 100644
--- a/libsepol/src/policydb_validate.c
+++ b/libsepol/src/policydb_validate.c
@@ -2,15 +2,24 @@
#include <sepol/policydb/conditional.h>
#include <sepol/policydb/ebitmap.h>
#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/services.h>
#include "debug.h"
#include "policydb_validate.h"
+#define bool_xor(a, b) (!(a) != !(b))
+#define bool_xnor(a, b) !bool_xor(a, b)
+
typedef struct validate {
uint32_t nprim;
ebitmap_t gaps;
} validate_t;
+typedef struct map_arg {
+ validate_t *flavors;
+ sepol_handle_t *handle;
+ int mls;
+} map_arg_t;
static int create_gap_ebitmap(char **val_to_name, uint32_t nprim, ebitmap_t *gaps)
{
@@ -115,6 +124,30 @@ static int validate_type_set(type_set_t *type_set, validate_t *type)
if (validate_ebitmap(&type_set->negset, type))
goto bad;
+ switch (type_set->flags) {
+ case 0:
+ case TYPE_STAR:
+ case TYPE_COMP:
+ break;
+ default:
+ goto bad;
+ }
+
+ return 0;
+
+bad:
+ return -1;
+}
+
+static int validate_empty_type_set(type_set_t *type_set)
+{
+ if (!ebitmap_is_empty(&type_set->types))
+ goto bad;
+ if (!ebitmap_is_empty(&type_set->negset))
+ goto bad;
+ if (type_set->flags != 0)
+ goto bad;
+
return 0;
bad:
@@ -124,9 +157,21 @@ bad:
static int validate_role_set(role_set_t *role_set, validate_t *role)
{
if (validate_ebitmap(&role_set->roles, role))
- return -1;
+ goto bad;
+
+ switch (role_set->flags) {
+ case 0:
+ case ROLE_STAR:
+ case ROLE_COMP:
+ break;
+ default:
+ goto bad;
+ }
return 0;
+
+bad:
+ return -1;
}
static int validate_scope(__attribute__ ((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
@@ -135,12 +180,23 @@ static int validate_scope(__attribute__ ((unused)) hashtab_key_t k, hashtab_datu
uint32_t *nprim = (uint32_t *)args;
unsigned int i;
+ switch (scope_datum->scope) {
+ case SCOPE_REQ:
+ case SCOPE_DECL:
+ break;
+ default:
+ goto bad;
+ }
+
for (i = 0; i < scope_datum->decl_ids_len; i++) {
if (!value_isvalid(scope_datum->decl_ids[i], *nprim))
- return -1;
+ goto bad;
}
return 0;
+
+bad:
+ return -1;
}
static int validate_scopes(sepol_handle_t *handle, symtab_t scopes[], avrule_block_t *block)
@@ -167,22 +223,110 @@ bad:
return -1;
}
-static int validate_constraint_nodes(sepol_handle_t *handle, constraint_node_t *cons, validate_t flavors[])
+static int validate_constraint_nodes(sepol_handle_t *handle, unsigned int nperms, constraint_node_t *cons, validate_t flavors[])
{
constraint_expr_t *cexp;
for (; cons; cons = cons->next) {
+ if (nperms == 0 && cons->permissions != 0)
+ goto bad;
+ if (nperms > 0 && cons->permissions == 0)
+ goto bad;
+ if (nperms > 0 && nperms != PERM_SYMTAB_SIZE && cons->permissions >= (UINT32_C(1) << nperms))
+ goto bad;
+
for (cexp = cons->expr; cexp; cexp = cexp->next) {
- if (cexp->attr & CEXPR_USER) {
- if (validate_ebitmap(&cexp->names, &flavors[SYM_USERS]))
+ if (cexp->expr_type == CEXPR_NAMES) {
+ if (cexp->attr & CEXPR_XTARGET && nperms != 0)
goto bad;
- } else if (cexp->attr & CEXPR_ROLE) {
- if (validate_ebitmap(&cexp->names, &flavors[SYM_ROLES]))
+ if (!(cexp->attr & CEXPR_TYPE)) {
+ if (validate_empty_type_set(cexp->type_names))
+ goto bad;
+ }
+
+ switch (cexp->op) {
+ case CEXPR_EQ:
+ case CEXPR_NEQ:
+ break;
+ default:
goto bad;
- } else if (cexp->attr & CEXPR_TYPE) {
- if (validate_ebitmap(&cexp->names, &flavors[SYM_TYPES]))
+ }
+
+ switch (cexp->attr) {
+ case CEXPR_USER:
+ case CEXPR_USER | CEXPR_TARGET:
+ case CEXPR_USER | CEXPR_XTARGET:
+ if (validate_ebitmap(&cexp->names, &flavors[SYM_USERS]))
+ goto bad;
+ break;
+ case CEXPR_ROLE:
+ case CEXPR_ROLE | CEXPR_TARGET:
+ case CEXPR_ROLE | CEXPR_XTARGET:
+ if (validate_ebitmap(&cexp->names, &flavors[SYM_ROLES]))
+ goto bad;
+ break;
+ case CEXPR_TYPE:
+ case CEXPR_TYPE | CEXPR_TARGET:
+ case CEXPR_TYPE | CEXPR_XTARGET:
+ if (validate_ebitmap(&cexp->names, &flavors[SYM_TYPES]))
+ goto bad;
+ if (validate_type_set(cexp->type_names, &flavors[SYM_TYPES]))
+ goto bad;
+ break;
+ default:
+ goto bad;
+ }
+ } else if (cexp->expr_type == CEXPR_ATTR) {
+ if (!ebitmap_is_empty(&cexp->names))
+ goto bad;
+ if (validate_empty_type_set(cexp->type_names))
+ goto bad;
+
+ switch (cexp->op) {
+ case CEXPR_EQ:
+ case CEXPR_NEQ:
+ break;
+ case CEXPR_DOM:
+ case CEXPR_DOMBY:
+ case CEXPR_INCOMP:
+ if ((cexp->attr & CEXPR_USER) || (cexp->attr & CEXPR_TYPE))
+ goto bad;
+ break;
+ default:
goto bad;
- if (validate_type_set(cexp->type_names, &flavors[SYM_TYPES]))
+ }
+
+ switch (cexp->attr) {
+ case CEXPR_USER:
+ case CEXPR_ROLE:
+ case CEXPR_TYPE:
+ case CEXPR_L1L2:
+ case CEXPR_L1H2:
+ case CEXPR_H1L2:
+ case CEXPR_H1H2:
+ case CEXPR_L1H1:
+ case CEXPR_L2H2:
+ break;
+ default:
+ goto bad;
+ }
+ } else {
+ switch (cexp->expr_type) {
+ case CEXPR_NOT:
+ case CEXPR_AND:
+ case CEXPR_OR:
+ break;
+ default:
+ goto bad;
+ }
+
+ if (cexp->op != 0)
+ goto bad;
+ if (cexp->attr != 0)
+ goto bad;
+ if (!ebitmap_is_empty(&cexp->names))
+ goto bad;
+ if (validate_empty_type_set(cexp->type_names))
goto bad;
}
}
@@ -199,10 +343,53 @@ static int validate_class_datum(sepol_handle_t *handle, class_datum_t *class, va
{
if (validate_value(class->s.value, &flavors[SYM_CLASSES]))
goto bad;
- if (validate_constraint_nodes(handle, class->constraints, flavors))
+ if (class->permissions.nprim > PERM_SYMTAB_SIZE)
+ goto bad;
+ if (validate_constraint_nodes(handle, class->permissions.nprim, class->constraints, flavors))
goto bad;
- if (validate_constraint_nodes(handle, class->validatetrans, flavors))
+ if (validate_constraint_nodes(handle, 0, class->validatetrans, flavors))
+ goto bad;
+
+ switch (class->default_user) {
+ case 0:
+ case DEFAULT_SOURCE:
+ case DEFAULT_TARGET:
+ break;
+ default:
+ goto bad;
+ }
+
+ switch (class->default_role) {
+ case 0:
+ case DEFAULT_SOURCE:
+ case DEFAULT_TARGET:
+ break;
+ default:
+ goto bad;
+ }
+
+ switch (class->default_type) {
+ case 0:
+ case DEFAULT_SOURCE:
+ case DEFAULT_TARGET:
+ break;
+ default:
+ goto bad;
+ }
+
+ switch (class->default_range) {
+ case 0:
+ case DEFAULT_SOURCE_LOW:
+ case DEFAULT_SOURCE_HIGH:
+ case DEFAULT_SOURCE_LOW_HIGH:
+ case DEFAULT_TARGET_LOW:
+ case DEFAULT_TARGET_HIGH:
+ case DEFAULT_TARGET_LOW_HIGH:
+ case DEFAULT_GLBLUB:
+ break;
+ default:
goto bad;
+ }
return 0;
@@ -211,6 +398,32 @@ bad:
return -1;
}
+static int validate_class_datum_wrapper(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+ map_arg_t *margs = args;
+
+ return validate_class_datum(margs->handle, d, margs->flavors);
+}
+
+static int validate_common_datum(sepol_handle_t *handle, common_datum_t *common)
+{
+ if (common->permissions.nprim > PERM_SYMTAB_SIZE)
+ goto bad;
+
+ return 0;
+
+bad:
+ ERR(handle, "Invalid common class datum");
+ return -1;
+}
+
+static int validate_common_datum_wrapper(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+ map_arg_t *margs = args;
+
+ return validate_common_datum(margs->handle, d);
+}
+
static int validate_role_datum(sepol_handle_t *handle, role_datum_t *role, validate_t flavors[])
{
if (validate_value(role->s.value, &flavors[SYM_ROLES]))
@@ -227,10 +440,17 @@ static int validate_role_datum(sepol_handle_t *handle, role_datum_t *role, valid
return 0;
bad:
- ERR(handle, "Invalid class datum");
+ ERR(handle, "Invalid role datum");
return -1;
}
+static int validate_role_datum_wrapper(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+ map_arg_t *margs = args;
+
+ return validate_role_datum(margs->handle, d, margs->flavors);
+}
+
static int validate_type_datum(sepol_handle_t *handle, type_datum_t *type, validate_t flavors[])
{
if (validate_value(type->s.value, &flavors[SYM_TYPES]))
@@ -240,6 +460,26 @@ static int validate_type_datum(sepol_handle_t *handle, type_datum_t *type, valid
if (type->bounds && validate_value(type->bounds, &flavors[SYM_TYPES]))
goto bad;
+ switch (type->flavor) {
+ case TYPE_TYPE:
+ case TYPE_ATTRIB:
+ case TYPE_ALIAS:
+ break;
+ default:
+ goto bad;
+ }
+
+ switch (type->flags) {
+ case 0:
+ case TYPE_FLAGS_PERMISSIVE:
+ case TYPE_FLAGS_EXPAND_ATTR_TRUE:
+ case TYPE_FLAGS_EXPAND_ATTR_FALSE:
+ case TYPE_FLAGS_EXPAND_ATTR:
+ break;
+ default:
+ goto bad;
+ }
+
return 0;
bad:
@@ -247,6 +487,13 @@ bad:
return -1;
}
+static int validate_type_datum_wrapper(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+ map_arg_t *margs = args;
+
+ return validate_type_datum(margs->handle, d, margs->flavors);
+}
+
static int validate_mls_semantic_cat(mls_semantic_cat_t *cat, validate_t *cats)
{
for (; cat; cat = cat->next) {
@@ -290,7 +537,41 @@ bad:
return -1;
}
-static int validate_user_datum(sepol_handle_t *handle, user_datum_t *user, validate_t flavors[])
+static int validate_mls_level(mls_level_t *level, validate_t *sens, validate_t *cats)
+{
+ if (validate_value(level->sens, sens))
+ goto bad;
+ if (validate_ebitmap(&level->cat, cats))
+ goto bad;
+
+ return 0;
+
+ bad:
+ return -1;
+}
+
+static int validate_level_datum(__attribute__ ((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+ level_datum_t *level = d;
+ validate_t *flavors = args;
+
+ return validate_mls_level(level->level, &flavors[SYM_LEVELS], &flavors[SYM_CATS]);
+}
+
+static int validate_mls_range(mls_range_t *range, validate_t *sens, validate_t *cats)
+{
+ if (validate_mls_level(&range->level[0], sens, cats))
+ goto bad;
+ if (validate_mls_level(&range->level[1], sens, cats))
+ goto bad;
+
+ return 0;
+
+ bad:
+ return -1;
+}
+
+static int validate_user_datum(sepol_handle_t *handle, user_datum_t *user, validate_t flavors[], int mls)
{
if (validate_value(user->s.value, &flavors[SYM_USERS]))
goto bad;
@@ -300,6 +581,10 @@ static int validate_user_datum(sepol_handle_t *handle, user_datum_t *user, valid
goto bad;
if (validate_mls_semantic_level(&user->dfltlevel, &flavors[SYM_LEVELS], &flavors[SYM_CATS]))
goto bad;
+ if (mls && validate_mls_range(&user->exp_range, &flavors[SYM_LEVELS], &flavors[SYM_CATS]))
+ goto bad;
+ if (mls && validate_mls_level(&user->exp_dfltlevel, &flavors[SYM_LEVELS], &flavors[SYM_CATS]))
+ goto bad;
if (user->bounds && validate_value(user->bounds, &flavors[SYM_USERS]))
goto bad;
@@ -310,32 +595,60 @@ bad:
return -1;
}
-static int validate_datum_arrays(sepol_handle_t *handle, policydb_t *p, validate_t flavors[])
+static int validate_user_datum_wrapper(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+ map_arg_t *margs = args;
+
+ return validate_user_datum(margs->handle, d, margs->flavors, margs->mls);
+}
+
+static int validate_bool_datum(sepol_handle_t *handle, cond_bool_datum_t *boolean, validate_t flavors[])
+{
+ if (validate_value(boolean->s.value, &flavors[SYM_BOOLS]))
+ goto bad;
+
+ switch (boolean->state) {
+ case 0:
+ case 1:
+ break;
+ default:
+ goto bad;
+ }
+
+ switch (boolean->flags) {
+ case 0:
+ case COND_BOOL_FLAGS_TUNABLE:
+ break;
+ default:
+ goto bad;
+ }
+
+ return 0;
+
+bad:
+ ERR(handle, "Invalid bool datum");
+ return -1;
+}
+
+static int validate_bool_datum_wrapper(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+ map_arg_t *margs = args;
+
+ return validate_bool_datum(margs->handle, d, margs->flavors);
+}
+
+static int validate_datum_array_gaps(sepol_handle_t *handle, policydb_t *p, validate_t flavors[])
{
unsigned int i;
for (i = 0; i < p->p_classes.nprim; i++) {
- if (p->class_val_to_struct[i]) {
- if (ebitmap_get_bit(&flavors[SYM_CLASSES].gaps, i))
- goto bad;
- if (validate_class_datum(handle, p->class_val_to_struct[i], flavors))
- goto bad;
- } else {
- if (!ebitmap_get_bit(&flavors[SYM_CLASSES].gaps, i))
- goto bad;
- }
+ if (bool_xnor(p->class_val_to_struct[i], ebitmap_get_bit(&flavors[SYM_CLASSES].gaps, i)))
+ goto bad;
}
for (i = 0; i < p->p_roles.nprim; i++) {
- if (p->role_val_to_struct[i]) {
- if (ebitmap_get_bit(&flavors[SYM_ROLES].gaps, i))
- goto bad;
- if (validate_role_datum(handle, p->role_val_to_struct[i], flavors))
- goto bad;
- } else {
- if (!ebitmap_get_bit(&flavors[SYM_ROLES].gaps, i))
- goto bad;
- }
+ if (bool_xnor(p->role_val_to_struct[i], ebitmap_get_bit(&flavors[SYM_ROLES].gaps, i)))
+ goto bad;
}
/*
@@ -344,34 +657,68 @@ static int validate_datum_arrays(sepol_handle_t *handle, policydb_t *p, validate
*/
if (p->policyvers < POLICYDB_VERSION_AVTAB || p->policyvers > POLICYDB_VERSION_PERMISSIVE) {
for (i = 0; i < p->p_types.nprim; i++) {
- if (p->type_val_to_struct[i]) {
- if (ebitmap_get_bit(&flavors[SYM_TYPES].gaps, i))
- goto bad;
- if (validate_type_datum(handle, p->type_val_to_struct[i], flavors))
- goto bad;
- } else {
- if (!ebitmap_get_bit(&flavors[SYM_TYPES].gaps, i))
- goto bad;
- }
+ if (bool_xnor(p->type_val_to_struct[i], ebitmap_get_bit(&flavors[SYM_TYPES].gaps, i)))
+ goto bad;
}
}
for (i = 0; i < p->p_users.nprim; i++) {
- if (p->user_val_to_struct[i]) {
- if (ebitmap_get_bit(&flavors[SYM_USERS].gaps, i))
- goto bad;
- if (validate_user_datum(handle, p->user_val_to_struct[i], flavors))
- goto bad;
- } else {
- if (!ebitmap_get_bit(&flavors[SYM_USERS].gaps, i))
- goto bad;
- }
+ if (bool_xnor(p->user_val_to_struct[i], ebitmap_get_bit(&flavors[SYM_USERS].gaps, i)))
+ goto bad;
+ }
+
+ for (i = 0; i < p->p_bools.nprim; i++) {
+ if (bool_xnor(p->bool_val_to_struct[i], ebitmap_get_bit(&flavors[SYM_BOOLS].gaps, i)))
+ goto bad;
}
return 0;
bad:
- ERR(handle, "Invalid datum arrays");
+ ERR(handle, "Invalid datum array gaps");
+ return -1;
+}
+
+static int validate_datum(__attribute__ ((unused))hashtab_key_t k, hashtab_datum_t d, void *args)
+{
+ symtab_datum_t *s = d;
+ uint32_t *nprim = (uint32_t *)args;
+
+ return !value_isvalid(s->value, *nprim);
+}
+
+static int validate_datum_array_entries(sepol_handle_t *handle, policydb_t *p, validate_t flavors[])
+{
+ map_arg_t margs = { flavors, handle, p->mls };
+
+ if (hashtab_map(p->p_commons.table, validate_common_datum_wrapper, &margs))
+ goto bad;
+
+ if (hashtab_map(p->p_classes.table, validate_class_datum_wrapper, &margs))
+ goto bad;
+
+ if (hashtab_map(p->p_roles.table, validate_role_datum_wrapper, &margs))
+ goto bad;
+
+ if (hashtab_map(p->p_types.table, validate_type_datum_wrapper, &margs))
+ goto bad;
+
+ if (hashtab_map(p->p_users.table, validate_user_datum_wrapper, &margs))
+ goto bad;
+
+ if (p->mls && hashtab_map(p->p_levels.table, validate_level_datum, flavors))
+ goto bad;
+
+ if (hashtab_map(p->p_cats.table, validate_datum, &flavors[SYM_CATS]))
+ goto bad;
+
+ if (hashtab_map(p->p_bools.table, validate_bool_datum_wrapper, &margs))
+ goto bad;
+
+ return 0;
+
+bad:
+ ERR(handle, "Invalid datum array entries");
return -1;
}
@@ -379,7 +726,7 @@ bad:
* Functions to validate a kernel policydb
*/
-static int validate_avtab_key(avtab_key_t *key, validate_t flavors[])
+static int validate_avtab_key(avtab_key_t *key, int conditional, validate_t flavors[])
{
if (validate_value(key->source_type, &flavors[SYM_TYPES]))
goto bad;
@@ -387,6 +734,23 @@ static int validate_avtab_key(avtab_key_t *key, validate_t flavors[])
goto bad;
if (validate_value(key->target_class, &flavors[SYM_CLASSES]))
goto bad;
+ switch (0xFFF & key->specified) {
+ case AVTAB_ALLOWED:
+ case AVTAB_AUDITALLOW:
+ case AVTAB_AUDITDENY:
+ case AVTAB_TRANSITION:
+ case AVTAB_MEMBER:
+ case AVTAB_CHANGE:
+ break;
+ case AVTAB_XPERMS_ALLOWED:
+ case AVTAB_XPERMS_AUDITALLOW:
+ case AVTAB_XPERMS_DONTAUDIT:
+ if (conditional)
+ goto bad;
+ break;
+ default:
+ goto bad;
+ }
return 0;
@@ -394,15 +758,22 @@ bad:
return -1;
}
-static int validate_avtab_key_wrapper(avtab_key_t *k, __attribute__ ((unused)) avtab_datum_t *d, void *args)
+static int validate_avtab_key_and_datum(avtab_key_t *k, avtab_datum_t *d, void *args)
{
validate_t *flavors = (validate_t *)args;
- return validate_avtab_key(k, flavors);
+
+ if (validate_avtab_key(k, 0, flavors))
+ return -1;
+
+ if ((k->specified & AVTAB_TYPE) && validate_value(d->data, &flavors[SYM_TYPES]))
+ return -1;
+
+ return 0;
}
static int validate_avtab(sepol_handle_t *handle, avtab_t *avtab, validate_t flavors[])
{
- if (avtab_map(avtab, validate_avtab_key_wrapper, flavors)) {
+ if (avtab_map(avtab, validate_avtab_key_and_datum, flavors)) {
ERR(handle, "Invalid avtab");
return -1;
}
@@ -416,7 +787,7 @@ static int validate_cond_av_list(sepol_handle_t *handle, cond_av_list_t *cond_av
for (; cond_av; cond_av = cond_av->next) {
for (avtab_ptr = cond_av->node; avtab_ptr; avtab_ptr = avtab_ptr->next) {
- if (validate_avtab_key(&avtab_ptr->key, flavors)) {
+ if (validate_avtab_key(&avtab_ptr->key, 1, flavors)) {
ERR(handle, "Invalid cond av list");
return -1;
}
@@ -426,7 +797,7 @@ static int validate_cond_av_list(sepol_handle_t *handle, cond_av_list_t *cond_av
return 0;
}
-static int validate_avrules(sepol_handle_t *handle, avrule_t *avrule, validate_t flavors[])
+static int validate_avrules(sepol_handle_t *handle, avrule_t *avrule, int conditional, validate_t flavors[])
{
class_perm_node_t *class;
@@ -440,6 +811,48 @@ static int validate_avrules(sepol_handle_t *handle, avrule_t *avrule, validate_t
if (validate_value(class->tclass, &flavors[SYM_CLASSES]))
goto bad;
}
+
+ switch(avrule->specified) {
+ case AVRULE_ALLOWED:
+ case AVRULE_AUDITALLOW:
+ case AVRULE_AUDITDENY:
+ case AVRULE_DONTAUDIT:
+ case AVRULE_TRANSITION:
+ case AVRULE_MEMBER:
+ case AVRULE_CHANGE:
+ break;
+ case AVRULE_NEVERALLOW:
+ case AVRULE_XPERMS_ALLOWED:
+ case AVRULE_XPERMS_AUDITALLOW:
+ case AVRULE_XPERMS_DONTAUDIT:
+ case AVRULE_XPERMS_NEVERALLOW:
+ if (conditional)
+ goto bad;
+ break;
+ default:
+ goto bad;
+ }
+
+ if (avrule->specified & AVRULE_XPERMS) {
+ if (!avrule->xperms)
+ goto bad;
+ switch (avrule->xperms->specified) {
+ case AVRULE_XPERMS_IOCTLFUNCTION:
+ case AVRULE_XPERMS_IOCTLDRIVER:
+ break;
+ default:
+ goto bad;
+ }
+ } else if (avrule->xperms)
+ goto bad;
+
+ switch(avrule->flags) {
+ case 0:
+ case RULE_SELF:
+ break;
+ default:
+ goto bad;
+ }
}
return 0;
@@ -475,9 +888,9 @@ static int validate_cond_list(sepol_handle_t *handle, cond_list_t *cond, validat
goto bad;
if (validate_cond_av_list(handle, cond->false_list, flavors))
goto bad;
- if (validate_avrules(handle, cond->avtrue_list, flavors))
+ if (validate_avrules(handle, cond->avtrue_list, 1, flavors))
goto bad;
- if (validate_avrules(handle, cond->avfalse_list, flavors))
+ if (validate_avrules(handle, cond->avfalse_list, 1, flavors))
goto bad;
if (validate_bool_id_array(handle, cond->bool_ids, cond->nbools, &flavors[SYM_BOOLS]))
goto bad;
@@ -559,6 +972,77 @@ static int validate_filename_trans_hashtab(sepol_handle_t *handle, hashtab_t fil
return 0;
}
+static int validate_context(context_struct_t *con, validate_t flavors[], int mls)
+{
+ if (validate_value(con->user, &flavors[SYM_USERS]))
+ return -1;
+ if (validate_value(con->role, &flavors[SYM_ROLES]))
+ return -1;
+ if (validate_value(con->type, &flavors[SYM_TYPES]))
+ return -1;
+ if (mls && validate_mls_range(&con->range, &flavors[SYM_LEVELS], &flavors[SYM_CATS]))
+ return -1;
+
+ return 0;
+}
+
+static int validate_ocontexts(sepol_handle_t *handle, policydb_t *p, validate_t flavors[])
+{
+ ocontext_t *octx;
+ unsigned int i;
+
+ for (i = 0; i < OCON_NUM; i++) {
+ for (octx = p->ocontexts[i]; octx; octx = octx->next) {
+ if (validate_context(&octx->context[0], flavors, p->mls))
+ goto bad;
+
+ if (p->target_platform == SEPOL_TARGET_SELINUX) {
+ switch (i) {
+ case OCON_FS:
+ case OCON_NETIF:
+ if (validate_context(&octx->context[1], flavors, p->mls))
+ goto bad;
+ break;
+ case OCON_FSUSE:
+ switch (octx->v.behavior) {
+ case SECURITY_FS_USE_XATTR:
+ case SECURITY_FS_USE_TRANS:
+ case SECURITY_FS_USE_TASK:
+ break;
+ default:
+ goto bad;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+
+bad:
+ ERR(handle, "Invalid ocontext");
+ return -1;
+}
+
+static int validate_genfs(sepol_handle_t *handle, policydb_t *p, validate_t flavors[])
+{
+ genfs_t *genfs;
+ ocontext_t *octx;
+
+ for (genfs = p->genfs; genfs; genfs = genfs->next) {
+ for (octx = genfs->head; octx; octx = octx->next) {
+ if (validate_context(&octx->context[0], flavors, p->mls))
+ goto bad;
+ }
+ }
+
+ return 0;
+
+bad:
+ ERR(handle, "Invalid genfs");
+ return -1;
+}
+
/*
* Functions to validate a module policydb
*/
@@ -666,14 +1150,6 @@ bad:
return -1;
}
-static int validate_datum(__attribute__ ((unused))hashtab_key_t k, hashtab_datum_t d, void *args)
-{
- symtab_datum_t *s = d;
- uint32_t *nprim = (uint32_t *)args;
-
- return !value_isvalid(s->value, *nprim);
-}
-
static int validate_symtabs(sepol_handle_t *handle, symtab_t symtabs[], validate_t flavors[])
{
unsigned int i;
@@ -696,7 +1172,7 @@ static int validate_avrule_blocks(sepol_handle_t *handle, avrule_block_t *avrule
for (decl = avrule_block->branch_list; decl != NULL; decl = decl->next) {
if (validate_cond_list(handle, decl->cond_list, flavors))
goto bad;
- if (validate_avrules(handle, decl->avrules, flavors))
+ if (validate_avrules(handle, decl->avrules, 0, flavors))
goto bad;
if (validate_role_trans_rules(handle, decl->role_tr_rules, flavors))
goto bad;
@@ -713,6 +1189,14 @@ static int validate_avrule_blocks(sepol_handle_t *handle, avrule_block_t *avrule
if (validate_symtabs(handle, decl->symtab, flavors))
goto bad;
}
+
+ switch (avrule_block->flags) {
+ case 0:
+ case AVRULE_OPTIONAL:
+ break;
+ default:
+ goto bad;
+ }
}
return 0;
@@ -722,6 +1206,71 @@ bad:
return -1;
}
+static int validate_permissives(sepol_handle_t *handle, policydb_t *p, validate_t flavors[])
+{
+ ebitmap_node_t *node;
+ unsigned i;
+
+ ebitmap_for_each_positive_bit(&p->permissive_map, node, i) {
+ if (validate_value(i, &flavors[SYM_TYPES]))
+ goto bad;
+ }
+
+ return 0;
+
+bad:
+ ERR(handle, "Invalid permissive type");
+ return -1;
+}
+
+static int validate_properties(sepol_handle_t *handle, policydb_t *p)
+{
+ switch (p->policy_type) {
+ case POLICY_KERN:
+ if (p->policyvers < POLICYDB_VERSION_MIN || p->policyvers > POLICYDB_VERSION_MAX)
+ goto bad;
+ break;
+ case POLICY_BASE:
+ case POLICY_MOD:
+ if (p->policyvers < MOD_POLICYDB_VERSION_MIN || p->policyvers > MOD_POLICYDB_VERSION_MAX)
+ goto bad;
+ break;
+ default:
+ goto bad;
+ }
+
+ switch (p->target_platform) {
+ case SEPOL_TARGET_SELINUX:
+ case SEPOL_TARGET_XEN:
+ break;
+ default:
+ goto bad;
+ }
+
+ switch (p->mls) {
+ case 0:
+ case 1:
+ break;
+ default:
+ goto bad;
+ }
+
+ switch (p->handle_unknown) {
+ case SEPOL_DENY_UNKNOWN:
+ case SEPOL_REJECT_UNKNOWN:
+ case SEPOL_ALLOW_UNKNOWN:
+ break;
+ default:
+ goto bad;
+ }
+
+ return 0;
+
+bad:
+ ERR(handle, "Invalid policy property");
+ return -1;
+}
+
static void validate_array_destroy(validate_t flavors[])
{
unsigned int i;
@@ -741,6 +1290,9 @@ int validate_policydb(sepol_handle_t *handle, policydb_t *p)
if (validate_array_init(p, flavors))
goto bad;
+ if (validate_properties(handle, p))
+ goto bad;
+
if (p->policy_type == POLICY_KERN) {
if (validate_avtab(handle, &p->te_avtab, flavors))
goto bad;
@@ -759,10 +1311,22 @@ int validate_policydb(sepol_handle_t *handle, policydb_t *p)
goto bad;
}
+ if (validate_ocontexts(handle, p, flavors))
+ goto bad;
+
+ if (validate_genfs(handle, p, flavors))
+ goto bad;
+
if (validate_scopes(handle, p->scope, p->global))
goto bad;
- if (validate_datum_arrays(handle, p, flavors))
+ if (validate_datum_array_gaps(handle, p, flavors))
+ goto bad;
+
+ if (validate_datum_array_entries(handle, p, flavors))
+ goto bad;
+
+ if (validate_permissives(handle, p, flavors))
goto bad;
validate_array_destroy(flavors);
diff --git a/libsepol/src/private.h b/libsepol/src/private.h
index 71287282..a8cc1472 100644
--- a/libsepol/src/private.h
+++ b/libsepol/src/private.h
@@ -44,7 +44,12 @@
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
-#define is_saturated(x) (x == (typeof(x))-1)
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+# define is_saturated(x) (x == (typeof(x))-1 || (x) > (1U << 16))
+#else
+# define is_saturated(x) (x == (typeof(x))-1)
+#endif
+
#define zero_or_saturated(x) ((x == 0) || is_saturated(x))
#define spaceship_cmp(a, b) (((a) > (b)) - ((a) < (b)))
@@ -78,3 +83,23 @@ extern int next_entry(void *buf, struct policy_file *fp, size_t bytes);
extern size_t put_entry(const void *ptr, size_t size, size_t n,
struct policy_file *fp);
extern int str_read(char **strp, struct policy_file *fp, size_t len);
+
+static inline void* mallocarray(size_t nmemb, size_t size) {
+ if (size && nmemb > (size_t)-1 / size) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ return malloc(nmemb * size);
+}
+
+#ifndef HAVE_REALLOCARRAY
+static inline void* reallocarray(void *ptr, size_t nmemb, size_t size) {
+ if (size && nmemb > (size_t)-1 / size) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ return realloc(ptr, nmemb * size);
+}
+#endif
diff --git a/libsepol/src/services.c b/libsepol/src/services.c
index 3407058f..29723729 100644
--- a/libsepol/src/services.c
+++ b/libsepol/src/services.c
@@ -94,7 +94,7 @@ static void push(char *expr_ptr)
else
new_stack_len = stack_len * 2;
- new_stack = realloc(stack, new_stack_len * sizeof(*stack));
+ new_stack = reallocarray(stack, new_stack_len, sizeof(*stack));
if (!new_stack) {
ERR(NULL, "unable to allocate stack space");
return;
@@ -449,8 +449,8 @@ static int constraint_expr_eval_reason(context_struct_t *scontext,
else
new_expr_list_len = expr_list_len * 2;
- new_expr_list = realloc(expr_list,
- new_expr_list_len * sizeof(*expr_list));
+ new_expr_list = reallocarray(expr_list,
+ new_expr_list_len, sizeof(*expr_list));
if (!new_expr_list) {
ERR(NULL, "failed to allocate expr buffer stack");
rc = -ENOMEM;
@@ -712,7 +712,7 @@ mls_ops:
* Generate the same number of answer buffer entries as expression
* buffers (as there will never be more).
*/
- answer_list = malloc(expr_count * sizeof(*answer_list));
+ answer_list = mallocarray(expr_count, sizeof(*answer_list));
if (!answer_list) {
ERR(NULL, "failed to allocate answer stack");
rc = -ENOMEM;
@@ -797,7 +797,7 @@ mls_ops:
for (x = 0; buffers[x] != NULL; x++) {
while (1) {
- p = *r_buf + reason_buf_used;
+ p = *r_buf ? (*r_buf + reason_buf_used) : NULL;
len = snprintf(p, reason_buf_len - reason_buf_used,
"%s", buffers[x]);
if (len < 0 || len >= reason_buf_len - reason_buf_used) {
@@ -1553,7 +1553,7 @@ static int validate_class(hashtab_key_t key, hashtab_datum_t datum, void *p)
cladatum2->comdatum->permissions.table)) {
ERR(NULL,
" in the access vector definition "
- "for class %s\n", key);
+ "for class %s", key);
return -1;
}
}
@@ -2163,7 +2163,7 @@ int sepol_get_user_sids(sepol_security_id_t fromsid,
}
usercon.user = user->s.value;
- mysids = malloc(maxnel * sizeof(sepol_security_id_t));
+ mysids = mallocarray(maxnel, sizeof(sepol_security_id_t));
if (!mysids) {
rc = -ENOMEM;
goto out;
@@ -2199,7 +2199,7 @@ int sepol_get_user_sids(sepol_security_id_t fromsid,
} else {
maxnel += SIDS_NEL;
mysids2 =
- malloc(maxnel *
+ mallocarray(maxnel,
sizeof(sepol_security_id_t));
if (!mysids2) {
diff --git a/libsepol/src/sidtab.c b/libsepol/src/sidtab.c
index 255e0725..adeae6eb 100644
--- a/libsepol/src/sidtab.c
+++ b/libsepol/src/sidtab.c
@@ -15,6 +15,7 @@
#include <sepol/policydb/sidtab.h>
#include "flask.h"
+#include "private.h"
#define SIDTAB_HASH(sid) \
(sid & SIDTAB_HASH_MASK)
@@ -27,7 +28,7 @@ int sepol_sidtab_init(sidtab_t * s)
{
int i;
- s->htable = malloc(sizeof(sidtab_ptr_t) * SIDTAB_SIZE);
+ s->htable = mallocarray(SIDTAB_SIZE, sizeof(sidtab_ptr_t));
if (!s->htable)
return -ENOMEM;
for (i = 0; i < SIDTAB_SIZE; i++)
diff --git a/libsepol/src/user_record.c b/libsepol/src/user_record.c
index ac520060..404fa3a8 100644
--- a/libsepol/src/user_record.c
+++ b/libsepol/src/user_record.c
@@ -4,6 +4,7 @@
#include "user_internal.h"
#include "debug.h"
+#include "private.h"
struct sepol_user {
/* This user's name */
@@ -182,8 +183,9 @@ int sepol_user_add_role(sepol_handle_t * handle,
if (!role_cp)
goto omem;
- roles_realloc = realloc(user->roles,
- sizeof(char *) * (user->num_roles + 1));
+ roles_realloc = reallocarray(user->roles,
+ user->num_roles + 1,
+ sizeof(char *));
if (!roles_realloc)
goto omem;
@@ -265,7 +267,7 @@ int sepol_user_get_roles(sepol_handle_t * handle,
unsigned int i;
const char **tmp_roles =
- (const char **)malloc(sizeof(char *) * user->num_roles);
+ (const char **)mallocarray(user->num_roles, sizeof(char *));
if (!tmp_roles)
goto omem;
diff --git a/libsepol/src/users.c b/libsepol/src/users.c
index b895b7f5..a7406214 100644
--- a/libsepol/src/users.c
+++ b/libsepol/src/users.c
@@ -226,17 +226,17 @@ int sepol_user_modify(sepol_handle_t * handle,
void *tmp_ptr;
/* Ensure reverse lookup array has enough space */
- tmp_ptr = realloc(policydb->user_val_to_struct,
- (policydb->p_users.nprim +
- 1) * sizeof(user_datum_t *));
+ tmp_ptr = reallocarray(policydb->user_val_to_struct,
+ policydb->p_users.nprim + 1,
+ sizeof(user_datum_t *));
if (!tmp_ptr)
goto omem;
policydb->user_val_to_struct = tmp_ptr;
policydb->user_val_to_struct[policydb->p_users.nprim] = NULL;
- tmp_ptr = realloc(policydb->sym_val_to_name[SYM_USERS],
- (policydb->p_users.nprim +
- 1) * sizeof(char *));
+ tmp_ptr = reallocarray(policydb->sym_val_to_name[SYM_USERS],
+ policydb->p_users.nprim + 1,
+ sizeof(char *));
if (!tmp_ptr)
goto omem;
policydb->sym_val_to_name[SYM_USERS] = tmp_ptr;
diff --git a/libsepol/src/util.c b/libsepol/src/util.c
index 902c63c5..1cd1308d 100644
--- a/libsepol/src/util.c
+++ b/libsepol/src/util.c
@@ -28,6 +28,8 @@
#include <sepol/policydb/policydb.h>
#include <sepol/policydb/util.h>
+#include "private.h"
+
struct val_to_name {
unsigned int val;
char *name;
@@ -40,6 +42,8 @@ struct val_to_name {
* 0). Return 0 on success, -1 on out of memory. */
int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a)
{
+ uint32_t *new;
+
if (cnt == NULL || a == NULL)
return -1;
@@ -48,17 +52,18 @@ int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a)
* than be smart about it, for now we realloc() the array each
* time a new uint32_t is added! */
if (*a != NULL)
- *a = (uint32_t *) realloc(*a, (*cnt + 1) * sizeof(uint32_t));
+ new = (uint32_t *) reallocarray(*a, *cnt + 1, sizeof(uint32_t));
else { /* empty list */
*cnt = 0;
- *a = (uint32_t *) malloc(sizeof(uint32_t));
+ new = (uint32_t *) malloc(sizeof(uint32_t));
}
- if (*a == NULL) {
+ if (new == NULL) {
return -1;
}
- (*a)[*cnt] = i;
+ new[*cnt] = i;
(*cnt)++;
+ *a = new;
return 0;
}
diff --git a/libsepol/src/write.c b/libsepol/src/write.c
index b09551f7..db244c08 100644
--- a/libsepol/src/write.c
+++ b/libsepol/src/write.c
@@ -2117,7 +2117,7 @@ static int scope_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
* buffer. this would have been easier with C99's
* dynamic arrays... */
rc = POLICYDB_ERROR;
- dyn_buf = malloc(items * sizeof(*dyn_buf));
+ dyn_buf = mallocarray(items, sizeof(*dyn_buf));
if (!dyn_buf)
goto err;
buf = dyn_buf;
diff --git a/libsepol/tests/Makefile b/libsepol/tests/Makefile
index fc9bd1a3..a72c327d 100644
--- a/libsepol/tests/Makefile
+++ b/libsepol/tests/Makefile
@@ -1,3 +1,4 @@
+ENV ?= env
M4 ?= m4
MKDIR ?= mkdir
EXE ?= libsepol-tests
@@ -44,10 +45,15 @@ clean:
rm -f $(objs) $(EXE)
rm -f $(policies)
rm -f policies/test-downgrade/policy.hi policies/test-downgrade/policy.lo
-
+# mkdir is run in a clean environment created by env -i to avoid failing under ASan with:
+#
+# ASan runtime does not come first in initial library list;
+# you should either link runtime to your application or manually preload it with LD_PRELOAD
+#
+# when the source code is built with ASan
test: $(EXE) $(policies)
- $(MKDIR) -p policies/test-downgrade
+ $(ENV) -i $(MKDIR) -p policies/test-downgrade
../../checkpolicy/checkpolicy -M policies/test-cond/refpolicy-base.conf -o policies/test-downgrade/policy.hi
./$(EXE)
diff --git a/mcstrans/Makefile b/mcstrans/Makefile
index c993a9f5..b20279ab 100644
--- a/mcstrans/Makefile
+++ b/mcstrans/Makefile
@@ -1,3 +1,9 @@
+PKG_CONFIG ?= pkg-config
+PCRE_MODULE := libpcre2-8
+PCRE_CFLAGS := $(shell $(PKG_CONFIG) --cflags $(PCRE_MODULE)) -DPCRE2_CODE_UNIT_WIDTH=8
+PCRE_LDLIBS := $(shell $(PKG_CONFIG) --libs $(PCRE_MODULE))
+export PCRE_MODULE PCRE_CFLAGS PCRE_LDLIBS
+
all:
$(MAKE) -C src
$(MAKE) -C utils
diff --git a/mcstrans/src/Makefile b/mcstrans/src/Makefile
index 76ef0557..ef518625 100644
--- a/mcstrans/src/Makefile
+++ b/mcstrans/src/Makefile
@@ -20,10 +20,10 @@ CFLAGS ?= -Wall -W -Wundef -Wmissing-noreturn -Wmissing-format-attribute
all: $(PROG)
$(PROG): $(PROG_OBJS) $(LIBSEPOLA)
- $(CC) $(LDFLAGS) -pie -o $@ $^ -lselinux -lcap -lpcre $(LDLIBS_LIBSEPOLA)
+ $(CC) $(LDFLAGS) -pie -o $@ $^ -lselinux -lcap $(PCRE_LDLIBS) $(LDLIBS_LIBSEPOLA)
%.o: %.c
- $(CC) $(CFLAGS) -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -fPIE -c -o $@ $<
+ $(CC) $(CFLAGS) $(PCRE_CFLAGS) -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -fPIE -c -o $@ $<
install: all
test -d $(DESTDIR)$(SBINDIR) || install -m 755 -d $(DESTDIR)$(SBINDIR)
diff --git a/mcstrans/src/mcscolor.c b/mcstrans/src/mcscolor.c
index a3838850..9ff0ce2f 100644
--- a/mcstrans/src/mcscolor.c
+++ b/mcstrans/src/mcscolor.c
@@ -11,6 +11,8 @@
#include <syslog.h>
#include <selinux/selinux.h>
#include <selinux/context.h>
+
+#include "mcscolor.h"
#include "mcstrans.h"
/* Define data structures */
diff --git a/mcstrans/src/mcscolor.h b/mcstrans/src/mcscolor.h
new file mode 100644
index 00000000..c37fe6ed
--- /dev/null
+++ b/mcstrans/src/mcscolor.h
@@ -0,0 +1,8 @@
+#ifndef __mcscolor_h__
+#define __mcscolor_h__
+
+extern void finish_context_colors(void);
+extern int init_colors(void);
+extern int raw_color(const char *raw, char **color_str);
+
+#endif
diff --git a/mcstrans/src/mcstrans.c b/mcstrans/src/mcstrans.c
index e92dfddb..d42760fd 100644
--- a/mcstrans/src/mcstrans.c
+++ b/mcstrans/src/mcstrans.c
@@ -26,7 +26,7 @@
#include <selinux/context.h>
#include <syslog.h>
#include <errno.h>
-#include <pcre.h>
+#include <pcre2.h>
#include <ctype.h>
#include <time.h>
#include <sys/time.h>
@@ -36,7 +36,6 @@
#include "mcstrans.h"
#define N_BUCKETS 1453
-#define OVECCOUNT (512*3)
#define log_error(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
@@ -82,9 +81,9 @@ typedef struct word_group {
affix_t *suffixes;
word_t *words;
- pcre *prefix_regexp;
- pcre *word_regexp;
- pcre *suffix_regexp;
+ pcre2_code *prefix_regexp;
+ pcre2_code *word_regexp;
+ pcre2_code *suffix_regexp;
ebitmap_t def;
@@ -109,7 +108,7 @@ typedef struct domain {
base_classification_t *base_classifications;
word_group_t *groups;
- pcre *base_classification_regexp;
+ pcre2_code *base_classification_regexp;
struct domain *next;
} domain_t;
@@ -136,7 +135,7 @@ typedef struct cat_constraint {
static cat_constraint_t *cat_constraints;
-unsigned int
+static unsigned int
hash(const char *str) {
unsigned int hash = 5381;
int c;
@@ -213,7 +212,7 @@ parse_category(ebitmap_t *e, const char *raw, int allowinverse)
return 0;
}
-int
+static int
parse_ebitmap(ebitmap_t *e, ebitmap_t *def, const char *raw) {
int rc = ebitmap_cpy(e, def);
if (rc < 0)
@@ -224,7 +223,7 @@ parse_ebitmap(ebitmap_t *e, ebitmap_t *def, const char *raw) {
return 0;
}
-mls_level_t *
+static mls_level_t *
parse_raw(const char *raw) {
mls_level_t *mls = calloc(1, sizeof(mls_level_t));
if (!mls)
@@ -248,7 +247,7 @@ err:
return NULL;
}
-void
+static void
destroy_word(word_t **list, word_t *word) {
if (!word) {
return;
@@ -267,7 +266,7 @@ destroy_word(word_t **list, word_t *word) {
free(word);
}
-word_t *
+static word_t *
create_word(word_t **list, const char *text) {
word_t *w = calloc(1, sizeof(word_t));
if (!w) {
@@ -291,7 +290,7 @@ err:
return NULL;
}
-void
+static void
destroy_group(word_group_t **list, word_group_t *group) {
for (; list && *list; list = &(*list)->next) {
if (*list == group) {
@@ -317,14 +316,14 @@ destroy_group(word_group_t **list, word_group_t *group) {
free(group->name);
free(group->sword);
free(group->join);
- pcre_free(group->prefix_regexp);
- pcre_free(group->word_regexp);
- pcre_free(group->suffix_regexp);
+ pcre2_code_free(group->prefix_regexp);
+ pcre2_code_free(group->word_regexp);
+ pcre2_code_free(group->suffix_regexp);
ebitmap_destroy(&group->def);
free(group);
}
-word_group_t *
+static word_group_t *
create_group(word_group_t **list, const char *name) {
word_group_t *group = calloc(1, sizeof(word_group_t));
if (!group)
@@ -357,7 +356,7 @@ err:
return NULL;
}
-void
+static void
destroy_domain(domain_t *domain) {
int i;
unsigned int rt = 0, tr = 0;
@@ -392,7 +391,7 @@ destroy_domain(domain_t *domain) {
free(domain->base_classifications);
domain->base_classifications = next;
}
- pcre_free(domain->base_classification_regexp);
+ pcre2_code_free(domain->base_classification_regexp);
while (domain->groups)
destroy_group(&domain->groups, domain->groups);
free(domain->name);
@@ -401,7 +400,7 @@ destroy_domain(domain_t *domain) {
syslog(LOG_INFO, "cache sizes: tr = %u, rt = %u", tr, rt);
}
-domain_t *
+static domain_t *
create_domain(const char *name) {
domain_t *domain = calloc(1, sizeof(domain_t));
if (!domain) {
@@ -425,7 +424,7 @@ err:
return NULL;
}
-int
+static int
add_word(word_group_t *group, char *raw, char *trans) {
if (strchr(trans,'-')) {
log_error("'%s'is invalid because '-' is illegal in modifiers.\n", trans);
@@ -451,7 +450,7 @@ add_word(word_group_t *group, char *raw, char *trans) {
return 0;
}
-int
+static int
add_constraint(char op, char *raw, char *tok) {
log_debug("%s\n", "add_constraint");
ebitmap_t empty;
@@ -521,7 +520,7 @@ add_constraint(char op, char *raw, char *tok) {
return 0;
}
-int
+static int
violates_constraints(mls_level_t *l) {
int nbits;
sens_constraint_t *s;
@@ -563,7 +562,7 @@ violates_constraints(mls_level_t *l) {
return 0;
}
-void
+static void
destroy_sens_constraint(sens_constraint_t **list, sens_constraint_t *constraint) {
if (!constraint) {
return;
@@ -580,7 +579,7 @@ destroy_sens_constraint(sens_constraint_t **list, sens_constraint_t *constraint)
free(constraint);
}
-void
+static void
destroy_cat_constraint(cat_constraint_t **list, cat_constraint_t *constraint) {
if (!constraint) {
return;
@@ -663,7 +662,7 @@ find_in_table(context_map_node_t **table, const char *key) {
return NULL;
}
-char *
+static char *
trim(char *str, const char *whitespace) {
char *p = str + strlen(str);
@@ -672,7 +671,7 @@ trim(char *str, const char *whitespace) {
return str;
}
-char *
+static char *
triml(char *str, const char *whitespace) {
char *p = str;
@@ -681,7 +680,7 @@ triml(char *str, const char *whitespace) {
return p;
}
-int
+static int
update(char **p, char *const val) {
free (*p);
*p = strdup(val);
@@ -692,7 +691,7 @@ update(char **p, char *const val) {
return 0;
}
-int
+static int
append(affix_t **affixes, const char *val) {
affix_t *affix = calloc(1, sizeof(affix_t));
if (!affix) {
@@ -887,7 +886,7 @@ init_translations(void) {
return(read_translations(selinux_translations_path()));
}
-char *
+static char *
extract_range(const char *incon) {
context_t con = context_new(incon);
if (!con) {
@@ -910,7 +909,7 @@ extract_range(const char *incon) {
return r;
}
-char *
+static char *
new_context_str(const char *incon, const char *range) {
char *rcon = NULL;
context_t con = context_new(incon);
@@ -931,7 +930,7 @@ exit:
return NULL;
}
-char *
+static char *
find_in_hashtable(const char *range, domain_t *domain, context_map_node_t **table) {
char *trans = NULL;
context_map_t *map = find_in_table(table, range);
@@ -946,13 +945,6 @@ find_in_hashtable(const char *range, domain_t *domain, context_map_node_t **tabl
return trans;
}
-void
-emit_whitespace(char*buffer, char *whitespace) {
- strcat(buffer, "[");
- strcat(buffer, whitespace);
- strcat(buffer, "]");
-}
-
static int
string_size(const void *p1, const void *p2) {
return strlen(*(char **)p2) - strlen(*(char **)p1);
@@ -969,20 +961,22 @@ word_size(const void *p1, const void *p2) {
return (w2_len - w1_len);
}
-void
-build_regexp(pcre **r, char *buffer) {
- const char *error;
- int error_offset;
+static void
+build_regexp(pcre2_code **r, char *buffer) {
+ int error;
+ PCRE2_SIZE error_offset;
if (*r)
- pcre_free(*r);
- *r = pcre_compile(buffer, PCRE_CASELESS, &error, &error_offset, NULL);
- if (error) {
- log_error("pcre=%s, error=%s\n", buffer, error ? error: "none");
+ pcre2_code_free(*r);
+ *r = pcre2_compile((PCRE2_SPTR8) buffer, PCRE2_ZERO_TERMINATED, PCRE2_CASELESS, &error, &error_offset, NULL);
+ if (!*r) {
+ PCRE2_UCHAR errbuf[256];
+ pcre2_get_error_message(error, errbuf, sizeof(errbuf));
+ log_error("pcre compilation of '%s' failed at offset %zu: %s\n", buffer, error_offset, errbuf);
}
buffer[0] = '\0';
}
-int
+static int
build_regexps(domain_t *domain) {
char buffer[1024 * 128];
buffer[0] = '\0';
@@ -1086,7 +1080,7 @@ build_regexps(domain_t *domain) {
return 0;
}
-char *
+static char *
compute_raw_from_trans(const char *level, domain_t *domain) {
#ifdef DEBUG
@@ -1095,12 +1089,12 @@ compute_raw_from_trans(const char *level, domain_t *domain) {
#endif
int rc = 0;
- int ovector[OVECCOUNT];
+ pcre2_match_data *match_data = NULL;
word_group_t *g = NULL;
char *work = NULL;
char *r = NULL;
- const char * match = NULL;
- int work_len;
+ char *match = NULL;
+ size_t work_len;
mls_level_t *mraw = NULL;
ebitmap_t set, clear, tmp;
@@ -1121,11 +1115,20 @@ compute_raw_from_trans(const char *level, domain_t *domain) {
if (!domain->base_classification_regexp)
goto err;
log_debug(" compute_raw_from_trans work = %s\n", work);
- rc = pcre_exec(domain->base_classification_regexp, 0, work, work_len, 0, PCRE_ANCHORED, ovector, OVECCOUNT);
+ match_data = pcre2_match_data_create_from_pattern(domain->base_classification_regexp, NULL);
+ if (!match_data) {
+ log_error("allocation error %s", strerror(errno));
+ goto err;
+ }
+ rc = pcre2_match(domain->base_classification_regexp, (PCRE2_SPTR8)work, work_len, 0, PCRE2_ANCHORED, match_data, NULL);
if (rc > 0) {
- match = NULL;
- pcre_get_substring(work, ovector, rc, 0, &match);
- log_debug(" compute_raw_from_trans match = %s len = %u\n", match, strlen(match));
+ const PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);
+ match = strndup(work + ovector[0], ovector[1] - ovector[0]);
+ if (!match) {
+ log_error("allocation error %s", strerror(errno));
+ goto err;
+ }
+ log_debug(" compute_raw_from_trans match = %s len = %zu\n", match, strlen(match));
base_classification_t *bc;
for (bc = domain->base_classifications; bc; bc = bc->next) {
if (!strcmp(bc->trans, match)) {
@@ -1145,12 +1148,23 @@ compute_raw_from_trans(const char *level, domain_t *domain) {
char *p=work + ovector[0] + ovector[1];
while (*p && (strchr(" ", *p) != NULL))
*p++ = '#';
- pcre_free((char *)match);
+
+ free(match);
match = NULL;
} else {
- log_debug(" compute_raw_from_trans no base classification matched %s\n", level);
+ switch (rc) {
+ case PCRE2_ERROR_NOMATCH:
+ log_debug(" compute_raw_from_trans no base classification matched %s\n", level);
+ break;
+ default:
+ log_error("compute_raw_from_trans: base matching error for input '%s': %d\n", level, rc);
+ break;
+ }
}
+ pcre2_match_data_free(match_data);
+ match_data = NULL;
+
if (mraw == NULL) {
goto err;
}
@@ -1161,23 +1175,43 @@ compute_raw_from_trans(const char *level, domain_t *domain) {
change = 0;
for (g = domain->groups; g && !change && !complete; g = g->next) {
int prefix = 0, suffix = 0;
- int prefix_offset = 0, prefix_len = 0;
- int suffix_offset = 0, suffix_len = 0;
+ PCRE2_SIZE prefix_offset = 0, prefix_len = 0;
+ PCRE2_SIZE suffix_offset = 0, suffix_len = 0;
if (g->prefix_regexp) {
- rc = pcre_exec(g->prefix_regexp, 0, work, work_len, 0, 0, ovector, OVECCOUNT);
+ match_data = pcre2_match_data_create_from_pattern(g->prefix_regexp, NULL);
+ if (!match_data) {
+ log_error("allocation error %s", strerror(errno));
+ goto err;
+ }
+ rc = pcre2_match(g->prefix_regexp, (PCRE2_SPTR8)work, work_len, 0, 0, match_data, NULL);
if (rc > 0) {
+ const PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);
prefix = 1;
prefix_offset = ovector[0];
prefix_len = ovector[1] - ovector[0];
+ } else if (rc != PCRE2_ERROR_NOMATCH) {
+ log_error("compute_raw_from_trans: prefix matching error for input '%s': %d\n", level, rc);
}
+ pcre2_match_data_free(match_data);
+ match_data = NULL;
}
if (g->suffix_regexp) {
- rc = pcre_exec(g->suffix_regexp, 0, work, work_len, 0, 0, ovector, OVECCOUNT);
+ match_data = pcre2_match_data_create_from_pattern(g->suffix_regexp, NULL);
+ if (!match_data) {
+ log_error("allocation error %s", strerror(errno));
+ goto err;
+ }
+ rc = pcre2_match(g->suffix_regexp, (PCRE2_SPTR8)work, work_len, 0, 0, match_data, NULL);
if (rc > 0) {
+ const PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);
suffix = 1;
suffix_offset = ovector[0];
suffix_len = ovector[1] - ovector[0];
+ } else if (rc != PCRE2_ERROR_NOMATCH) {
+ log_error("compute_raw_from_trans: suffix matching error for input '%s': %d\n", level, rc);
}
+ pcre2_match_data_free(match_data);
+ match_data = NULL;
}
/* anchors prefix ^, suffix $ */
@@ -1186,14 +1220,23 @@ compute_raw_from_trans(const char *level, domain_t *domain) {
(g->suffixes && suffix)) &&
g->word_regexp) {
char *s = work + prefix_offset + prefix_len;
- int l = (suffix_len ? suffix_offset : work_len) - prefix_len - prefix_offset;
- rc = pcre_exec(g->word_regexp, 0, s, l, 0, 0, ovector, OVECCOUNT);
+ PCRE2_SIZE len = (suffix_len ? suffix_offset : work_len) - prefix_len - prefix_offset;
+ match_data = pcre2_match_data_create_from_pattern(g->word_regexp, NULL);
+ if (!match_data) {
+ log_error("allocation error %s", strerror(errno));
+ goto err;
+ }
+ rc = pcre2_match(g->word_regexp, (PCRE2_SPTR8)s, len, 0, 0, match_data, NULL);
if (rc > 0) {
- match = NULL;
- pcre_get_substring(s, ovector, rc, 0, &match);
- trim((char *)match, g->whitespace);
+ const PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);
+ match = strndup(s + ovector[0], ovector[1] - ovector[0]);
+ if (!match) {
+ log_error("allocation error %s", strerror(errno));
+ goto err;
+ }
+ trim(match, g->whitespace);
if (*match) {
- char *p = triml((char *)match, g->whitespace);
+ char *p = triml(match, g->whitespace);
while (p && *p) {
int plen = strlen(p);
unsigned int i;
@@ -1230,9 +1273,13 @@ compute_raw_from_trans(const char *level, domain_t *domain) {
memset(work + suffix_offset, '#', suffix_len);
memset(s + ovector[0], '#', ovector[1] - ovector[0]);
}
- pcre_free((void *)match);
+ free(match);
match = NULL;
+ } else if (rc != PCRE2_ERROR_NOMATCH) {
+ log_error("compute_raw_from_trans: word matching error for input '%s' for substring '%s': %d\n", level, s, rc);
}
+ pcre2_match_data_free(match_data);
+ match_data = NULL;
}
/* YYY */
complete=1;
@@ -1271,14 +1318,15 @@ err:
mls_level_destroy(mraw);
free(mraw);
free(work);
- pcre_free((void *)match);
+ free(match);
ebitmap_destroy(&tmp);
ebitmap_destroy(&set);
ebitmap_destroy(&clear);
+ pcre2_match_data_free(match_data);
return NULL;
}
-char *
+static char *
compute_trans_from_raw(const char *level, domain_t *domain) {
#ifdef DEBUG
diff --git a/mcstrans/src/mcstrans.h b/mcstrans/src/mcstrans.h
index e5cda93b..0addb325 100644
--- a/mcstrans/src/mcstrans.h
+++ b/mcstrans/src/mcstrans.h
@@ -6,4 +6,3 @@ extern int init_translations(void);
extern void finish_context_translations(void);
extern int trans_context(const char *, char **);
extern int untrans_context(const char *, char **);
-
diff --git a/mcstrans/src/mcstransd.c b/mcstrans/src/mcstransd.c
index 59c152e7..536c0f32 100644
--- a/mcstrans/src/mcstransd.c
+++ b/mcstrans/src/mcstransd.c
@@ -16,6 +16,8 @@
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/un.h>
+
+#include "mcscolor.h"
#include "mcstrans.h"
#ifdef UNUSED
@@ -43,15 +45,6 @@
#define log_debug(fmt, ...) do {} while (0)
#endif
-extern int init_translations(void);
-extern void finish_context_translations(void);
-extern int trans_context(const char *, char **);
-extern int untrans_context(const char *, char **);
-
-extern int init_colors(void);
-extern void finish_context_colors(void);
-extern int raw_color(const char *, char **);
-
#define SETRANSD_PATHNAME "/sbin/mcstransd"
/* name of program (for error messages) */
@@ -514,7 +507,7 @@ initialize(void)
}
-void dropprivs(void)
+static void dropprivs(void)
{
cap_t new_caps;
diff --git a/mcstrans/utils/Makefile b/mcstrans/utils/Makefile
index 9dfe7723..a48f4e72 100644
--- a/mcstrans/utils/Makefile
+++ b/mcstrans/utils/Makefile
@@ -14,13 +14,13 @@ endif
all: $(TARGETS)
transcon: transcon.o ../src/mcstrans.o ../src/mls_level.o $(LIBSEPOLA)
- $(CC) $(LDFLAGS) -o $@ $^ -lpcre -lselinux $(LDLIBS_LIBSEPOLA)
+ $(CC) $(LDFLAGS) -o $@ $^ $(PCRE_LDLIBS) -lselinux $(LDLIBS_LIBSEPOLA)
untranscon: untranscon.o ../src/mcstrans.o ../src/mls_level.o $(LIBSEPOLA)
- $(CC) $(LDFLAGS) -o $@ $^ -lpcre -lselinux $(LDLIBS_LIBSEPOLA)
+ $(CC) $(LDFLAGS) -o $@ $^ $(PCRE_LDLIBS) -lselinux $(LDLIBS_LIBSEPOLA)
%.o: %.c
- $(CC) $(CFLAGS) -D_GNU_SOURCE -I../src -fPIE -c -o $@ $<
+ $(CC) $(CFLAGS) $(PCRE_CFLAGS) -D_GNU_SOURCE -I../src -fPIE -c -o $@ $<
install: all
-mkdir -p $(DESTDIR)$(SBINDIR)
diff --git a/policycoreutils/man/man5/selinux_config.5 b/policycoreutils/man/man5/selinux_config.5
index 58b42a0e..f391befb 100644
--- a/policycoreutils/man/man5/selinux_config.5
+++ b/policycoreutils/man/man5/selinux_config.5
@@ -32,7 +32,7 @@ The \fIconfig\fR file supports the following parameters:
.br
\fBSELINUXTYPE = \fIpolicy_name\fR
.br
-\fBREQUIREUSERS = \fI0\fR | \fI1\fR
+\fBREQUIRESEUSERS = \fI0\fR | \fI1\fR
.br
\fBAUTORELABEL = \fI0\fR | \fI1\fR
.RE
diff --git a/policycoreutils/man/ru/man5/selinux_config.5 b/policycoreutils/man/ru/man5/selinux_config.5
index 40039e57..8c0db9ae 100644
--- a/policycoreutils/man/ru/man5/selinux_config.5
+++ b/policycoreutils/man/ru/man5/selinux_config.5
@@ -34,7 +34,7 @@ config \- файл конфигурации подсистемы SELinux.
.br
\fBSELINUXTYPE = \fIpolicy_name\fR
.br
-\fBREQUIREUSERS = \fI0\fR | \fI1\fR
+\fBREQUIRESEUSERS = \fI0\fR | \fI1\fR
.br
\fBAUTORELABEL = \fI0\fR | \fI1\fR
.RE
diff --git a/policycoreutils/newrole/Makefile b/policycoreutils/newrole/Makefile
index 4dedb7dd..b3ccf671 100644
--- a/policycoreutils/newrole/Makefile
+++ b/policycoreutils/newrole/Makefile
@@ -91,3 +91,16 @@ indent:
relabel: install
/sbin/restorecon $(DESTDIR)$(BINDIR)/newrole
+
+test-build-options:
+ $(MAKE) PAMH=y AUDITH=y AUDIT_LOG_PRIV=y NAMESPACE_PRIV=y clean newrole
+ $(MAKE) PAMH=y AUDITH=y AUDIT_LOG_PRIV=y NAMESPACE_PRIV=n clean newrole
+ $(MAKE) PAMH=y AUDITH=y AUDIT_LOG_PRIV=n NAMESPACE_PRIV=y clean newrole
+ $(MAKE) PAMH=y AUDITH=y AUDIT_LOG_PRIV=n NAMESPACE_PRIV=n clean newrole
+ $(MAKE) PAMH=y AUDITH=y AUDIT_LOG_PRIV=y NAMESPACE_PRIV=y clean newrole
+ $(MAKE) PAMH=y AUDITH=n AUDIT_LOG_PRIV=n NAMESPACE_PRIV=y clean newrole
+ $(MAKE) PAMH=y AUDITH=n AUDIT_LOG_PRIV=n NAMESPACE_PRIV=n clean newrole
+ $(MAKE) PAMH=n AUDITH=y AUDIT_LOG_PRIV=y NAMESPACE_PRIV=n clean newrole
+ $(MAKE) PAMH=n AUDITH=y AUDIT_LOG_PRIV=n NAMESPACE_PRIV=n clean newrole
+ $(MAKE) PAMH=n AUDITH=n AUDIT_LOG_PRIV=n NAMESPACE_PRIV=n clean newrole
+ $(MAKE) clean
diff --git a/policycoreutils/newrole/hashtab.c b/policycoreutils/newrole/hashtab.c
index bc502836..26d4f4c7 100644
--- a/policycoreutils/newrole/hashtab.c
+++ b/policycoreutils/newrole/hashtab.c
@@ -44,7 +44,7 @@ hashtab_t hashtab_create(unsigned int (*hash_value) (hashtab_t h,
int hashtab_insert(hashtab_t h, hashtab_key_t key, hashtab_datum_t datum)
{
- int hvalue;
+ unsigned int hvalue;
hashtab_ptr_t prev, cur, newnode;
if (!h)
@@ -83,7 +83,7 @@ int hashtab_remove(hashtab_t h, hashtab_key_t key,
void (*destroy) (hashtab_key_t k,
hashtab_datum_t d, void *args), void *args)
{
- int hvalue;
+ unsigned int hvalue;
hashtab_ptr_t cur, last;
if (!h)
@@ -115,7 +115,7 @@ int hashtab_remove(hashtab_t h, hashtab_key_t key,
hashtab_datum_t hashtab_search(hashtab_t h, const_hashtab_key_t key)
{
- int hvalue;
+ unsigned int hvalue;
hashtab_ptr_t cur;
if (!h)
@@ -160,8 +160,9 @@ int hashtab_map(hashtab_t h,
int (*apply) (hashtab_key_t k,
hashtab_datum_t d, void *args), void *args)
{
- unsigned int i, ret;
+ unsigned int i;
hashtab_ptr_t cur;
+ int ret;
if (!h)
return HASHTAB_SUCCESS;
diff --git a/policycoreutils/newrole/newrole.c b/policycoreutils/newrole/newrole.c
index 31b51c5a..ae37d725 100644
--- a/policycoreutils/newrole/newrole.c
+++ b/policycoreutils/newrole/newrole.c
@@ -100,7 +100,6 @@
#endif
#define DEFAULT_PATH "/usr/bin:/bin"
-#define DEFAULT_CONTEXT_SIZE 255 /* first guess at context size */
extern char **environ;
@@ -115,7 +114,7 @@ extern char **environ;
*
* Returns malloc'd memory
*/
-static char *build_new_range(char *newlevel, const char *range)
+static char *build_new_range(const char *newlevel, const char *range)
{
char *newrangep = NULL;
const char *tmpptr;
@@ -166,7 +165,7 @@ static char *build_new_range(char *newlevel, const char *range)
#include <security/pam_appl.h> /* for PAM functions */
#include <security/pam_misc.h> /* for misc_conv PAM utility function */
-const char *service_name = "newrole";
+static const char *service_name = "newrole";
/* authenticate_via_pam()
*
@@ -182,7 +181,7 @@ const char *service_name = "newrole";
* program. This is the only function in this program that makes PAM
* calls.
*/
-int authenticate_via_pam(const char *ttyn, pam_handle_t * pam_handle)
+static int authenticate_via_pam(const char *ttyn, pam_handle_t * pam_handle)
{
int result = 0; /* set to 0 (not authenticated) by default */
@@ -230,14 +229,13 @@ static int free_hashtab_entry(hashtab_key_t key, hashtab_datum_t d,
static unsigned int reqsymhash(hashtab_t h, const_hashtab_key_t key)
{
- char *p, *keyp;
+ const char *p;
size_t size;
unsigned int val;
val = 0;
- keyp = (char *)key;
- size = strlen(keyp);
- for (p = keyp; ((size_t) (p - keyp)) < size; p++)
+ size = strlen(key);
+ for (p = key; ((size_t) (p - key)) < size; p++)
val =
(val << 4 | (val >> (8 * sizeof(unsigned int) - 4))) ^ (*p);
return val & (h->size - 1);
@@ -335,6 +333,14 @@ static int read_pam_config(void)
#define PASSWORD_PROMPT _("Password:") /* prompt for getpass() */
+static void memzero(void *ptr, size_t size)
+{
+ volatile unsigned char * volatile p = ptr;
+ while (size--) {
+ *p++ = '\0';
+ }
+}
+
/* authenticate_via_shadow_passwd()
*
* in: uname - the calling user's user name
@@ -348,11 +354,12 @@ static int read_pam_config(void)
* This function uses the shadow passwd file to thenticate the user running
* this program.
*/
-int authenticate_via_shadow_passwd(const char *uname)
+static int authenticate_via_shadow_passwd(const char *uname)
{
struct spwd *p_shadow_line;
char *unencrypted_password_s;
char *encrypted_password_s;
+ int ret;
setspent();
p_shadow_line = getspnam(uname);
@@ -370,10 +377,18 @@ int authenticate_via_shadow_passwd(const char *uname)
}
/* Use crypt() to encrypt user's input password. */
+ errno = 0;
encrypted_password_s = crypt(unencrypted_password_s,
p_shadow_line->sp_pwdp);
- memset(unencrypted_password_s, 0, strlen(unencrypted_password_s));
- return (!strcmp(encrypted_password_s, p_shadow_line->sp_pwdp));
+ memzero(unencrypted_password_s, strlen(unencrypted_password_s));
+ if (errno || !encrypted_password_s) {
+ fprintf(stderr, _("Cannot encrypt password.\n"));
+ return 0;
+ }
+
+ ret = !strcmp(encrypted_password_s, p_shadow_line->sp_pwdp);
+ memzero(encrypted_password_s, strlen(encrypted_password_s));
+ return ret;
}
#endif /* if/else USE_PAM */
@@ -623,7 +638,7 @@ static inline int drop_capabilities(__attribute__ ((__unused__)) int full)
* This function will set the uid values to be that of caller's uid, and
* will drop any privilege which may have been raised.
*/
-static int transition_to_caller_uid()
+static int transition_to_caller_uid(void)
{
uid_t uid = getuid();
@@ -850,7 +865,6 @@ static int parse_command_line_arguments(int argc, char **argv, char *ttyn,
case 'V':
printf("newrole: %s version %s\n", PACKAGE, VERSION);
exit(0);
- break;
case 'p':
*preserve_environment = 1;
break;
diff --git a/policycoreutils/run_init/open_init_pty.c b/policycoreutils/run_init/open_init_pty.c
index 150cb45e..19101c50 100644
--- a/policycoreutils/run_init/open_init_pty.c
+++ b/policycoreutils/run_init/open_init_pty.c
@@ -244,7 +244,7 @@ int main(int argc, char *argv[])
rb_init(&inbuf, inbuf_mem, sizeof(inbuf_mem));
rb_init(&outbuf, outbuf_mem, sizeof(outbuf_mem));
- if (argc == 1) {
+ if (argc < 2) {
printf("usage: %s PROGRAM [ARGS]...\n", argv[0]);
exit(1);
}
diff --git a/policycoreutils/run_init/run_init.c b/policycoreutils/run_init/run_init.c
index 545490a2..ce499781 100644
--- a/policycoreutils/run_init/run_init.c
+++ b/policycoreutils/run_init/run_init.c
@@ -86,8 +86,6 @@
/* The file containing the context to run
* the scripts under. */
-int authenticate_via_pam(const struct passwd *);
-
/* authenticate_via_pam()
*
* in: p_passwd_line - struct containing data from our user's line in
@@ -104,7 +102,7 @@ int authenticate_via_pam(const struct passwd *);
*
*/
-int authenticate_via_pam(const struct passwd *p_passwd_line)
+static int authenticate_via_pam(const struct passwd *p_passwd_line)
{
int result = 0; /* our result, set to 0 (not authenticated) by default */
@@ -169,8 +167,6 @@ int authenticate_via_pam(const struct passwd *p_passwd_line)
#define PASSWORD_PROMPT _("Password:") /* prompt for getpass() */
-int authenticate_via_shadow_passwd(const struct passwd *);
-
/* authenticate_via_shadow_passwd()
*
* in: p_passwd_line - struct containing data from our user's line in
@@ -187,7 +183,7 @@ int authenticate_via_shadow_passwd(const struct passwd *);
*
*/
-int authenticate_via_shadow_passwd(const struct passwd *p_passwd_line)
+static int authenticate_via_shadow_passwd(const struct passwd *p_passwd_line)
{
struct spwd *p_shadow_line; /* struct derived from shadow passwd file line */
@@ -238,7 +234,7 @@ int authenticate_via_shadow_passwd(const struct passwd *p_passwd_line)
* return: 0 When success
* -1 When failure
*/
-int authenticate_user(void)
+static int authenticate_user(void)
{
#define INITLEN 255
@@ -303,7 +299,7 @@ int authenticate_user(void)
* out: The CONTEXT associated with the context.
* return: 0 on success, -1 on failure.
*/
-int get_init_context(char **context)
+static int get_init_context(char **context)
{
FILE *fp;
diff --git a/policycoreutils/scripts/fixfiles b/policycoreutils/scripts/fixfiles
index 6fb12e04..7df4303a 100755
--- a/policycoreutils/scripts/fixfiles
+++ b/policycoreutils/scripts/fixfiles
@@ -109,6 +109,7 @@ fullFlag=0
BOOTTIME=""
VERBOSE="-p"
FORCEFLAG=""
+THREADS=""
RPMFILES=""
PREFC=""
RESTORE_MODE=""
@@ -152,7 +153,7 @@ newer() {
shift
LogReadOnly
for m in `echo $FILESYSTEMSRW`; do
- find $m -mount -newermt $DATE -print0 2>/dev/null | ${RESTORECON} ${FORCEFLAG} ${VERBOSE} $* -i -0 -f -
+ find $m -mount -newermt $DATE -print0 2>/dev/null | ${RESTORECON} ${FORCEFLAG} ${VERBOSE} ${THREADS} $* -i -0 -f -
done;
}
@@ -196,7 +197,7 @@ if [ -f ${PREFC} -a -x /usr/bin/diff ]; then
esac; \
fi; \
done | \
- ${RESTORECON} ${VERBOSE} ${EXCLUDEDIRS} ${FORCEFLAG} $* -i -R -f -; \
+ ${RESTORECON} ${VERBOSE} ${EXCLUDEDIRS} ${FORCEFLAG} ${THREADS} $* -i -R -f -; \
rm -f ${TEMPFILE} ${PREFCTEMPFILE}
fi
}
@@ -234,11 +235,11 @@ LogExcluded
case "$RESTORE_MODE" in
RPMFILES)
for i in `echo "$RPMFILES" | sed 's/,/ /g'`; do
- rpmlist $i | ${RESTORECON} ${VERBOSE} ${EXCLUDEDIRS} ${FORCEFLAG} $* -i -R -f -
+ rpmlist $i | ${RESTORECON} ${VERBOSE} ${EXCLUDEDIRS} ${FORCEFLAG} ${THREADS} $* -i -R -f -
done
;;
FILEPATH)
- ${RESTORECON} ${VERBOSE} ${EXCLUDEDIRS} ${FORCEFLAG} $* -R -- "$FILEPATH"
+ ${RESTORECON} ${VERBOSE} ${EXCLUDEDIRS} ${FORCEFLAG} ${THREADS} $* -R -- "$FILEPATH"
;;
*)
if [ -n "${FILESYSTEMSRW}" ]; then
@@ -246,7 +247,7 @@ case "$RESTORE_MODE" in
echo "${OPTION}ing `echo ${FILESYSTEMSRW}`"
if [ -z "$BIND_MOUNT_FILESYSTEMS" ]; then
- ${SETFILES} ${VERBOSE} ${EXCLUDEDIRS} ${FORCEFLAG} $* -q ${FC} ${FILESYSTEMSRW}
+ ${SETFILES} ${VERBOSE} ${EXCLUDEDIRS} ${FORCEFLAG} $* -q ${THREADS} ${FC} ${FILESYSTEMSRW}
else
# we bind mount so we can fix the labels of files that have already been
# mounted over
@@ -256,7 +257,7 @@ case "$RESTORE_MODE" in
mkdir -p "${TMP_MOUNT}${m}" || exit 1
mount --bind "${m}" "${TMP_MOUNT}${m}" || exit 1
- ${SETFILES} ${VERBOSE} ${EXCLUDEDIRS} ${FORCEFLAG} $* -q ${FC} -r "${TMP_MOUNT}" "${TMP_MOUNT}${m}"
+ ${SETFILES} ${VERBOSE} ${EXCLUDEDIRS} ${FORCEFLAG} ${THREADS} $* -q ${FC} -r "${TMP_MOUNT}" "${TMP_MOUNT}${m}"
umount "${TMP_MOUNT}${m}" || exit 1
rm -rf "${TMP_MOUNT}" || echo "Error cleaning up."
done;
@@ -329,8 +330,9 @@ case "$1" in
fi
> /.autorelabel || exit $?
[ -z "$FORCEFLAG" ] || echo -n "$FORCEFLAG " >> /.autorelabel
- [ -z "$BOOTTIME" ] || echo -N $BOOTTIME >> /.autorelabel
- [ -z "$BIND_MOUNT_FILESYSTEMS" ] || echo "-M" >> /.autorelabel
+ [ -z "$BOOTTIME" ] || echo -n "-N $BOOTTIME " >> /.autorelabel
+ [ -z "$BIND_MOUNT_FILESYSTEMS" ] || echo -n "-M " >> /.autorelabel
+ [ -z "$THREADS" ] || echo -n "$THREADS " >> /.autorelabel
# Force full relabel if SELinux is not enabled
selinuxenabled || echo -F > /.autorelabel
echo "System will relabel on next boot"
@@ -342,17 +344,17 @@ esac
}
usage() {
echo $"""
-Usage: $0 [-v] [-F] [-M] [-f] relabel
+Usage: $0 [-v] [-F] [-M] [-f] [-T nthreads] relabel
or
-Usage: $0 [-v] [-F] [-B | -N time ] { check | restore | verify }
+Usage: $0 [-v] [-F] [-B | -N time ] [-T nthreads] { check | restore | verify }
or
-Usage: $0 [-v] [-F] { check | restore | verify } dir/file ...
+Usage: $0 [-v] [-F] [-T nthreads] { check | restore | verify } dir/file ...
or
-Usage: $0 [-v] [-F] -R rpmpackage[,rpmpackage...] { check | restore | verify }
+Usage: $0 [-v] [-F] [-T nthreads] -R rpmpackage[,rpmpackage...] { check | restore | verify }
or
-Usage: $0 [-v] [-F] -C PREVIOUS_FILECONTEXT { check | restore | verify }
+Usage: $0 [-v] [-F] [-T nthreads] -C PREVIOUS_FILECONTEXT { check | restore | verify }
or
-Usage: $0 [-F] [-M] [-B] onboot
+Usage: $0 [-F] [-M] [-B] [-T nthreads] onboot
"""
}
@@ -371,7 +373,7 @@ set_restore_mode() {
}
# See how we were called.
-while getopts "N:BC:FfR:l:vM" i; do
+while getopts "N:BC:FfR:l:vMT:" i; do
case "$i" in
B)
BOOTTIME=`/bin/who -b | awk '{print $3}'`
@@ -406,6 +408,9 @@ while getopts "N:BC:FfR:l:vM" i; do
f)
fullFlag=1
;;
+ T)
+ THREADS="-T $OPTARG"
+ ;;
*)
usage
exit 1
diff --git a/policycoreutils/scripts/fixfiles.8 b/policycoreutils/scripts/fixfiles.8
index c4e894e5..9a317d91 100644
--- a/policycoreutils/scripts/fixfiles.8
+++ b/policycoreutils/scripts/fixfiles.8
@@ -6,22 +6,22 @@ fixfiles \- fix file SELinux security contexts.
.na
.B fixfiles
-.I [\-v] [\-F] [-M] [\-f] relabel
+.I [\-v] [\-F] [-M] [\-f] [\-T nthreads] relabel
.B fixfiles
-.I [\-v] [\-F] { check | restore | verify } dir/file ...
+.I [\-v] [\-F] [\-T nthreads] { check | restore | verify } dir/file ...
.B fixfiles
-.I [\-v] [\-F] [\-B | \-N time ] { check | restore | verify }
+.I [\-v] [\-F] [\-B | \-N time ] [\-T nthreads] { check | restore | verify }
.B fixfiles
-.I [\-v] [\-F] \-R rpmpackagename[,rpmpackagename...] { check | restore | verify }
+.I [\-v] [\-F] [\-T nthreads] \-R rpmpackagename[,rpmpackagename...] { check | restore | verify }
.B fixfiles
-.I [\-v] [\-F] \-C PREVIOUS_FILECONTEXT { check | restore | verify }
+.I [\-v] [\-F] [\-T nthreads] \-C PREVIOUS_FILECONTEXT { check | restore | verify }
.B fixfiles
-.I [-F] [-M] [-B] onboot
+.I [-F] [-M] [-B] [\-T nthreads] onboot
.ad
@@ -76,6 +76,11 @@ Bind mount filesystems before relabeling them, this allows fixing the context of
.B -v
Modify verbosity from progress to verbose. (Run restorecon with \-v instead of \-p)
+.TP
+.B \-T nthreads
+Use parallel relabeling, see
+.B setfiles(8)
+
.SH "ARGUMENTS"
One of:
.TP
diff --git a/policycoreutils/secon/secon.c b/policycoreutils/secon/secon.c
index a0957d09..d624fa13 100644
--- a/policycoreutils/secon/secon.c
+++ b/policycoreutils/secon/secon.c
@@ -333,6 +333,9 @@ static void cmd_line(int argc, char *argv[])
opts->from_type = OPTS_FROM_CUR;
if (opts->from_type == OPTS_FROM_ARG) {
+ if (!argv[0])
+ errx(EXIT_FAILURE, "No argument given");
+
opts->f.arg = argv[0];
if (xstreq(argv[0], "-"))
diff --git a/policycoreutils/semodule/semodule.8 b/policycoreutils/semodule/semodule.8
index 18d4f708..d1735d21 100644
--- a/policycoreutils/semodule/semodule.8
+++ b/policycoreutils/semodule/semodule.8
@@ -23,6 +23,13 @@ force a reload of policy
.B \-B, \-\-build
force a rebuild of policy (also reloads unless \-n is used)
.TP
+.B \-\-rebuild-if-modules-changed
+Force a rebuild of the policy if any changes to module content are detected
+(by comparing with checksum from the last transaction). One can use this
+instead of \-B to ensure that any changes to the module store done by an
+external tool (e.g. a package manager) are applied, while automatically
+skipping the rebuild if there are no new changes.
+.TP
.B \-D, \-\-disable_dontaudit
Temporarily remove dontaudits from policy. Reverts whenever policy is rebuilt
.TP
@@ -95,6 +102,9 @@ only modules listed in \-\-extract after this option.
.B \-H,\-\-hll
Extract module as an HLL file. This only affects the \-\-extract option and
only modules listed in \-\-extract after this option.
+.TP
+.B \-m,\-\-checksum
+Add SHA256 checksum of modules to the list output.
.SH EXAMPLE
.nf
@@ -130,6 +140,9 @@ $ semodule \-B \-S "/tmp/var/lib/selinux"
# Write the HLL version of puppet and the CIL version of wireshark
# modules at priority 400 to the current working directory
$ semodule \-X 400 \-\-hll \-E puppet \-\-cil \-E wireshark
+# Check whether a module in "localmodule.pp" file is same as installed module "localmodule"
+$ /usr/libexec/selinux/hll/pp localmodule.pp | sha256sum
+$ semodule -l -m | grep localmodule
.fi
.SH SEE ALSO
diff --git a/policycoreutils/semodule/semodule.c b/policycoreutils/semodule/semodule.c
index c815f015..1ed8e690 100644
--- a/policycoreutils/semodule/semodule.c
+++ b/policycoreutils/semodule/semodule.c
@@ -47,6 +47,7 @@ static int verbose;
static int reload;
static int no_reload;
static int build;
+static int check_ext_changes;
static int disable_dontaudit;
static int preserve_tunables;
static int ignore_module_cache;
@@ -57,6 +58,7 @@ static semanage_handle_t *sh = NULL;
static char *store;
static char *store_root;
int extract_cil = 0;
+static int checksum = 0;
extern char *optarg;
extern int optind;
@@ -147,6 +149,10 @@ static void usage(char *progname)
printf(" -S,--store-path use an alternate path for the policy store root\n");
printf(" -c, --cil extract module as cil. This only affects module extraction.\n");
printf(" -H, --hll extract module as hll. This only affects module extraction.\n");
+ printf(" -m, --checksum print module checksum (SHA256).\n");
+ printf(" --rebuild-if-modules-changed\n"
+ " force policy rebuild if module content changed since\n"
+ " last rebuild (based on checksum)\n");
}
/* Sets the global mode variable to new_mode, but only if no other
@@ -178,6 +184,7 @@ static void set_mode(enum client_modes new_mode, char *arg)
static void parse_command_line(int argc, char **argv)
{
static struct option opts[] = {
+ {"rebuild-if-modules-changed", 0, NULL, '\0'},
{"store", required_argument, NULL, 's'},
{"base", required_argument, NULL, 'b'},
{"help", 0, NULL, 'h'},
@@ -200,19 +207,31 @@ static void parse_command_line(int argc, char **argv)
{"disable", required_argument, NULL, 'd'},
{"path", required_argument, NULL, 'p'},
{"store-path", required_argument, NULL, 'S'},
+ {"checksum", 0, NULL, 'm'},
{NULL, 0, NULL, 0}
};
int extract_selected = 0;
int cil_hll_set = 0;
- int i;
+ int i, longind;
verbose = 0;
reload = 0;
no_reload = 0;
+ check_ext_changes = 0;
priority = 400;
while ((i =
- getopt_long(argc, argv, "s:b:hi:l::vr:u:RnNBDCPX:e:d:p:S:E:cH", opts,
- NULL)) != -1) {
+ getopt_long(argc, argv, "s:b:hi:l::vr:u:RnNBDCPX:e:d:p:S:E:cHm",
+ opts, &longind)) != -1) {
switch (i) {
+ case '\0':
+ switch(longind) {
+ case 0: /* --rebuild-if-modules-changed */
+ check_ext_changes = 1;
+ break;
+ default:
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
case 'b':
fprintf(stderr, "The --base option is deprecated. Use --install instead.\n");
set_mode(INSTALL_M, optarg);
@@ -287,6 +306,9 @@ static void parse_command_line(int argc, char **argv)
case 'd':
set_mode(DISABLE_M, optarg);
break;
+ case 'm':
+ checksum = 1;
+ break;
case '?':
default:{
usage(argv[0]);
@@ -294,13 +316,13 @@ static void parse_command_line(int argc, char **argv)
}
}
}
- if ((build || reload) && num_commands) {
+ if ((build || reload || check_ext_changes) && num_commands) {
fprintf(stderr,
"build or reload should not be used with other commands\n");
usage(argv[0]);
exit(1);
}
- if (num_commands == 0 && reload == 0 && build == 0) {
+ if (num_commands == 0 && reload == 0 && build == 0 && check_ext_changes == 0) {
fprintf(stderr, "At least one mode must be specified.\n");
usage(argv[0]);
exit(1);
@@ -338,6 +360,42 @@ static void parse_command_line(int argc, char **argv)
}
}
+/* Get module checksum */
+static char *hash_module_data(const char *module_name, const int prio) {
+ semanage_module_key_t *modkey = NULL;
+ char *hash_str = NULL;
+ void *hash = NULL;
+ size_t hash_len = 0;
+ int result;
+
+ result = semanage_module_key_create(sh, &modkey);
+ if (result != 0) {
+ goto cleanup;
+ }
+
+ result = semanage_module_key_set_name(sh, modkey, module_name);
+ if (result != 0) {
+ goto cleanup;
+ }
+
+ result = semanage_module_key_set_priority(sh, modkey, prio);
+ if (result != 0) {
+ goto cleanup;
+ }
+
+ result = semanage_module_compute_checksum(sh, modkey, 1, &hash_str,
+ &hash_len);
+ if (result != 0) {
+ goto cleanup;
+ }
+
+cleanup:
+ free(hash);
+ semanage_module_key_destroy(sh, modkey);
+ free(modkey);
+ return hash_str;
+}
+
int main(int argc, char *argv[])
{
int i, commit = 0;
@@ -353,7 +411,7 @@ int main(int argc, char *argv[])
cil_set_log_level(CIL_ERR + verbose);
- if (build)
+ if (build || check_ext_changes)
commit = 1;
sh = semanage_handle_create();
@@ -392,7 +450,7 @@ int main(int argc, char *argv[])
}
}
- if (build) {
+ if (build || check_ext_changes) {
if ((result = semanage_begin_transaction(sh)) < 0) {
fprintf(stderr, "%s: Could not begin transaction: %s\n",
argv[0], errno ? strerror(errno) : "");
@@ -546,6 +604,8 @@ cleanup_extract:
int modinfos_len = 0;
semanage_module_info_t *m = NULL;
int j = 0;
+ char *module_checksum = NULL;
+ uint16_t pri = 0;
if (verbose) {
printf
@@ -570,7 +630,18 @@ cleanup_extract:
result = semanage_module_info_get_name(sh, m, &name);
if (result != 0) goto cleanup_list;
- printf("%s\n", name);
+ result = semanage_module_info_get_priority(sh, m, &pri);
+ if (result != 0) goto cleanup_list;
+
+ printf("%s", name);
+ if (checksum) {
+ module_checksum = hash_module_data(name, pri);
+ if (module_checksum) {
+ printf(" %s", module_checksum);
+ free(module_checksum);
+ }
+ }
+ printf("\n");
}
}
else if (strcmp(mode_arg, "full") == 0) {
@@ -585,12 +656,16 @@ cleanup_extract:
}
/* calculate column widths */
- size_t column[4] = { 0, 0, 0, 0 };
+ size_t column[5] = { 0, 0, 0, 0, 0 };
/* fixed width columns */
column[0] = sizeof("000") - 1;
column[3] = sizeof("disabled") - 1;
+ result = semanage_module_compute_checksum(sh, NULL, 0, NULL,
+ &column[4]);
+ if (result != 0) goto cleanup_list;
+
/* variable width columns */
const char *tmp = NULL;
size_t size;
@@ -607,12 +682,11 @@ cleanup_extract:
if (result != 0) goto cleanup_list;
size = strlen(tmp);
- if (size > column[3]) column[3] = size;
+ if (size > column[2]) column[2] = size;
}
/* print out each module */
for (j = 0; j < modinfos_len; j++) {
- uint16_t pri = 0;
const char *name = NULL;
int enabled = 0;
const char *lang_ext = NULL;
@@ -631,11 +705,20 @@ cleanup_extract:
result = semanage_module_info_get_lang_ext(sh, m, &lang_ext);
if (result != 0) goto cleanup_list;
- printf("%0*u %-*s %-*s %-*s\n",
+ printf("%0*u %-*s %-*s %-*s",
(int)column[0], pri,
(int)column[1], name,
(int)column[2], lang_ext,
(int)column[3], enabled ? "" : "disabled");
+ if (checksum) {
+ module_checksum = hash_module_data(name, pri);
+ if (module_checksum) {
+ printf(" %-*s", (int)column[4], module_checksum);
+ free(module_checksum);
+ }
+ }
+ printf("\n");
+
}
}
else {
@@ -740,6 +823,8 @@ cleanup_disable:
semanage_set_reload(sh, 0);
if (build)
semanage_set_rebuild(sh, 1);
+ if (check_ext_changes)
+ semanage_set_check_ext_changes(sh, 1);
if (disable_dontaudit)
semanage_set_disable_dontaudit(sh, 1);
else if (build)
diff --git a/policycoreutils/sestatus/sestatus.c b/policycoreutils/sestatus/sestatus.c
index ceee0d52..7dcc9944 100644
--- a/policycoreutils/sestatus/sestatus.c
+++ b/policycoreutils/sestatus/sestatus.c
@@ -35,7 +35,7 @@ static unsigned int COL = 32;
extern char *selinux_mnt;
-int cmp_cmdline(const char *command, int pid)
+static int cmp_cmdline(const char *command, int pid)
{
char buf[BUFSIZE];
@@ -59,7 +59,7 @@ int cmp_cmdline(const char *command, int pid)
return 0;
}
-int pidof(const char *command)
+static int pidof(const char *command)
{
/* inspired by killall5.c from psmisc */
char stackpath[PATH_MAX + 1], *p;
@@ -92,7 +92,7 @@ int pidof(const char *command)
return ret;
}
-void load_checks(char *pc[], int *npc, char *fc[], int *nfc)
+static void load_checks(char *pc[], int *npc, char *fc[], int *nfc)
{
FILE *fp = fopen(CONF, "r");
@@ -168,11 +168,9 @@ void load_checks(char *pc[], int *npc, char *fc[], int *nfc)
return;
}
-void printf_tab(const char *outp)
+static void printf_tab(const char *outp)
{
- char buf[20];
- snprintf(buf, sizeof(buf), "%%-%us", COL);
- printf(buf, outp);
+ printf("%-*s", COL, outp);
}
diff --git a/policycoreutils/setfiles/Makefile b/policycoreutils/setfiles/Makefile
index 63d81850..d7670a8f 100644
--- a/policycoreutils/setfiles/Makefile
+++ b/policycoreutils/setfiles/Makefile
@@ -6,7 +6,7 @@ MANDIR = $(PREFIX)/share/man
AUDITH ?= $(shell test -f /usr/include/libaudit.h && echo y)
CFLAGS ?= -g -Werror -Wall -W
-override LDLIBS += -lselinux -lsepol
+override LDLIBS += -lselinux -lsepol -lpthread
ifeq ($(AUDITH), y)
override CFLAGS += -DUSE_AUDIT
diff --git a/policycoreutils/setfiles/restore.c b/policycoreutils/setfiles/restore.c
index 9d688c60..e9ae33ad 100644
--- a/policycoreutils/setfiles/restore.c
+++ b/policycoreutils/setfiles/restore.c
@@ -29,7 +29,7 @@ void restore_init(struct restore_opts *opts)
opts->hnd = selabel_open(SELABEL_CTX_FILE, selinux_opts, 3);
if (!opts->hnd) {
- perror(opts->selabel_opt_path);
+ perror(opts->selabel_opt_path ? opts->selabel_opt_path : selinux_file_context_path());
exit(1);
}
@@ -72,7 +72,7 @@ void restore_finish(void)
}
}
-int process_glob(char *name, struct restore_opts *opts)
+int process_glob(char *name, struct restore_opts *opts, size_t nthreads)
{
glob_t globbuf;
size_t i = 0;
@@ -91,8 +91,9 @@ int process_glob(char *name, struct restore_opts *opts)
continue;
if (len > 0 && strcmp(&globbuf.gl_pathv[i][len], "/..") == 0)
continue;
- rc = selinux_restorecon(globbuf.gl_pathv[i],
- opts->restorecon_flags);
+ rc = selinux_restorecon_parallel(globbuf.gl_pathv[i],
+ opts->restorecon_flags,
+ nthreads);
if (rc < 0)
errors = rc;
}
diff --git a/policycoreutils/setfiles/restore.h b/policycoreutils/setfiles/restore.h
index ac6ad680..bb35a1db 100644
--- a/policycoreutils/setfiles/restore.h
+++ b/policycoreutils/setfiles/restore.h
@@ -49,7 +49,7 @@ struct restore_opts {
void restore_init(struct restore_opts *opts);
void restore_finish(void);
void add_exclude(const char *directory);
-int process_glob(char *name, struct restore_opts *opts);
+int process_glob(char *name, struct restore_opts *opts, size_t nthreads);
extern char **exclude_list;
#endif
diff --git a/policycoreutils/setfiles/restorecon.8 b/policycoreutils/setfiles/restorecon.8
index 668486f6..e07db2c8 100644
--- a/policycoreutils/setfiles/restorecon.8
+++ b/policycoreutils/setfiles/restorecon.8
@@ -33,6 +33,8 @@ restorecon \- restore file(s) default SELinux security contexts.
.RB [ \-W ]
.RB [ \-I | \-D ]
.RB [ \-x ]
+.RB [ \-T
+.IR nthreads ]
.SH "DESCRIPTION"
This manual page describes the
@@ -160,6 +162,13 @@ prevent
.B restorecon
from crossing file system boundaries.
.TP
+.BI \-T \ nthreads
+use up to
+.I nthreads
+threads. Specify 0 to create as many threads as there are available
+CPU cores; 1 to use only a single thread (default); or any positive
+number to use the given number of threads (if possible).
+.TP
.SH "ARGUMENTS"
.IR pathname \ ...
The pathname for the file(s) to be relabeled.
diff --git a/policycoreutils/setfiles/setfiles.8 b/policycoreutils/setfiles/setfiles.8
index 4d28bc9a..15f939d1 100644
--- a/policycoreutils/setfiles/setfiles.8
+++ b/policycoreutils/setfiles/setfiles.8
@@ -19,6 +19,8 @@ setfiles \- set SELinux file security contexts.
.RB [ \-W ]
.RB [ \-F ]
.RB [ \-I | \-D ]
+.RB [ \-T
+.IR nthreads ]
.I spec_file
.IR pathname \ ...
@@ -161,6 +163,13 @@ quote marks or backslashes. The
option of GNU
.B find
produces input suitable for this mode.
+.TP
+.BI \-T \ nthreads
+use up to
+.I nthreads
+threads. Specify 0 to create as many threads as there are available
+CPU cores; 1 to use only a single thread (default); or any positive
+number to use the given number of threads (if possible).
.SH "ARGUMENTS"
.TP
diff --git a/policycoreutils/setfiles/setfiles.c b/policycoreutils/setfiles/setfiles.c
index f018d161..ab7016ac 100644
--- a/policycoreutils/setfiles/setfiles.c
+++ b/policycoreutils/setfiles/setfiles.c
@@ -1,4 +1,5 @@
#include "restore.h"
+#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio_ext.h>
@@ -34,20 +35,20 @@ static __attribute__((__noreturn__)) void usage(const char *const name)
{
if (iamrestorecon) {
fprintf(stderr,
- "usage: %s [-iIDFmnprRv0x] [-e excludedir] pathname...\n"
- "usage: %s [-iIDFmnprRv0x] [-e excludedir] -f filename\n",
+ "usage: %s [-iIDFmnprRv0xT] [-e excludedir] pathname...\n"
+ "usage: %s [-iIDFmnprRv0xT] [-e excludedir] -f filename\n",
name, name);
} else {
fprintf(stderr,
- "usage: %s [-diIDlmnpqvEFW] [-e excludedir] [-r alt_root_path] [-c policyfile] spec_file pathname...\n"
- "usage: %s [-diIDlmnpqvEFW] [-e excludedir] [-r alt_root_path] [-c policyfile] spec_file -f filename\n"
- "usage: %s -s [-diIDlmnpqvFW] spec_file\n",
+ "usage: %s [-diIDlmnpqvEFWT] [-e excludedir] [-r alt_root_path] [-c policyfile] spec_file pathname...\n"
+ "usage: %s [-diIDlmnpqvEFWT] [-e excludedir] [-r alt_root_path] [-c policyfile] spec_file -f filename\n"
+ "usage: %s -s [-diIDlmnpqvFWT] spec_file\n",
name, name, name);
}
exit(-1);
}
-void set_rootpath(const char *arg)
+static void set_rootpath(const char *arg)
{
if (strlen(arg) == 1 && strncmp(arg, "/", 1) == 0) {
fprintf(stderr, "%s: invalid alt_rootpath: %s\n",
@@ -64,7 +65,7 @@ void set_rootpath(const char *arg)
}
}
-int canoncon(char **contextp)
+static int canoncon(char **contextp)
{
char *context = *contextp, *tmpcon;
int rc = 0;
@@ -144,12 +145,12 @@ int main(int argc, char **argv)
int opt, i = 0;
const char *input_filename = NULL;
int use_input_file = 0;
- char *buf = NULL;
- size_t buf_len;
+ char *buf = NULL, *endptr;
+ size_t buf_len, nthreads = 1;
const char *base;
int errors = 0;
- const char *ropts = "e:f:hiIDlmno:pqrsvFRW0x";
- const char *sopts = "c:de:f:hiIDlmno:pqr:svEFR:W0";
+ const char *ropts = "e:f:hiIDlmno:pqrsvFRW0xT:";
+ const char *sopts = "c:de:f:hiIDlmno:pqr:svEFR:W0T:";
const char *opts;
union selinux_callback cb;
@@ -162,6 +163,10 @@ int main(int argc, char **argv)
policyfile = NULL;
r_opts.abort_on_error = 0;
+ if (!argv[0]) {
+ fprintf(stderr, "Called without required program name!\n");
+ exit(-1);
+ }
r_opts.progname = strdup(argv[0]);
if (!r_opts.progname) {
fprintf(stderr, "%s: Out of memory!\n", argv[0]);
@@ -370,6 +375,11 @@ int main(int argc, char **argv)
usage(argv[0]);
}
break;
+ case 'T':
+ nthreads = strtoull(optarg, &endptr, 10);
+ if (*optarg == '\0' || *endptr != '\0')
+ usage(argv[0]);
+ break;
case 'h':
case '?':
usage(argv[0]);
@@ -417,7 +427,7 @@ int main(int argc, char **argv)
altpath = argv[optind];
optind++;
- } else if (argc == 1)
+ } else if (argc < 2)
usage(argv[0]);
/* Set selabel_open options. */
@@ -448,13 +458,13 @@ int main(int argc, char **argv)
buf[len - 1] = 0;
if (!strcmp(buf, "/"))
r_opts.mass_relabel = SELINUX_RESTORECON_MASS_RELABEL;
- errors |= process_glob(buf, &r_opts) < 0;
+ errors |= process_glob(buf, &r_opts, nthreads) < 0;
}
if (strcmp(input_filename, "-") != 0)
fclose(f);
} else {
for (i = optind; i < argc; i++)
- errors |= process_glob(argv[i], &r_opts) < 0;
+ errors |= process_glob(argv[i], &r_opts, nthreads) < 0;
}
maybe_audit_mass_relabel(r_opts.mass_relabel, errors);
diff --git a/python/audit2allow/sepolgen-ifgen-attr-helper.c b/python/audit2allow/sepolgen-ifgen-attr-helper.c
index f010c958..6f3ba962 100644
--- a/python/audit2allow/sepolgen-ifgen-attr-helper.c
+++ b/python/audit2allow/sepolgen-ifgen-attr-helper.c
@@ -56,7 +56,7 @@ static int perm_name(hashtab_key_t key, hashtab_datum_t datum, void *data)
return 0;
}
-int render_access_mask(uint32_t av, avtab_key_t *key, policydb_t *policydbp,
+static int render_access_mask(uint32_t av, avtab_key_t *key, policydb_t *policydbp,
FILE *fp)
{
struct val_to_name v;
@@ -111,7 +111,7 @@ struct callback_data
FILE *fp;
};
-int output_avrule(avtab_key_t *key, avtab_datum_t *datum, void *args)
+static int output_avrule(avtab_key_t *key, avtab_datum_t *datum, void *args)
{
struct callback_data *cb_data = (struct callback_data *)args;
@@ -217,7 +217,7 @@ static policydb_t *load_policy(const char *filename)
}
-void usage(char *progname)
+static void usage(char *progname)
{
printf("usage: %s out_file [policy_file]\n", progname);
}
diff --git a/python/semanage/semanage-fcontext.8 b/python/semanage/semanage-fcontext.8
index 49635ba7..1ebf085f 100644
--- a/python/semanage/semanage-fcontext.8
+++ b/python/semanage/semanage-fcontext.8
@@ -3,7 +3,7 @@
semanage\-fcontext \- SELinux Policy Management file context tool
.SH "SYNOPSIS"
-.B semanage fcontext [\-h] [\-n] [\-N] [\-S STORE] [ \-\-add ( \-t TYPE \-f FTYPE \-r RANGE \-s SEUSER | \-e EQUAL ) FILE_SPEC ) | \-\-delete ( \-t TYPE \-f FTYPE | \-e EQUAL ) FILE_SPEC ) | \-\-deleteall | \-\-extract | \-\-list [\-C] | \-\-modify ( \-t TYPE \-f FTYPE \-r RANGE \-s SEUSER | \-e EQUAL ) FILE_SPEC ) ]
+.B semanage fcontext [\-h] [\-n] [\-N] [\-S STORE] [ \-\-add ( \-t TYPE \-f FTYPE \-r RANGE \-s SEUSER | \-e EQUAL ) FILE_SPEC | \-\-delete ( \-t TYPE \-f FTYPE | \-e EQUAL ) FILE_SPEC | \-\-deleteall | \-\-extract | \-\-list [\-C] | \-\-modify ( \-t TYPE \-f FTYPE \-r RANGE \-s SEUSER | \-e EQUAL ) FILE_SPEC ]
.SH "DESCRIPTION"
semanage is used to configure certain elements of
diff --git a/python/sepolgen/src/sepolgen/refparser.py b/python/sepolgen/src/sepolgen/refparser.py
index e611637f..1bb90564 100644
--- a/python/sepolgen/src/sepolgen/refparser.py
+++ b/python/sepolgen/src/sepolgen/refparser.py
@@ -261,7 +261,7 @@ def t_IDENTIFIER(t):
return t
def t_FILENAME(t):
- r'\"[a-zA-Z0-9_\-\+\.\$\*~ :]+\"'
+ r'\"[a-zA-Z0-9_\-\+\.\$\*~ :\[\]]+\"'
# Handle any keywords
t.type = reserved.get(t.value,'FILENAME')
return t
diff --git a/sandbox/seunshare.c b/sandbox/seunshare.c
index d626e98d..8917a0f9 100644
--- a/sandbox/seunshare.c
+++ b/sandbox/seunshare.c
@@ -89,7 +89,7 @@ static int drop_privs(uid_t uid)
/**
* If the user sends a siginto to seunshare, kill the child's session
*/
-void handler(int sig) {
+static void handler(int sig) {
if (child > 0) kill(-child,sig);
}
diff --git a/scripts/ci/fedora-test-runner.sh b/scripts/ci/fedora-test-runner.sh
index f817499b..3ce2c3a6 100755
--- a/scripts/ci/fedora-test-runner.sh
+++ b/scripts/ci/fedora-test-runner.sh
@@ -36,7 +36,7 @@ dnf install -y \
libcap-devel \
libcap-ng-devel \
pam-devel \
- pcre-devel \
+ pcre2-devel \
xmlto \
python3-devel \
ruby-devel \
diff --git a/scripts/oss-fuzz.sh b/scripts/oss-fuzz.sh
index 16cc3c0a..72d275e8 100755
--- a/scripts/oss-fuzz.sh
+++ b/scripts/oss-fuzz.sh
@@ -32,7 +32,7 @@ SANITIZER=${SANITIZER:-address}
flags="-O1 -fno-omit-frame-pointer -gline-tables-only -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=$SANITIZER -fsanitize=fuzzer-no-link"
export CC=${CC:-clang}
-export CFLAGS=${CFLAGS:-$flags}
+export CFLAGS="${CFLAGS:-$flags} -I$DESTDIR/usr/include -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64"
export CXX=${CXX:-clang++}
export CXXFLAGS=${CXXFLAGS:-$flags}
@@ -49,11 +49,24 @@ make -C libsepol clean
# shellcheck disable=SC2016
make -C libsepol V=1 LD_SONAME_FLAGS='-soname,$(LIBSO),--version-script=$(LIBMAP)' -j"$(nproc)" install
+## secilc fuzzer ##
+
# CFLAGS, CXXFLAGS and LIB_FUZZING_ENGINE have to be split to be accepted by
# the compiler/linker so they shouldn't be quoted
# shellcheck disable=SC2086
-$CC $CFLAGS -I"$DESTDIR/usr/include" -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -c -o secilc-fuzzer.o libsepol/fuzz/secilc-fuzzer.c
+$CC $CFLAGS -c -o secilc-fuzzer.o libsepol/fuzz/secilc-fuzzer.c
# shellcheck disable=SC2086
$CXX $CXXFLAGS $LIB_FUZZING_ENGINE secilc-fuzzer.o "$DESTDIR/usr/lib/libsepol.a" -o "$OUT/secilc-fuzzer"
zip -r "$OUT/secilc-fuzzer_seed_corpus.zip" secilc/test
+
+## binary policy fuzzer ##
+
+# CFLAGS, CXXFLAGS and LIB_FUZZING_ENGINE have to be split to be accepted by
+# the compiler/linker so they shouldn't be quoted
+# shellcheck disable=SC2086
+$CC $CFLAGS -c -o binpolicy-fuzzer.o libsepol/fuzz/binpolicy-fuzzer.c
+# shellcheck disable=SC2086
+$CXX $CXXFLAGS $LIB_FUZZING_ENGINE binpolicy-fuzzer.o "$DESTDIR/usr/lib/libsepol.a" -o "$OUT/binpolicy-fuzzer"
+
+zip -j "$OUT/binpolicy-fuzzer_seed_corpus.zip" libsepol/fuzz/policy.bin
diff --git a/secilc/docs/cil_file_labeling_statements.md b/secilc/docs/cil_file_labeling_statements.md
index ed7b7bf9..73f73885 100644
--- a/secilc/docs/cil_file_labeling_statements.md
+++ b/secilc/docs/cil_file_labeling_statements.md
@@ -36,11 +36,13 @@ Define entries for labeling files. The compiler will produce these entries in a
<col width="44%" />
<col width="55%" />
</colgroup>
-<tbody>
+<thead>
<tr class="odd">
<td align="left"><p><strong>keyword</strong></p></td>
<td align="left"><p><strong>file_contexts entry</strong></p></td>
</tr>
+</thead>
+<tbody>
<tr class="even">
<td align="left"><p><code>file</code></p></td>
<td align="left"><p><code>--</code></p></td>
@@ -185,7 +187,7 @@ Used to allocate a security context to filesystems that cannot support any of th
**Statement definition:**
```secil
- (genfscon fsname path context_id)
+ (genfscon fsname path [file_type] context_id)
```
**Where:**
@@ -209,6 +211,10 @@ Used to allocate a security context to filesystems that cannot support any of th
<td align="left"><p>If <code>fsname</code> is <code>proc</code>, then the partial path (see examples). For all other types this must be ‘<code>/</code>’.</p></td>
</tr>
<tr class="even">
+<td align="left"><p><code>file_type</code></p></td>
+<td align="left"><p>Optional keyword representing a file type. Valid values are the same as in [`filecon`](cil_file_labeling_statements.md#filecon) rules.</p></td>
+</tr>
+<tr class="odd">
<td align="left"><p><code>context_id</code></p></td>
<td align="left"><p>A previously declared <code>context</code> identifier or an anonymous security context (<code>user role type levelrange</code>), the range MUST be defined whether the policy is MLS/MCS enabled or not.</p></td>
</tr>