feat(aa-log): new structure for apparmor rules.

This commit is contained in:
Alexandre Pujol 2023-09-25 00:06:07 +01:00
parent 99d1a4e302
commit 923bb66eba
No known key found for this signature in database
GPG Key ID: C5469996F0DF68EC
18 changed files with 428 additions and 192 deletions

17
pkg/aa/capability.go Normal file
View File

@ -0,0 +1,17 @@
// apparmor.d - Full set of apparmor profiles
// Copyright (C) 2021-2023 Alexandre Pujol <alexandre@pujol.io>
// SPDX-License-Identifier: GPL-2.0-only
package aa
type Capability struct {
Qualifier
Name string
}
func CapabilityFromLog(log map[string]string, noNewPrivs, fileInherit bool) ApparmorRule {
return &Capability{
Qualifier: NewQualifier(false, noNewPrivs, fileInherit),
Name: log["capname"],
}
}

19
pkg/aa/change_profile.go Normal file
View File

@ -0,0 +1,19 @@
// apparmor.d - Full set of apparmor profiles
// Copyright (C) 2021-2023 Alexandre Pujol <alexandre@pujol.io>
// SPDX-License-Identifier: GPL-2.0-only
package aa
type ChangeProfile struct {
ExecMode string
Exec string
ProfileName string
}
func ChangeProfileFromLog(log map[string]string, noNewPrivs, fileInherit bool) ApparmorRule {
return &ChangeProfile{
ExecMode: log["mode"],
Exec: log["exec"],
ProfileName: log["name"],
}
}

29
pkg/aa/dbus.go Normal file
View File

@ -0,0 +1,29 @@
// apparmor.d - Full set of apparmor profiles
// Copyright (C) 2021-2023 Alexandre Pujol <alexandre@pujol.io>
// SPDX-License-Identifier: GPL-2.0-only
package aa
type Dbus struct {
Qualifier
Access string
Bus string
Name string
Path string
Interface string
Member string
Label string
}
func DbusFromLog(log map[string]string, noNewPrivs, fileInherit bool) ApparmorRule {
return &Dbus{
Qualifier: NewQualifier(false, noNewPrivs, fileInherit),
Access: log["mask"],
Bus: log["bus"],
Name: log["name"],
Path: log["path"],
Interface: log["interface"],
Member: log["member"],
Label: log["peer_label"],
}
}

25
pkg/aa/file.go Normal file
View File

@ -0,0 +1,25 @@
// apparmor.d - Full set of apparmor profiles
// Copyright (C) 2021-2023 Alexandre Pujol <alexandre@pujol.io>
// SPDX-License-Identifier: GPL-2.0-only
package aa
type File struct {
Qualifier
Path string
Access string
Target string
}
func FileFromLog(log map[string]string, noNewPrivs, fileInherit bool) ApparmorRule {
owner := false
if log["fsuid"] == log["ouid"] && log["OUID"] != "root" {
owner = true
}
return &File{
Qualifier: NewQualifier(owner, noNewPrivs, fileInherit),
Path: log["name"],
Access: maskToAccess[log["requested_mask"]],
Target: log["target"],
}
}

12
pkg/aa/include.go Normal file
View File

@ -0,0 +1,12 @@
// apparmor.d - Full set of apparmor profiles
// Copyright (C) 2021-2023 Alexandre Pujol <alexandre@pujol.io>
// SPDX-License-Identifier: GPL-2.0-only
package aa
type Include struct {
IfExists bool
Path string
IsMagic bool
}

12
pkg/aa/io_uring.go Normal file
View File

@ -0,0 +1,12 @@
// apparmor.d - Full set of apparmor profiles
// Copyright (C) 2021-2023 Alexandre Pujol <alexandre@pujol.io>
// SPDX-License-Identifier: GPL-2.0-only
package aa
type IOUring struct {
Qualifier
Access string
Label string
}

72
pkg/aa/mount.go Normal file
View File

@ -0,0 +1,72 @@
// apparmor.d - Full set of apparmor profiles
// Copyright (C) 2021-2023 Alexandre Pujol <alexandre@pujol.io>
// SPDX-License-Identifier: GPL-2.0-only
package aa
import "golang.org/x/exp/slices"
type MountConditions struct {
Fs string
Op string
FsType string
Options []string
}
type Mount struct {
Qualifier
MountConditions
Source string
MountPoint string
}
func MountFromLog(log map[string]string, noNewPrivs, fileInherit bool) ApparmorRule {
return &Mount{
Qualifier: NewQualifier(false, noNewPrivs, fileInherit),
MountConditions: MountConditions{
Fs: "",
Op: "",
FsType: log["fstype"],
Options: []string{},
},
Source: log["srcname"],
MountPoint: log["name"],
}
}
type Umount struct {
Qualifier
MountConditions
MountPoint string
}
func UmountFromLog(log map[string]string, noNewPrivs, fileInherit bool) ApparmorRule {
return &Umount{
Qualifier: NewQualifier(false, noNewPrivs, fileInherit),
MountConditions: MountConditions{
Fs: "",
Op: "",
FsType: log["fstype"],
Options: []string{},
},
MountPoint: log["name"],
}
}
type Remount struct {
Qualifier
MountConditions
MountPoint string
}
func RemountFromLog(log map[string]string, noNewPrivs, fileInherit bool) ApparmorRule {
return &Remount{
Qualifier: NewQualifier(false, noNewPrivs, fileInherit),
MountConditions: MountConditions{
Fs: "",
Op: "",
FsType: log["fstype"],
Options: []string{},
},
MountPoint: log["name"],
}
}

21
pkg/aa/mqueue.go Normal file
View File

@ -0,0 +1,21 @@
// apparmor.d - Full set of apparmor profiles
// Copyright (C) 2021-2023 Alexandre Pujol <alexandre@pujol.io>
// SPDX-License-Identifier: GPL-2.0-only
package aa
type Mqueue struct {
Qualifier
Access string
Type string
Label string
}
func MqueueFromLog(log map[string]string, noNewPrivs, fileInherit bool) ApparmorRule {
return &Mqueue{
Qualifier: NewQualifier(false, noNewPrivs, fileInherit),
Access: maskToAccess[log["requested_mask"]],
Type: log["type"],
Label: log["label"],
}
}

34
pkg/aa/network.go Normal file
View File

@ -0,0 +1,34 @@
// apparmor.d - Full set of apparmor profiles
// Copyright (C) 2021-2023 Alexandre Pujol <alexandre@pujol.io>
// SPDX-License-Identifier: GPL-2.0-only
package aa
type AddressExpr struct {
Source string
Destination string
Port string
}
type Network struct {
Qualifier
Domain string
Type string
Protocol string
AddressExpr
}
func NetworkFromLog(log map[string]string, noNewPrivs, fileInherit bool) ApparmorRule {
return &Network{
Qualifier: NewQualifier(false, noNewPrivs, fileInherit),
AddressExpr: AddressExpr{
Source: log["laddr"],
Destination: log["faddr"],
Port: log["lport"],
},
Domain: log["family"],
Type: log["sock_type"],
Protocol: log["protocol"],
}
}

21
pkg/aa/pivot_root.go Normal file
View File

@ -0,0 +1,21 @@
// apparmor.d - Full set of apparmor profiles
// Copyright (C) 2021-2023 Alexandre Pujol <alexandre@pujol.io>
// SPDX-License-Identifier: GPL-2.0-only
package aa
type PivotRoot struct {
Qualifier
OldRoot string
NewRoot string
TargetProfile string
}
func PivotRootFromLog(log map[string]string, noNewPrivs, fileInherit bool) ApparmorRule {
return &PivotRoot{
Qualifier: NewQualifier(false, noNewPrivs, fileInherit),
OldRoot: log["oldroot"],
NewRoot: log["root"],
TargetProfile: log["name"],
}
}

View File

@ -23,6 +23,31 @@ type AppArmorProfile struct {
Profile
}
// Preamble section of a profile
type Preamble struct {
Abi []Abi
Includes []Include
Aliases []Alias
Variables []Variable
}
// Profile section of a profile
type Profile struct {
Name string
Attachments []string
Attributes map[string]string
Flags []string
Rules Rules
}
// ApparmorRule generic interface
type ApparmorRule interface {
Less(other any) bool
Equals(other any) bool
}
type Rules []ApparmorRule
func NewAppArmorProfile() *AppArmorProfile {
return &AppArmorProfile{}
}

20
pkg/aa/ptrace.go Normal file
View File

@ -0,0 +1,20 @@
// apparmor.d - Full set of apparmor profiles
// Copyright (C) 2021-2023 Alexandre Pujol <alexandre@pujol.io>
// SPDX-License-Identifier: GPL-2.0-only
package aa
type Ptrace struct {
Qualifier
Access string
Peer string
}
func PtraceFromLog(log map[string]string, noNewPrivs, fileInherit bool) ApparmorRule {
return &Ptrace{
Qualifier: NewQualifier(false, noNewPrivs, fileInherit),
Access: maskToAccess[log["requested_mask"]],
Peer: log["peer"],
}
}

11
pkg/aa/rlimit.go Normal file
View File

@ -0,0 +1,11 @@
// apparmor.d - Full set of apparmor profiles
// Copyright (C) 2021-2023 Alexandre Pujol <alexandre@pujol.io>
// SPDX-License-Identifier: GPL-2.0-only
package aa
type Rlimit struct {
Key string
Op string
Value string
}

View File

@ -4,42 +4,6 @@
package aa
// Preamble section of a profile
type Preamble struct {
Abi []Abi
PreambleIncludes []Include
Aliases []Alias
Variables []Variable
}
// Profile section of a profile
type Profile struct {
Name string
Attachments []string
Attributes []string
Flags []string
Rules
}
type Rules struct {
Includes []Include
Rlimit []Rlimit
Userns Userns
Capability []Capability
Network []Network
Mount []Mount
Umount []Umount
Remount []Remount
PivotRoot []PivotRoot
ChangeProfile []ChangeProfile
Unix []Unix
Ptrace []Ptrace
Signal []Signal
Dbus []Dbus
File []File
}
// Qualifier to apply extra settings to a rule
type Qualifier struct {
Audit bool
@ -49,159 +13,6 @@ type Qualifier struct {
FileInherit bool
}
// Preamble rules
type Abi struct {
Path string
IsMagic bool
}
type Alias struct {
Path string
RewrittenPath string
}
type Include struct {
IfExists bool
Path string
IsMagic bool
}
type Variable struct {
Name string
Values []string
}
// Profile rules
type Rlimit struct {
Key string
Op string
Value string
}
type Userns struct {
Qualifier
Create bool
}
type Capability struct {
Qualifier
Name string
}
type AddressExpr struct {
Source string
Destination string
Port string
}
type Network struct {
Qualifier
Domain string
Type string
Protocol string
AddressExpr
}
type MountConditions struct {
Fs string
Op string
FsType string
Options []string
}
type Mount struct {
Qualifier
MountConditions
Source string
MountPoint string
}
type Umount struct {
Qualifier
MountConditions
MountPoint string
}
type Remount struct {
Qualifier
MountConditions
MountPoint string
}
type PivotRoot struct {
Qualifier
OldRoot string
NewRoot string
TargetProfile string
}
type ChangeProfile struct {
ExecMode string
Exec string
ProfileName string
}
type IOUring struct {
Qualifier
Access string
Label string
}
type Signal struct {
Qualifier
Access string
Set string
Peer string
}
type Ptrace struct {
Qualifier
Access string
Peer string
}
type Unix struct {
Qualifier
Access string
Type string
Protocol string
Address string
Label string
Attr string
Opt string
Peer string
PeerAddr string
}
type Mqueue struct {
Qualifier
Access string
Type string
Label string
}
type Dbus struct {
Qualifier
Access string
Bus string
Name string
Path string
Interface string
Member string
Label string
}
type File struct {
Qualifier
Path string
Access string
Target string
}
// Rules constructors from logs
func NewQualifier(owner, noNewPrivs, fileInherit bool) Qualifier {
return Qualifier{
Audit: false,
@ -303,4 +114,36 @@ func NewDbus(log map[string]string, noNewPrivs, fileInherit bool) Dbus {
Member: log["member"],
Label: log["peer_label"],
}
// Preamble specific rules
type Abi struct {
Path string
IsMagic bool
}
func (r Abi) Less(other Abi) bool {
if r.Path == other.Path {
return r.IsMagic == other.IsMagic
}
return r.Path < other.Path
}
func (r Abi) Equals(other Abi) bool {
return r.Path == other.Path && r.IsMagic == other.IsMagic
}
type Alias struct {
Path string
RewrittenPath string
}
func (r Alias) Less(other Alias) bool {
if r.Path == other.Path {
return r.RewrittenPath < other.RewrittenPath
}
return r.Path < other.Path
}
func (r Alias) Equals(other Alias) bool {
return r.Path == other.Path && r.RewrittenPath == other.RewrittenPath
}

22
pkg/aa/signal.go Normal file
View File

@ -0,0 +1,22 @@
// apparmor.d - Full set of apparmor profiles
// Copyright (C) 2021-2023 Alexandre Pujol <alexandre@pujol.io>
// SPDX-License-Identifier: GPL-2.0-only
package aa
type Signal struct {
Qualifier
Access string
Set string
Peer string
}
func SignalFromLog(log map[string]string, noNewPrivs, fileInherit bool) ApparmorRule {
return &Signal{
Qualifier: NewQualifier(false, noNewPrivs, fileInherit),
Access: maskToAccess[log["requested_mask"]],
Set: log["signal"],
Peer: log["peer"],
}
}

33
pkg/aa/unix.go Normal file
View File

@ -0,0 +1,33 @@
// apparmor.d - Full set of apparmor profiles
// Copyright (C) 2021-2023 Alexandre Pujol <alexandre@pujol.io>
// SPDX-License-Identifier: GPL-2.0-only
package aa
type Unix struct {
Qualifier
Access string
Type string
Protocol string
Address string
Label string
Attr string
Opt string
Peer string
PeerAddr string
}
func UnixFromLog(log map[string]string, noNewPrivs, fileInherit bool) ApparmorRule {
return &Unix{
Qualifier: NewQualifier(false, noNewPrivs, fileInherit),
Access: maskToAccess[log["requested_mask"]],
Type: log["sock_type"],
Protocol: log["protocol"],
Address: log["addr"],
Label: log["peer_label"],
Attr: log["attr"],
Opt: log["opt"],
Peer: log["peer"],
PeerAddr: log["peer_addr"],
}
}

18
pkg/aa/userns.go Normal file
View File

@ -0,0 +1,18 @@
// apparmor.d - Full set of apparmor profiles
// Copyright (C) 2021-2023 Alexandre Pujol <alexandre@pujol.io>
// SPDX-License-Identifier: GPL-2.0-only
package aa
type Userns struct {
Qualifier
Create bool
}
func UsernsFromLog(log map[string]string, noNewPrivs, fileInherit bool) ApparmorRule {
return &Userns{
Qualifier: NewQualifier(false, noNewPrivs, fileInherit),
Create: true,
}
}

View File

@ -17,10 +17,12 @@ import (
var (
regVariablesDef = regexp.MustCompile(`@{(.*)}\s*[+=]+\s*(.*)`)
regVariablesRef = regexp.MustCompile(`@{([^{}]+)}`)
)
// Default Apparmor magic directory: /etc/apparmor.d/.
var MagicRoot = paths.New("/etc/apparmor.d")
type Variable struct {
Name string
Values []string
}
// DefaultTunables return a minimal working profile to build the profile
// It should not be used when loading file from /etc/apparmor.d