2023-04-19 18:40:40 +02:00
|
|
|
// apparmor.d - Full set of apparmor profiles
|
2024-02-07 00:16:21 +01:00
|
|
|
// Copyright (C) 2023-2024 Alexandre Pujol <alexandre@pujol.io>
|
2023-04-19 18:40:40 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
|
|
|
|
|
|
|
package aa
|
|
|
|
|
|
|
|
import (
|
|
|
|
"reflect"
|
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
2024-04-15 00:58:34 +02:00
|
|
|
// TODO: space in variable need to be tested.
|
|
|
|
// @{name} = "Mullvad VPN"
|
|
|
|
// profile mullvad-gui /{opt/"Mullvad/mullvad-gui,opt/VPN"/mullvad-gui,mullvad-gui} flags=(attach_disconnected,complain) {
|
|
|
|
|
2023-08-18 00:00:52 +02:00
|
|
|
func TestDefaultTunables(t *testing.T) {
|
2023-04-19 18:40:40 +02:00
|
|
|
tests := []struct {
|
2023-07-25 23:01:07 +02:00
|
|
|
name string
|
|
|
|
want *AppArmorProfile
|
2023-04-19 18:40:40 +02:00
|
|
|
}{
|
|
|
|
{
|
2023-07-25 23:01:07 +02:00
|
|
|
name: "aa",
|
2023-04-19 18:40:40 +02:00
|
|
|
want: &AppArmorProfile{
|
2023-08-18 00:00:52 +02:00
|
|
|
Preamble: Preamble{
|
2024-04-15 00:58:34 +02:00
|
|
|
Variables: []*Variable{
|
|
|
|
{Name: "bin", Values: []string{"/{,usr/}{,s}bin"}},
|
|
|
|
{Name: "lib", Values: []string{"/{,usr/}lib{,exec,32,64}"}},
|
|
|
|
{Name: "multiarch", Values: []string{"*-linux-gnu*"}},
|
|
|
|
{Name: "HOME", Values: []string{"/home/*"}},
|
|
|
|
{Name: "user_share_dirs", Values: []string{"/home/*/.local/share"}},
|
|
|
|
{Name: "etc_ro", Values: []string{"/{,usr/}etc/"}},
|
|
|
|
{Name: "int", Values: []string{"[0-9]{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}{[0-9],}"}},
|
2023-08-18 00:00:52 +02:00
|
|
|
},
|
2023-04-19 18:40:40 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
2023-08-18 00:00:52 +02:00
|
|
|
if got := DefaultTunables(); !reflect.DeepEqual(got, tt.want) {
|
2024-04-06 00:34:44 +02:00
|
|
|
t.Errorf("DefaultTunables() = %v, want %v", got, tt.want)
|
2023-04-19 18:40:40 +02:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAppArmorProfile_ParseVariables(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
content string
|
2024-04-15 00:58:34 +02:00
|
|
|
want []*Variable
|
2023-04-19 18:40:40 +02:00
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "firefox",
|
|
|
|
content: `@{firefox_name} = firefox{,-esr,-bin}
|
|
|
|
@{firefox_lib_dirs} = /{usr/,}lib{,32,64}/@{firefox_name} /opt/@{firefox_name}
|
|
|
|
@{firefox_config_dirs} = @{HOME}/.mozilla/
|
|
|
|
@{firefox_cache_dirs} = @{user_cache_dirs}/mozilla/
|
|
|
|
@{exec_path} = /{usr/,}bin/@{firefox_name} @{firefox_lib_dirs}/@{firefox_name}
|
|
|
|
`,
|
2024-04-15 00:58:34 +02:00
|
|
|
want: []*Variable{
|
|
|
|
{Name: "firefox_name", Values: []string{"firefox{,-esr,-bin}"}},
|
|
|
|
{Name: "firefox_lib_dirs", Values: []string{"/{usr/,}lib{,32,64}/@{firefox_name}", "/opt/@{firefox_name}"}},
|
|
|
|
{Name: "firefox_config_dirs", Values: []string{"@{HOME}/.mozilla/"}},
|
|
|
|
{Name: "firefox_cache_dirs", Values: []string{"@{user_cache_dirs}/mozilla/"}},
|
|
|
|
{Name: "exec_path", Values: []string{"/{usr/,}bin/@{firefox_name}", "@{firefox_lib_dirs}/@{firefox_name}"}},
|
2023-04-19 18:40:40 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "xorg",
|
|
|
|
content: `@{exec_path} = /{usr/,}bin/X
|
|
|
|
@{exec_path} += /{usr/,}bin/Xorg{,.bin}
|
|
|
|
@{exec_path} += /{usr/,}lib/Xorg{,.wrap}
|
|
|
|
@{exec_path} += /{usr/,}lib/xorg/Xorg{,.wrap}`,
|
2024-04-15 00:58:34 +02:00
|
|
|
want: []*Variable{
|
|
|
|
{Name: "exec_path", Values: []string{
|
2023-04-19 18:40:40 +02:00
|
|
|
"/{usr/,}bin/X",
|
|
|
|
"/{usr/,}bin/Xorg{,.bin}",
|
|
|
|
"/{usr/,}lib/Xorg{,.wrap}",
|
2023-08-18 00:00:52 +02:00
|
|
|
"/{usr/,}lib/xorg/Xorg{,.wrap}"},
|
2023-04-19 18:40:40 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2023-09-25 01:13:18 +02:00
|
|
|
{
|
|
|
|
name: "snapd",
|
|
|
|
content: `@{lib_dirs} = @{lib}/ /snap/snapd/@{int}@{lib}
|
|
|
|
@{exec_path} = @{lib_dirs}/snapd/snapd`,
|
2024-04-15 00:58:34 +02:00
|
|
|
want: []*Variable{
|
|
|
|
{Name: "lib_dirs", Values: []string{"@{lib}/", "/snap/snapd/@{int}@{lib}"}},
|
|
|
|
{Name: "exec_path", Values: []string{"@{lib_dirs}/snapd/snapd"}},
|
2023-09-25 01:13:18 +02:00
|
|
|
},
|
|
|
|
},
|
2023-04-19 18:40:40 +02:00
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
2023-08-18 00:00:52 +02:00
|
|
|
p := NewAppArmorProfile()
|
2023-07-25 23:01:07 +02:00
|
|
|
p.ParseVariables(tt.content)
|
2023-04-19 18:40:40 +02:00
|
|
|
if !reflect.DeepEqual(p.Variables, tt.want) {
|
|
|
|
t.Errorf("AppArmorProfile.ParseVariables() = %v, want %v", p.Variables, tt.want)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-24 13:51:16 +02:00
|
|
|
func TestAppArmorProfile_resolve(t *testing.T) {
|
|
|
|
tests := []struct {
|
2023-08-18 00:00:52 +02:00
|
|
|
name string
|
|
|
|
input string
|
|
|
|
want []string
|
2023-04-24 13:51:16 +02:00
|
|
|
}{
|
2024-04-15 00:58:34 +02:00
|
|
|
{
|
|
|
|
name: "default",
|
|
|
|
input: "@{etc_ro}",
|
|
|
|
want: []string{"/{,usr/}etc/"},
|
|
|
|
},
|
2023-04-24 13:51:16 +02:00
|
|
|
{
|
2023-08-18 00:00:52 +02:00
|
|
|
name: "empty",
|
|
|
|
input: "@{}",
|
|
|
|
want: []string{"@{}"},
|
2023-04-24 13:51:16 +02:00
|
|
|
},
|
2024-04-15 00:58:34 +02:00
|
|
|
{
|
|
|
|
name: "nil",
|
|
|
|
input: "@{foo}",
|
|
|
|
want: []string{},
|
|
|
|
},
|
2023-04-24 13:51:16 +02:00
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
2023-08-18 00:00:52 +02:00
|
|
|
p := DefaultTunables()
|
2023-04-24 13:51:16 +02:00
|
|
|
if got := p.resolve(tt.input); !reflect.DeepEqual(got, tt.want) {
|
|
|
|
t.Errorf("AppArmorProfile.resolve() = %v, want %v", got, tt.want)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-19 18:40:40 +02:00
|
|
|
func TestAppArmorProfile_ResolveAttachments(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
2024-04-15 00:58:34 +02:00
|
|
|
variables []*Variable
|
2023-04-19 18:40:40 +02:00
|
|
|
want []string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "firefox",
|
2024-04-15 00:58:34 +02:00
|
|
|
variables: []*Variable{
|
|
|
|
{Name: "firefox_name", Values: []string{"firefox{,-esr,-bin}"}},
|
|
|
|
{Name: "firefox_lib_dirs", Values: []string{"/{usr/,}/lib{,32,64}/@{firefox_name}", "/opt/@{firefox_name}"}},
|
|
|
|
{Name: "exec_path", Values: []string{"/{usr/,}bin/@{firefox_name}", "@{firefox_lib_dirs}/@{firefox_name}"}},
|
2023-04-19 18:40:40 +02:00
|
|
|
},
|
|
|
|
want: []string{
|
|
|
|
"/{usr/,}bin/firefox{,-esr,-bin}",
|
|
|
|
"/{usr/,}/lib{,32,64}/firefox{,-esr,-bin}/firefox{,-esr,-bin}",
|
|
|
|
"/opt/firefox{,-esr,-bin}/firefox{,-esr,-bin}",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "chromium",
|
2024-04-15 00:58:34 +02:00
|
|
|
variables: []*Variable{
|
|
|
|
{Name: "name", Values: []string{"chromium"}},
|
|
|
|
{Name: "lib_dirs", Values: []string{"/{usr/,}lib/@{name}"}},
|
|
|
|
{Name: "exec_path", Values: []string{"@{lib_dirs}/@{name}"}},
|
2023-04-19 18:40:40 +02:00
|
|
|
},
|
|
|
|
want: []string{
|
|
|
|
"/{usr/,}lib/chromium/chromium",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "geoclue",
|
2024-04-15 00:58:34 +02:00
|
|
|
variables: []*Variable{
|
|
|
|
{Name: "libexec", Values: []string{"/{usr/,}libexec"}},
|
|
|
|
{Name: "exec_path", Values: []string{"@{libexec}/geoclue", "@{libexec}/geoclue-2.0/demos/agent"}},
|
2023-04-19 18:40:40 +02:00
|
|
|
},
|
|
|
|
want: []string{
|
|
|
|
"/{usr/,}libexec/geoclue",
|
|
|
|
"/{usr/,}libexec/geoclue-2.0/demos/agent",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "opera",
|
2024-04-15 00:58:34 +02:00
|
|
|
variables: []*Variable{
|
|
|
|
{Name: "multiarch", Values: []string{"*-linux-gnu*"}},
|
|
|
|
{Name: "name", Values: []string{"opera{,-beta,-developer}"}},
|
|
|
|
{Name: "lib_dirs", Values: []string{"/{usr/,}lib/@{multiarch}/@{name}"}},
|
|
|
|
{Name: "exec_path", Values: []string{"@{lib_dirs}/@{name}"}},
|
2023-04-19 18:40:40 +02:00
|
|
|
},
|
|
|
|
want: []string{
|
|
|
|
"/{usr/,}lib/*-linux-gnu*/opera{,-beta,-developer}/opera{,-beta,-developer}",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
2023-08-18 00:00:52 +02:00
|
|
|
p := NewAppArmorProfile()
|
|
|
|
p.Variables = tt.variables
|
2023-04-19 18:40:40 +02:00
|
|
|
p.ResolveAttachments()
|
|
|
|
if !reflect.DeepEqual(p.Attachments, tt.want) {
|
|
|
|
t.Errorf("AppArmorProfile.ResolveAttachments() = %v, want %v", p.Attachments, tt.want)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAppArmorProfile_NestAttachments(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
Attachments []string
|
|
|
|
want string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "firefox",
|
|
|
|
Attachments: []string{
|
|
|
|
"/{usr/,}bin/firefox{,-esr,-bin}",
|
|
|
|
"/{usr/,}lib{,32,64}/firefox{,-esr,-bin}/firefox{,-esr,-bin}",
|
|
|
|
"/opt/firefox{,-esr,-bin}/firefox{,-esr,-bin}",
|
|
|
|
},
|
|
|
|
want: "/{{usr/,}bin/firefox{,-esr,-bin},{usr/,}lib{,32,64}/firefox{,-esr,-bin}/firefox{,-esr,-bin},opt/firefox{,-esr,-bin}/firefox{,-esr,-bin}}",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "geoclue",
|
|
|
|
Attachments: []string{
|
|
|
|
"/{usr/,}libexec/geoclue",
|
|
|
|
"/{usr/,}libexec/geoclue-2.0/demos/agent",
|
|
|
|
},
|
|
|
|
want: "/{{usr/,}libexec/geoclue,{usr/,}libexec/geoclue-2.0/demos/agent}",
|
|
|
|
},
|
2023-04-19 22:48:53 +02:00
|
|
|
{
|
|
|
|
name: "null",
|
|
|
|
Attachments: []string{},
|
|
|
|
want: "",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "empty",
|
|
|
|
Attachments: []string{""},
|
|
|
|
want: "",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "not valid aare",
|
|
|
|
Attachments: []string{"/file", "relative"},
|
|
|
|
want: "/{file,relative}",
|
|
|
|
},
|
2023-04-19 18:40:40 +02:00
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
2023-08-18 00:00:52 +02:00
|
|
|
p := NewAppArmorProfile()
|
|
|
|
p.Attachments = tt.Attachments
|
2023-04-19 18:40:40 +02:00
|
|
|
if got := p.NestAttachments(); got != tt.want {
|
|
|
|
t.Errorf("AppArmorProfile.NestAttachments() = %v, want %v", got, tt.want)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|