github.com/alexandrev/docker@v1.9.0/daemon/execdriver/native/apparmor.go (about) 1 // +build linux 2 3 package native 4 5 import ( 6 "bufio" 7 "fmt" 8 "io" 9 "os" 10 "os/exec" 11 "path" 12 "strings" 13 "text/template" 14 15 "github.com/opencontainers/runc/libcontainer/apparmor" 16 ) 17 18 const ( 19 apparmorProfilePath = "/etc/apparmor.d/docker" 20 ) 21 22 type data struct { 23 Name string 24 Imports []string 25 InnerImports []string 26 } 27 28 const baseTemplate = ` 29 {{range $value := .Imports}} 30 {{$value}} 31 {{end}} 32 33 profile {{.Name}} flags=(attach_disconnected,mediate_deleted) { 34 {{range $value := .InnerImports}} 35 {{$value}} 36 {{end}} 37 38 network, 39 capability, 40 file, 41 umount, 42 43 deny @{PROC}/{*,**^[0-9*],sys/kernel/shm*} wkx, 44 deny @{PROC}/sysrq-trigger rwklx, 45 deny @{PROC}/mem rwklx, 46 deny @{PROC}/kmem rwklx, 47 deny @{PROC}/kcore rwklx, 48 49 deny mount, 50 51 deny /sys/[^f]*/** wklx, 52 deny /sys/f[^s]*/** wklx, 53 deny /sys/fs/[^c]*/** wklx, 54 deny /sys/fs/c[^g]*/** wklx, 55 deny /sys/fs/cg[^r]*/** wklx, 56 deny /sys/firmware/efi/efivars/** rwklx, 57 deny /sys/kernel/security/** rwklx, 58 } 59 ` 60 61 func generateProfile(out io.Writer) error { 62 compiled, err := template.New("apparmor_profile").Parse(baseTemplate) 63 if err != nil { 64 return err 65 } 66 data := &data{ 67 Name: "docker-default", 68 } 69 if tunablesExists() { 70 data.Imports = append(data.Imports, "#include <tunables/global>") 71 } else { 72 data.Imports = append(data.Imports, "@{PROC}=/proc/") 73 } 74 if abstractionsExists() { 75 data.InnerImports = append(data.InnerImports, "#include <abstractions/base>") 76 } 77 if err := compiled.Execute(out, data); err != nil { 78 return err 79 } 80 return nil 81 } 82 83 // check if the tunables/global exist 84 func tunablesExists() bool { 85 _, err := os.Stat("/etc/apparmor.d/tunables/global") 86 return err == nil 87 } 88 89 // check if abstractions/base exist 90 func abstractionsExists() bool { 91 _, err := os.Stat("/etc/apparmor.d/abstractions/base") 92 return err == nil 93 } 94 95 func installAppArmorProfile() error { 96 if !apparmor.IsEnabled() { 97 return nil 98 } 99 100 // Make sure /etc/apparmor.d exists 101 if err := os.MkdirAll(path.Dir(apparmorProfilePath), 0755); err != nil { 102 return err 103 } 104 105 f, err := os.OpenFile(apparmorProfilePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) 106 if err != nil { 107 return err 108 } 109 if err := generateProfile(f); err != nil { 110 f.Close() 111 return err 112 } 113 f.Close() 114 115 cmd := exec.Command("/sbin/apparmor_parser", "-r", "-W", "docker") 116 // to use the parser directly we have to make sure we are in the correct 117 // dir with the profile 118 cmd.Dir = "/etc/apparmor.d" 119 120 output, err := cmd.CombinedOutput() 121 if err != nil { 122 return fmt.Errorf("Error loading docker apparmor profile: %s (%s)", err, output) 123 } 124 return nil 125 } 126 127 func hasAppArmorProfileLoaded(profile string) error { 128 file, err := os.Open("/sys/kernel/security/apparmor/profiles") 129 if err != nil { 130 return err 131 } 132 r := bufio.NewReader(file) 133 for { 134 p, err := r.ReadString('\n') 135 if err != nil { 136 return err 137 } 138 if strings.HasPrefix(p, profile+" ") { 139 return nil 140 } 141 } 142 }