Skip to content

Commit

Permalink
snaptool: check for binary existance in InternalToolPath()
Browse files Browse the repository at this point in the history
The current version of `InternalToolPath()` does not actually
checks in all cases if the binary is actually there. Historically
this was not a problem but with recent snapd releases we have
the internal tool `apparmor_parser` that is only available in
the `snapd` snap but not in the `core` snap. This means that
on systems that have the snapd deb and only core `InternalToolPath`
may return `/snap/core/123/usr/lib/snapd/apparmor_parser` even
if this tool in not available inside the core snap.

This commit fixes this by checking if the actual executable
is available.
  • Loading branch information
mvo5 committed Sep 27, 2023
1 parent 8b353cc commit da91a24
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 14 deletions.
5 changes: 4 additions & 1 deletion snapdtool/tool_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,10 @@ func InternalToolPath(tool string) (string, error) {
// only assume mounted location when path contains
// /usr/, but does not start with one
prefix := exe[:idx]
return filepath.Join(prefix, "/usr/lib/snapd", tool), nil
maybeTool := filepath.Join(prefix, "/usr/lib/snapd", tool)
if osutil.IsExecutable(maybeTool) {
return maybeTool, nil
}
}
if idx == -1 {
// or perhaps some other random location, make sure the tool
Expand Down
42 changes: 29 additions & 13 deletions snapdtool/tool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,17 @@ func (s *toolSuite) fakeCoreVersion(c *C, coreDir, version string) {
c.Assert(os.WriteFile(filepath.Join(p, "info"), []byte("VERSION="+version), 0644), IsNil)
}

func makeFakeExe(c *C, path string) {
err := os.MkdirAll(filepath.Dir(path), 0755)
c.Assert(err, IsNil)
err = os.WriteFile(path, nil, 0755)
c.Assert(err, IsNil)
}

func (s *toolSuite) fakeInternalTool(c *C, coreDir, toolName string) string {
s.fakeCoreVersion(c, coreDir, "42")
p := filepath.Join(coreDir, "/usr/lib/snapd", toolName)
c.Assert(os.WriteFile(p, nil, 0755), IsNil)
makeFakeExe(c, p)

return p
}
Expand Down Expand Up @@ -223,37 +230,46 @@ func (s *toolSuite) TestInternalToolPathWithReexec(c *C) {
}

func (s *toolSuite) TestInternalToolPathWithOtherLocation(c *C) {
s.fakeInternalTool(c, s.snapdPath, "potato")
tmpdir := c.MkDir()
restore := snapdtool.MockOsReadlink(func(string) (string, error) {
return filepath.Join("/tmp/tmp.foo_1234/usr/lib/snapd/snapd"), nil
return filepath.Join(tmpdir, "/tmp/tmp.foo_1234/usr/lib/snapd/snapd"), nil
})
defer restore()

devTool := filepath.Join(tmpdir, "/tmp/tmp.foo_1234/usr/lib/snapd/potato")
makeFakeExe(c, devTool)

path, err := snapdtool.InternalToolPath("potato")
c.Check(err, IsNil)
c.Check(path, Equals, "/tmp/tmp.foo_1234/usr/lib/snapd/potato")
c.Check(path, Equals, tmpdir+"/tmp/tmp.foo_1234/usr/lib/snapd/potato")
}

func (s *toolSuite) TestInternalToolSnapPathWithOtherLocation(c *C) {
tmpdir := c.MkDir()
restore := snapdtool.MockOsReadlink(func(string) (string, error) {
return filepath.Join("/tmp/tmp.foo_1234/usr/bin/snap"), nil
return filepath.Join(tmpdir, "/tmp/tmp.foo_1234/usr/bin/snap"), nil
})
defer restore()

devTool := filepath.Join(tmpdir, "/tmp/tmp.foo_1234/usr/lib/snapd/potato")
makeFakeExe(c, devTool)

path, err := snapdtool.InternalToolPath("potato")
c.Check(err, IsNil)
c.Check(path, Equals, "/tmp/tmp.foo_1234/usr/lib/snapd/potato")
c.Check(path, Equals, tmpdir+"/tmp/tmp.foo_1234/usr/lib/snapd/potato")
}

func (s *toolSuite) TestInternalToolPathWithOtherCrazyLocation(c *C) {
tmpdir := c.MkDir()
s.fakeInternalTool(c, filepath.Join(tmpdir, "/usr/foo/usr/tmp/tmp.foo_1234"), "potato")
restore := snapdtool.MockOsReadlink(func(string) (string, error) {
return filepath.Join("/usr/foo/usr/tmp/tmp.foo_1234/usr/bin/snap"), nil
return filepath.Join(tmpdir, "/usr/foo/usr/tmp/tmp.foo_1234/usr/bin/snap"), nil
})
defer restore()

path, err := snapdtool.InternalToolPath("potato")
c.Check(err, IsNil)
c.Check(path, Equals, "/usr/foo/usr/tmp/tmp.foo_1234/usr/lib/snapd/potato")
c.Check(path, Equals, tmpdir+"/usr/foo/usr/tmp/tmp.foo_1234/usr/lib/snapd/potato")
}

func (s *toolSuite) TestInternalToolPathWithDevLocationFallback(c *C) {
Expand Down Expand Up @@ -290,18 +306,16 @@ func (s *toolSuite) TestInternalToolPathWithOtherDevLocationNonExecutable(c *C)
})
defer restore()

devTool := filepath.Join(dirs.GlobalRootDir, "/tmp/non-executable-potato")
err := os.MkdirAll(filepath.Dir(devTool), 0755)
c.Assert(err, IsNil)
err = os.WriteFile(devTool, []byte(""), 0644)
c.Assert(err, IsNil)
devTool := filepath.Join(dirs.GlobalRootDir, "/tmp/potato")
makeFakeExe(c, devTool)

path, err := snapdtool.InternalToolPath("non-executable-potato")
c.Check(err, IsNil)
c.Check(path, Equals, filepath.Join(dirs.DistroLibExecDir, "non-executable-potato"))
}

func (s *toolSuite) TestInternalToolPathSnapdPathReexec(c *C) {
s.fakeInternalTool(c, filepath.Join(dirs.SnapMountDir, "core/111"), "snapd")
restore := snapdtool.MockOsReadlink(func(string) (string, error) {
return filepath.Join(dirs.SnapMountDir, "core/111/usr/bin/snap"), nil
})
Expand All @@ -313,10 +327,12 @@ func (s *toolSuite) TestInternalToolPathSnapdPathReexec(c *C) {
}

func (s *toolSuite) TestInternalToolPathSnapdSnap(c *C) {
s.fakeInternalTool(c, filepath.Join(dirs.SnapMountDir, "snapd/22"), "snapd")
restore := snapdtool.MockOsReadlink(func(string) (string, error) {
return filepath.Join(dirs.SnapMountDir, "snapd/22/usr/bin/snap"), nil
})
defer restore()

p, err := snapdtool.InternalToolPath("snapd")
c.Assert(err, IsNil)
c.Check(p, Equals, filepath.Join(dirs.SnapMountDir, "/snapd/22/usr/lib/snapd/snapd"))
Expand Down

0 comments on commit da91a24

Please sign in to comment.