diff options
| -rw-r--r-- | interfaces/apparmor/template.go | 1 | ||||
| -rw-r--r-- | sandbox/apparmor/apparmor.go | 30 | ||||
| -rw-r--r-- | sandbox/apparmor/apparmor_test.go | 60 | ||||
| -rw-r--r-- | sandbox/apparmor/export_test.go | 1 | ||||
| -rw-r--r-- | tests/core/basic18/task.yaml | 9 | ||||
| -rw-r--r-- | tests/core/basic20plus/task.yaml | 9 | ||||
| -rw-r--r-- | tests/main/snapd-snap/task.yaml | 6 |
7 files changed, 115 insertions, 1 deletions
diff --git a/interfaces/apparmor/template.go b/interfaces/apparmor/template.go index e9f3eafaa4..11e218acf3 100644 --- a/interfaces/apparmor/template.go +++ b/interfaces/apparmor/template.go @@ -1072,6 +1072,7 @@ profile snap-update-ns.###SNAP_INSTANCE_NAME### (attach_disconnected) { # snap checks if vendored apparmor parser should be used at startup /usr/lib/snapd/info r, + /lib/apparmor/functions r, ###SNIPPETS### } diff --git a/sandbox/apparmor/apparmor.go b/sandbox/apparmor/apparmor.go index d0932ee1d1..24d82f04ca 100644 --- a/sandbox/apparmor/apparmor.go +++ b/sandbox/apparmor/apparmor.go @@ -20,6 +20,7 @@ package apparmor import ( + "bufio" "bytes" "fmt" "io/ioutil" @@ -31,6 +32,7 @@ import ( "sync" "github.com/snapcore/snapd/dirs" + "github.com/snapcore/snapd/logger" "github.com/snapcore/snapd/osutil" "github.com/snapcore/snapd/snapdtool" "github.com/snapcore/snapd/strutil" @@ -405,6 +407,32 @@ func probeParserFeatures() ([]string, error) { return features, nil } +func systemAppArmorLoadsSnapPolicy() bool { + // on older Ubuntu systems the system installed apparmor may try and + // load snapd generated apparmor policy (LP: #2024637) + f, err := os.Open(filepath.Join(dirs.GlobalRootDir, "/lib/apparmor/functions")) + if err != nil { + if !os.IsNotExist(err) { + logger.Debugf("cannot open apparmor functions file: %v", err) + } + return false + } + defer f.Close() + + scanner := bufio.NewScanner(f) + for scanner.Scan() { + line := scanner.Text() + if strings.Contains(line, dirs.SnapAppArmorDir) { + return true + } + } + if scanner.Err() != nil { + logger.Debugf("cannot scan apparmor functions file: %v", scanner.Err()) + } + + return false +} + func snapdAppArmorSupportsReexecImpl() bool { hostInfoDir := filepath.Join(dirs.GlobalRootDir, dirs.CoreLibExecDir) _, flags, err := snapdtool.SnapdVersionFromInfoFile(hostInfoDir) @@ -422,7 +450,7 @@ func AppArmorParser() (cmd *exec.Cmd, internal bool, err error) { // - but only use the internal one when we know that the system // installed snapd-apparmor support re-exec if path, err := snapdtool.InternalToolPath("apparmor_parser"); err == nil { - if osutil.IsExecutable(path) && snapdAppArmorSupportsReexec() { + if osutil.IsExecutable(path) && snapdAppArmorSupportsReexec() && !systemAppArmorLoadsSnapPolicy() { prefix := strings.TrimSuffix(path, "apparmor_parser") // when using the internal apparmor_parser also use // its own configuration and includes etc plus diff --git a/sandbox/apparmor/apparmor_test.go b/sandbox/apparmor/apparmor_test.go index 038865aea3..863e966c10 100644 --- a/sandbox/apparmor/apparmor_test.go +++ b/sandbox/apparmor/apparmor_test.go @@ -33,6 +33,7 @@ import ( . "gopkg.in/check.v1" "github.com/snapcore/snapd/dirs" + "github.com/snapcore/snapd/logger" "github.com/snapcore/snapd/osutil" "github.com/snapcore/snapd/sandbox/apparmor" "github.com/snapcore/snapd/snapdtool" @@ -539,3 +540,62 @@ func (s *apparmorSuite) TestSetupConfCacheDirsWithInternalApparmor(c *C) { apparmor.SetupConfCacheDirs("/newdir") c.Check(apparmor.SnapConfineAppArmorDir, Equals, "/newdir/var/lib/snapd/apparmor/snap-confine.internal") } + +func (s *apparmorSuite) TestSystemAppArmorLoadsSnapPolicyErr(c *C) { + fakeroot := c.MkDir() + dirs.SetRootDir(fakeroot) + fakeApparmorFunctionsPath := filepath.Join(fakeroot, "/lib/apparmor/functions") + err := os.MkdirAll(filepath.Dir(fakeApparmorFunctionsPath), 0750) + c.Assert(err, IsNil) + + os.Setenv("SNAPD_DEBUG", "1") + defer os.Unsetenv("SNAPD_DEBUG") + + log, restore := logger.MockLogger() + defer restore() + + // no log output on missing file + c.Check(apparmor.SystemAppArmorLoadsSnapPolicy(), Equals, false) + c.Check(log.String(), Equals, "") + + // permissions are ignored as root + if os.Getuid() == 0 { + return + } + // log generated for errors + err = ioutil.WriteFile(fakeApparmorFunctionsPath, nil, 0100) + c.Assert(err, IsNil) + c.Check(apparmor.SystemAppArmorLoadsSnapPolicy(), Equals, false) + c.Check(log.String(), Matches, `(?ms).* DEBUG: cannot open apparmor functions file: open .*/lib/apparmor/functions: permission denied`) +} + +func (s *apparmorSuite) TestSystemAppArmorLoadsSnapPolicy(c *C) { + fakeroot := c.MkDir() + dirs.SetRootDir(fakeroot) + + // systemAppArmorLoadsSnapPolicy() will look at this path so it + // needs to be the real path, not a faked one + dirs.SnapAppArmorDir = dirs.SnapAppArmorDir[len(fakeroot):] + + fakeApparmorFunctionsPath := filepath.Join(fakeroot, "/lib/apparmor/functions") + err := os.MkdirAll(filepath.Dir(fakeApparmorFunctionsPath), 0755) + c.Assert(err, IsNil) + + for _, tc := range []struct { + apparmorFunctionsContent string + expectedResult bool + }{ + {"", false}, + {"unrelated content", false}, + // 16.04 + {`PROFILES_SNAPPY="/var/lib/snapd/apparmor/profiles"`, true}, + // 18.04 + {`PROFILES_VAR="/var/lib/snapd/apparmor/profiles"`, true}, + } { + err := ioutil.WriteFile(fakeApparmorFunctionsPath, []byte(tc.apparmorFunctionsContent), 0644) + c.Assert(err, IsNil) + + loadsPolicy := apparmor.SystemAppArmorLoadsSnapPolicy() + c.Check(loadsPolicy, Equals, tc.expectedResult, Commentf("%v", tc)) + } +} diff --git a/sandbox/apparmor/export_test.go b/sandbox/apparmor/export_test.go index 567b36218d..0027859da5 100644 --- a/sandbox/apparmor/export_test.go +++ b/sandbox/apparmor/export_test.go @@ -102,6 +102,7 @@ var ( PreferredParserFeatures = preferredParserFeatures SnapdAppArmorSupportsRexecImpl = snapdAppArmorSupportsReexecImpl + SystemAppArmorLoadsSnapPolicy = systemAppArmorLoadsSnapPolicy ) func FreshAppArmorAssessment() { diff --git a/tests/core/basic18/task.yaml b/tests/core/basic18/task.yaml index 2ba03a3e48..b898689e25 100644 --- a/tests/core/basic18/task.yaml +++ b/tests/core/basic18/task.yaml @@ -25,3 +25,12 @@ execute: | echo "Ensure passwd/group is available for snaps" test-snapd-sh-core18.sh -c 'cat /var/lib/extrausers/passwd' | MATCH test + + # ensure apparmor works, see LP: 2024637 + systemctl status apparmor.service + + # reboot to double check that apparmor still works after the reboot + # (LP: 2024637) + if [ "$SPREAD_REBOOT" = 0 ]; then + REBOOT + fi diff --git a/tests/core/basic20plus/task.yaml b/tests/core/basic20plus/task.yaml index 40a297ca02..63647c39be 100644 --- a/tests/core/basic20plus/task.yaml +++ b/tests/core/basic20plus/task.yaml @@ -111,3 +111,12 @@ execute: | echo "${loop}" | MATCH "/dev/loop[0-9]+" losetup -O ro -n --raw "${loop}" | MATCH "1" done + + # ensure apparmor works, see LP: 2024637 + systemctl status apparmor.service + + # reboot to double check that apparmor still works after the reboot + # (LP: 2024637) + if [ "$SPREAD_REBOOT" = 0 ]; then + REBOOT + fi diff --git a/tests/main/snapd-snap/task.yaml b/tests/main/snapd-snap/task.yaml index 64e2bef335..d6c88542fb 100644 --- a/tests/main/snapd-snap/task.yaml +++ b/tests/main/snapd-snap/task.yaml @@ -235,6 +235,12 @@ execute: | echo "Ensure we restarted into the snapd snap" "$TESTSTOOLS"/journal-state match-log 'restarting into "/snap/snapd/' + # see LP:2024637 + if grep -q /var/lib/snapd/apparmor/ /lib/apparmor/functions; then + echo "SKIP: cannot test builtin apparmor parser until /lib/apparmor/functions stops loading the snapd profiles" + exit 0 + fi + echo "Ensure sandbox-features shows the internal apparmor_parser" snap debug sandbox-features --required apparmor:parser:snapd-internal |
