From ac2386957bc6d6d9582dc25e2febabb90f063b51 Mon Sep 17 00:00:00 2001 From: Alexandre Pujol Date: Tue, 9 Nov 2021 22:41:12 +0000 Subject: [PATCH] Rewrite aa-log. --- .gitlab-ci.yml | 25 ++++++ PKGBUILD | 17 +++- apparmor.d/profiles-a-f/aa-log | 12 +-- root/usr/bin/aa-log | 24 ------ src/cmd/aa-log/main.go | 143 +++++++++++++++++++++++++++++++++ src/go.mod | 3 + src/go.sum | 0 7 files changed, 186 insertions(+), 38 deletions(-) delete mode 100755 root/usr/bin/aa-log create mode 100644 src/cmd/aa-log/main.go create mode 100644 src/go.mod create mode 100644 src/go.sum diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ebd41150..3756e9af 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,8 @@ --- +include: + - template: Security/SAST.gitlab-ci.yml + variables: PKGDEST: $CI_PROJECT_DIR/packages PACKAGER: 'Alexandre Pujol ' @@ -21,6 +24,28 @@ bash: PKGBUILD debian/apparmor.d.postinst debian/apparmor.d.postrm +golangci-lint: + stage: lint + image: golangci/golangci-lint + script: + - cd src && golangci-lint run + +goreport: + stage: lint + image: golang + before_script: + - cd /tmp + - git clone https://github.com/gojp/goreportcard.git + - cd goreportcard + - make install + - go install ./cmd/goreportcard-cli + - cd $CI_PROJECT_DIR + script: + - goreportcard-cli -v -t 90 + +sast: + stage: lint + # Package Build # ------------- diff --git a/PKGBUILD b/PKGBUILD index d85016f5..9ccae5b4 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -5,10 +5,11 @@ pkgname=apparmor.d pkgver=0.001 pkgrel=1 pkgdesc="Full set of apparmor profiles" -arch=("any") +arch=("x86_64") url="https://github.com/roddhjav/$pkgname" license=('GPL2') depends=('apparmor') +makedepends=('go' 'git') pkgver() { cd "$srcdir/$pkgname" @@ -22,6 +23,16 @@ prepare() { ./configure --distribution=archlinux } +build() { + cd "$srcdir/$pkgname/src" + export CGO_CPPFLAGS="${CPPFLAGS}" + export CGO_CFLAGS="${CFLAGS}" + export CGO_CXXFLAGS="${CXXFLAGS}" + export CGO_LDFLAGS="${LDFLAGS}" + export GOFLAGS="-buildmode=pie -trimpath -ldflags=-linkmode=external -mod=readonly -modcacherw" + go build -o ../.build/ ./cmd/aa-log +} + package() { local _build='.build/apparmor.d' cd "$srcdir/$pkgname" @@ -45,6 +56,6 @@ package() { "$pkgdir/usr/lib/systemd/system/$service.d/apparmor.conf" done - # Set special access rights - chmod 0755 "$pkgdir"/usr/bin/* + # Internal tool + install -Dm755 .build/aa-log "$pkgdir"/usr/bin/aa-log } diff --git a/apparmor.d/profiles-a-f/aa-log b/apparmor.d/profiles-a-f/aa-log index 2e549f1b..fb6cb82a 100644 --- a/apparmor.d/profiles-a-f/aa-log +++ b/apparmor.d/profiles-a-f/aa-log @@ -12,19 +12,9 @@ profile aa-log @{exec_path} { @{exec_path} mr, - /{usr/,}bin/{,ba,da}sh rix, - /{usr/,}bin/awk rix, - /{usr/,}bin/env rix, - /{usr/,}bin/gawk rix, - /{usr/,}bin/grep rix, - /{usr/,}bin/mawk rix, - /{usr/,}bin/sed rix, - - /usr/share/terminfo/x/xterm-256color r, - /var/log/audit/audit.log r, - /dev/tty rw, + @{sys}/kernel/mm/transparent_hugepage/hpage_pmd_size r, include if exists } \ No newline at end of file diff --git a/root/usr/bin/aa-log b/root/usr/bin/aa-log deleted file mode 100755 index 018da7e9..00000000 --- a/root/usr/bin/aa-log +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash -# Review AppArmor generated messages -# Copyright (C) 2021 Alexandre Pujol -# SPDX-License-Identifier: GPL-2.0-only -# - -readonly LOGFILE=/var/log/audit/audit.log - -# Parses AppArmor logs to hide unnecessary information and remove duplicates. -_apparmor_log() { - local state="$1" profile="$2" - grep -a "$state" "$LOGFILE" \ - | grep "profile=\"$profile.*\"" \ - | sed -e 's/AVC //' \ - -e "s/apparmor=\"$state\"/$state/" \ - -e 's/type=msg=audit(.*): //' \ - -e 's/pid=.* comm/comm/' \ - -e 's/ fsuid.*//' \ - | awk '!x[$0]++' - -} - -_apparmor_log DENIED "$@" -_apparmor_log ALLOWED "$@" diff --git a/src/cmd/aa-log/main.go b/src/cmd/aa-log/main.go new file mode 100644 index 00000000..87b799e9 --- /dev/null +++ b/src/cmd/aa-log/main.go @@ -0,0 +1,143 @@ +// aa-log - Review AppArmor generated messages +// Copyright (C) 2021 Alexandre Pujol +// SPDX-License-Identifier: GPL-2.0-only + +package main + +import ( + "bufio" + "fmt" + "os" + "regexp" + "strings" +) + +// LogFile is the path to the file to query +const LogFile = "/var/log/audit/audit.log" + +// Colors +const ( + Reset = "\033[0m" + FgYellow = "\033[33m" + FgBlue = "\033[34m" + FgMagenta = "\033[35m" + BoldRed = "\033[1;31m" + BoldGreen = "\033[1;32m" +) + +// AppArmorLog describes a apparmor log entry +type AppArmorLog struct { + State string + Profile string + Operation string + Name string + Content string +} + +func removeDuplicateLog(logs []string) []string { + list := []string{} + keys := make(map[string]interface{}) + keys[""] = true + for _, log := range logs { + if _, v := keys[log]; !v { + keys[log] = true + list = append(list, log) + } + } + return list +} + +func parseApparmorLogs(file *os.File, profile string) []AppArmorLog { + log := "" + exp := fmt.Sprintf("^.*apparmor=(\"DENIED\"|\"ALLOWED\").* profile=\"%s.*\".*$", profile) + isAppArmorLog := regexp.MustCompile(exp) + + // Select Apparmor logs + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := scanner.Text() + if isAppArmorLog.MatchString(line) { + log += line + "\n" + } + } + + // Clean logs + cleanAppArmorLogs := []*regexp.Regexp{ + regexp.MustCompile(`type=AVC msg=audit(.*): `), + regexp.MustCompile(` fsuid.*`), + } + for _, clean := range cleanAppArmorLogs { + log = clean.ReplaceAllLiteralString(log, "") + } + replaceAppArmorLogs := regexp.MustCompile(`pid=.* comm`) + log = replaceAppArmorLogs.ReplaceAllLiteralString(log, "comm") + + // Remove doublon in logs + logs := strings.Split(log, "\n") + logs = removeDuplicateLog(logs) + + // Parse log into ApparmorLog struct + aaLogs := make([]AppArmorLog, 0) + getState := regexp.MustCompile(`apparmor=\"([A-Z]*)\"`) + getProfile := regexp.MustCompile(`profile=\"([A-Za-z0-9_.\-/]*)\" `) + getOperation := regexp.MustCompile(`operation="(\w+)"`) + getName := regexp.MustCompile(` name=([A-Za-z0-9_.\-/#"]*)`) + cleanContent := []*regexp.Regexp{getState, getProfile, getOperation, getName} + for _, log := range logs { + name := "" + names := getName.FindStringSubmatch(log) + if len(names) >= 2 { + name = strings.Trim(names[1], `"`) + } + + content := log + for _, clean := range cleanContent { + content = clean.ReplaceAllLiteralString(content, "") + } + aaLogs = append(aaLogs, + AppArmorLog{ + State: getState.FindStringSubmatch(log)[1], + Profile: getProfile.FindStringSubmatch(log)[1], + Operation: getOperation.FindStringSubmatch(log)[1], + Name: name, + Content: content[2:], + }) + } + + return aaLogs +} + +func printFormatedApparmorLogs(aaLogs []AppArmorLog) { + state := map[string]string{ + "DENIED": BoldRed + "DENIED " + Reset, + "ALLOWED": BoldGreen + "ALLOWED" + Reset, + } + for _, log := range aaLogs { + fmt.Println(state[log.State], + FgBlue+log.Profile, + FgYellow+log.Operation, + FgMagenta+log.Name+Reset, + log.Content) + } +} + +func main() { + profile := "" + if len(os.Args) >= 2 { + profile = os.Args[1] + } + + file, err := os.Open(LogFile) + if err != nil { + fmt.Println(err.Error()) + return + } + defer func() { + if err := file.Close(); err != nil { + fmt.Println("Error closing file:", err) + } + }() + + aaLogs := parseApparmorLogs(file, profile) + printFormatedApparmorLogs(aaLogs) +} diff --git a/src/go.mod b/src/go.mod new file mode 100644 index 00000000..993e156a --- /dev/null +++ b/src/go.mod @@ -0,0 +1,3 @@ +module gitlab.com/roddhjav/apparmor.d + +go 1.17 diff --git a/src/go.sum b/src/go.sum new file mode 100644 index 00000000..e69de29b