App-EvalServerAdvanced

 view release on metacpan or  search on metacpan

lib/App/EvalServerAdvanced/Seccomp.pm  view on Meta::CPAN

}

method build_seccomp() {
  croak "build_seccomp called more than once" if ($self->_finalized);
  $self->_finalized(1);

  for my $profile_key (keys $self->profiles->%*) {
    my $profile_obj = $self->profiles->{$profile_key};

    $self->_used_sets({});
    my @rules = $profile_obj->to_seccomp($self);
    $self->_rendered_profiles->{$profile_key} = \@rules;
  }
}

sub calculate_permutations {
  my ($self) = @_;
  # TODO this is possible to implement with bitwise checks in seccomp, producing fewer rules.  it should be faster, but is more annoying to implement currently

  my %full_permute;

  for my $permute (keys %{$self->_permutes}) {
    my @modes = @{$self->_permutes->{$permute}} = sort {$a <=> $b} uniq @{$self->_permutes->{$permute}};

    # Produce every bitpattern for this permutation
    for my $bit (1..(2**@modes) - 1) {
      my $q = 1;
      my $mode = 0;
      #printf "%04b: ", $b;
      do {
        if ($q & $bit) {
          my $r = int(log($q)/log(2)+0.5); # get the position

          $mode |= $modes[$r];

          #print "$r";
        }
        $q <<= 1;
      } while ($q <= $bit);

      push $full_permute{$permute}->@*, $mode;
    }
  }

  # This originally sorted the values, why? it shouldn't matter.  must have been for easier sanity checking?
  for my $k (keys %full_permute) {
    $full_permute{$k}->@* = uniq $full_permute{$k}->@*
  }

  return \%full_permute;
}

method apply_seccomp($profile_name) {
  # TODO LOAD the rules

  my $seccomp = Linux::Seccomp->new(SCMP_ACT_KILL);

  for my $rule ($self->_rendered_profiles->{$profile_name}->@* ) {
      # TODO make this support raw syscall numbers?
      my $syscall = $rule->{syscall};
      # If it looks like it's not a raw number, try to resolve.
      $syscall = Linux::Seccomp::syscall_resolve_name($syscall) if ($syscall =~ /\D/);
      my @rules = ($rule->{rules}//[])->@*;

      my %actions = (
        ALLOW => SCMP_ACT_ALLOW,
        KILL  => SCMP_ACT_KILL,
        TRAP  => SCMP_ACT_TRAP,
      );

      my $action = $actions{$rule->{action}//""} // SCMP_ACT_ALLOW;

       if ($rule->{action} && $rule->{action} =~ /^\s*ERRNO\((-?\d+)\)\s*$/ ) { # send errno() to the process
         # TODO, support constants? keys from %! maybe? Errno module?
         $action = SCMP_ACT_ERRNO($1 // -1);
       } elsif ($rule->{action} && $rule->{action} =~ /^\s*TRACE\((-?\d+)?\)\s*$/) { # hit ptrace with msgnum
         $action = SCMP_ACT_TRACE($1 // 0);
       }

  #    printf "%s => [%s]\n", $rule->{syscall}, join("", map {sprintf "\n    $_->[0] $_->[1] $_->[2]"} @rules);
      $seccomp->rule_add($action, $syscall, @rules);
  }

  $seccomp->load;
}

method engage($profile_name) {
  $self->build_seccomp();
  $self->apply_seccomp($profile_name);
}

sub load_plugin {
  my ($self, $plugin_name) = @_;

  return $self->_plugins->{$plugin_name} if (exists $self->_plugins->{$plugin_name});

  check_module_name($plugin_name);

  if ($plugin_name !~ /^App::EvalServerAdvanced::Seccomp::Plugin::/) {
    my $plugin;
    if (config->sandbox->plugin_base) { # if we have a plugin base configured, use it first.
      my $plugin_filename = module_notional_filename($plugin_name);
      my $path = path(config->sandbox->plugin_base); # get the only path we'll load short stuff from by it's short name, otherwise deleting a file or a typo could load something we don't want

      my $full_path = $path->child($plugin_filename);

      $plugin = $plugin_name if (eval {require $full_path}); # TODO check if it was a failure to find, or a failure to compile.  failure to compile should still be fatal.
  }

    unless ($plugin) {
      # we couldnt' load it from the plugin base, try from @INC with a fully qualified name
      my $fullname = "App::EvalServerAdvanced::Seccomp::Plugin::$plugin_name";
      $plugin = $fullname if (eval {require_module($fullname)});
      # TODO log errors from module loading
    }

    die "Failed to find plugin $plugin_name" unless $plugin;

    $self->_plugins->{$plugin_name} = $plugin;
    $plugin->init_plugin($self);
    return $plugin;



( run in 1.159 second using v1.01-cache-2.11-cpan-39bf76dae61 )