github.com/gunjan5/docker@v1.8.2/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}/sys/fs/** wklx,
    44    deny @{PROC}/fs/** wklx,
    45    deny @{PROC}/sysrq-trigger rwklx,
    46    deny @{PROC}/mem rwklx,
    47    deny @{PROC}/kmem rwklx,
    48    deny @{PROC}/kcore rwklx,
    49    deny @{PROC}/sys/kernel/[^s][^h][^m]* wklx,
    50    deny @{PROC}/sys/kernel/*/** wklx,
    51  
    52    deny mount,
    53  
    54    deny /sys/[^f]*/** wklx,
    55    deny /sys/f[^s]*/** wklx,
    56    deny /sys/fs/[^c]*/** wklx,
    57    deny /sys/fs/c[^g]*/** wklx,
    58    deny /sys/fs/cg[^r]*/** wklx,
    59    deny /sys/firmware/efi/efivars/** rwklx,
    60    deny /sys/kernel/security/** rwklx,
    61  }
    62  `
    63  
    64  func generateProfile(out io.Writer) error {
    65  	compiled, err := template.New("apparmor_profile").Parse(baseTemplate)
    66  	if err != nil {
    67  		return err
    68  	}
    69  	data := &data{
    70  		Name: "docker-default",
    71  	}
    72  	if tunablesExists() {
    73  		data.Imports = append(data.Imports, "#include <tunables/global>")
    74  	} else {
    75  		data.Imports = append(data.Imports, "@{PROC}=/proc/")
    76  	}
    77  	if abstractionsExists() {
    78  		data.InnerImports = append(data.InnerImports, "#include <abstractions/base>")
    79  	}
    80  	if err := compiled.Execute(out, data); err != nil {
    81  		return err
    82  	}
    83  	return nil
    84  }
    85  
    86  // check if the tunables/global exist
    87  func tunablesExists() bool {
    88  	_, err := os.Stat("/etc/apparmor.d/tunables/global")
    89  	return err == nil
    90  }
    91  
    92  // check if abstractions/base exist
    93  func abstractionsExists() bool {
    94  	_, err := os.Stat("/etc/apparmor.d/abstractions/base")
    95  	return err == nil
    96  }
    97  
    98  func installAppArmorProfile() error {
    99  	if !apparmor.IsEnabled() {
   100  		return nil
   101  	}
   102  
   103  	// Make sure /etc/apparmor.d exists
   104  	if err := os.MkdirAll(path.Dir(apparmorProfilePath), 0755); err != nil {
   105  		return err
   106  	}
   107  
   108  	f, err := os.OpenFile(apparmorProfilePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
   109  	if err != nil {
   110  		return err
   111  	}
   112  	if err := generateProfile(f); err != nil {
   113  		f.Close()
   114  		return err
   115  	}
   116  	f.Close()
   117  
   118  	cmd := exec.Command("/sbin/apparmor_parser", "-r", "-W", "docker")
   119  	// to use the parser directly we have to make sure we are in the correct
   120  	// dir with the profile
   121  	cmd.Dir = "/etc/apparmor.d"
   122  
   123  	output, err := cmd.CombinedOutput()
   124  	if err != nil {
   125  		return fmt.Errorf("Error loading docker apparmor profile: %s (%s)", err, output)
   126  	}
   127  	return nil
   128  }
   129  
   130  func hasAppArmorProfileLoaded(profile string) error {
   131  	file, err := os.Open("/sys/kernel/security/apparmor/profiles")
   132  	if err != nil {
   133  		return err
   134  	}
   135  	r := bufio.NewReader(file)
   136  	for {
   137  		p, err := r.ReadString('\n')
   138  		if err != nil {
   139  			return err
   140  		}
   141  		if strings.HasPrefix(p, profile+" ") {
   142  			return nil
   143  		}
   144  	}
   145  }