2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-31 06:16:03 +00:00

expand automated profile generation to to allow profile generation from stdin

This extends the auto-profile generation so that it can take profiles formated
in standard profile language augemented by a few special variables for
the automatically generated rules.  This will all extended the regression
tests in ways that are not currently supported, because mkprofile format
does not match of the profile language.

the special apparmorish variables are
@{gen_elf name} - generate rules for elf binaries
@{gen_bin name} - generate rules for a binary
@{gen_def} - generate default rules
@{gen name} - do @{gen_def} @{gen_bin name}

To generate a profile you do

genprofile --stdin <<EOF
/profile/name {
@{gen /profile/name}
}
EOF

eg. to generate the equivalent of
  genprofile
you would do
  genprofile --stdin <<EOF
  $test {
  @{gen $test}
  }
EOF

and the equiv of
  genprofile $file:rw
would be
  genprofile --stdin <<EOF
  $test {
  @{gen $test}
  $file rw,
  }


while it takes a little more to generate a base profile than the old syntax, it
use the actual profile language (augmented with the special variables), it is a
lot more flexible, and a lot easier to expand when new rule types are added.

eg. of something not possible with the current auto generation
    Generate a profile with a child profile and hat and a trailing profile

genprofile --stdin <<EOF
$test {
@{gen $test}

  profile $bin/open {
@{gen $bin/open}
  }

  ^hatfoo {
     $file rw,
  }
}
profile $bin/exec {
@{gen $bin/exec}
}
EOF

Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-By: Steve Beattie <sbeattie@ubuntu.com>
This commit is contained in:
John Johansen
2012-04-11 15:55:54 -07:00
parent 852907e1cc
commit 562eb63964

View File

@@ -16,6 +16,7 @@ my $nowarn = '';
my $nodefault;
my $noimage;
my $escape = '';
my $usestdin = '';
my %output_rules;
my $hat = "__no_hat";
my %flags;
@@ -26,19 +27,22 @@ GetOptions(
'help|h' => \$help,
'nodefault|N' => \$nodefault,
'noimage|I' => \$noimage,
'stdin' => \$usestdin,
);
sub usage {
print STDERR "$__VERSION__\n";
print STDERR "Usage $0 [--nowarn|--escape] execname [rules]\n";
print STDERR " $0 --help\n";
print STDERR " $0 --stdin\n";
print STDERR " nowarn: don't warn if execname does not exist\n";
print STDERR " nodefault: don't include default rules/ldd output\n";
print STDERR " escape: escape stuff that would be treated as regexs\n";
print STDERR " help: print this message\n";
}
&usage && exit 0 if ($help || @ARGV < 1);
# genprofile passes in $bin:w as default rule atm
&usage && exit 0 if ($help || (!$usestdin && @ARGV < 1) || ($usestdin && @ARGV != 2));
sub head ($) {
my $file = shift;
@@ -214,34 +218,6 @@ sub gen_addimage($) {
}
}
my $bin = shift @ARGV;
!(-e $bin || $nowarn) && print STDERR "Warning: execname '$bin': no such file or directory\n";
unless ($nodefault) {
gen_default_rules();
gen_binary($bin);
}
for my $rule (@ARGV) {
#($fn, @rules) = split (/:/, $rule);
if ($rule =~ /^(tcp|udp)/) {
# netdomain rules
gen_netdomain($rule);
} elsif ($rule =~ /^network:/) {
gen_network($rule);
} elsif ($rule =~ /^cap:/) {
gen_cap($rule);
} elsif ($rule =~ /^flag:/) {
gen_flag($rule);
} elsif ($rule =~ /^hat:/) {
gen_hat($rule);
} elsif ($rule =~ /^addimage:/) {
gen_addimage($rule);
} else {
gen_file($rule);
}
}
sub emit_flags($) {
my $hat = shift;
@@ -255,26 +231,99 @@ sub emit_flags($) {
}
}
print STDOUT "# Profile autogenerated by $__VERSION__\n";
print STDOUT "$bin ";
emit_flags('__no_hat');
print STDOUT "{\n";
foreach my $outrule (@{$output_rules{'__no_hat'}}) {
print STDOUT $outrule;
}
foreach my $hat (keys %output_rules) {
if (not $hat =~ /^__no_hat$/) {
print STDOUT "\n ^$hat";
emit_flags($hat);
print STDOUT " {\n";
foreach my $outrule (@{$output_rules{$hat}}) {
print STDOUT " $outrule";
# generate profiles based on cmd line arguments
sub gen_from_args() {
my $bin = shift @ARGV;
!(-e $bin || $nowarn) && print STDERR "Warning: execname '$bin': no such file or directory\n";
unless ($nodefault) {
gen_default_rules();
gen_binary($bin);
}
for my $rule (@ARGV) {
#($fn, @rules) = split (/:/, $rule);
if ($rule =~ /^(tcp|udp)/) {
# netdomain rules
gen_netdomain($rule);
} elsif ($rule =~ /^network:/) {
gen_network($rule);
} elsif ($rule =~ /^cap:/) {
gen_cap($rule);
} elsif ($rule =~ /^flag:/) {
gen_flag($rule);
} elsif ($rule =~ /^hat:/) {
gen_hat($rule);
} elsif ($rule =~ /^addimage:/) {
gen_addimage($rule);
} else {
gen_file($rule);
}
}
print STDOUT "# Profile autogenerated by $__VERSION__\n";
print STDOUT "$bin ";
emit_flags('__no_hat');
print STDOUT "{\n";
foreach my $outrule (@{$output_rules{'__no_hat'}}) {
print STDOUT $outrule;
}
foreach my $hat (keys %output_rules) {
if (not $hat =~ /^__no_hat$/) {
print STDOUT "\n ^$hat";
emit_flags($hat);
print STDOUT " {\n";
foreach my $outrule (@{$output_rules{$hat}}) {
print STDOUT " $outrule";
}
print STDOUT " }\n";
}
}
#foreach my $hat keys
#foreach my $outrule (@output_rules) {
# print STDOUT $outrule;
#}
print STDOUT "}\n";
}
#generate the profiles from stdin, interpreting and replacing the following sequences
# @{gen_elf name} - generate rules for elf binaries
# @{gen_bin name} - generate rules for a binary
# @{gen_def} - generate default rules
# @{gen name} - do @{gen_def} @{gen_bin name}
sub emit_and_clear_rules() {
foreach my $outrule (@{$output_rules{'__no_hat'}}) {
print STDOUT $outrule;
}
undef %output_rules;
}
sub gen_from_stdin() {
while(<STDIN>) {
chomp;
if ($_ =~ m/@\{gen_def}/) {
gen_default_rules();
emit_and_clear_rules();
} elsif ($_ =~ m/@\{gen_bin\s+(.+)\}/) {
gen_binary($1);
emit_and_clear_rules();
} elsif ($_ =~ m/@\{gen_elf\s+(.+)\}/) {
gen_elf_binary($1);
emit_and_clear_rules();
} elsif ($_ =~ m/@\{gen\s+(.+)\}/) {
gen_default_rules();
gen_binary($1);
emit_and_clear_rules();
} else {
print STDOUT "$_\n" ;
}
print STDOUT " }\n";
}
}
#foreach my $hat keys
#foreach my $outrule (@output_rules) {
# print STDOUT $outrule;
#}
print STDOUT "}\n";
if ($usestdin) {
gen_from_stdin();
} else {
gen_from_args();
}