101
101
my $date_module = "None";
103
103
my %templates = (
104
"path" => "(time,counter,type,profile,sdmode,mode,resource,prog,pid,severity) VALUES(?,?,'path',?,?,?,?,?,?,?)",
105
"link" => "(time,counter,type,profile,sdmode,resource,target,prog,pid,severity) VALUES(?,?,'link',?,?,?,?,?,?,?)",
106
"chattr" => "(time,counter,type,profile,sdmode,resource,mode,prog,pid,severity) VALUES(?,?,'chattr',?,?,?,?,?,?,?)",
107
"capability" => "(time,counter,type,profile,sdmode,resource,prog,pid,severity) VALUES(?,?,'capability',?,?,?,?,?,?)",
108
"unknown_hat" => "(time,counter,type,profile,sdmode,resource,pid) VALUES(?,?,'unknown_hat',?,?,?,?)",
109
"fork" => "(time,counter,type,profile,sdmode,pid,resource) VALUES(?,?,'fork',?,?,?,?)",
110
"changing_profile" => "(time,counter,type,profile,sdmode,pid) VALUES(?,?,'changing_profile',?,?,?)",
111
"profile_replacement" => "(time,counter,type,profile,sdmode,prog,pid,severity) VALUES(?,?,'profile_replacement',?,?,?,?,?)",
112
"removed" => "(time,counter,type,severity) VALUES(?,?,'removed',?)",
113
"initialized" => "(time,counter,type,resource,severity) VALUES(?,?,'initialized',?,?)",
114
"ctrl_var" => "(time,counter,type,resource,mode,severity) VALUES(?,?,'ctrl_var',?,?,?)",
104
"path" => "(time,counter,type,op,profile,sdmode,mode_req,mode_deny,resource,prog,pid,severity) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)",
105
"link" => "(time,counter,type,op,profile,sdmode,resource,target,prog,pid,severity) VALUES(?,?,?,?,?,?,?,?,?,?,?)",
106
"chattr" => "(time,counter,type,op,profile,sdmode,resource,mode_req,mode_deny,prog,pid,severity) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)",
107
"capability" => "(time,counter,type,op,profile,sdmode,resource,prog,pid,severity) VALUES(?,?,?,?,?,?,?,?,?,?)",
108
"capable" => "(time,counter,type,op,prog,pid,profile) VALUES(?,?,?,?,?,?,?)",
109
"unknown_hat" => "(time,counter,type,op,profile,sdmode,resource,pid) VALUES(?,?,?,?,?,?,?,?)",
110
"fork" => "(time,counter,type,op,profile,sdmode,pid,resource) VALUES(?,?,?,?,?,?,?,?)",
111
"changing_profile" => "(time,counter,type,op,profile,sdmode,pid) VALUES(?,?,?,?,?,?,?)",
112
"profile_replacement" => "(time,counter,type,op,profile,sdmode,prog,pid,severity) VALUES(?,?,?,?,?,?,?,?,?)",
113
"net" => "(time,counter,type,op,net_family,net_socktype,net_proto,pid,profile) VALUES(?,?,?,?,?,?,?,?,?)",
114
"removed" => "(time,counter,type,op,severity) VALUES(?,?,?,?,?)",
115
"initialized" => "(time,counter,type,op,resource,severity) VALUES(?,?,?,?,?,?)",
116
"ctrl_var" => "(time,counter,type,op,resource,mode_req,mode_deny,severity) VALUES(?,?,?,?,?,?,?,?)",
117
"profile_load" => "(time,counter,type,op,resource,prog,pid) VALUES(?,?,?,?,?,?,?)",
117
120
##########################################################################
403
413
##########################################################################
414
# Parse event record into key-value pairs
421
my $event = LibAppArmor::parse_record($msg);
423
# resource is an alternate term for 'name1' below
424
# mode is an alternate term for 'mode_deny' below
425
$ev{'time'} = LibAppArmor::aa_log_record::swig_epoch_get($event);
426
$ev{'op'} = LibAppArmor::aa_log_record::swig_operation_get($event);
427
$ev{'pid'} = LibAppArmor::aa_log_record::swig_pid_get($event);
428
$ev{'mode_deny'} = LibAppArmor::aa_log_record::swig_denied_mask_get($event);
429
$ev{'mode_req'} = LibAppArmor::aa_log_record::swig_requested_mask_get($event);
430
$ev{'profile'}= LibAppArmor::aa_log_record::swig_profile_get($event);
431
$ev{'prog'} = LibAppArmor::aa_log_record::swig_name_get($event);
432
$ev{'name2'} = LibAppArmor::aa_log_record::swig_name2_get($event);
433
$ev{'attr'} = LibAppArmor::aa_log_record::swig_attribute_get($event);
434
$ev{'parent'} = LibAppArmor::aa_log_record::swig_parent_get($event);
435
$ev{'magic_token'} = LibAppArmor::aa_log_record::swig_magic_token_get($event);
436
$ev{'resource'} = LibAppArmor::aa_log_record::swig_info_get($event);
437
$ev{'active_hat'} = LibAppArmor::aa_log_record::swig_active_hat_get($event);
438
$ev{'sdmode'} = LibAppArmor::aa_log_record::swig_event_get($event);
441
if ( $ev{'op'} && $ev{'op'} =~ /socket/ ) {
442
next if $ev{'op'} =~ /create/;
443
$ev{'net_family'} = LibAppArmor::aa_log_record::swig_net_family_get($event);
444
$ev{'net_proto'} = LibAppArmor::aa_log_record::swig_net_protocol_get($event);
445
$ev{'net_socktype'} = LibAppArmor::aa_log_record::swig_net_sock_type_get($event);
448
LibAppArmor::free_record($event);
450
if ( ! $ev{'time'} ) { $ev{'time'} = time; }
452
# remove null responses
454
if ( ! $ev{$_} || $ev{$_} !~ /\w+/) {delete($ev{$_}); }
455
#errlog "EVENT: $_ is $ev{$_}";
458
if ( $ev{'sdmode'} ) {
459
#0 = invalid, 1 = error, 2 = AUDIT, 3 = ALLOW/PERMIT,
460
#4 = DENIED/REJECTED, 5 = HINT, 6 = STATUS/config change
461
if ( $ev{'sdmode'} == 2 ) { $ev{'sdmode'} = "AUDITING"; }
462
elsif ( $ev{'sdmode'} == 3 ) { $ev{'sdmode'} = "PERMITING"; }
463
elsif ( $ev{'sdmode'} == 4 ) { $ev{'sdmode'} = "REJECTING"; }
464
else { delete($ev{'sdmode'}); }
405
470
sub process_event ($$) {
407
473
my $logmsg = shift;
411
if ($logmsg =~ /^(?:type=(?:APPARMOR|UNKNOWN\[1500\]) msg=|$REdate\s+\S+\s+(?:kernel:\s+)*)audit\((\d+).\d+:\d+\): (.+)$/) {
412
($time, $mesg) = ($1, $2);
414
# have we rolled over to another second yet?
415
if ($time ne $lasttime) {
420
} elsif ($logmsg =~ /^\s*($REdate)\s+\S+\s+(?:kernel:\s+)*(SubDomain|AppArmor):\s+(.+)$/) {
421
($time, $mesg) = ($1, $3);
423
# have we rolled over to another second yet?
424
if ($time ne $lasttime) {
426
$timestamp = parsedate($time);
431
# not one of ours, just return
480
return unless $logmsg && $logmsg =~ /APPARMOR/;
481
my $ev = parseEvent($logmsg);
484
if ( ! $ev->{'op'} || $ev->{'op'} eq 'clone') { return; }
486
$time = time; # XXX - do we want current time or $ev->{'time'}?
488
if ($time ne $lasttime) {
449
508
$last_inserted_time = undef;
452
# workaround for syslog uglyness.
453
if ($mesg =~ s/(PERMITTING|REJECTING|AUDITING)-SYSLOGFIX/$1/) {
457
if ($mesg =~ /(PERMITTING|REJECTING|AUDITING) (\S+) access to (.+?) \((\S+)\((\d+)\) profile (\S+) active (\S+)\)/) {
458
my ($sdmode, $mode, $resource, $prog, $pid, $profile, $hat) = ($1, $2, $3, $4, $5, $6, $7);
460
$profile .= "^$hat" if $profile ne $hat;
463
if ($sdmode eq "REJECTING") {
464
$severity = $sevdb->rank($resource, $mode);
466
# we only do notification for enforce mode events
467
if ($config->{verbose_freq}) {
468
if ( ($severity >= $config->{verbose_level})
469
|| (($severity == -1) && $config->{verbose_unknown}))
471
push @verbose_buffer, [ $timestamp, $counter, $logmsg ];
475
if ($config->{summary_freq}) {
476
if ( ($severity >= $config->{summary_level})
477
|| (($severity == -1) && $config->{summary_unknown}))
479
push @summary_buffer, [ $timestamp, $counter, "path", $prog, $mode, $resource ];
483
if ($config->{terse_freq}) {
484
if ( ($severity >= $config->{terse_level})
485
|| (($severity == -1) && $config->{terse_unknown}))
487
push @terse_buffer, [ $timestamp, $counter, "dummy" ];
493
push @commit_buffer, [ "path", $timestamp, $counter, $profile, $sdmode, $mode, $resource, $prog, $pid, $severity ];
496
} elsif ($mesg =~ /(PERMITTING|REJECTING|AUDITING) link access from (.+?) to (.+?) \((\S+)\((\d+)\) profile (\S+) active (\S+)\)/) {
497
my ($sdmode, $link, $target, $prog, $pid, $profile, $hat) = ($1, $2, $3, $4, $5, $6, $7);
499
$profile .= "^$hat" if $profile ne $hat;
502
if ($sdmode eq "REJECTING") {
503
$severity = $sevdb->rank($target, "l");
505
# we only do notification for enforce mode events
506
if ($config->{verbose_freq}) {
507
if ( ($severity >= $config->{verbose_level})
508
|| (($severity == -1) && $config->{verbose_unknown}))
510
push @verbose_buffer, [ $timestamp, $counter, $logmsg ];
514
if ($config->{summary_freq}) {
515
if ( ($severity >= $config->{summary_level})
516
|| (($severity == -1) && $config->{summary_unknown}))
518
push @summary_buffer, [ $timestamp, $counter, "link", $prog, $link, $target ];
522
if ($config->{terse_freq}) {
523
if ( ($severity >= $config->{terse_level})
524
|| (($severity == -1) && $config->{terse_unknown}))
526
push @terse_buffer, [ $timestamp, $counter ];
531
push @commit_buffer, [ "link", $timestamp, $counter, $profile, $sdmode, $link, $target, $prog, $pid, $severity ];
534
} elsif ($mesg =~ /(PERMITTING|REJECTING|AUDITING) attribute \((\S*)\) change to (.+)? \((\S+)\((\d+)\) profile (\S+) active (\S+)\)/) {
535
my ($sdmode, $attrch, $resource, $prog, $pid, $profile, $hat) = ($1, $2, $3, $4, $5, $6, $7);
537
$profile .= "^$hat" if $profile ne $hat;
540
if ($sdmode eq "REJECTING") {
541
$severity = $sevdb->rank($resource, "w");
543
# we only do notification for enforce mode events
544
if ($config->{verbose_freq}) {
545
if ( ($severity >= $config->{verbose_level})
546
|| (($severity == -1) && $config->{verbose_unknown}))
548
push @verbose_buffer, [ $timestamp, $counter, $logmsg ];
552
if ($config->{summary_freq}) {
553
if ( ($severity >= $config->{summary_level})
554
|| (($severity == -1) && $config->{summary_unknown}))
556
push @summary_buffer, [ $timestamp, $counter, "attrch", $prog, $resource, $attrch ];
560
if ($config->{terse_freq}) {
561
if ( ($severity >= $config->{terse_level})
562
|| (($severity == -1) && $config->{terse_unknown}))
564
push @terse_buffer, [ $timestamp, $counter ];
569
push @commit_buffer, [ "chattr", $timestamp, $counter, $profile, $sdmode, $resource, $attrch, $prog, $pid, $severity ];
572
} elsif (m/(PERMITTING|REJECTING) (?:mk|rm)dir on (.+) \((\S+)\((\d+)\) profile (\S+) active (\S+)\)/) {
573
my ($sdmode, $resource, $prog, $pid, $profile, $hat) = ($1, $2, $3, $4, $5, $6);
575
$profile .= "^$hat" if $profile ne $hat;
580
if ($sdmode eq "REJECTING") {
581
$severity = $sevdb->rank($resource, $mode);
583
# we only do notification for enforce mode events
584
if ($config->{verbose_freq}) {
585
if ( ($severity >= $config->{verbose_level})
586
|| (($severity == -1) && $config->{verbose_unknown}))
588
push @verbose_buffer, [ $timestamp, $counter, $logmsg ];
592
if ($config->{summary_freq}) {
593
if ( ($severity >= $config->{summary_level})
594
|| (($severity == -1) && $config->{summary_unknown}))
596
push @summary_buffer, [ $timestamp, $counter, "path", $prog, $mode, $resource ];
600
if ($config->{terse_freq}) {
601
if ( ($severity >= $config->{terse_level})
602
|| (($severity == -1) && $config->{terse_unknown}))
604
push @terse_buffer, [ $timestamp, $counter, "dummy" ];
610
push @commit_buffer, [ "path", $timestamp, $counter, $profile, $sdmode, $mode, $resource, $prog, $pid, $severity ];
612
} elsif (/(PERMITTING|REJECTING) xattr (\S+) on (.+) \((\S+)\((\d+)\) profile (\S+) active (\S+)\)/) {
613
my ($sdmode, $xattr_op, $resource, $prog, $pid, $profile, $hat) = ($1, $2, $3, $4, $5, $6, $7);
615
$profile .= "^$hat" if $profile ne $hat;
618
if ($xattr_op eq "get" || $xattr_op eq "list") {
620
} elsif ($xattr_op eq "set" || $xattr_op eq "remove") {
625
if ($sdmode eq "REJECTING") {
626
$severity = $sevdb->rank($resource, $mode);
628
# we only do notification for enforce mode events
629
if ($config->{verbose_freq}) {
630
if ( ($severity >= $config->{verbose_level})
631
|| (($severity == -1) && $config->{verbose_unknown}))
633
push @verbose_buffer, [ $timestamp, $counter, $logmsg ];
637
if ($config->{summary_freq}) {
638
if ( ($severity >= $config->{summary_level})
639
|| (($severity == -1) && $config->{summary_unknown}))
641
push @summary_buffer, [ $timestamp, $counter, "path", $prog, $mode, $resource ];
645
if ($config->{terse_freq}) {
646
if ( ($severity >= $config->{terse_level})
647
|| (($severity == -1) && $config->{terse_unknown}))
649
push @terse_buffer, [ $timestamp, $counter, "dummy" ];
655
push @commit_buffer, [ "path", $timestamp, $counter, $profile, $sdmode, $mode, $resource, $prog, $pid, $severity ];
658
} elsif ($mesg =~ /(PERMITTING|REJECTING|AUDITING) access to capability '(.+?)' \((\S+)\((\d+)\) profile (\S+) active (\S+)\)/) {
659
my ($sdmode, $capability, $prog, $pid, $profile, $hat) = ($1, $2, $3, $4, $5, $6, $7);
661
$profile .= "^$hat" if $profile ne $hat;
664
if ($sdmode eq "REJECTING") {
665
$severity = $sevdb->rank(uc("cap_$capability"));
667
# we only do notification for enforce mode events
668
if ($config->{verbose_freq}) {
669
if ( ($severity >= $config->{verbose_level})
670
|| (($severity == -1) && $config->{verbose_unknown}))
672
push @verbose_buffer, [ $timestamp, $counter, $logmsg ];
676
if ($config->{summary_freq}) {
677
if ( ($severity >= $config->{summary_level})
678
|| (($severity == -1) && $config->{summary_unknown}))
680
push @summary_buffer, [ $timestamp, $counter, "capability", $prog, $capability ];
684
if ($config->{terse_freq}) {
685
if ( ($severity >= $config->{terse_level})
686
|| (($severity == -1) && $config->{terse_unknown}))
688
push @terse_buffer, [ $timestamp, $counter ];
693
push @commit_buffer, [ "capability", $timestamp, $counter, $profile, $sdmode, $capability, $prog, $pid, $severity ];
696
} elsif ($mesg =~ /LOGPROF-HINT unknown_hat (\S+) pid=(\d+) profile=(\S+) active=(\S+)/) {
697
my ($uhat, $pid, $profile, $hat) = ($1, $2, $3, $4);
699
$profile .= "^$hat" if $profile ne $hat;
701
push @commit_buffer, [ "unknown_hat", $timestamp, $counter, $profile, "PERMITTING", $uhat, $pid ];
704
} elsif ($mesg =~ /LOGPROF-HINT fork pid=(\d+) child=(\d+) profile=(\S+) active=(\S+)/) {
705
my ($pid, $child, $profile, $hat) = ($1, $2, $3, $4);
707
$profile .= "^$hat" if $profile ne $hat;
709
push @commit_buffer, [ "fork", $timestamp, $counter, $profile, "PERMITTING", $pid, $child ];
712
} elsif ($mesg =~ /LOGPROF-HINT changing_profile pid=(\d+) newprofile=(\S+)/) {
713
my ($pid, $newprofile) = ($1, $2);
715
push @commit_buffer, [ "changing_profile", $timestamp, $counter, $newprofile, "PERMITTING", $pid ];
718
} elsif ($mesg =~ /LOGPROF-HINT fork pid=(\d+) child=(\d+)/) {
719
my ($pid, $child) = ($1, $2);
721
push @commit_buffer, [ "fork", $timestamp, $counter, "null-complain-profile", "PERMITTING", $pid, $child ];
724
} elsif ($mesg =~ /LOGPROF-HINT changing_profile pid=(\d+)/) {
727
push @commit_buffer, [ "changing_profile", $timestamp, $counter, "null-complain-profile", "PERMITTING", $pid ];
730
} elsif ($mesg =~ /(PERMITTING|REJECTING|AUDITING) access to profile replacement \((\S+)\((\d+)\) profile (\S+) active (\S+)\)/) {
731
my ($sdmode, $prog, $pid, $profile, $hat) = ($1, $2, $3, $4, $5, $6, $7);
733
$profile .= "^$hat" if $profile ne $hat;
511
if ( $ev->{'sdmode'} && $ev->{'sdmode'} eq "REJECTING") {
512
$severity = $sevdb->rank($ev->{'prog'}, $ev->{'mode_req'});
513
if ( ! $severity ) { $severity = "-1"; }
737
515
# we only do notification for enforce mode events
738
516
if ($config->{verbose_freq}) {
755
534
if ( ($severity >= $config->{terse_level})
756
535
|| (($severity == -1) && $config->{terse_unknown}))
758
push @terse_buffer, [ $timestamp, $counter ];
537
push @terse_buffer, [ $timestamp, $counter, "dummy" ];
762
push @commit_buffer, [ "profile_replacement", $timestamp, $counter, $profile, $sdmode, $prog, $pid, $severity ];
765
} elsif ($mesg =~ /(SubDomain|AppArmor) protection removed/) {
767
push @commit_buffer, [ "removed", $timestamp, $counter, 10 ];
770
} elsif ($mesg =~ /(SubDomain|AppArmor) \(version (\S+)\) initialized/) {
773
push @commit_buffer, [ "initialized", $timestamp, $counter, $version, 10 ];
776
} elsif ($mesg =~ /Control variable '(\S+)' changed to (\S+)/) {
777
my ($variable, $value) = ($1, $2);
779
push @commit_buffer, [ "ctrl_var", $timestamp, $counter, $variable, $value, 10 ];
543
unless ( $ev->{'op'} ) {
544
my $errmsg = "ERROR: No operation found: ";
545
for my $k (sort keys(%$ev)) {
546
$errmsg .= "$k is $ev->{$k}, ";
552
# Format the message to match the db template
553
if ($ev->{'op'} eq 'link' ) {
555
push(@eventList, [$time,$counter,$type,$ev->{'profile'},$ev->{'sdmode'},
556
$ev->{'resource'},$ev->{'target'},$ev->{'prog'},$ev->{'pid'},$severity]);
557
} elsif ($ev->{'op'} eq 'attribute') {
559
push(@eventList, []);
560
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
561
$ev->{'resource'},$ev->{'mode_req'},$ev->{'mode_deny'},$ev->{'prog'},
562
$ev->{'pid'},$severity]);
563
} elsif ($ev->{'op'} eq 'capability') {
564
$type = 'capability';
565
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
566
$ev->{'resource'},$ev->{'prog'},$ev->{'pid'},$severity]);
567
} elsif ($ev->{'op'} eq 'capable') {
569
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'prog'},
570
$ev->{'profile'},$ev->{'pid'}]);
571
} elsif ($ev->{'op'} =~ /ontrol variable/ ) {
573
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'resource'},
574
$ev->{'mode_req'},$ev->{'mode_deny'},$severity]);
575
} elsif ($ev->{'op'} eq 'unknown_hat') {
576
$type = 'unknown_hat';
577
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
578
$ev->{'resource'},$ev->{'pid'},$severity]);
579
} elsif ($ev->{'op'} eq 'fork') {
581
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
582
$ev->{'pid'},$ev->{'resource'}]);
583
} elsif ($ev->{'op'} eq 'changing_profile') {
584
$type = 'changing_profile';
585
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
587
} elsif ($ev->{'op'} eq 'profile_load') {
588
$type = 'profile_load';
589
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'resource'},
590
$ev->{'prog'},$ev->{'pid'}]);
591
} elsif ($ev->{'op'} eq 'profile_replace') {
592
$type = 'profile_replacement';
593
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
594
$ev->{'prog'},$ev->{'pid'},$severity]);
595
} elsif ($ev->{'op'} eq 'removed') {
597
push(@eventList, [$time,$counter,$type,$ev->{'op'},$severity]);
598
} elsif ($ev->{'op'} eq 'initialized') {
599
$type = 'initialized';
600
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'resource'},$severity]);
601
} elsif ( $ev->{'op'} =~ /socket/) {
603
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'net_family'},
604
$ev->{'net_sock_type'},$ev->{'net_proto'},$ev->{'pid'},$ev->{'profile'}]);
784
errlog "Unhandled log message: $logmsg";
607
if ( ! $ev->{'prog'} ) { $ev->{'prog'} = "NIL"; }
608
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},
609
$ev->{'sdmode'},$ev->{'mode_req'},$ev->{'mode_deny'},$ev->{'resource'},
610
$ev->{'prog'},$ev->{'pid'},$severity]);
613
push(@commit_buffer, @eventList);
788
618
sub dump_events {