AppArmor: runtime check if it's enabled on the host

Check at runtime if AppArmor is enabled on the host.

Signed-off-by: Valentin Rothberg <vrothberg@suse.com>

Closes: #1128
Approved by: mheon
This commit is contained in:
Valentin Rothberg
2018-07-22 17:45:36 +02:00
committed by Atomic Bot
parent 2c11e38b24
commit 8569ed0305
7 changed files with 96 additions and 6 deletions

View File

@ -196,7 +196,7 @@ func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string) error {
}
}
if config.ApparmorProfile == "" {
if config.ApparmorProfile == "" && apparmor.IsEnabled() {
// Unless specified otherwise, make sure that the default AppArmor
// profile is installed. To avoid redundantly loading the profile
// on each invocation, check if it's loaded before installing it.
@ -231,7 +231,11 @@ func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string) error {
logrus.Infof("Sucessfully loaded AppAmor profile '%s'", profile)
config.ApparmorProfile = profile
}
} else {
} else if config.ApparmorProfile != "" {
if !apparmor.IsEnabled() {
return fmt.Errorf("profile specified but AppArmor is disabled on the host")
}
isLoaded, err := apparmor.IsLoaded(config.ApparmorProfile)
if err != nil {
switch err {

View File

@ -1,7 +1,4 @@
#!/bin/bash
if pkg-config libapparmor 2> /dev/null ; then
# Travis CI does not support AppArmor, so we cannot run tests there.
if [ -z "$TRAVIS" ]; then
echo apparmor
fi
echo apparmor
fi

View File

@ -12,6 +12,9 @@ type versionExpected struct {
}
func TestParseVersion(t *testing.T) {
if !IsEnabled() {
t.Skip("AppArmor disabled: skipping tests")
}
versions := []versionExpected{
{
output: `AppArmor parser version 2.10

View File

@ -10,8 +10,15 @@ import (
"path"
"strings"
"text/template"
runcaa "github.com/opencontainers/runc/libcontainer/apparmor"
)
// IsEnabled returns true if AppArmor is enabled on the host.
func IsEnabled() bool {
return runcaa.IsEnabled()
}
// profileData holds information about the given profile for generation.
type profileData struct {
// Name is profile name.

View File

@ -2,6 +2,11 @@
package apparmor
// IsEnabled returns true if AppArmor is enabled on the host.
func IsEnabled() bool {
return false
}
// InstallDefault generates a default profile in a temp directory determined by
// os.TempDir(), then loads the profile into the kernel using 'apparmor_parser'.
func InstallDefault(name string) error {

View File

@ -0,0 +1,54 @@
// +build apparmor,linux
package apparmor
import (
"fmt"
"io/ioutil"
"os"
)
// IsEnabled returns true if apparmor is enabled for the host.
func IsEnabled() bool {
if _, err := os.Stat("/sys/kernel/security/apparmor"); err == nil && os.Getenv("container") == "" {
if _, err = os.Stat("/sbin/apparmor_parser"); err == nil {
buf, err := ioutil.ReadFile("/sys/module/apparmor/parameters/enabled")
return err == nil && len(buf) > 1 && buf[0] == 'Y'
}
}
return false
}
func setprocattr(attr, value string) error {
// Under AppArmor you can only change your own attr, so use /proc/self/
// instead of /proc/<tid>/ like libapparmor does
path := fmt.Sprintf("/proc/self/attr/%s", attr)
f, err := os.OpenFile(path, os.O_WRONLY, 0)
if err != nil {
return err
}
defer f.Close()
_, err = fmt.Fprintf(f, "%s", value)
return err
}
// changeOnExec reimplements aa_change_onexec from libapparmor in Go
func changeOnExec(name string) error {
value := "exec " + name
if err := setprocattr("exec", value); err != nil {
return fmt.Errorf("apparmor failed to apply profile: %s", err)
}
return nil
}
// ApplyProfile will apply the profile with the specified name to the process after
// the next exec.
func ApplyProfile(name string) error {
if name == "" {
return nil
}
return changeOnExec(name)
}

View File

@ -0,0 +1,20 @@
// +build !apparmor !linux
package apparmor
import (
"errors"
)
var ErrApparmorNotEnabled = errors.New("apparmor: config provided but apparmor not supported")
func IsEnabled() bool {
return false
}
func ApplyProfile(name string) error {
if name != "" {
return ErrApparmorNotEnabled
}
return nil
}