Skip to content

Commit

Permalink
Allow rootless containers to use AppArmor profiles
Browse files Browse the repository at this point in the history
Previously, Podman would print an error if you tried to run a container
with an AppArmor profile as a non-root user, e.g.

    $ podman run --security-opt apparmor=my-profile ...
    Error: Apparmor profile "my-profile" specified, but Apparmor is not
    enabled on this system

In fact, the only thing that Podman needs root privileges for is reading
/sys/kernel/security/apparmor/profiles to see if the profile is already
loaded, which isn't strictly necessary.

This commit removes the 'IsLoaded()' check that occurs when you try to
specify an AppArmor profile as a non-root user, as well as the other
checks in pkg/apparmor/ for whether the program is running as UID 0. The
check for whether the AppArmor profile is loaded should now be deferred
to the container runtime at the point where it writes to either
/proc/self/attr/exec or /proc/self/attr/apparmor/exec, since the write
should fail if the profile is not loaded.

Closes #958.

Signed-off-by: kernelmethod <[email protected]>
  • Loading branch information
kernelmethod committed Mar 11, 2022
1 parent ac6671d commit 55d217f
Show file tree
Hide file tree
Showing 3 changed files with 4 additions and 36 deletions.
2 changes: 0 additions & 2 deletions pkg/apparmor/apparmor.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,4 @@ const (
var (
// 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")
)
35 changes: 4 additions & 31 deletions pkg/apparmor/apparmor_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"text/template"

"github.com/containers/common/pkg/apparmor/internal/supported"
"github.com/containers/storage/pkg/unshare"
runcaa "github.com/opencontainers/runc/libcontainer/apparmor"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -77,10 +76,6 @@ 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 unshare.IsRootless() {
return ErrApparmorRootless
}

p := profileData{
Name: name,
}
Expand Down Expand Up @@ -137,12 +132,9 @@ func DefaultContent(name string) ([]byte, error) {
}

// IsLoaded checks if a profile with the given name has been loaded into the
// kernel.
// kernel. This function checks for the existence of a profile by reading
// /sys/kernel/security/apparmor/profiles, and hence requires root permissions.
func IsLoaded(name string) (bool, error) {
if name != "" && unshare.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) {
Expand Down Expand Up @@ -238,25 +230,13 @@ func parseAAParserVersion(output string) (int, error) {
// 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.
// default AppArmor profile. If it's a default profile, return
// DefaultLipodProfilePrefix, otherwise the specified one.
func CheckProfileAndLoadDefault(name string) (string, error) {
if name == "unconfined" {
return name, nil
}

// AppArmor is not supported in rootless mode as it requires root
// privileges. Return an error in case a specific profile is specified.
if unshare.IsRootless() {
if name != "" {
return "", errors.Wrapf(ErrApparmorRootless, "cannot load AppArmor profile %q", name)
} else {
logrus.Debug("Skipping loading default AppArmor profile (rootless mode)")
return "", nil
}
}

// Check if AppArmor is disabled and error out if a profile is to be set.
if !runcaa.IsEnabled() {
if name == "" {
Expand All @@ -271,13 +251,6 @@ func CheckProfileAndLoadDefault(name string) (string, error) {
} else if !strings.HasPrefix(name, ProfilePrefix) {
// If the specified name is not a default one, ignore it and return the
// name.
isLoaded, err := IsLoaded(name)
if err != nil {
return "", errors.Wrapf(err, "verify if profile %s is loaded", name)
}
if !isLoaded {
return "", errors.Errorf("AppArmor profile %q specified but not loaded", name)
}
return name, nil
}

Expand Down
3 changes: 0 additions & 3 deletions pkg/apparmor/internal/supported/supported.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,6 @@ func NewAppArmorVerifier() *ApparmorVerifier {
// - 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")
}
Expand Down

0 comments on commit 55d217f

Please sign in to comment.