github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/profiles/apparmor/apparmor.go (about)

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