summaryrefslogtreecommitdiff
path: root/pkg/apparmor
diff options
context:
space:
mode:
authorValentin Rothberg <rothberg@redhat.com>2019-01-09 14:54:58 +0100
committerValentin Rothberg <rothberg@redhat.com>2019-01-09 22:18:11 +0100
commitedb285d17675061832aceaf72021b87aba149438 (patch)
tree332f020dfc754a2a2ecaa80bd2891392c81305f1 /pkg/apparmor
parentc37f73159609b203545ca6fe54c86b9deacfca21 (diff)
downloadpodman-edb285d17675061832aceaf72021b87aba149438.tar.gz
podman-edb285d17675061832aceaf72021b87aba149438.tar.bz2
podman-edb285d17675061832aceaf72021b87aba149438.zip
apparmor: apply default profile at container initialization
Apply the default AppArmor profile at container initialization to cover all possible code paths (i.e., podman-{start,run}) before executing the runtime. This allows moving most of the logic into pkg/apparmor. Also make the loading and application of the default AppArmor profile versio-indepenent by checking for the `libpod-default-` prefix and over-writing the profile in the run-time spec if needed. The intitial run-time spec of the container differs a bit from the applied one when having started the container, which results in displaying a potentially outdated AppArmor profile when inspecting a container. To fix that, load the container config from the file system if present and use it to display the data. Fixes: #2107 Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
Diffstat (limited to 'pkg/apparmor')
-rw-r--r--pkg/apparmor/apparmor.go7
-rw-r--r--pkg/apparmor/apparmor_linux.go66
-rw-r--r--pkg/apparmor/apparmor_unsupported.go16
3 files changed, 83 insertions, 6 deletions
diff --git a/pkg/apparmor/apparmor.go b/pkg/apparmor/apparmor.go
index 8b9f99477..45c029c07 100644
--- a/pkg/apparmor/apparmor.go
+++ b/pkg/apparmor/apparmor.go
@@ -2,11 +2,16 @@ package apparmor
import (
"errors"
+ libpodVersion "github.com/containers/libpod/version"
)
var (
+ // DefaultLipodProfilePrefix is used for version-independent presence checks.
+ DefaultLipodProfilePrefix = "libpod-default" + "-"
// DefaultLibpodProfile is the name of default libpod AppArmor profile.
- DefaultLibpodProfile = "libpod-default"
+ DefaultLibpodProfile = DefaultLipodProfilePrefix + libpodVersion.Version
// ErrApparmorUnsupported indicates that AppArmor support is not supported.
ErrApparmorUnsupported = errors.New("AppArmor is not supported")
+ // ErrApparmorRootless indicates that AppArmor support is not supported in rootless mode.
+ ErrApparmorRootless = errors.New("AppArmor is not supported in rootless mode")
)
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
+}
diff --git a/pkg/apparmor/apparmor_unsupported.go b/pkg/apparmor/apparmor_unsupported.go
index df1336b07..b2b4de5f5 100644
--- a/pkg/apparmor/apparmor_unsupported.go
+++ b/pkg/apparmor/apparmor_unsupported.go
@@ -2,19 +2,25 @@
package apparmor
-// IsEnabled returns true if AppArmor is enabled on the host.
+// IsEnabled dummy.
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'.
+// InstallDefault dummy.
func InstallDefault(name string) error {
return ErrApparmorUnsupported
}
-// IsLoaded checks if a profile with the given name has been loaded into the
-// kernel.
+// IsLoaded dummy.
func IsLoaded(name string) (bool, error) {
return false, ErrApparmorUnsupported
}
+
+// CheckProfileAndLoadDefault dummy.
+func CheckProfileAndLoadDefault(name string) (string, error) {
+ if name == "" {
+ return "", nil
+ }
+ return "", ErrApparmorUnsupported
+}