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:
		
							parent
							
								
									2c11e38b24
								
							
						
					
					
						commit
						8569ed0305
					
				| 
						 | 
				
			
			@ -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 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										54
									
								
								vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										54
									
								
								vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go
								
								
									generated
								
								
									vendored
								
								
									Normal 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)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_disabled.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										20
									
								
								vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_disabled.go
								
								
									generated
								
								
									vendored
								
								
									Normal 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
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue