mirror of
https://github.com/roddhjav/apparmor.d.git
synced 2025-01-30 23:05:11 +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
|
@ -43,7 +43,8 @@ func (d *DirectiveBase) Message() string {
|
||||||
// Directive options
|
// Directive options
|
||||||
type Option struct {
|
type Option struct {
|
||||||
Name string
|
Name string
|
||||||
Args map[string]string
|
ArgMap map[string]string
|
||||||
|
ArgList []string
|
||||||
File *paths.Path
|
File *paths.Path
|
||||||
Raw string
|
Raw string
|
||||||
}
|
}
|
||||||
|
@ -52,18 +53,20 @@ func NewOption(file *paths.Path, match []string) *Option {
|
||||||
if len(match) != 3 {
|
if len(match) != 3 {
|
||||||
panic(fmt.Sprintf("Invalid directive: %v", match))
|
panic(fmt.Sprintf("Invalid directive: %v", match))
|
||||||
}
|
}
|
||||||
args := map[string]string{}
|
argList := strings.Fields(match[2])
|
||||||
for _, t := range strings.Fields(match[2]) {
|
argMap := map[string]string{}
|
||||||
|
for _, t := range argList {
|
||||||
tmp := strings.Split(t, "=")
|
tmp := strings.Split(t, "=")
|
||||||
if len(tmp) < 2 {
|
if len(tmp) < 2 {
|
||||||
args[tmp[0]] = ""
|
argMap[tmp[0]] = ""
|
||||||
} else {
|
} else {
|
||||||
args[tmp[0]] = tmp[1]
|
argMap[tmp[0]] = tmp[1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &Option{
|
return &Option{
|
||||||
Name: match[1],
|
Name: match[1],
|
||||||
Args: args,
|
ArgMap: argMap,
|
||||||
|
ArgList: argList,
|
||||||
File: file,
|
File: file,
|
||||||
Raw: match[0],
|
Raw: match[0],
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,32 @@ import (
|
||||||
"github.com/arduino/go-paths-helper"
|
"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) {
|
func TestNewOption(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -28,12 +54,13 @@ func TestNewOption(t *testing.T) {
|
||||||
},
|
},
|
||||||
want: &Option{
|
want: &Option{
|
||||||
Name: "dbus",
|
Name: "dbus",
|
||||||
Args: map[string]string{
|
ArgMap: map[string]string{
|
||||||
"bus": "system",
|
"bus": "system",
|
||||||
"name": "org.gnome.DisplayManager",
|
"name": "org.gnome.DisplayManager",
|
||||||
"own": "",
|
"own": "",
|
||||||
},
|
},
|
||||||
File: paths.New(""),
|
ArgList: []string{"own", "bus=system", "name=org.gnome.DisplayManager"},
|
||||||
|
File: nil,
|
||||||
Raw: " #aa:dbus own bus=system name=org.gnome.DisplayManager",
|
Raw: " #aa:dbus own bus=system name=org.gnome.DisplayManager",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -47,8 +74,9 @@ func TestNewOption(t *testing.T) {
|
||||||
},
|
},
|
||||||
want: &Option{
|
want: &Option{
|
||||||
Name: "only",
|
Name: "only",
|
||||||
Args: map[string]string{"opensuse": ""},
|
ArgMap: map[string]string{"opensuse": ""},
|
||||||
File: paths.New(""),
|
ArgList: []string{"opensuse"},
|
||||||
|
File: nil,
|
||||||
Raw: " #aa:only opensuse",
|
Raw: " #aa:only opensuse",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -50,21 +50,13 @@ func setInterfaces(rules map[string]string) []string {
|
||||||
|
|
||||||
func (d Dbus) Apply(opt *Option, profile string) string {
|
func (d Dbus) Apply(opt *Option, profile string) string {
|
||||||
var p *aa.AppArmorProfile
|
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 {
|
switch action {
|
||||||
case "own":
|
case "own":
|
||||||
p = d.own(opt.Args)
|
p = d.own(opt.ArgMap)
|
||||||
case "talk":
|
case "talk":
|
||||||
p = d.talk(opt.Args)
|
p = d.talk(opt.ArgMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
generatedDbus := p.String()
|
generatedDbus := p.String()
|
||||||
|
@ -74,22 +66,31 @@ func (d Dbus) Apply(opt *Option, profile string) string {
|
||||||
return profile
|
return profile
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d Dbus) sanityCheck(action string, opt *Option) {
|
func (d Dbus) sanityCheck(opt *Option) string {
|
||||||
if _, present := opt.Args["name"]; !present {
|
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))
|
panic(fmt.Sprintf("Missing name for 'dbus: %s' in %s", action, opt.File))
|
||||||
}
|
}
|
||||||
if _, present := opt.Args["bus"]; !present {
|
if _, present := opt.ArgMap["bus"]; !present {
|
||||||
panic(fmt.Sprintf("Missing bus for '%s' in %s", opt.Args["name"], opt.File))
|
panic(fmt.Sprintf("Missing bus for '%s' in %s", opt.ArgMap["name"], opt.File))
|
||||||
}
|
}
|
||||||
if _, present := opt.Args["label"]; !present && action == "talk" {
|
if _, present := opt.ArgMap["label"]; !present && action == "talk" {
|
||||||
panic(fmt.Sprintf("Missing label for '%s' in %s", opt.Args["name"], opt.File))
|
panic(fmt.Sprintf("Missing label for '%s' in %s", opt.ArgMap["name"], opt.File))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set default values
|
// Set default values
|
||||||
if _, present := opt.Args["path"]; !present {
|
if _, present := opt.ArgMap["path"]; !present {
|
||||||
opt.Args["path"] = "/" + strings.Replace(opt.Args["name"], ".", "/", -1) + "{,/**}"
|
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 {
|
func (d Dbus) own(rules map[string]string) *aa.AppArmorProfile {
|
||||||
|
|
|
@ -43,11 +43,12 @@ func TestDbus_Apply(t *testing.T) {
|
||||||
name: "own",
|
name: "own",
|
||||||
opt: &Option{
|
opt: &Option{
|
||||||
Name: "dbus",
|
Name: "dbus",
|
||||||
Args: map[string]string{
|
ArgMap: map[string]string{
|
||||||
"bus": "system",
|
"bus": "system",
|
||||||
"name": "org.freedesktop.systemd1",
|
"name": "org.freedesktop.systemd1",
|
||||||
"own": "",
|
"own": "",
|
||||||
},
|
},
|
||||||
|
ArgList: []string{"own", "bus=system", "name=org.freedesktop.systemd1"},
|
||||||
File: nil,
|
File: nil,
|
||||||
Raw: " #aa:dbus own bus=system name=org.freedesktop.systemd1",
|
Raw: " #aa:dbus own bus=system name=org.freedesktop.systemd1",
|
||||||
},
|
},
|
||||||
|
@ -58,12 +59,13 @@ func TestDbus_Apply(t *testing.T) {
|
||||||
name: "own-interface",
|
name: "own-interface",
|
||||||
opt: &Option{
|
opt: &Option{
|
||||||
Name: "dbus",
|
Name: "dbus",
|
||||||
Args: map[string]string{
|
ArgMap: map[string]string{
|
||||||
"bus": "session",
|
"bus": "session",
|
||||||
"name": "com.rastersoft.dingextension",
|
"name": "com.rastersoft.dingextension",
|
||||||
"interface": "org.gtk.Actions",
|
"interface": "org.gtk.Actions",
|
||||||
"own": "",
|
"own": "",
|
||||||
},
|
},
|
||||||
|
ArgList: []string{"own", "bus=session", "name=com.rastersoft.dingextension", "interface=org.gtk.Actions"},
|
||||||
File: nil,
|
File: nil,
|
||||||
Raw: " #aa:dbus own bus=session name=com.rastersoft.dingextension interface=org.gtk.Actions",
|
Raw: " #aa:dbus own bus=session name=com.rastersoft.dingextension interface=org.gtk.Actions",
|
||||||
},
|
},
|
||||||
|
@ -102,12 +104,13 @@ func TestDbus_Apply(t *testing.T) {
|
||||||
name: "talk",
|
name: "talk",
|
||||||
opt: &Option{
|
opt: &Option{
|
||||||
Name: "dbus",
|
Name: "dbus",
|
||||||
Args: map[string]string{
|
ArgMap: map[string]string{
|
||||||
"bus": "system",
|
"bus": "system",
|
||||||
"name": "org.freedesktop.Accounts",
|
"name": "org.freedesktop.Accounts",
|
||||||
"label": "accounts-daemon",
|
"label": "accounts-daemon",
|
||||||
"talk": "",
|
"talk": "",
|
||||||
},
|
},
|
||||||
|
ArgList: []string{"talk", "bus=system", "name=org.freedesktop.Accounts", "label=accounts-daemon"},
|
||||||
File: nil,
|
File: nil,
|
||||||
Raw: " #aa:dbus talk bus=system name=org.freedesktop.Accounts label=accounts-daemon",
|
Raw: " #aa:dbus talk bus=system name=org.freedesktop.Accounts label=accounts-daemon",
|
||||||
},
|
},
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/roddhjav/apparmor.d/pkg/aa"
|
"github.com/roddhjav/apparmor.d/pkg/aa"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Exec struct {
|
type Exec struct {
|
||||||
|
@ -26,16 +27,14 @@ func init() {
|
||||||
func (d Exec) Apply(opt *Option, profile string) string {
|
func (d Exec) Apply(opt *Option, profile string) string {
|
||||||
transition := "Px"
|
transition := "Px"
|
||||||
transitions := []string{"P", "U", "p", "u", "PU", "pu"}
|
transitions := []string{"P", "U", "p", "u", "PU", "pu"}
|
||||||
for _, t := range transitions {
|
t := opt.ArgList[0]
|
||||||
if _, present := opt.Args[t]; present {
|
if slices.Contains(transitions, t) {
|
||||||
transition = t + "x"
|
transition = t + "x"
|
||||||
delete(opt.Args, t)
|
delete(opt.ArgMap, t)
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p := &aa.AppArmorProfile{}
|
p := &aa.AppArmorProfile{}
|
||||||
for name := range opt.Args {
|
for name := range opt.ArgMap {
|
||||||
content, err := rootApparmord.Join(name).ReadFile()
|
content, err := rootApparmord.Join(name).ReadFile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
@ -23,7 +23,8 @@ func TestExec_Apply(t *testing.T) {
|
||||||
rootApparmord: paths.New("../../../apparmor.d/groups/kde/"),
|
rootApparmord: paths.New("../../../apparmor.d/groups/kde/"),
|
||||||
opt: &Option{
|
opt: &Option{
|
||||||
Name: "exec",
|
Name: "exec",
|
||||||
Args: map[string]string{"DiscoverNotifier": ""},
|
ArgMap: map[string]string{"DiscoverNotifier": ""},
|
||||||
|
ArgList: []string{"DiscoverNotifier"},
|
||||||
File: nil,
|
File: nil,
|
||||||
Raw: " #aa:exec DiscoverNotifier",
|
Raw: " #aa:exec DiscoverNotifier",
|
||||||
},
|
},
|
||||||
|
@ -36,7 +37,8 @@ func TestExec_Apply(t *testing.T) {
|
||||||
rootApparmord: paths.New("../../../apparmor.d/groups/freedesktop/"),
|
rootApparmord: paths.New("../../../apparmor.d/groups/freedesktop/"),
|
||||||
opt: &Option{
|
opt: &Option{
|
||||||
Name: "exec",
|
Name: "exec",
|
||||||
Args: map[string]string{"U": "", "polkit-agent-helper": ""},
|
ArgMap: map[string]string{"U": "", "polkit-agent-helper": ""},
|
||||||
|
ArgList: []string{"U", "polkit-agent-helper"},
|
||||||
File: nil,
|
File: nil,
|
||||||
Raw: " #aa:exec U polkit-agent-helper",
|
Raw: " #aa:exec U polkit-agent-helper",
|
||||||
},
|
},
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
oss "github.com/roddhjav/apparmor.d/pkg/os"
|
oss "github.com/roddhjav/apparmor.d/pkg/os"
|
||||||
"golang.org/x/exp/maps"
|
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -37,7 +36,7 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterRuleForUs(opt *Option) bool {
|
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 {
|
func filter(only bool, opt *Option, profile string) string {
|
||||||
|
|
|
@ -25,7 +25,8 @@ func TestFilterOnly_Apply(t *testing.T) {
|
||||||
family: "apt",
|
family: "apt",
|
||||||
opt: &Option{
|
opt: &Option{
|
||||||
Name: "only",
|
Name: "only",
|
||||||
Args: map[string]string{"apt": ""},
|
ArgMap: map[string]string{"apt": ""},
|
||||||
|
ArgList: []string{"apt"},
|
||||||
File: nil,
|
File: nil,
|
||||||
Raw: " @{bin}/arch-audit rPx, #aa:only apt",
|
Raw: " @{bin}/arch-audit rPx, #aa:only apt",
|
||||||
},
|
},
|
||||||
|
@ -38,7 +39,8 @@ func TestFilterOnly_Apply(t *testing.T) {
|
||||||
family: "pacman",
|
family: "pacman",
|
||||||
opt: &Option{
|
opt: &Option{
|
||||||
Name: "only",
|
Name: "only",
|
||||||
Args: map[string]string{"zypper": ""},
|
ArgMap: map[string]string{"zypper": ""},
|
||||||
|
ArgList: []string{"zypper"},
|
||||||
File: nil,
|
File: nil,
|
||||||
Raw: " #aa:only zypper",
|
Raw: " #aa:only zypper",
|
||||||
},
|
},
|
||||||
|
@ -99,7 +101,8 @@ func TestFilterExclude_Apply(t *testing.T) {
|
||||||
family: "apt",
|
family: "apt",
|
||||||
opt: &Option{
|
opt: &Option{
|
||||||
Name: "exclude",
|
Name: "exclude",
|
||||||
Args: map[string]string{"debian": ""},
|
ArgMap: map[string]string{"debian": ""},
|
||||||
|
ArgList: []string{"debian"},
|
||||||
File: nil,
|
File: nil,
|
||||||
Raw: " @{bin}/dpkg rPx -> child-dpkg, #aa:exclude debian",
|
Raw: " @{bin}/dpkg rPx -> child-dpkg, #aa:exclude debian",
|
||||||
},
|
},
|
||||||
|
@ -112,7 +115,8 @@ func TestFilterExclude_Apply(t *testing.T) {
|
||||||
family: "apt",
|
family: "apt",
|
||||||
opt: &Option{
|
opt: &Option{
|
||||||
Name: "exclude",
|
Name: "exclude",
|
||||||
Args: map[string]string{"debian": ""},
|
ArgMap: map[string]string{"debian": ""},
|
||||||
|
ArgList: []string{"debian"},
|
||||||
File: nil,
|
File: nil,
|
||||||
Raw: " @{bin}/dpkg rPx -> child-dpkg, #aa:exclude debian",
|
Raw: " @{bin}/dpkg rPx -> child-dpkg, #aa:exclude debian",
|
||||||
},
|
},
|
||||||
|
|
|
@ -41,7 +41,7 @@ func init() {
|
||||||
|
|
||||||
func (s Stack) Apply(opt *Option, profile string) string {
|
func (s Stack) Apply(opt *Option, profile string) string {
|
||||||
res := ""
|
res := ""
|
||||||
for name := range opt.Args {
|
for name := range opt.ArgMap {
|
||||||
tmp, err := rootApparmord.Join(name).ReadFile()
|
tmp, err := rootApparmord.Join(name).ReadFile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
@ -23,7 +23,8 @@ func TestStack_Apply(t *testing.T) {
|
||||||
rootApparmord: paths.New("../../../apparmor.d/groups/freedesktop/"),
|
rootApparmord: paths.New("../../../apparmor.d/groups/freedesktop/"),
|
||||||
opt: &Option{
|
opt: &Option{
|
||||||
Name: "stack",
|
Name: "stack",
|
||||||
Args: map[string]string{"plymouth": ""},
|
ArgMap: map[string]string{"plymouth": ""},
|
||||||
|
ArgList: []string{"plymouth"},
|
||||||
File: nil,
|
File: nil,
|
||||||
Raw: " #aa:stack plymouth",
|
Raw: " #aa:stack plymouth",
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue