diff options
Diffstat (limited to 'pkg/apparmor/apparmor_linux.go')
-rw-r--r-- | pkg/apparmor/apparmor_linux.go | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/pkg/apparmor/apparmor_linux.go b/pkg/apparmor/apparmor_linux.go index b0e3ca0fd..0787b3fa5 100644 --- a/pkg/apparmor/apparmor_linux.go +++ b/pkg/apparmor/apparmor_linux.go @@ -13,7 +13,10 @@ import ( "strings" "text/template" + "github.com/containers/libpod/pkg/rootless" runcaa "github.com/opencontainers/runc/libcontainer/apparmor" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) // profileDirectory is the file store for apparmor profiles and macros. @@ -21,6 +24,9 @@ var profileDirectory = "/etc/apparmor.d" // IsEnabled returns true if AppArmor is enabled on the host. func IsEnabled() bool { + if rootless.IsRootless() { + return false + } return runcaa.IsEnabled() } @@ -71,6 +77,10 @@ func macroExists(m string) bool { // InstallDefault generates a default profile and loads it into the kernel // using 'apparmor_parser'. func InstallDefault(name string) error { + if rootless.IsRootless() { + return ErrApparmorRootless + } + p := profileData{ Name: name, } @@ -97,6 +107,10 @@ func InstallDefault(name string) error { // IsLoaded checks if a profile with the given name has been loaded into the // kernel. func IsLoaded(name string) (bool, error) { + if name != "" && rootless.IsRootless() { + return false, errors.Wrapf(ErrApparmorRootless, "cannot load AppArmor profile %q", name) + } + file, err := os.Open("/sys/kernel/security/apparmor/profiles") if err != nil { if os.IsNotExist(err) { @@ -188,3 +202,55 @@ func parseAAParserVersion(output string) (int, error) { return numericVersion, nil } + +// CheckProfileAndLoadDefault checks if the specified profile is loaded and +// loads the DefaultLibpodProfile if the specified on is prefixed by +// DefaultLipodProfilePrefix. This allows to always load and apply the latest +// default AppArmor profile. Note that AppArmor requires root. If it's a +// default profile, return DefaultLipodProfilePrefix, otherwise the specified +// one. +func CheckProfileAndLoadDefault(name string) (string, error) { + if name == "unconfined" { + return name, nil + } + + if name != "" && rootless.IsRootless() { + return "", errors.Wrapf(ErrApparmorRootless, "cannot load AppArmor profile %q", name) + } + + if name != "" && !runcaa.IsEnabled() { + return "", fmt.Errorf("profile %q specified but AppArmor is disabled on the host", name) + } + + // If the specified name is not empty or is not a default libpod one, + // ignore it and return the name. + if name != "" && !strings.HasPrefix(name, DefaultLipodProfilePrefix) { + isLoaded, err := IsLoaded(name) + if err != nil { + return "", err + } + if !isLoaded { + return "", fmt.Errorf("AppArmor profile %q specified but not loaded") + } + return name, nil + } + + name = DefaultLibpodProfile + // To avoid expensive redundant loads on each invocation, check + // if it's loaded before installing it. + isLoaded, err := IsLoaded(name) + if err != nil { + return "", err + } + if !isLoaded { + err = InstallDefault(name) + if err != nil { + return "", err + } + logrus.Infof("successfully loaded AppAmor profile %q", name) + } else { + logrus.Infof("AppAmor profile %q is already loaded", name) + } + + return name, nil +} |