Using {{if major}}{{if minor}} doesn't work as expected when the major
version changes. In addition, this didn't support patch levels (which is
necessary in some cases when distributions ship apparmor weirdly).
Signed-off-by: Aleksa Sarai <asarai@suse.com>
| ... | ... |
@@ -11,8 +11,7 @@ import ( |
| 11 | 11 |
) |
| 12 | 12 |
|
| 13 | 13 |
type profileData struct {
|
| 14 |
- MajorVersion int |
|
| 15 |
- MinorVersion int |
|
| 14 |
+ Version int |
|
| 16 | 15 |
} |
| 17 | 16 |
|
| 18 | 17 |
func main() {
|
| ... | ... |
@@ -23,13 +22,12 @@ func main() {
|
| 23 | 23 |
// parse the arg |
| 24 | 24 |
apparmorProfilePath := os.Args[1] |
| 25 | 25 |
|
| 26 |
- majorVersion, minorVersion, err := aaparser.GetVersion() |
|
| 26 |
+ version, err := aaparser.GetVersion() |
|
| 27 | 27 |
if err != nil {
|
| 28 | 28 |
log.Fatal(err) |
| 29 | 29 |
} |
| 30 | 30 |
data := profileData{
|
| 31 |
- MajorVersion: majorVersion, |
|
| 32 |
- MinorVersion: minorVersion, |
|
| 31 |
+ Version: version, |
|
| 33 | 32 |
} |
| 34 | 33 |
fmt.Printf("apparmor_parser is of version %+v\n", data)
|
| 35 | 34 |
|
| ... | ... |
@@ -20,11 +20,11 @@ profile /usr/bin/docker (attach_disconnected, complain) {
|
| 20 | 20 |
|
| 21 | 21 |
umount, |
| 22 | 22 |
pivot_root, |
| 23 |
-{{if ge .MajorVersion 2}}{{if ge .MinorVersion 9}}
|
|
| 23 |
+{{if ge .Version 209000}}
|
|
| 24 | 24 |
signal (receive) peer=@{profile_name},
|
| 25 | 25 |
signal (receive) peer=unconfined, |
| 26 | 26 |
signal (send), |
| 27 |
-{{end}}{{end}}
|
|
| 27 |
+{{end}}
|
|
| 28 | 28 |
network, |
| 29 | 29 |
capability, |
| 30 | 30 |
owner /** rw, |
| ... | ... |
@@ -46,12 +46,12 @@ profile /usr/bin/docker (attach_disconnected, complain) {
|
| 46 | 46 |
/etc/ld.so.cache r, |
| 47 | 47 |
/etc/passwd r, |
| 48 | 48 |
|
| 49 |
-{{if ge .MajorVersion 2}}{{if ge .MinorVersion 9}}
|
|
| 49 |
+{{if ge .Version 209000}}
|
|
| 50 | 50 |
ptrace peer=@{profile_name},
|
| 51 | 51 |
ptrace (read) peer=docker-default, |
| 52 | 52 |
deny ptrace (trace) peer=docker-default, |
| 53 | 53 |
deny ptrace peer=/usr/bin/docker///bin/ps, |
| 54 |
-{{end}}{{end}}
|
|
| 54 |
+{{end}}
|
|
| 55 | 55 |
|
| 56 | 56 |
/usr/lib/** rm, |
| 57 | 57 |
/lib/** rm, |
| ... | ... |
@@ -72,11 +72,11 @@ profile /usr/bin/docker (attach_disconnected, complain) {
|
| 72 | 72 |
/sbin/zfs rCx, |
| 73 | 73 |
/sbin/apparmor_parser rCx, |
| 74 | 74 |
|
| 75 |
-{{if ge .MajorVersion 2}}{{if ge .MinorVersion 9}}
|
|
| 75 |
+{{if ge .Version 209000}}
|
|
| 76 | 76 |
# Transitions |
| 77 | 77 |
change_profile -> docker-*, |
| 78 | 78 |
change_profile -> unconfined, |
| 79 |
-{{end}}{{end}}
|
|
| 79 |
+{{end}}
|
|
| 80 | 80 |
|
| 81 | 81 |
profile /bin/cat (complain) {
|
| 82 | 82 |
/etc/ld.so.cache r, |
| ... | ... |
@@ -98,10 +98,10 @@ profile /usr/bin/docker (attach_disconnected, complain) {
|
| 98 | 98 |
/dev/null rw, |
| 99 | 99 |
/bin/ps mr, |
| 100 | 100 |
|
| 101 |
-{{if ge .MajorVersion 2}}{{if ge .MinorVersion 9}}
|
|
| 101 |
+{{if ge .Version 209000}}
|
|
| 102 | 102 |
# We don't need ptrace so we'll deny and ignore the error. |
| 103 | 103 |
deny ptrace (read, trace), |
| 104 |
-{{end}}{{end}}
|
|
| 104 |
+{{end}}
|
|
| 105 | 105 |
|
| 106 | 106 |
# Quiet dac_override denials |
| 107 | 107 |
deny capability dac_override, |
| ... | ... |
@@ -119,15 +119,15 @@ profile /usr/bin/docker (attach_disconnected, complain) {
|
| 119 | 119 |
/proc/tty/drivers r, |
| 120 | 120 |
} |
| 121 | 121 |
profile /sbin/iptables (complain) {
|
| 122 |
-{{if ge .MajorVersion 2}}{{if ge .MinorVersion 9}}
|
|
| 122 |
+{{if ge .Version 209000}}
|
|
| 123 | 123 |
signal (receive) peer=/usr/bin/docker, |
| 124 |
-{{end}}{{end}}
|
|
| 124 |
+{{end}}
|
|
| 125 | 125 |
capability net_admin, |
| 126 | 126 |
} |
| 127 | 127 |
profile /sbin/auplink flags=(attach_disconnected, complain) {
|
| 128 |
-{{if ge .MajorVersion 2}}{{if ge .MinorVersion 9}}
|
|
| 128 |
+{{if ge .Version 209000}}
|
|
| 129 | 129 |
signal (receive) peer=/usr/bin/docker, |
| 130 |
-{{end}}{{end}}
|
|
| 130 |
+{{end}}
|
|
| 131 | 131 |
capability sys_admin, |
| 132 | 132 |
capability dac_override, |
| 133 | 133 |
|
| ... | ... |
@@ -146,9 +146,9 @@ profile /usr/bin/docker (attach_disconnected, complain) {
|
| 146 | 146 |
/proc/[0-9]*/mounts rw, |
| 147 | 147 |
} |
| 148 | 148 |
profile /sbin/modprobe /bin/kmod (complain) {
|
| 149 |
-{{if ge .MajorVersion 2}}{{if ge .MinorVersion 9}}
|
|
| 149 |
+{{if ge .Version 209000}}
|
|
| 150 | 150 |
signal (receive) peer=/usr/bin/docker, |
| 151 |
-{{end}}{{end}}
|
|
| 151 |
+{{end}}
|
|
| 152 | 152 |
capability sys_module, |
| 153 | 153 |
/etc/ld.so.cache r, |
| 154 | 154 |
/lib/** rm, |
| ... | ... |
@@ -162,9 +162,9 @@ profile /usr/bin/docker (attach_disconnected, complain) {
|
| 162 | 162 |
} |
| 163 | 163 |
# xz works via pipes, so we do not need access to the filesystem. |
| 164 | 164 |
profile /usr/bin/xz (complain) {
|
| 165 |
-{{if ge .MajorVersion 2}}{{if ge .MinorVersion 9}}
|
|
| 165 |
+{{if ge .Version 209000}}
|
|
| 166 | 166 |
signal (receive) peer=/usr/bin/docker, |
| 167 |
-{{end}}{{end}}
|
|
| 167 |
+{{end}}
|
|
| 168 | 168 |
/etc/ld.so.cache r, |
| 169 | 169 |
/lib/** rm, |
| 170 | 170 |
/usr/bin/xz rm, |
| ... | ... |
@@ -14,13 +14,13 @@ const ( |
| 14 | 14 |
) |
| 15 | 15 |
|
| 16 | 16 |
// GetVersion returns the major and minor version of apparmor_parser. |
| 17 |
-func GetVersion() (int, int, error) {
|
|
| 17 |
+func GetVersion() (int, error) {
|
|
| 18 | 18 |
output, err := cmd("", "--version")
|
| 19 | 19 |
if err != nil {
|
| 20 |
- return -1, -1, err |
|
| 20 |
+ return -1, err |
|
| 21 | 21 |
} |
| 22 | 22 |
|
| 23 |
- return parseVersion(string(output)) |
|
| 23 |
+ return parseVersion(output) |
|
| 24 | 24 |
} |
| 25 | 25 |
|
| 26 | 26 |
// LoadProfile runs `apparmor_parser -r -W` on a specified apparmor profile to |
| ... | ... |
@@ -47,30 +47,46 @@ func cmd(dir string, arg ...string) (string, error) {
|
| 47 | 47 |
} |
| 48 | 48 |
|
| 49 | 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) {
|
|
| 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) {
|
|
| 52 | 53 |
// output is in the form of the following: |
| 53 | 54 |
// AppArmor parser version 2.9.1 |
| 54 | 55 |
// Copyright (C) 1999-2008 Novell Inc. |
| 55 | 56 |
// Copyright 2009-2012 Canonical Ltd. |
| 57 |
+ |
|
| 56 | 58 |
lines := strings.SplitN(output, "\n", 2) |
| 57 | 59 |
words := strings.Split(lines[0], " ") |
| 58 | 60 |
version := words[len(words)-1] |
| 59 | 61 |
|
| 60 | 62 |
// split by major minor version |
| 61 | 63 |
v := strings.Split(version, ".") |
| 62 |
- if len(v) < 2 {
|
|
| 63 |
- return -1, -1, fmt.Errorf("parsing major minor version failed for output: `%s`", output)
|
|
| 64 |
+ if len(v) == 0 || len(v) > 3 {
|
|
| 65 |
+ return -1, fmt.Errorf("parsing version failed for output: `%s`", output)
|
|
| 64 | 66 |
} |
| 65 | 67 |
|
| 68 |
+ // Default the versions to 0. |
|
| 69 |
+ var majorVersion, minorVersion, patchLevel int |
|
| 70 |
+ |
|
| 66 | 71 |
majorVersion, err := strconv.Atoi(v[0]) |
| 67 | 72 |
if err != nil {
|
| 68 |
- return -1, -1, err |
|
| 73 |
+ return -1, err |
|
| 69 | 74 |
} |
| 70 |
- minorVersion, err := strconv.Atoi(v[1]) |
|
| 71 |
- if err != nil {
|
|
| 72 |
- return -1, -1, err |
|
| 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 |
+ } |
|
| 73 | 87 |
} |
| 74 | 88 |
|
| 75 |
- return majorVersion, minorVersion, nil |
|
| 89 |
+ // major*10^5 + minor*10^3 + patch*10^0 |
|
| 90 |
+ numericVersion := majorVersion*1e5 + minorVersion*1e3 + patchLevel |
|
| 91 |
+ return numericVersion, nil |
|
| 76 | 92 |
} |
| ... | ... |
@@ -5,9 +5,8 @@ import ( |
| 5 | 5 |
) |
| 6 | 6 |
|
| 7 | 7 |
type versionExpected struct {
|
| 8 |
- output string |
|
| 9 |
- major int |
|
| 10 |
- minor int |
|
| 8 |
+ output string |
|
| 9 |
+ version int |
|
| 11 | 10 |
} |
| 12 | 11 |
|
| 13 | 12 |
func TestParseVersion(t *testing.T) {
|
| ... | ... |
@@ -18,8 +17,7 @@ Copyright (C) 1999-2008 Novell Inc. |
| 18 | 18 |
Copyright 2009-2012 Canonical Ltd. |
| 19 | 19 |
|
| 20 | 20 |
`, |
| 21 |
- major: 2, |
|
| 22 |
- minor: 10, |
|
| 21 |
+ version: 210000, |
|
| 23 | 22 |
}, |
| 24 | 23 |
{
|
| 25 | 24 |
output: `AppArmor parser version 2.8 |
| ... | ... |
@@ -27,8 +25,7 @@ Copyright (C) 1999-2008 Novell Inc. |
| 27 | 27 |
Copyright 2009-2012 Canonical Ltd. |
| 28 | 28 |
|
| 29 | 29 |
`, |
| 30 |
- major: 2, |
|
| 31 |
- minor: 8, |
|
| 30 |
+ version: 208000, |
|
| 32 | 31 |
}, |
| 33 | 32 |
{
|
| 34 | 33 |
output: `AppArmor parser version 2.20 |
| ... | ... |
@@ -36,8 +33,7 @@ Copyright (C) 1999-2008 Novell Inc. |
| 36 | 36 |
Copyright 2009-2012 Canonical Ltd. |
| 37 | 37 |
|
| 38 | 38 |
`, |
| 39 |
- major: 2, |
|
| 40 |
- minor: 20, |
|
| 39 |
+ version: 220000, |
|
| 41 | 40 |
}, |
| 42 | 41 |
{
|
| 43 | 42 |
output: `AppArmor parser version 2.05 |
| ... | ... |
@@ -45,21 +41,33 @@ Copyright (C) 1999-2008 Novell Inc. |
| 45 | 45 |
Copyright 2009-2012 Canonical Ltd. |
| 46 | 46 |
|
| 47 | 47 |
`, |
| 48 |
- major: 2, |
|
| 49 |
- minor: 5, |
|
| 48 |
+ version: 205000, |
|
| 49 |
+ }, |
|
| 50 |
+ {
|
|
| 51 |
+ output: `AppArmor parser version 2.9.95 |
|
| 52 |
+Copyright (C) 1999-2008 Novell Inc. |
|
| 53 |
+Copyright 2009-2012 Canonical Ltd. |
|
| 54 |
+ |
|
| 55 |
+`, |
|
| 56 |
+ version: 209095, |
|
| 57 |
+ }, |
|
| 58 |
+ {
|
|
| 59 |
+ output: `AppArmor parser version 3.14.159 |
|
| 60 |
+Copyright (C) 1999-2008 Novell Inc. |
|
| 61 |
+Copyright 2009-2012 Canonical Ltd. |
|
| 62 |
+ |
|
| 63 |
+`, |
|
| 64 |
+ version: 314159, |
|
| 50 | 65 |
}, |
| 51 | 66 |
} |
| 52 | 67 |
|
| 53 | 68 |
for _, v := range versions {
|
| 54 |
- major, minor, err := parseVersion(v.output) |
|
| 69 |
+ version, err := parseVersion(v.output) |
|
| 55 | 70 |
if err != nil {
|
| 56 | 71 |
t.Fatalf("expected error to be nil for %#v, got: %v", v, err)
|
| 57 | 72 |
} |
| 58 |
- if major != v.major {
|
|
| 59 |
- t.Fatalf("expected major version to be %d, was %d, for: %#v\n", v.major, major, v)
|
|
| 60 |
- } |
|
| 61 |
- if minor != v.minor {
|
|
| 62 |
- t.Fatalf("expected minor version to be %d, was %d, for: %#v\n", v.minor, minor, v)
|
|
| 73 |
+ if version != v.version {
|
|
| 74 |
+ t.Fatalf("expected version to be %d, was %d, for: %#v\n", v.version, version, v)
|
|
| 63 | 75 |
} |
| 64 | 76 |
} |
| 65 | 77 |
} |
| ... | ... |
@@ -30,10 +30,8 @@ type profileData struct {
|
| 30 | 30 |
Imports []string |
| 31 | 31 |
// InnerImports defines the apparmor functions to import in the profile. |
| 32 | 32 |
InnerImports []string |
| 33 |
- // MajorVersion is the apparmor_parser major version. |
|
| 34 |
- MajorVersion int |
|
| 35 |
- // MinorVersion is the apparmor_parser minor version. |
|
| 36 |
- MinorVersion int |
|
| 33 |
+ // Version is the {major, minor, patch} version of apparmor_parser as a single number.
|
|
| 34 |
+ Version int |
|
| 37 | 35 |
} |
| 38 | 36 |
|
| 39 | 37 |
// generateDefault creates an apparmor profile from ProfileData. |
| ... | ... |
@@ -38,13 +38,13 @@ profile {{.Name}} flags=(attach_disconnected,mediate_deleted) {
|
| 38 | 38 |
deny /sys/firmware/efi/efivars/** rwklx, |
| 39 | 39 |
deny /sys/kernel/security/** rwklx, |
| 40 | 40 |
|
| 41 |
-{{if ge .MajorVersion 2}}{{if ge .MinorVersion 8}}
|
|
| 41 |
+{{if ge .Version 208000}}
|
|
| 42 | 42 |
# suppress ptrace denials when using 'docker ps' or using 'ps' inside a container |
| 43 | 43 |
ptrace (trace,read) peer=docker-default, |
| 44 |
-{{end}}{{end}}
|
|
| 45 |
-{{if ge .MajorVersion 2}}{{if ge .MinorVersion 9}}
|
|
| 44 |
+{{end}}
|
|
| 45 |
+{{if ge .Version 209000}}
|
|
| 46 | 46 |
# docker daemon confinement requires explict allow rule for signal |
| 47 | 47 |
signal (receive) set=(kill,term) peer={{.ExecPath}},
|
| 48 |
-{{end}}{{end}}
|
|
| 48 |
+{{end}}
|
|
| 49 | 49 |
} |
| 50 | 50 |
` |