-
Notifications
You must be signed in to change notification settings - Fork 187
/
supported.go
113 lines (94 loc) · 2.91 KB
/
supported.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package supported
import (
"os"
"os/exec"
"path/filepath"
"sync"
"github.com/containers/storage/pkg/unshare"
runcaa "github.com/opencontainers/runc/libcontainer/apparmor"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -generate
// ApparmorVerifier is the global struct for verifying if AppAmor is available
// on the system.
type ApparmorVerifier struct {
impl verifierImpl
parserBinaryPath string
}
var (
singleton *ApparmorVerifier
once sync.Once
)
// NewAppArmorVerifier can be used to retrieve a new ApparmorVerifier instance.
func NewAppArmorVerifier() *ApparmorVerifier {
once.Do(func() {
singleton = &ApparmorVerifier{impl: &defaultVerifier{}}
})
return singleton
}
// IsSupported returns nil if AppAmor is supported by the host system.
// The method will error if:
// - the process runs in rootless mode
// - AppArmor is disabled by the host system
// - the `apparmor_parser` binary is not discoverable
func (a *ApparmorVerifier) IsSupported() error {
if a.impl.UnshareIsRootless() {
return errors.New("AppAmor is not supported on rootless containers")
}
if !a.impl.RuncIsEnabled() {
return errors.New("AppArmor not supported by the host system")
}
_, err := a.FindAppArmorParserBinary()
return err
}
// FindAppArmorParserBinary returns the `apparmor_parser` binary either from
// `/sbin` or from `$PATH`. It returns an error if the binary could not be
// found.
func (a *ApparmorVerifier) FindAppArmorParserBinary() (string, error) {
// Use the memoized path if available
if a.parserBinaryPath != "" {
logrus.Debugf("Using %s binary", a.parserBinaryPath)
return a.parserBinaryPath, nil
}
const (
binary = "apparmor_parser"
sbin = "/sbin"
)
// `/sbin` is not always in `$PATH`, so we check it explicitly
sbinBinaryPath := filepath.Join(sbin, binary)
if _, err := a.impl.OsStat(sbinBinaryPath); err == nil {
logrus.Debugf("Found %s binary in %s", binary, sbinBinaryPath)
a.parserBinaryPath = sbinBinaryPath
return sbinBinaryPath, nil
}
// Fallback to checking $PATH
if path, err := a.impl.ExecLookPath(binary); err == nil {
logrus.Debugf("Found %s binary in %s", binary, path)
a.parserBinaryPath = path
return path, nil
}
return "", errors.Errorf(
"%s binary neither found in %s nor $PATH", binary, sbin,
)
}
//counterfeiter:generate . verifierImpl
type verifierImpl interface {
UnshareIsRootless() bool
RuncIsEnabled() bool
OsStat(name string) (os.FileInfo, error)
ExecLookPath(file string) (string, error)
}
type defaultVerifier struct{}
func (d *defaultVerifier) UnshareIsRootless() bool {
return unshare.IsRootless()
}
func (d *defaultVerifier) RuncIsEnabled() bool {
return runcaa.IsEnabled()
}
func (d *defaultVerifier) OsStat(name string) (os.FileInfo, error) {
return os.Stat(name)
}
func (d *defaultVerifier) ExecLookPath(file string) (string, error) {
return exec.LookPath(file)
}