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

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