github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/libcontainer/apparmor/apparmor_linux.go (about) 1 package apparmor 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "sync" 8 9 "github.com/opencontainers/runc/libcontainer/utils" 10 ) 11 12 var ( 13 appArmorEnabled bool 14 checkAppArmor sync.Once 15 ) 16 17 // isEnabled returns true if apparmor is enabled for the host. 18 func isEnabled() bool { 19 checkAppArmor.Do(func() { 20 if _, err := os.Stat("/sys/kernel/security/apparmor"); err == nil { 21 buf, err := os.ReadFile("/sys/module/apparmor/parameters/enabled") 22 appArmorEnabled = err == nil && len(buf) > 1 && buf[0] == 'Y' 23 } 24 }) 25 return appArmorEnabled 26 } 27 28 func setProcAttr(attr, value string) error { 29 attr = utils.CleanPath(attr) 30 attrSubPath := "attr/apparmor/" + attr 31 if _, err := os.Stat("/proc/self/" + attrSubPath); errors.Is(err, os.ErrNotExist) { 32 // fall back to the old convention 33 attrSubPath = "attr/" + attr 34 } 35 36 // Under AppArmor you can only change your own attr, so there's no reason 37 // to not use /proc/thread-self/ (instead of /proc/<tid>/, like libapparmor 38 // does). 39 attrPath, closer := utils.ProcThreadSelf(attrSubPath) 40 defer closer() 41 42 f, err := os.OpenFile(attrPath, os.O_WRONLY, 0) 43 if err != nil { 44 return err 45 } 46 defer f.Close() 47 48 if err := utils.EnsureProcHandle(f); err != nil { 49 return err 50 } 51 52 _, err = f.WriteString(value) 53 return err 54 } 55 56 // changeOnExec reimplements aa_change_onexec from libapparmor in Go 57 func changeOnExec(name string) error { 58 if err := setProcAttr("exec", "exec "+name); err != nil { 59 return fmt.Errorf("apparmor failed to apply profile: %w", err) 60 } 61 return nil 62 } 63 64 // applyProfile will apply the profile with the specified name to the process after 65 // the next exec. It is only supported on Linux and produces an error on other 66 // platforms. 67 func applyProfile(name string) error { 68 if name == "" { 69 return nil 70 } 71 72 return changeOnExec(name) 73 }