github.com/sijibomii/docker@v0.0.0-20231230191044-5cf6ca554647/pkg/aaparser/aaparser.go (about)

     1  // Package aaparser is a convenience package interacting with `apparmor_parser`.
     2  package aaparser
     3  
     4  import (
     5  	"fmt"
     6  	"os/exec"
     7  	"path/filepath"
     8  	"strconv"
     9  	"strings"
    10  )
    11  
    12  const (
    13  	binary = "apparmor_parser"
    14  )
    15  
    16  // GetVersion returns the major and minor version of apparmor_parser.
    17  func GetVersion() (int, error) {
    18  	output, err := cmd("", "--version")
    19  	if err != nil {
    20  		return -1, err
    21  	}
    22  
    23  	return parseVersion(output)
    24  }
    25  
    26  // LoadProfile runs `apparmor_parser -r -W` on a specified apparmor profile to
    27  // replace and write it to disk.
    28  func LoadProfile(profilePath string) error {
    29  	_, err := cmd(filepath.Dir(profilePath), "-r", "-W", filepath.Base(profilePath))
    30  	if err != nil {
    31  		return err
    32  	}
    33  	return nil
    34  }
    35  
    36  // cmd runs `apparmor_parser` with the passed arguments.
    37  func cmd(dir string, arg ...string) (string, error) {
    38  	c := exec.Command(binary, arg...)
    39  	c.Dir = dir
    40  
    41  	output, err := c.CombinedOutput()
    42  	if err != nil {
    43  		return "", fmt.Errorf("running `%s %s` failed with output: %s\nerror: %v", c.Path, strings.Join(c.Args, " "), string(output), err)
    44  	}
    45  
    46  	return string(output), nil
    47  }
    48  
    49  // parseVersion takes the output from `apparmor_parser --version` and returns
    50  // a representation of the {major, minor, patch} version as a single number of
    51  // the form MMmmPPP {major, minor, patch}.
    52  func parseVersion(output string) (int, error) {
    53  	// output is in the form of the following:
    54  	// AppArmor parser version 2.9.1
    55  	// Copyright (C) 1999-2008 Novell Inc.
    56  	// Copyright 2009-2012 Canonical Ltd.
    57  
    58  	lines := strings.SplitN(output, "\n", 2)
    59  	words := strings.Split(lines[0], " ")
    60  	version := words[len(words)-1]
    61  
    62  	// split by major minor version
    63  	v := strings.Split(version, ".")
    64  	if len(v) == 0 || len(v) > 3 {
    65  		return -1, fmt.Errorf("parsing version failed for output: `%s`", output)
    66  	}
    67  
    68  	// Default the versions to 0.
    69  	var majorVersion, minorVersion, patchLevel int
    70  
    71  	majorVersion, err := strconv.Atoi(v[0])
    72  	if err != nil {
    73  		return -1, err
    74  	}
    75  
    76  	if len(v) > 1 {
    77  		minorVersion, err = strconv.Atoi(v[1])
    78  		if err != nil {
    79  			return -1, err
    80  		}
    81  	}
    82  	if len(v) > 2 {
    83  		patchLevel, err = strconv.Atoi(v[2])
    84  		if err != nil {
    85  			return -1, err
    86  		}
    87  	}
    88  
    89  	// major*10^5 + minor*10^3 + patch*10^0
    90  	numericVersion := majorVersion*1e5 + minorVersion*1e3 + patchLevel
    91  	return numericVersion, nil
    92  }