github.com/robingeuze/docker@v1.11.1/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  
    12  	"github.com/docker/docker/pkg/aaparser"
    13  	"github.com/docker/docker/utils/templates"
    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  	// Imports defines the apparmor functions to import, before defining the profile.
    28  	Imports []string
    29  	// InnerImports defines the apparmor functions to import in the profile.
    30  	InnerImports []string
    31  	// Version is the {major, minor, patch} version of apparmor_parser as a single number.
    32  	Version int
    33  }
    34  
    35  // generateDefault creates an apparmor profile from ProfileData.
    36  func (p *profileData) generateDefault(out io.Writer) error {
    37  	compiled, err := templates.NewParse("apparmor_profile", baseTemplate)
    38  	if err != nil {
    39  		return err
    40  	}
    41  
    42  	if macroExists("tunables/global") {
    43  		p.Imports = append(p.Imports, "#include <tunables/global>")
    44  	} else {
    45  		p.Imports = append(p.Imports, "@{PROC}=/proc/")
    46  	}
    47  
    48  	if macroExists("abstractions/base") {
    49  		p.InnerImports = append(p.InnerImports, "#include <abstractions/base>")
    50  	}
    51  
    52  	ver, err := aaparser.GetVersion()
    53  	if err != nil {
    54  		return err
    55  	}
    56  	p.Version = ver
    57  
    58  	if err := compiled.Execute(out, p); err != nil {
    59  		return err
    60  	}
    61  	return nil
    62  }
    63  
    64  // macrosExists checks if the passed macro exists.
    65  func macroExists(m string) bool {
    66  	_, err := os.Stat(path.Join(profileDirectory, m))
    67  	return err == nil
    68  }
    69  
    70  // InstallDefault generates a default profile and installs it in the
    71  // ProfileDirectory with `apparmor_parser`.
    72  func InstallDefault(name string) error {
    73  	// Make sure the path where they want to save the profile exists
    74  	if err := os.MkdirAll(profileDirectory, 0755); err != nil {
    75  		return err
    76  	}
    77  
    78  	p := profileData{
    79  		Name: name,
    80  	}
    81  
    82  	f, err := os.OpenFile(defaultProfilePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
    83  	if err != nil {
    84  		return err
    85  	}
    86  	if err := p.generateDefault(f); err != nil {
    87  		f.Close()
    88  		return err
    89  	}
    90  	f.Close()
    91  
    92  	if err := aaparser.LoadProfile(defaultProfilePath); err != nil {
    93  		return err
    94  	}
    95  
    96  	return nil
    97  }
    98  
    99  // IsLoaded checks if a passed profile has been loaded into the kernel.
   100  func IsLoaded(name string) error {
   101  	file, err := os.Open("/sys/kernel/security/apparmor/profiles")
   102  	if err != nil {
   103  		return err
   104  	}
   105  	r := bufio.NewReader(file)
   106  	for {
   107  		p, err := r.ReadString('\n')
   108  		if err != nil {
   109  			return err
   110  		}
   111  		if strings.HasPrefix(p, name+" ") {
   112  			return nil
   113  		}
   114  	}
   115  }