@@ -15,6 +15,7 @@ import (
1515 "text/template"
1616
1717 "github.com/containers/common/pkg/apparmor/internal/supported"
18+ "github.com/containers/storage/pkg/unshare"
1819 runcaa "github.com/opencontainers/runc/libcontainer/apparmor"
1920 "github.com/pkg/errors"
2021 "github.com/sirupsen/logrus"
@@ -77,6 +78,10 @@ func macroExists(m string) bool {
7778// InstallDefault generates a default profile and loads it into the kernel
7879// using 'apparmor_parser'.
7980func InstallDefault (name string ) error {
81+ if unshare .IsRootless () {
82+ return ErrApparmorRootless
83+ }
84+
8085 p := profileData {
8186 Name : name ,
8287 }
@@ -133,9 +138,12 @@ func DefaultContent(name string) ([]byte, error) {
133138}
134139
135140// IsLoaded checks if a profile with the given name has been loaded into the
136- // kernel. This function checks for the existence of a profile by reading
137- // /sys/kernel/security/apparmor/profiles, and hence requires root permissions.
141+ // kernel.
138142func IsLoaded (name string ) (bool , error ) {
143+ if name != "" && unshare .IsRootless () {
144+ return false , errors .Wrapf (ErrApparmorRootless , "cannot load AppArmor profile %q" , name )
145+ }
146+
139147 file , err := os .Open ("/sys/kernel/security/apparmor/profiles" )
140148 if err != nil {
141149 if os .IsNotExist (err ) {
@@ -231,13 +239,25 @@ func parseAAParserVersion(output string) (int, error) {
231239// CheckProfileAndLoadDefault checks if the specified profile is loaded and
232240// loads the DefaultLibpodProfile if the specified on is prefixed by
233241// DefaultLipodProfilePrefix. This allows to always load and apply the latest
234- // default AppArmor profile. If it's a default profile, return
235- // DefaultLipodProfilePrefix, otherwise the specified one.
242+ // default AppArmor profile. Note that AppArmor requires root. If it's a
243+ // default profile, return DefaultLipodProfilePrefix, otherwise the specified
244+ // one.
236245func CheckProfileAndLoadDefault (name string ) (string , error ) {
237246 if name == "unconfined" {
238247 return name , nil
239248 }
240249
250+ // AppArmor is not supported in rootless mode as it requires root
251+ // privileges. Return an error in case a specific profile is specified.
252+ if unshare .IsRootless () {
253+ if name != "" {
254+ return "" , errors .Wrapf (ErrApparmorRootless , "cannot load AppArmor profile %q" , name )
255+ } else {
256+ logrus .Debug ("Skipping loading default AppArmor profile (rootless mode)" )
257+ return "" , nil
258+ }
259+ }
260+
241261 // Check if AppArmor is disabled and error out if a profile is to be set.
242262 if ! runcaa .IsEnabled () {
243263 if name == "" {
@@ -252,6 +272,13 @@ func CheckProfileAndLoadDefault(name string) (string, error) {
252272 } else if ! strings .HasPrefix (name , ProfilePrefix ) {
253273 // If the specified name is not a default one, ignore it and return the
254274 // name.
275+ isLoaded , err := IsLoaded (name )
276+ if err != nil {
277+ return "" , errors .Wrapf (err , "verify if profile %s is loaded" , name )
278+ }
279+ if ! isLoaded {
280+ return "" , errors .Errorf ("AppArmor profile %q specified but not loaded" , name )
281+ }
255282 return name , nil
256283 }
257284
0 commit comments