Hello, While diagnosing avc messages, I found the log message too spread-out to form a mental picture, since the lack of some rules often result in several domain domains barking. This reminds me of unforgiving Ada compilers spilling out loads of messages. I did not want to use audit2allow too quickly until I understood what the machine is not happy with. So, I needed a message format that let me to that. Here is a simple perl script to parse log files for avc denial messages, index, sort them, and print them in tree (single depth) view, which I hastily put together last night. I hope it will help others as it did for me. Please feel free to modify it for your own use. You can index the message by any key, for example scontext, tcontext, action, name and etc. You can also specify the log files to parse. By default, the script trim the context string of the _u, _r and _t, which are good for rule readability in source files, but clutter diagnostic print out. However, if this bothers you, disable trimming by --trim=no option. To get help and condition of usage, avctree --help. It is best to pipe the output to less so that you can navigate. A typical partial print out is as follows (this one indexed by tcontext): # --------------------------------------------------------------------------------[tcontext] | +-[root-object-default ] | +<- system-system-initrc_su su(1753) : dir : search : home : dm-0 : 49182 | +-[root-object-selinux_config] | +<- root-system-semanage semodule(3584) : dir : rename : active : sdb1 : 49833 | +-[root-object-user_home ] | +<- root-system-semanage semodule(10359) : lnk_file : read : targeted : sdb1 : 98758 | +<- root-system-semanage semodule(11006) : lnk_file : read : policy : sdb1 : 98764 | +<- root-system-semanage semodule(3584) : lnk_file : read : targeted : sdb1 : 98758 | +-[system-object-default ] | +<- system-system-initrc_su su(1753) : dir : search : / : dm-0 : 2 | +<- system-system-hald hald(1958) : dir : getattr : / : dm-0 : 2 | No PP module for this script yet. This script use basic Perl features, so, as along you have base Perl package installed, it should work. Be happy to hear any comments or suggestion for improving this. /ks #------------------------------------------- cut here ----------------------------------------- #!/usr/bin/perl -w sub lmsg { print <<LMSG;; # Copyright (C) 2007, LEE, "Kok Seng" (kokseng at ieee dot org) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # 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, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # LMSG } my $version='1.0.0'; use strict; use warnings; my $thisScript = $0; $thisScript =~ s#([^/]+[/]|)(\w+)#$2#; # ---------------------------------------------------------------------------------------------- use Getopt::Long; sub usage { lmsg; print "Usage:\n"; print <<USAGETXT; Utility to format avc messages for readability -------------------------------------------------------------------------------------------- $thisScript [[options] ...] Options: --log=[ all | file,...] : List log files to parse, delimited by comma. no argument or all => /var/log/messages, /var/log/kernel --tags : Show time and audit tags --key=key,... : List messages indexed-sorted by specified key no argument or all => all keys Not specified => scontext,tcontext,action,comm,name --trim=yes|no|1|0 : Trim context string. Default: yes --help -------------------------------------------------------------------------------------------- Examples: a. $thisScript --key=scontext Print avc messages indexed-sorted by source context. b. $thisScript --key=tcontext Print avc messages indexed-sorted by target context. c. $thisScript --key=comm Print avc messages indexed-sorted by command executed. d. $thisScript --key=name Print avc messages indexed-sorted by target object's name. e. $thisScript --key=all or $thisScript --key Print avc messages indexed-sorted by all keys. f. $thisScript Print avc messages indexed-sorted by scontext, tcontext, comm, name (default) g. $thisScript --trim=no Print avc messages without trimming context string. h. $thisScript --log=/var/log/messages,/var/log/messages.1,/var/log/messages.2 Print avc messages from log files listed (delimited by comma). i. $thisScript --tags Print avc messages, including in each message the log time tag and audit tag. USAGETXT exit -1; } # my $logARG; # Log files to parse my $tagsARG; # Show time and audit tags my $catARG; # Categories to print my $helpARG; # Help my $trimARG; # Trim context string for readability usage(), exit unless GetOptions( 'log:s' => \$logARG, 'tags!' => \$tagsARG, 'key:s' => \$catARG, 'trim:s' => \$trimARG, 'help!' => \$helpARG ); usage() if (defined($helpARG)); ## ---------------------------------------------------------------------------------------------- ## Option: skip tags my $skiptags = defined($tagsARG)?0:1; ## Option: log files my @logOPT = grep -d $_, split /,|\n|\r/, $logARG if (defined($logARG)); @logOPT = ('/var/log/messages','/var/log/kernel','/var/log/debug') if (defined($logARG) && ((!scalar @logOPT) || grep /all/, @logOPT)); @logOPT = ('/var/log/kernel') if (!scalar @logOPT && -d '/var/log/kernel'); @logOPT = ('/var/log/messages') if (!scalar @logOPT); ## Option: Category my @catOPT = split /,|\n|\r/, $catARG if (defined($catARG)); my @catDEF = ('scontext','tcontext','comm','name'); ## Option: Trim my $trimOPT = defined($trimARG) ? ($trimARG =~ /no|0|/i ? 0 : 1 ) : 1; ## ---------------------------------------------------------------------------------------------- # ## Regular _expression_ for parsing avc's 'denied' messages my $avcRE = qr/^(\w{3}\s+\d{2}\s+\d{2}:\d{2}:\d{2})[\s\w]+:\s*audit\(([\d.:]+)\)\s*:\s*avc\s*:\s*denied\s+\{\s+(\w+)\s+}\s+for\s+(.*)/; ## Holds indexed avc message records my %avc; ## ---------------------------------------------------------------------------------------------- ## contextFMT # Format context string for readability sub contextFMT { my $ctxt = shift; my ($u,$r,$t,$l) = split /:/, $ctxt; $u =~ s/(.*)_./$1/; $r =~ s/(.*)_./$1/; $t =~ s/(.*)_./$1/; return $u . '-' . $r . '-' . $t; } ## ---------------------------------------------------------------------------------------------- ## readLOG log-file-name # Reads the specified log file sub readLOG { my $avc = shift; my $logfile = shift; my $logsn = ($logfile =~ /.*\/(.*)$/)[0]; my $tmax = defined($avc->{'_tcontext_max_'})?$avc->{'_tcontext_max_'}:0; my $smax = defined($avc->{'_scontext_max_'})?$avc->{'_scontext_max_'}:0; open LOGF, '<' . $logfile || die "Cannot open input file: $logfile"; while (<LOGF>) { s/\r|\n//g; next if (!$_); next if (!/\s+avc:\s+/); my ($timetag, $audit, $action, $detail) = ($_ =~ /$avcRE/); next if (!defined($action)||!defined($detail)||!defined($timetag)||!defined($audit)); # okay, we have a avc 'denied' message my %this; # this hash will keep the message's key=value my @fields = split /\s|\r|\n/, $detail; foreach (@fields) { next if (!$_); my ($key,$val) = split/=/; next if (!$key||!$val); $val =~ s/[\"\']*([^\"\']*)[\"\']*/$1/; $this{"$key"} = $val; } next if (!defined($this{'scontext'}) || !defined($this{'tcontext'})); $this{'action'} = $action; $this{'timetag'} = $timetag; $this{'audit'} = $audit; $this{'file'}= $logsn; if ($trimOPT) { $this{'scontext'} = contextFMT($this{'scontext'}); $this{'tcontext'} = contextFMT($this{'tcontext'}); } $smax = length($this{'scontext'}) if ($smax < length($this{'scontext'})); $tmax = length($this{'tcontext'}) if ($tmax < length($this{'tcontext'})); # Okay, let's index the records with various keys foreach (keys %this) { next if (/audit|timetag|file/); $avc->{$_} = {} if (!defined($avc->{$_})); $avc->{$_}->{$this{$_}} = [()] if (!defined($avc->{$_}->{$this{$_}})); push @{$avc->{$_}->{$this{$_}}}, \%this; } } close LOGF; $avc->{'_scontext_max_'} = $smax; $avc->{'_tcontext_max_'} = $tmax; } ## ---------------------------------------------------------------------------------------------- ## # keyTREE key # Show selected key in a tree view sub keyTREE { my $avc = shift; my $kcat = shift; my $showfile = shift; my $hcat = $avc->{$kcat}; my $lvl = 1; my $isSctx = ($kcat =~ /scontext/); my $isTctx = ($kcat =~ /tcontext/); my $smax = $isSctx ? 0 : $avc->{'_scontext_max_'}; my $tmax = $isTctx ? 0 : $avc->{'_tcontext_max_'}; return if (/_scontext_max_|_tcontext_max_/); print "\n# "; for ($_=0; $_ < 80; $_++) {print "-";} print "[", $kcat, "]\n"; foreach my $kmsg (sort keys %$hcat) { printf "|\n+-[%-*s]\n", $smax, $hcat->{$kmsg}[0]->{$kcat}; $lvl++; my $buf; my $i; my $cnt = scalar @{$hcat->{$kmsg}}; foreach my $hmsg (@{$hcat->{$kmsg}}) { $buf .= sprintf "%s %-*s %s %-*s %s%s(%s) : %s : %s %s%s%s\n", $isTctx? '+<-' : '+->', $smax, $isSctx?'':$hmsg->{'scontext'}, $isTctx||$isSctx ? '' : '-+->', $tmax, $isTctx?'':$hmsg->{'tcontext'}, defined($showfile)? $hmsg->{'file'}.'> ':'', $hmsg->{'comm'}, $hmsg->{'pid'}, $hmsg->{'tclass'}, $hmsg->{'action'}, defined($hmsg->{'name'})?': '.$hmsg->{'name'}:'', defined($hmsg->{'key'})?' : '.$hmsg->{'key'}:'', defined($hmsg->{'dev'})?' : '.$hmsg->{'dev'} . (defined($hmsg->{'ino'})?' : '.$hmsg->{'ino'}:'') : '' ; $i = $lvl; $buf = '| ' . $buf while (--$i); print $buf; $buf = ""; foreach my $kmsg (sort keys %$hmsg) { next if ($kmsg =~ /file|scontext|tcontext|comm|pid|tclass|action|name|dev|ino|key|$kcat/); next if ($skiptags && $kmsg =~ /timetag|audit/); $buf .= sprintf "%s=%s ", $kmsg, $hmsg->{$kmsg}; } if ($buf) { $buf = sprintf "%*s%s\n", ($cnt==1)?$smax+$tmax+10+2:$smax+$tmax+10, ,"", $buf; $i = (--$cnt)? $lvl:$lvl-1; $buf = '| ' . $buf while ($i--); print $buf; $buf = ""; } } $lvl--; } $lvl--; } ## ---------------------------------------------------------------------------------------------- # Parse log files readLOG(\%avc, $_) foreach (@logOPT); # Decide which category to print @catOPT = (sort keys %avc) if (defined($catARG) && (! scalar @catOPT) || grep /all/,@catOPT ) ; @catOPT = @catDEF if (!defined($catARG)); print "\n> Copyright (C) 2007, LEE, \"Kok Seng\" (kokseng at ieee dot org)"; print "\n> Notice: get help and condition of usage inforamtion regarding this script: $thisScript --help\n"; keyTREE(\%avc, $_,scalar @logOPT > 1?1:undef) foreach (@catOPT); ## ---------------------------------------------------------------------------------------------- # vim :ts=4:sw=4: 1; |
-- fedora-selinux-list mailing list fedora-selinux-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/fedora-selinux-list