github.com/ncdc/docker@v0.10.1-0.20160129113957-6c6729ef5b74/profiles/apparmor/apparmor.go (about)

     1  // +build linux
     2  
     3  package apparmor
     4  
     5  import (
     6  	"bufio"
     7  	"io"
     8  	"os"
     9  	"path"
    10  	"strings"
    11  	"text/template"
    12  
    13  	"github.com/docker/docker/pkg/aaparser"
    14  )
    15  
    16  var (
    17  	// profileDirectory is the file store for apparmor profiles and macros.
    18  	profileDirectory = "/etc/apparmor.d"
    19  	// defaultProfilePath is the default path for the apparmor profile to be saved.
    20  	defaultProfilePath = path.Join(profileDirectory, "docker")
    21  )
    22  
    23  // profileData holds information about the given profile for generation.
    24  type profileData struct {
    25  	// Name is profile name.
    26  	Name string
    27  	// ExecPath is the path to the docker binary.
    28  	ExecPath string
    29  	// Imports defines the apparmor functions to import, before defining the profile.
    30  	Imports []string
    31  	// InnerImports defines the apparmor functions to import in the profile.
    32  	InnerImports []string
    33  	// MajorVersion is the apparmor_parser major version.
    34  	MajorVersion int
    35  	// MinorVersion is the apparmor_parser minor version.
    36  	MinorVersion int
    37  }
    38  
    39  // generateDefault creates an apparmor profile from ProfileData.
    40  func (p *profileData) generateDefault(out io.Writer) error {
    41  	compiled, err := template.New("apparmor_profile").Parse(baseTemplate)
    42  	if err != nil {
    43  		return err
    44  	}
    45  	if macroExists("tunables/global") {
    46  		p.Imports = append(p.Imports, "#include <tunables/global>")
    47  	} else {
    48  		p.Imports = append(p.Imports, "@{PROC}=/proc/")
    49  	}
    50  	if macroExists("abstractions/base") {
    51  		p.InnerImports = append(p.InnerImports, "#include <abstractions/base>")
    52  	}
    53  	if err := compiled.Execute(out, p); err != nil {
    54  		return err
    55  	}
    56  	return nil
    57  }
    58  
    59  // macrosExists checks if the passed macro exists.
    60  func macroExists(m string) bool {
    61  	_, err := os.Stat(path.Join(profileDirectory, m))
    62  	return err == nil
    63  }
    64  
    65  // InstallDefault generates a default profile and installs it in the
    66  // ProfileDirectory with `apparmor_parser`.
    67  func InstallDefault(name string) error {
    68  	// Make sure the path where they want to save the profile exists
    69  	if err := os.MkdirAll(profileDirectory, 0755); err != nil {
    70  		return err
    71  	}
    72  
    73  	p := profileData{
    74  		Name: name,
    75  	}
    76  
    77  	f, err := os.OpenFile(defaultProfilePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
    78  	if err != nil {
    79  		return err
    80  	}
    81  	if err := p.generateDefault(f); err != nil {
    82  		f.Close()
    83  		return err
    84  	}
    85  	f.Close()
    86  
    87  	if err := aaparser.LoadProfile(defaultProfilePath); err != nil {
    88  		return err
    89  	}
    90  
    91  	return nil
    92  }
    93  
    94  // IsLoaded checks if a passed profile as been loaded into the kernel.
    95  func IsLoaded(name string) error {
    96  	file, err := os.Open("/sys/kernel/security/apparmor/profiles")
    97  	if err != nil {
    98  		return err
    99  	}
   100  	r := bufio.NewReader(file)
   101  	for {
   102  		p, err := r.ReadString('\n')
   103  		if err != nil {
   104  			return err
   105  		}
   106  		if strings.HasPrefix(p, name+" ") {
   107  			return nil
   108  		}
   109  	}
   110  }