github.com/olljanat/moby@v1.13.1/profiles/apparmor/apparmor.go (about)

     1  // +build linux
     2  
     3  package apparmor
     4  
     5  import (
     6  	"bufio"
     7  	"io"
     8  	"io/ioutil"
     9  	"os"
    10  	"path"
    11  	"strings"
    12  
    13  	"github.com/docker/docker/pkg/aaparser"
    14  	"github.com/docker/docker/utils/templates"
    15  )
    16  
    17  var (
    18  	// profileDirectory is the file store for apparmor profiles and macros.
    19  	profileDirectory = "/etc/apparmor.d"
    20  )
    21  
    22  // profileData holds information about the given profile for generation.
    23  type profileData struct {
    24  	// Name is profile name.
    25  	Name string
    26  	// Imports defines the apparmor functions to import, before defining the profile.
    27  	Imports []string
    28  	// InnerImports defines the apparmor functions to import in the profile.
    29  	InnerImports []string
    30  	// Version is the {major, minor, patch} version of apparmor_parser as a single number.
    31  	Version int
    32  }
    33  
    34  // generateDefault creates an apparmor profile from ProfileData.
    35  func (p *profileData) generateDefault(out io.Writer) error {
    36  	compiled, err := templates.NewParse("apparmor_profile", baseTemplate)
    37  	if err != nil {
    38  		return err
    39  	}
    40  
    41  	if macroExists("tunables/global") {
    42  		p.Imports = append(p.Imports, "#include <tunables/global>")
    43  	} else {
    44  		p.Imports = append(p.Imports, "@{PROC}=/proc/")
    45  	}
    46  
    47  	if macroExists("abstractions/base") {
    48  		p.InnerImports = append(p.InnerImports, "#include <abstractions/base>")
    49  	}
    50  
    51  	ver, err := aaparser.GetVersion()
    52  	if err != nil {
    53  		return err
    54  	}
    55  	p.Version = ver
    56  
    57  	if err := compiled.Execute(out, p); err != nil {
    58  		return err
    59  	}
    60  	return nil
    61  }
    62  
    63  // macrosExists checks if the passed macro exists.
    64  func macroExists(m string) bool {
    65  	_, err := os.Stat(path.Join(profileDirectory, m))
    66  	return err == nil
    67  }
    68  
    69  // InstallDefault generates a default profile in a temp directory determined by
    70  // os.TempDir(), then loads the profile into the kernel using 'apparmor_parser'.
    71  func InstallDefault(name string) error {
    72  	p := profileData{
    73  		Name: name,
    74  	}
    75  
    76  	// Install to a temporary directory.
    77  	f, err := ioutil.TempFile("", name)
    78  	if err != nil {
    79  		return err
    80  	}
    81  	profilePath := f.Name()
    82  
    83  	defer f.Close()
    84  	defer os.Remove(profilePath)
    85  
    86  	if err := p.generateDefault(f); err != nil {
    87  		f.Close()
    88  		return err
    89  	}
    90  
    91  	if err := aaparser.LoadProfile(profilePath); err != nil {
    92  		return err
    93  	}
    94  
    95  	return nil
    96  }
    97  
    98  // IsLoaded checks if a profile with the given name has been loaded into the
    99  // kernel.
   100  func IsLoaded(name string) (bool, error) {
   101  	file, err := os.Open("/sys/kernel/security/apparmor/profiles")
   102  	if err != nil {
   103  		return false, err
   104  	}
   105  	defer file.Close()
   106  
   107  	r := bufio.NewReader(file)
   108  	for {
   109  		p, err := r.ReadString('\n')
   110  		if err == io.EOF {
   111  			break
   112  		}
   113  		if err != nil {
   114  			return false, err
   115  		}
   116  		if strings.HasPrefix(p, name+" ") {
   117  			return true, nil
   118  		}
   119  	}
   120  
   121  	return false, nil
   122  }