mirror of
https://github.com/roddhjav/apparmor.d.git
synced 2025-01-30 14:55:15 +01:00
build(directive): support both liust & map.
This commit is contained in:
parent
f81ceb9185
commit
88fcdd8c8e
10 changed files with 126 additions and 86 deletions
|
@ -42,30 +42,33 @@ func (d *DirectiveBase) Message() string {
|
|||
|
||||
// Directive options
|
||||
type Option struct {
|
||||
Name string
|
||||
Args map[string]string
|
||||
File *paths.Path
|
||||
Raw string
|
||||
Name string
|
||||
ArgMap map[string]string
|
||||
ArgList []string
|
||||
File *paths.Path
|
||||
Raw string
|
||||
}
|
||||
|
||||
func NewOption(file *paths.Path, match []string) *Option {
|
||||
if len(match) != 3 {
|
||||
panic(fmt.Sprintf("Invalid directive: %v", match))
|
||||
}
|
||||
args := map[string]string{}
|
||||
for _, t := range strings.Fields(match[2]) {
|
||||
argList := strings.Fields(match[2])
|
||||
argMap := map[string]string{}
|
||||
for _, t := range argList {
|
||||
tmp := strings.Split(t, "=")
|
||||
if len(tmp) < 2 {
|
||||
args[tmp[0]] = ""
|
||||
argMap[tmp[0]] = ""
|
||||
} else {
|
||||
args[tmp[0]] = tmp[1]
|
||||
argMap[tmp[0]] = tmp[1]
|
||||
}
|
||||
}
|
||||
return &Option{
|
||||
Name: match[1],
|
||||
Args: args,
|
||||
File: file,
|
||||
Raw: match[0],
|
||||
Name: match[1],
|
||||
ArgMap: argMap,
|
||||
ArgList: argList,
|
||||
File: file,
|
||||
Raw: match[0],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,32 @@ import (
|
|||
"github.com/arduino/go-paths-helper"
|
||||
)
|
||||
|
||||
func TestDirective_Usage(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
d Directive
|
||||
wantMessage string
|
||||
wantUsage string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
d: Directives["stack"],
|
||||
wantMessage: "Stack directive applied",
|
||||
wantUsage: `#aa:stack profiles_name...`,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.d.Usage(); got != tt.wantUsage {
|
||||
t.Errorf("Directive.Usage() = %v, want %v", got, tt.wantUsage)
|
||||
}
|
||||
if got := tt.d.Message(); got != tt.wantMessage {
|
||||
t.Errorf("Directive.Usage() = %v, want %v", got, tt.wantMessage)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewOption(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
@ -28,13 +54,14 @@ func TestNewOption(t *testing.T) {
|
|||
},
|
||||
want: &Option{
|
||||
Name: "dbus",
|
||||
Args: map[string]string{
|
||||
ArgMap: map[string]string{
|
||||
"bus": "system",
|
||||
"name": "org.gnome.DisplayManager",
|
||||
"own": "",
|
||||
},
|
||||
File: paths.New(""),
|
||||
Raw: " #aa:dbus own bus=system name=org.gnome.DisplayManager",
|
||||
ArgList: []string{"own", "bus=system", "name=org.gnome.DisplayManager"},
|
||||
File: nil,
|
||||
Raw: " #aa:dbus own bus=system name=org.gnome.DisplayManager",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -46,10 +73,11 @@ func TestNewOption(t *testing.T) {
|
|||
"opensuse",
|
||||
},
|
||||
want: &Option{
|
||||
Name: "only",
|
||||
Args: map[string]string{"opensuse": ""},
|
||||
File: paths.New(""),
|
||||
Raw: " #aa:only opensuse",
|
||||
Name: "only",
|
||||
ArgMap: map[string]string{"opensuse": ""},
|
||||
ArgList: []string{"opensuse"},
|
||||
File: nil,
|
||||
Raw: " #aa:only opensuse",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -50,21 +50,13 @@ func setInterfaces(rules map[string]string) []string {
|
|||
|
||||
func (d Dbus) Apply(opt *Option, profile string) string {
|
||||
var p *aa.AppArmorProfile
|
||||
var action string
|
||||
if _, ok := opt.Args["own"]; ok {
|
||||
action = "own"
|
||||
} else if _, ok := opt.Args["talk"]; ok {
|
||||
action = "talk"
|
||||
} else {
|
||||
panic(fmt.Sprintf("Unknown dbus action: %s in %s", opt.Name, opt.File))
|
||||
}
|
||||
|
||||
d.sanityCheck(action, opt)
|
||||
action := d.sanityCheck(opt)
|
||||
switch action {
|
||||
case "own":
|
||||
p = d.own(opt.Args)
|
||||
p = d.own(opt.ArgMap)
|
||||
case "talk":
|
||||
p = d.talk(opt.Args)
|
||||
p = d.talk(opt.ArgMap)
|
||||
}
|
||||
|
||||
generatedDbus := p.String()
|
||||
|
@ -74,22 +66,31 @@ func (d Dbus) Apply(opt *Option, profile string) string {
|
|||
return profile
|
||||
}
|
||||
|
||||
func (d Dbus) sanityCheck(action string, opt *Option) {
|
||||
if _, present := opt.Args["name"]; !present {
|
||||
func (d Dbus) sanityCheck(opt *Option) string {
|
||||
if len(opt.ArgList) < 1 {
|
||||
panic(fmt.Sprintf("Unknown dbus action: %s in %s", opt.Name, opt.File))
|
||||
}
|
||||
action := opt.ArgList[0]
|
||||
if action != "own" && action != "talk" {
|
||||
panic(fmt.Sprintf("Unknown dbus action: %s in %s", opt.Name, opt.File))
|
||||
}
|
||||
|
||||
if _, present := opt.ArgMap["name"]; !present {
|
||||
panic(fmt.Sprintf("Missing name for 'dbus: %s' in %s", action, opt.File))
|
||||
}
|
||||
if _, present := opt.Args["bus"]; !present {
|
||||
panic(fmt.Sprintf("Missing bus for '%s' in %s", opt.Args["name"], opt.File))
|
||||
if _, present := opt.ArgMap["bus"]; !present {
|
||||
panic(fmt.Sprintf("Missing bus for '%s' in %s", opt.ArgMap["name"], opt.File))
|
||||
}
|
||||
if _, present := opt.Args["label"]; !present && action == "talk" {
|
||||
panic(fmt.Sprintf("Missing label for '%s' in %s", opt.Args["name"], opt.File))
|
||||
if _, present := opt.ArgMap["label"]; !present && action == "talk" {
|
||||
panic(fmt.Sprintf("Missing label for '%s' in %s", opt.ArgMap["name"], opt.File))
|
||||
}
|
||||
|
||||
// Set default values
|
||||
if _, present := opt.Args["path"]; !present {
|
||||
opt.Args["path"] = "/" + strings.Replace(opt.Args["name"], ".", "/", -1) + "{,/**}"
|
||||
if _, present := opt.ArgMap["path"]; !present {
|
||||
opt.ArgMap["path"] = "/" + strings.Replace(opt.ArgMap["name"], ".", "/", -1) + "{,/**}"
|
||||
}
|
||||
opt.Args["name"] += "{,.*}"
|
||||
opt.ArgMap["name"] += "{,.*}"
|
||||
return action
|
||||
}
|
||||
|
||||
func (d Dbus) own(rules map[string]string) *aa.AppArmorProfile {
|
||||
|
|
|
@ -43,13 +43,14 @@ func TestDbus_Apply(t *testing.T) {
|
|||
name: "own",
|
||||
opt: &Option{
|
||||
Name: "dbus",
|
||||
Args: map[string]string{
|
||||
ArgMap: map[string]string{
|
||||
"bus": "system",
|
||||
"name": "org.freedesktop.systemd1",
|
||||
"own": "",
|
||||
},
|
||||
File: nil,
|
||||
Raw: " #aa:dbus own bus=system name=org.freedesktop.systemd1",
|
||||
ArgList: []string{"own", "bus=system", "name=org.freedesktop.systemd1"},
|
||||
File: nil,
|
||||
Raw: " #aa:dbus own bus=system name=org.freedesktop.systemd1",
|
||||
},
|
||||
profile: " #aa:dbus own bus=system name=org.freedesktop.systemd1",
|
||||
want: dbusOwnSystemd1,
|
||||
|
@ -58,14 +59,15 @@ func TestDbus_Apply(t *testing.T) {
|
|||
name: "own-interface",
|
||||
opt: &Option{
|
||||
Name: "dbus",
|
||||
Args: map[string]string{
|
||||
ArgMap: map[string]string{
|
||||
"bus": "session",
|
||||
"name": "com.rastersoft.dingextension",
|
||||
"interface": "org.gtk.Actions",
|
||||
"own": "",
|
||||
},
|
||||
File: nil,
|
||||
Raw: " #aa:dbus own bus=session name=com.rastersoft.dingextension interface=org.gtk.Actions",
|
||||
ArgList: []string{"own", "bus=session", "name=com.rastersoft.dingextension", "interface=org.gtk.Actions"},
|
||||
File: nil,
|
||||
Raw: " #aa:dbus own bus=session name=com.rastersoft.dingextension interface=org.gtk.Actions",
|
||||
},
|
||||
profile: " #aa:dbus own bus=session name=com.rastersoft.dingextension interface=org.gtk.Actions",
|
||||
want: ` dbus bind bus=session name=com.rastersoft.dingextension{,.*},
|
||||
|
@ -102,14 +104,15 @@ func TestDbus_Apply(t *testing.T) {
|
|||
name: "talk",
|
||||
opt: &Option{
|
||||
Name: "dbus",
|
||||
Args: map[string]string{
|
||||
ArgMap: map[string]string{
|
||||
"bus": "system",
|
||||
"name": "org.freedesktop.Accounts",
|
||||
"label": "accounts-daemon",
|
||||
"talk": "",
|
||||
},
|
||||
File: nil,
|
||||
Raw: " #aa:dbus talk bus=system name=org.freedesktop.Accounts label=accounts-daemon",
|
||||
ArgList: []string{"talk", "bus=system", "name=org.freedesktop.Accounts", "label=accounts-daemon"},
|
||||
File: nil,
|
||||
Raw: " #aa:dbus talk bus=system name=org.freedesktop.Accounts label=accounts-daemon",
|
||||
},
|
||||
profile: " #aa:dbus talk bus=system name=org.freedesktop.Accounts label=accounts-daemon",
|
||||
want: ` dbus send bus=system path=/org/freedesktop/Accounts{,/**}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/roddhjav/apparmor.d/pkg/aa"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
type Exec struct {
|
||||
|
@ -26,16 +27,14 @@ func init() {
|
|||
func (d Exec) Apply(opt *Option, profile string) string {
|
||||
transition := "Px"
|
||||
transitions := []string{"P", "U", "p", "u", "PU", "pu"}
|
||||
for _, t := range transitions {
|
||||
if _, present := opt.Args[t]; present {
|
||||
transition = t + "x"
|
||||
delete(opt.Args, t)
|
||||
break
|
||||
}
|
||||
t := opt.ArgList[0]
|
||||
if slices.Contains(transitions, t) {
|
||||
transition = t + "x"
|
||||
delete(opt.ArgMap, t)
|
||||
}
|
||||
|
||||
p := &aa.AppArmorProfile{}
|
||||
for name := range opt.Args {
|
||||
for name := range opt.ArgMap {
|
||||
content, err := rootApparmord.Join(name).ReadFile()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
|
@ -22,10 +22,11 @@ func TestExec_Apply(t *testing.T) {
|
|||
name: "exec",
|
||||
rootApparmord: paths.New("../../../apparmor.d/groups/kde/"),
|
||||
opt: &Option{
|
||||
Name: "exec",
|
||||
Args: map[string]string{"DiscoverNotifier": ""},
|
||||
File: nil,
|
||||
Raw: " #aa:exec DiscoverNotifier",
|
||||
Name: "exec",
|
||||
ArgMap: map[string]string{"DiscoverNotifier": ""},
|
||||
ArgList: []string{"DiscoverNotifier"},
|
||||
File: nil,
|
||||
Raw: " #aa:exec DiscoverNotifier",
|
||||
},
|
||||
profile: ` #aa:exec DiscoverNotifier`,
|
||||
want: ` @{lib}/@{multiarch}/{,libexec/}DiscoverNotifier Px,
|
||||
|
@ -35,10 +36,11 @@ func TestExec_Apply(t *testing.T) {
|
|||
name: "exec-unconfined",
|
||||
rootApparmord: paths.New("../../../apparmor.d/groups/freedesktop/"),
|
||||
opt: &Option{
|
||||
Name: "exec",
|
||||
Args: map[string]string{"U": "", "polkit-agent-helper": ""},
|
||||
File: nil,
|
||||
Raw: " #aa:exec U polkit-agent-helper",
|
||||
Name: "exec",
|
||||
ArgMap: map[string]string{"U": "", "polkit-agent-helper": ""},
|
||||
ArgList: []string{"U", "polkit-agent-helper"},
|
||||
File: nil,
|
||||
Raw: " #aa:exec U polkit-agent-helper",
|
||||
},
|
||||
profile: ` #aa:exec U polkit-agent-helper`,
|
||||
want: ` @{lib}/polkit-[0-9]/polkit-agent-helper-[0-9] Ux,
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
"strings"
|
||||
|
||||
oss "github.com/roddhjav/apparmor.d/pkg/os"
|
||||
"golang.org/x/exp/maps"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
|
@ -37,7 +36,7 @@ func init() {
|
|||
}
|
||||
|
||||
func filterRuleForUs(opt *Option) bool {
|
||||
return slices.Contains(maps.Keys(opt.Args), oss.Distribution) || slices.Contains(maps.Keys(opt.Args), oss.Family)
|
||||
return slices.Contains(opt.ArgList, oss.Distribution) || slices.Contains(opt.ArgList, oss.Family)
|
||||
}
|
||||
|
||||
func filter(only bool, opt *Option, profile string) string {
|
||||
|
|
|
@ -24,10 +24,11 @@ func TestFilterOnly_Apply(t *testing.T) {
|
|||
dist: "debian",
|
||||
family: "apt",
|
||||
opt: &Option{
|
||||
Name: "only",
|
||||
Args: map[string]string{"apt": ""},
|
||||
File: nil,
|
||||
Raw: " @{bin}/arch-audit rPx, #aa:only apt",
|
||||
Name: "only",
|
||||
ArgMap: map[string]string{"apt": ""},
|
||||
ArgList: []string{"apt"},
|
||||
File: nil,
|
||||
Raw: " @{bin}/arch-audit rPx, #aa:only apt",
|
||||
},
|
||||
profile: " @{bin}/arch-audit rPx, #aa:only apt",
|
||||
want: " @{bin}/arch-audit rPx, #aa:only apt",
|
||||
|
@ -37,10 +38,11 @@ func TestFilterOnly_Apply(t *testing.T) {
|
|||
dist: "arch",
|
||||
family: "pacman",
|
||||
opt: &Option{
|
||||
Name: "only",
|
||||
Args: map[string]string{"zypper": ""},
|
||||
File: nil,
|
||||
Raw: " #aa:only zypper",
|
||||
Name: "only",
|
||||
ArgMap: map[string]string{"zypper": ""},
|
||||
ArgList: []string{"zypper"},
|
||||
File: nil,
|
||||
Raw: " #aa:only zypper",
|
||||
},
|
||||
profile: `
|
||||
/tmp/apt-changelog-@{rand6}/ w,
|
||||
|
@ -98,10 +100,11 @@ func TestFilterExclude_Apply(t *testing.T) {
|
|||
dist: "debian",
|
||||
family: "apt",
|
||||
opt: &Option{
|
||||
Name: "exclude",
|
||||
Args: map[string]string{"debian": ""},
|
||||
File: nil,
|
||||
Raw: " @{bin}/dpkg rPx -> child-dpkg, #aa:exclude debian",
|
||||
Name: "exclude",
|
||||
ArgMap: map[string]string{"debian": ""},
|
||||
ArgList: []string{"debian"},
|
||||
File: nil,
|
||||
Raw: " @{bin}/dpkg rPx -> child-dpkg, #aa:exclude debian",
|
||||
},
|
||||
profile: " @{bin}/dpkg rPx -> child-dpkg, #aa:exclude debian",
|
||||
want: "",
|
||||
|
@ -111,10 +114,11 @@ func TestFilterExclude_Apply(t *testing.T) {
|
|||
dist: "whonix",
|
||||
family: "apt",
|
||||
opt: &Option{
|
||||
Name: "exclude",
|
||||
Args: map[string]string{"debian": ""},
|
||||
File: nil,
|
||||
Raw: " @{bin}/dpkg rPx -> child-dpkg, #aa:exclude debian",
|
||||
Name: "exclude",
|
||||
ArgMap: map[string]string{"debian": ""},
|
||||
ArgList: []string{"debian"},
|
||||
File: nil,
|
||||
Raw: " @{bin}/dpkg rPx -> child-dpkg, #aa:exclude debian",
|
||||
},
|
||||
profile: " @{bin}/dpkg rPx -> child-dpkg, #aa:exclude debian",
|
||||
want: " @{bin}/dpkg rPx -> child-dpkg, #aa:exclude debian",
|
||||
|
|
|
@ -41,7 +41,7 @@ func init() {
|
|||
|
||||
func (s Stack) Apply(opt *Option, profile string) string {
|
||||
res := ""
|
||||
for name := range opt.Args {
|
||||
for name := range opt.ArgMap {
|
||||
tmp, err := rootApparmord.Join(name).ReadFile()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
|
@ -22,10 +22,11 @@ func TestStack_Apply(t *testing.T) {
|
|||
name: "stack",
|
||||
rootApparmord: paths.New("../../../apparmor.d/groups/freedesktop/"),
|
||||
opt: &Option{
|
||||
Name: "stack",
|
||||
Args: map[string]string{"plymouth": ""},
|
||||
File: nil,
|
||||
Raw: " #aa:stack plymouth",
|
||||
Name: "stack",
|
||||
ArgMap: map[string]string{"plymouth": ""},
|
||||
ArgList: []string{"plymouth"},
|
||||
File: nil,
|
||||
Raw: " #aa:stack plymouth",
|
||||
},
|
||||
profile: `
|
||||
profile parent @{exec_path} {
|
||||
|
|
Loading…
Reference in a new issue