Commit d81c96c1 authored by Frederic Danis's avatar Frederic Danis

apparmor: Remove dependency on auditd

AppArmor info are accessible through jounalctl.
Replace the aa_log_extract_tokens.pl by shell version, removing
dependencies on auditd and libapparmor-perl packages.

Fixes: APERTIS-6233
Signed-off-by: Frederic Danis's avatarFrédéric Danis <frederic.danis@collabora.com>
parent d7ce92bc
etc/apparmor.d/home.chaiwala.bin
usr/bin/aa_get_complaints.sh
usr/bin/aa_log_extract_tokens.pl
usr/bin/aa_log_extract_tokens.sh
usr/bin/test-daemon
usr/bin/watch-aa
#!/bin/sh
# vim: set sts=4 sw=4 et tw=80 :
#
# This script needs `aa_log_extract_tokens.pl` to be in PATH
#
# This script needs `aa_log_extract_tokens.sh` to be in PATH
#
set -e
......@@ -36,8 +36,8 @@ say "Installing dependencies ..."
sudo apt-get -y --force-yes install apparmor-utils
say "Checking for apparmor complaints ..."
sudo cat /var/log/audit/audit.log | aa_log_extract_tokens.pl \
PERMITTING REJECTING > "${TMPDIR}/complaint_tokens.log"
sudo journalctl -b -t audit -o cat | aa_log_extract_tokens.sh \
PERMIT DENIED > "${TMPDIR}/complaint_tokens.log"
if ! [ -s "${TMPDIR}/complaint_tokens.log" ]; then
say "No complaints found!"
......@@ -48,7 +48,7 @@ say "Complaints found, creating report ..."
# Collate logs
# The "|| true" is because this is all best-effort: we don't want to
# fail to collect info because of "set -e".
sudo cat /var/log/audit/audit.log > "${TMPDIR}/audit.log" || true
sudo journalctl -b -t audit > "${TMPDIR}/audit.log" || true
sudo ps aux > "${TMPDIR}/ps_aux.log" || true
sudo journalctl -b > "${TMPDIR}/journalctl.log" || true
uname -a > "${TMPDIR}/uname.log" || true
......
#!/usr/bin/env perl
# vim: set sts=4 sw=4 et tw=80 :
#
# Copyright (c) 2006 Novell, Inc. All Rights Reserved.
# Copyright (c) 2010 Canonical, Ltd.
# Copyright (c) 2012-2015 Collabora Ltd.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
# License as published by the Free Software Foundation.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, contact Novell, Inc.
#
# To contact Novell about this file by physical or electronic mail,
# you may find current contact information at www.novell.com.
# Example script to extract tokens from apparmor events in audit.log
# We use auditd because otherwise messages are lost if they come too quickly
# http://wiki.apparmor.net/index.php/AppArmorMonitoring#Realtime_information
#
#
# Example complaint event:
# type=AVC msg=audit(1344659645.579:153): apparmor="ALLOWED" operation="open"
# parent=15215 profile="/home/chaiwala/bin/*" name="/etc/group" pid=15216
# comm="ls" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
#
# Example audit event:
# type=AVC msg=audit(1344735566.384:827): apparmor="AUDIT" operation="getattr"
# parent=16769 profile="/home/chaiwala/bin/*" name="/etc/localtime" pid=16770
# comm="ls" requested_mask="r" fsuid=1000 ouid=0
#
use strict;
use warnings;
use LibAppArmor qw();
use constant DEBUG => $ENV{AA_LOG_DEBUG};
my $event;
my $record;
my $value;
my $profile_wanted;
my @event_modes;
my @skip_names;
my %records_order;
sub usage {
print("Usage: $0 <event mode> [event mode]...\n");
print("And pipe logs to it\n");
print("Valid values for [event mode] are: PERMITTING, REJECTING, AUDITING\n");
}
# Ensure there are some arguments
if ($#ARGV < 0) {
usage();
exit(1);
}
# Ensure that the arguments are all valid
foreach (@ARGV) {
SWITCH: {
if (/PERMITTING/) { last SWITCH; }
if (/REJECTING/) { last SWITCH; }
if (/AUDITING/) { last SWITCH; }
usage();
exit(1);
}
}
# Valid values we'll use: PERMITTING, REJECTING, AUDITING
# Valid values that we're not interested in: STATUS, ERROR, UNKNOWN, HINT
# PERMITTING is emitted when:
# * AppArmor is in "normal" audit mode[1]
# * A profile loaded in complain mode matches something
# REJECTING is emitted when:
# * AppArmor is in "normal" audit mode[1]
# * A profile loaded in enforce mode matches something
# AUDITING is emitted when:
# * AppArmor is in "all" audit mode[1]
#
# 1. http://wiki.apparmor.net/index.php/AppArmor_Failures#Module_audit_settings
@event_modes = @ARGV;
# We're being lazy and getting arguments from the environment instead of doing
# getopt parsing
$profile_wanted = $ENV{'AA_PROFILE_WANTED'};
# Regex of file paths to skip accesses to
@skip_names=(
"/etc/ld\.so\.cache",
"/lib/i386-linux-gnu/libc.*\.so",
"/dev/pts/.*",
"/dev/(null|zero|random|urandom)",
);
# Arbitrary order, but we want to keep it constant.
# chaiwala-apparmor-tests rely on the following order.
%records_order = (
'profile' => 1,
'sdmode' => 2,
'denied_mask' => 3,
'operation' => 4,
'name' => 5,
'request_mask' => 6,
);
sub records_sort {
if (exists $records_order{$a} && exists $records_order{$b})
{
return ($records_order{$a}) <=> ($records_order{$b});
}
if (! exists $records_order{$a} && !exists $records_order{$b})
{
return $a cmp $b;
}
return exists $records_order{$a} ? -1 : 1;
}
# Simplified from Immunix::AppArmor.
sub stringify_sdmode {
my $sdmode = shift;
return 'ERROR' if $sdmode == 1;
return 'AUDITING' if $sdmode == 2;
return 'PERMITTING' if $sdmode == 3;
return 'REJECTING' if $sdmode == 4;
return 'HINT' if $sdmode == 5;
return 'STATUS' if $sdmode == 6;
# no idea - output *something*
return $sdmode;
}
# Simplified from Immunix::AppArmor. We're not using its parse_event
# because that only works properly for events whose mask is something
# like r or w, not for events whose mask is more like receive or send;
# this version is more "raw", and hopefully a little more robust against
# AA changes.
sub parse_event {
my %ev = ();
my $msg = shift;
chomp($msg);
my $event = LibAppArmor::parse_record($msg);
$ev{resource} = LibAppArmor::aa_log_record::swig_info_get($event);
$ev{active_hat} = LibAppArmor::aa_log_record::swig_active_hat_get($event);
$ev{sdmode} = LibAppArmor::aa_log_record::swig_event_get($event);
$ev{time} = LibAppArmor::aa_log_record::swig_epoch_get($event);
$ev{operation} = LibAppArmor::aa_log_record::swig_operation_get($event);
$ev{profile} = LibAppArmor::aa_log_record::swig_profile_get($event);
$ev{name} = LibAppArmor::aa_log_record::swig_name_get($event);
$ev{name2} = LibAppArmor::aa_log_record::swig_name2_get($event);
$ev{attr} = LibAppArmor::aa_log_record::swig_attribute_get($event);
$ev{parent} = LibAppArmor::aa_log_record::swig_parent_get($event);
$ev{pid} = LibAppArmor::aa_log_record::swig_pid_get($event);
$ev{task} = LibAppArmor::aa_log_record::swig_task_get($event);
$ev{info} = LibAppArmor::aa_log_record::swig_info_get($event);
$ev{denied_mask} = LibAppArmor::aa_log_record::swig_denied_mask_get($event);
$ev{request_mask} = LibAppArmor::aa_log_record::swig_requested_mask_get($event);
$ev{magic_token} = LibAppArmor::aa_log_record::swig_magic_token_get($event);
$ev{family} = LibAppArmor::aa_log_record::swig_net_family_get($event);
$ev{protocol} = LibAppArmor::aa_log_record::swig_net_protocol_get($event);
$ev{sock_type} = LibAppArmor::aa_log_record::swig_net_sock_type_get($event);
LibAppArmor::free_record($event);
if (! $ev{sdmode}) {
return undef;
}
$ev{sdmode} = stringify_sdmode($ev{sdmode});
if (DEBUG) {
print STDERR "/----\n";
foreach my $k (sort keys %ev) {
if (defined $ev{$k}) {
print STDERR "\t", $k, "\t", $ev{$k}, "\n";
}
}
print STDERR "\\----\n";
}
return \%ev;
}
EVENT: while (<STDIN>) {
# This doesn't give us all the tokens, unfortunately.
# Only gives us: profile, sdmode, time, denied_mask, pid, operation,
# parent (parent pid), name (filename), request_mask
# (FIXME: it could now give more if we want them)
$event = parse_event($_);
if (!$event ||
!(grep { $_ eq $$event{'sdmode'} } @event_modes) ||
($profile_wanted && ($$event{'profile'} ne $profile_wanted)))
{
next EVENT;
}
foreach (@skip_names) {
if (defined $$event{'name'} && $$event{'name'} =~ /$_/) {
next EVENT;
}
}
print "====\n";
# This is pretty much it. Go forth and use this hash in whatever way.
foreach $record (sort records_sort keys %$event) {
$value = $$event{$record};
next unless $value;
# Skip records that keep changing with every invocation
SWITCH: {
if ($record eq "time") { last SWITCH; }
if ($record eq "pid") { last SWITCH; }
if ($record eq "parent") { last SWITCH; }
print "$record:$value\n";
}
}
}
#!/bin/sh
# vim: set sts=4 sw=4 et tw=80 :
usage() {
echo "Usage: $0 <event mode> [event mode]..."
echo "And pipe logs to it"
echo "Valid values for [event mode] are: PERMIT, DENIED, AUDIT"
}
events=""
while [ $# -gt 0 ] ; do
case $1 in
AUDIT|PERMIT|DENIED)
events="$events $1"
;;
*)
echo Unknow parameter $1
echo
usage
exit 1
;;
esac
shift
done
# Pass in audit string, returns formatted block pretty similat as
# `aa_log_extract_tokens.pl` would have provided. Need to return:
#
# profile:/usr/bin/ribchester
# apparmor:AUDIT
# operation:exec
# name:/bin/cp
# requested_mask:x
# info:ix fallback
# target:/usr/bin/ribchester
#
# profile:/usr/bin/busctl
# apparmor:DENIED
# denied_mask:r
# operation:open
# name:/proc/879/stat
# requested_mask:r
#
# Note: apparmor uses the term "DENIED" rather than "REJECTING"
awk -v events="$events" '
BEGIN {
# Get requested event modes
split(events, event_modes, " ")
# List of entries to return
split("profile apparmor denied_mask operation name requested_mask info target ", entries, " ")
}
{
# Parse log entry
for (i = 1; i <= NF; i++) {
n = index($i, "=");
if(n) {
key = substr($i, 1, n - 1)
value = substr($i, n + 1)
# awk split stdin on space, recreate quoted strings
if (match(value, "^\".*") && !match(value, "^\".*\"")) {
i++
while (!match($i, ".*\"")) {
value = value " " $i
i++
}
value = value " " $i
}
# Strip quotes
gsub("\"","",value)
vars[key] = value
}
}
}
{
for (x in event_modes) {
if (vars["apparmor"] == event_modes[x]) {
print "===="
for (key in entries) {
if (entries[key] in vars)
print entries[key] ":" vars[entries[key]]
}
}
}
delete vars
}
'
#!/bin/sh
exec /usr/bin/tail -n 0 -f /var/log/audit/audit.log | /usr/bin/aa_log_extract_tokens.pl PERMITTING REJECTING
exec sudo journalctl -b -t audit -o cat -f | /usr/bin/aa_log_extract_tokens.sh PERMIT DENIED
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment