Signed-off-by: Jessica Frazelle <acidburn@docker.com>
| ... | ... |
@@ -4,7 +4,6 @@ package native |
| 4 | 4 |
|
| 5 | 5 |
import ( |
| 6 | 6 |
"bufio" |
| 7 |
- "fmt" |
|
| 8 | 7 |
"io" |
| 9 | 8 |
"os" |
| 10 | 9 |
"os/exec" |
| ... | ... |
@@ -137,15 +136,10 @@ func installAppArmorProfile() error {
|
| 137 | 137 |
} |
| 138 | 138 |
f.Close() |
| 139 | 139 |
|
| 140 |
- cmd := exec.Command("/sbin/apparmor_parser", "-r", "-W", "docker")
|
|
| 141 |
- // to use the parser directly we have to make sure we are in the correct |
|
| 142 |
- // dir with the profile |
|
| 143 |
- cmd.Dir = "/etc/apparmor.d" |
|
| 144 |
- |
|
| 145 |
- output, err := cmd.CombinedOutput() |
|
| 146 |
- if err != nil {
|
|
| 147 |
- return fmt.Errorf("Error loading docker apparmor profile: %s (%s)", err, output)
|
|
| 140 |
+ if err := aaparser.LoadProfile(apparmorProfilePath); err != nil {
|
|
| 141 |
+ return err |
|
| 148 | 142 |
} |
| 143 |
+ |
|
| 149 | 144 |
return nil |
| 150 | 145 |
} |
| 151 | 146 |
|
| ... | ... |
@@ -1,35 +1,66 @@ |
| 1 |
+// Package aaparser is a convenience package interacting with `apparmor_parser`. |
|
| 1 | 2 |
package aaparser |
| 2 | 3 |
|
| 3 | 4 |
import ( |
| 4 | 5 |
"fmt" |
| 5 |
- "log" |
|
| 6 | 6 |
"os/exec" |
| 7 |
+ "path/filepath" |
|
| 7 | 8 |
"strconv" |
| 8 | 9 |
"strings" |
| 9 | 10 |
) |
| 10 | 11 |
|
| 11 |
-// GetVersion returns the major and minor version of apparmor_parser |
|
| 12 |
+const ( |
|
| 13 |
+ binary = "apparmor_parser" |
|
| 14 |
+) |
|
| 15 |
+ |
|
| 16 |
+// GetVersion returns the major and minor version of apparmor_parser. |
|
| 12 | 17 |
func GetVersion() (int, int, error) {
|
| 13 |
- // get the apparmor_version version |
|
| 14 |
- cmd := exec.Command("apparmor_parser", "--version")
|
|
| 18 |
+ output, err := cmd("", "--version")
|
|
| 19 |
+ if err != nil {
|
|
| 20 |
+ return -1, -1, err |
|
| 21 |
+ } |
|
| 22 |
+ |
|
| 23 |
+ return parseVersion(string(output)) |
|
| 24 |
+} |
|
| 15 | 25 |
|
| 16 |
- output, err := cmd.CombinedOutput() |
|
| 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)) |
|
| 17 | 30 |
if err != nil {
|
| 18 |
- log.Fatalf("getting apparmor_parser version failed: %s (%s)", err, output)
|
|
| 31 |
+ return err |
|
| 19 | 32 |
} |
| 33 |
+ return nil |
|
| 34 |
+} |
|
| 20 | 35 |
|
| 21 |
- // parse the version from the output |
|
| 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 |
+// the major and minor version for `apparor_parser`. |
|
| 51 |
+func parseVersion(output string) (int, int, error) {
|
|
| 22 | 52 |
// output is in the form of the following: |
| 23 | 53 |
// AppArmor parser version 2.9.1 |
| 24 | 54 |
// Copyright (C) 1999-2008 Novell Inc. |
| 25 | 55 |
// Copyright 2009-2012 Canonical Ltd. |
| 26 |
- lines := strings.SplitN(string(output), "\n", 2) |
|
| 56 |
+ lines := strings.SplitN(output, "\n", 2) |
|
| 27 | 57 |
words := strings.Split(lines[0], " ") |
| 28 | 58 |
version := words[len(words)-1] |
| 59 |
+ |
|
| 29 | 60 |
// split by major minor version |
| 30 | 61 |
v := strings.Split(version, ".") |
| 31 | 62 |
if len(v) < 2 {
|
| 32 |
- return -1, -1, fmt.Errorf("parsing major minor version failed for %q", version)
|
|
| 63 |
+ return -1, -1, fmt.Errorf("parsing major minor version failed for output: `%s`", output)
|
|
| 33 | 64 |
} |
| 34 | 65 |
|
| 35 | 66 |
majorVersion, err := strconv.Atoi(v[0]) |
| 36 | 67 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,65 @@ |
| 0 |
+package aaparser |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "testing" |
|
| 4 |
+) |
|
| 5 |
+ |
|
| 6 |
+type versionExpected struct {
|
|
| 7 |
+ output string |
|
| 8 |
+ major int |
|
| 9 |
+ minor int |
|
| 10 |
+} |
|
| 11 |
+ |
|
| 12 |
+func TestParseVersion(t *testing.T) {
|
|
| 13 |
+ versions := []versionExpected{
|
|
| 14 |
+ {
|
|
| 15 |
+ output: `AppArmor parser version 2.10 |
|
| 16 |
+Copyright (C) 1999-2008 Novell Inc. |
|
| 17 |
+Copyright 2009-2012 Canonical Ltd. |
|
| 18 |
+ |
|
| 19 |
+`, |
|
| 20 |
+ major: 2, |
|
| 21 |
+ minor: 10, |
|
| 22 |
+ }, |
|
| 23 |
+ {
|
|
| 24 |
+ output: `AppArmor parser version 2.8 |
|
| 25 |
+Copyright (C) 1999-2008 Novell Inc. |
|
| 26 |
+Copyright 2009-2012 Canonical Ltd. |
|
| 27 |
+ |
|
| 28 |
+`, |
|
| 29 |
+ major: 2, |
|
| 30 |
+ minor: 8, |
|
| 31 |
+ }, |
|
| 32 |
+ {
|
|
| 33 |
+ output: `AppArmor parser version 2.20 |
|
| 34 |
+Copyright (C) 1999-2008 Novell Inc. |
|
| 35 |
+Copyright 2009-2012 Canonical Ltd. |
|
| 36 |
+ |
|
| 37 |
+`, |
|
| 38 |
+ major: 2, |
|
| 39 |
+ minor: 20, |
|
| 40 |
+ }, |
|
| 41 |
+ {
|
|
| 42 |
+ output: `AppArmor parser version 2.05 |
|
| 43 |
+Copyright (C) 1999-2008 Novell Inc. |
|
| 44 |
+Copyright 2009-2012 Canonical Ltd. |
|
| 45 |
+ |
|
| 46 |
+`, |
|
| 47 |
+ major: 2, |
|
| 48 |
+ minor: 5, |
|
| 49 |
+ }, |
|
| 50 |
+ } |
|
| 51 |
+ |
|
| 52 |
+ for _, v := range versions {
|
|
| 53 |
+ major, minor, err := parseVersion(v.output) |
|
| 54 |
+ if err != nil {
|
|
| 55 |
+ t.Fatalf("expected error to be nil for %#v, got: %v", v, err)
|
|
| 56 |
+ } |
|
| 57 |
+ if major != v.major {
|
|
| 58 |
+ t.Fatalf("expected major version to be %d, was %d, for: %#v\n", v.major, major, v)
|
|
| 59 |
+ } |
|
| 60 |
+ if minor != v.minor {
|
|
| 61 |
+ t.Fatalf("expected minor version to be %d, was %d, for: %#v\n", v.minor, minor, v)
|
|
| 62 |
+ } |
|
| 63 |
+ } |
|
| 64 |
+} |