github.com/rawahars/moby@v24.0.4+incompatible/profiles/apparmor/apparmor.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  package apparmor // import "github.com/docker/docker/profiles/apparmor"
     5  
     6  import (
     7  	"bufio"
     8  	"io"
     9  	"os"
    10  	"path"
    11  	"strings"
    12  	"text/template"
    13  
    14  	"github.com/docker/docker/pkg/aaparser"
    15  )
    16  
    17  // profileDirectory is the file store for apparmor profiles and macros.
    18  const profileDirectory = "/etc/apparmor.d"
    19  
    20  // profileData holds information about the given profile for generation.
    21  type profileData struct {
    22  	// Name is profile name.
    23  	Name string
    24  	// DaemonProfile is the profile name of our daemon.
    25  	DaemonProfile 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  }
    31  
    32  // generateDefault creates an apparmor profile from ProfileData.
    33  func (p *profileData) generateDefault(out io.Writer) error {
    34  	compiled, err := template.New("apparmor_profile").Parse(baseTemplate)
    35  	if err != nil {
    36  		return err
    37  	}
    38  
    39  	if macroExists("tunables/global") {
    40  		p.Imports = append(p.Imports, "#include <tunables/global>")
    41  	} else {
    42  		p.Imports = append(p.Imports, "@{PROC}=/proc/")
    43  	}
    44  
    45  	if macroExists("abstractions/base") {
    46  		p.InnerImports = append(p.InnerImports, "#include <abstractions/base>")
    47  	}
    48  
    49  	return compiled.Execute(out, p)
    50  }
    51  
    52  // macrosExists checks if the passed macro exists.
    53  func macroExists(m string) bool {
    54  	_, err := os.Stat(path.Join(profileDirectory, m))
    55  	return err == nil
    56  }
    57  
    58  // InstallDefault generates a default profile in a temp directory determined by
    59  // os.TempDir(), then loads the profile into the kernel using 'apparmor_parser'.
    60  func InstallDefault(name string) error {
    61  	p := profileData{
    62  		Name: name,
    63  	}
    64  
    65  	// Figure out the daemon profile.
    66  	currentProfile, err := os.ReadFile("/proc/self/attr/current")
    67  	if err != nil {
    68  		// If we couldn't get the daemon profile, assume we are running
    69  		// unconfined which is generally the default.
    70  		currentProfile = nil
    71  	}
    72  	daemonProfile := string(currentProfile)
    73  	// Normally profiles are suffixed by " (enforcing)" or similar. AppArmor
    74  	// profiles cannot contain spaces so this doesn't restrict daemon profile
    75  	// names.
    76  	if parts := strings.SplitN(daemonProfile, " ", 2); len(parts) >= 1 {
    77  		daemonProfile = parts[0]
    78  	}
    79  	if daemonProfile == "" {
    80  		daemonProfile = "unconfined"
    81  	}
    82  	p.DaemonProfile = daemonProfile
    83  
    84  	// Install to a temporary directory.
    85  	f, err := os.CreateTemp("", name)
    86  	if err != nil {
    87  		return err
    88  	}
    89  	profilePath := f.Name()
    90  
    91  	defer f.Close()
    92  	defer os.Remove(profilePath)
    93  
    94  	if err := p.generateDefault(f); err != nil {
    95  		return err
    96  	}
    97  
    98  	return aaparser.LoadProfile(profilePath)
    99  }
   100  
   101  // IsLoaded checks if a profile with the given name has been loaded into the
   102  // kernel.
   103  func IsLoaded(name string) (bool, error) {
   104  	file, err := os.Open("/sys/kernel/security/apparmor/profiles")
   105  	if err != nil {
   106  		return false, err
   107  	}
   108  	defer file.Close()
   109  
   110  	r := bufio.NewReader(file)
   111  	for {
   112  		p, err := r.ReadString('\n')
   113  		if err == io.EOF {
   114  			break
   115  		}
   116  		if err != nil {
   117  			return false, err
   118  		}
   119  		if strings.HasPrefix(p, name+" ") {
   120  			return true, nil
   121  		}
   122  	}
   123  
   124  	return false, nil
   125  }