summaryrefslogtreecommitdiff
path: root/policy
diff options
context:
space:
mode:
authorKonrad Lipinski <k.lipinski2@partner.samsung.com>2018-09-14 14:14:17 +0200
committerKonrad Lipinski <k.lipinski2@partner.samsung.com>2018-10-10 15:53:59 +0200
commit75293c9c70f3f04c86721039bedfd6e0bf0786a8 (patch)
tree0df3266bd2eb1ee79895deeab61ccb06ecc03c61 /policy
parent4e5b938c96cf8a76606417c4ae2bfadb0b6e7fbe (diff)
downloadsecurity-manager-75293c9c70f3f04c86721039bedfd6e0bf0786a8.tar.gz
security-manager-75293c9c70f3f04c86721039bedfd6e0bf0786a8.tar.bz2
security-manager-75293c9c70f3f04c86721039bedfd6e0bf0786a8.zip
Replace smack rule storage with straight-from-db rule loader
Details: * remove %{TZ_SYS_VAR}/security-manager/rules{,-merged} directories * add security-manager-rules-loader that ** performs database migration/recovery ** writes smack rules from a coherent database directly to load2 * add generate-rule-code generator that translates rule templates (*.smack files) into c++ code for use in the loader * remove security-manager-init-db binary and replace its invocation with sh$ security-manager-rules-loader no-load * replace dd invocation with security-manager-rules-loader in the rule loader service * add explicit dependency to ensure the loader runs before the manager * refactor manager code ** remove the majority of database migration/recovery code on grounds of loader having run beforehand ** replace defensive remnants of said code with an emergency invocation sh$ security-manager-rules-loader fallback-only to apply fallback on database schmea errors ** remove rule file maintenance (not needed anymore) TODO: * *.smack template files are still used by the manager at runtime, removing them is optional and would require a substantial refactor best placed in a separate commit Pros: * optimize flash usage (rule files were prone to quadratic explosion) * solve database-rulefiles coherence problem * make the rule loader performance more scalable and typically better * simplify and speed up the manager a bit by dropping rule file code Change-Id: I7d79d5ec7e66c9dfe6563dbb3f76bf6ab6669589
Diffstat (limited to 'policy')
-rw-r--r--policy/CMakeLists.txt10
-rwxr-xr-xpolicy/generate-rule-code152
-rwxr-xr-xpolicy/updates/update-policy-to-v7.sh11
3 files changed, 173 insertions, 0 deletions
diff --git a/policy/CMakeLists.txt b/policy/CMakeLists.txt
index a4ed18d6..381245d7 100644
--- a/policy/CMakeLists.txt
+++ b/policy/CMakeLists.txt
@@ -17,3 +17,13 @@ INSTALL(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/security-manager-policy-reload DEST
# FOTA updater
INSTALL(FILES 241.security-manager.policy-update.sh DESTINATION ${FOTA_DIR})
+
+SET(GEN_FILE ${GEN_PATH}/generated-rule-templates.h)
+SET(GENERATOR "./generate-rule-code")
+
+ADD_CUSTOM_COMMAND(OUTPUT ${GEN_FILE}
+ COMMAND mkdir -p "${GEN_PATH}"
+ COMMAND ${GENERATOR} *.smack > ${GEN_FILE}
+ DEPENDS ${GENERATOR} "*.smack"
+)
+ADD_CUSTOM_TARGET(generate_rule_template_code DEPENDS ${GEN_FILE})
diff --git a/policy/generate-rule-code b/policy/generate-rule-code
new file mode 100755
index 00000000..50c270e8
--- /dev/null
+++ b/policy/generate-rule-code
@@ -0,0 +1,152 @@
+#!/usr/bin/env perl
+# Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License
+
+# the generated file is included verbatim into security-manager-rules-writer.cpp
+# therein lie more comments
+
+use strict; use warnings; use 5.10.1;
+sub member { my $m = shift; grep { $_ eq $m } @_ }
+
+# rule groups (roughly correspond to variables used and functions generated)
+my @rulesAuthor;
+my @rulesPkgLabelAuthor;
+my @rulesPkgLabel;
+my @rulesPathRW;
+my @rulesPath;
+my @rulesSharedRO;
+
+# one rule per line, either on stdin or in file arguments
+my @lines;
+while (<>) { chomp; push @lines, $_; }
+
+# process lines in sorted order so that similar rules are clustered together
+for (sort @lines) {
+ # make sure the rule is canonical - it's important for the writer (which makes assumptions about rule width and such)
+ die "heading whitespace ($_)" if /^\s/;
+ die "trailing whitespace ($_)" if /\s$/;
+ die "non-space whitespace ($_)" if grep {/[^ ]/} /(\s)/g;
+ die "two or more consecutive spaces ($_)" if / /;
+
+ # the rule is split into an odd number of segments (3 or 5): verbatim variable verbatim (variable verbatim)?
+ # ex. "System ~PROCESS~ rwxat" -> ("System ", "PROCESS", " rwxat")
+ # even elements are variables, odd ones verbatim strings
+ my @segments = split /~/;
+
+ # segment-based validation
+ die "rule without variables ($_)" if @segments < 2;
+ die "too many variables ($_)" if @segments > 5;
+ die "even number of segments ($_)" if !(@segments % 2);
+ die "ending segment empty ($_)" if !length $segments[-1];
+ my %varCount;
+ for (@segments[grep {$_%2} 0..$#segments]) {
+ die "unknown var ($_)" if !member $_, qw(PATH_TRUSTED PROCESS PATH_RO PATH_RW PATH_SHARED_RO);
+ ++$varCount{$_};
+ }
+ die "first segment ending with non-space character ($_)" if length $segments[0] && $segments[0] !~ / $/;
+ die "last segment starting with non-space character ($_)" if length $segments[-1] && $segments[-1] !~ /^ /;
+ die "variables not surrounded with whitespace ($_)" if grep {/^$/ || /^[^ ]/ || /[^ ]$/} @segments[grep {!($_%2)} 2..$#segments-2];
+
+ # make sure the permission string is a valid constant
+ my ($prePerm, $permChars) = $segments[-1] =~ /(.* )([^ ]*)$/;
+ my %perm;
+ for (split //, $permChars) {
+ die "unknown permission char ($_) in ($segments[-1])" if !member $_, split //, "rwxatlb";
+ die "duplicate permission char ($_) in ($segments[-1])" if exists $perm{$_};
+ $perm{$_} = 1;
+ }
+
+ # sort permission string characters to improve constant sharing in the writer
+ $segments[-1] = $prePerm . join '', grep {exists $perm{$_}} split //, "rwxatlb";
+
+ # partition rules into rough groups
+ if (1 == keys %varCount) {
+ # single variable rules
+ if (exists $varCount{PATH_TRUSTED}) {
+ push @rulesAuthor, [@segments];
+ } elsif (exists $varCount{PATH_SHARED_RO}) {
+ push @rulesSharedRO, [@segments];
+ } elsif (exists $varCount{PATH_RO}) {
+ push @rulesPath, [@segments];
+ } elsif (exists $varCount{PATH_RW}) {
+ push @rulesPathRW, [@segments];
+ } else { # PROCESS
+ push @rulesPkgLabel, [@segments];
+ }
+ } else {
+ # multi variable rules
+ die "multi-variable rule ($_) does not contain ~PROCESS~" if !exists $varCount{PROCESS};
+ if (exists $varCount{PATH_TRUSTED}) {
+ push @rulesPkgLabelAuthor, [@segments];
+ } elsif (exists $varCount{PATH_RO} || exists $varCount{PATH_RW}) {
+ push @rulesPkgLabel, [@segments];
+ } else {
+ die "unsupported multi-variable rule ($_)";
+ }
+ }
+}
+
+# for non-hybrid packages, ~PATH_RW~ == ~PROCESS~
+# this may lead to rule duplication between @rulesPathRW and @rulesPkgLabel
+#
+# in order to avoid this, @rulesPathRW is split into two groups:
+# rules having an isomorphic ~PROCESS~ rule end up in @rulesPathRWHybridOnly (not to be applied to non-hybrid packages)
+# other rules end up in @rulesPath (applied to all packages)
+my @pureProcessRulesAsPathRWRule = map {3 != @$_ ? () : ($_->[0].'~PATH_RW~'.$_->[2])} @rulesPkgLabel;
+my @rulesPathRWHybridOnly;
+push @rulesPath, grep {
+ my $asRule = $_->[0].'~PATH_RW~'.$_->[2];
+ my $hasRedudnantProcessRule = member $asRule, @pureProcessRulesAsPathRWRule;
+ push @rulesPathRWHybridOnly, $_ if $hasRedudnantProcessRule;
+ !$hasRedudnantProcessRule;
+} @rulesPathRW;
+
+# generate a function that writes a sequence of rules
+sub rules {
+ my $functionName = shift;
+ my $mustBeNonempty = shift;
+ die "($functionName()) has no rules - remove the call and propagate to make sure the loader stays fast" if $mustBeNonempty && !@_;
+ say "inl void $functionName() {";
+ for (@_) {
+ my @segments = @$_;
+ print " rule(";
+ for (0..$#segments/2-1) {
+ my $verbatim = $segments[2*$_];
+ my $wildcard = $segments[2*$_ + 1];
+ my $var = 'pkgL';
+ if ($wildcard eq 'PROCESS') {
+ $segments[2*$_+2] =~ s/^ //;
+ $var = 'pl';
+ } elsif ($wildcard eq 'PATH_TRUSTED') {
+ $verbatim .= 'User::Author::';
+ $var = 'pathTrusted';
+ } elsif ($wildcard eq 'PATH_RO') {
+ $segments[2*$_+2] = '::RO'.$segments[2*$_+2];
+ } elsif ($wildcard eq 'PATH_SHARED_RO') {
+ $segments[2*$_+2] = '::SharedRO'.$segments[2*$_+2];
+ }
+ print "\"$verbatim\", " if length $verbatim;
+ print "$var, ";
+ }
+ say "\"$segments[-1]\");";
+ }
+ say "}";
+}
+
+rules 'rulesAuthor', 0, @rulesAuthor;
+rules 'rulesPkgLabelAuthor', 1, @rulesPkgLabelAuthor;
+rules 'rulesPkgLabel', 0, @rulesPkgLabel;
+rules 'rulesPathRWHybridOnly', 0, @rulesPathRWHybridOnly;
+rules 'rulesPath', 0, @rulesPath;
+rules 'rulesSharedRO', 0, @rulesSharedRO;
diff --git a/policy/updates/update-policy-to-v7.sh b/policy/updates/update-policy-to-v7.sh
new file mode 100755
index 00000000..4f0b4508
--- /dev/null
+++ b/policy/updates/update-policy-to-v7.sh
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+
+export PATH=/sbin:/usr/sbin:/bin:/usr/bin
+
+. /etc/tizen-platform.conf
+
+systemctl stop security-manager.service security-manager.socket
+
+rm -rf "$TZ_SYS_VAR"/security-manager/rules{,-merged}
+
+systemctl start security-manager.service security-manager.socket