From ba94f4ef0f1920932f45cd5f7290c3a8fc6dcd81 Mon Sep 17 00:00:00 2001 From: James Henstridge Date: Fri, 8 Sep 2017 17:12:05 +0800 Subject: [PATCH 1/5] interfaces: mount host system fonts in desktop interface --- interfaces/builtin/desktop.go | 69 ++++++++++++++++++++++++++---- interfaces/builtin/desktop_test.go | 37 ++++++++++++++++ 2 files changed, 98 insertions(+), 8 deletions(-) diff --git a/interfaces/builtin/desktop.go b/interfaces/builtin/desktop.go index 4459bb2fd8b..1bd30cc7168 100644 --- a/interfaces/builtin/desktop.go +++ b/interfaces/builtin/desktop.go @@ -19,6 +19,14 @@ package builtin +import ( + "github.com/snapcore/snapd/interfaces" + "github.com/snapcore/snapd/interfaces/apparmor" + "github.com/snapcore/snapd/interfaces/mount" + "github.com/snapcore/snapd/osutil" + "github.com/snapcore/snapd/release" +) + const desktopSummary = `allows access to basic graphical desktop resources` const desktopBaseDeclarationSlots = ` @@ -117,13 +125,58 @@ dbus (send) deny /{dev,run,var/run}/shm/lttng-ust-* rw, ` +var desktopFontconfigDirs = []string{ + "/usr/share/fonts", + "/usr/local/share/fonts", + "/var/cache/fontconfig", +} + +type desktopInterface struct{} + +func (iface *desktopInterface) Name() string { + return "desktop" +} + +func (iface *desktopInterface) StaticInfo() interfaces.StaticInfo { + return interfaces.StaticInfo{ + Summary: desktopSummary, + ImplicitOnClassic: true, + BaseDeclarationSlots: desktopBaseDeclarationSlots, + } +} + +func (iface *desktopInterface) SanitizeSlot(slot *interfaces.Slot) error { + return sanitizeSlotReservedForOS(iface, slot) +} + +func (iface *desktopInterface) AutoConnect(*interfaces.Plug, *interfaces.Slot) bool { + return true +} + +func (iface *desktopInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.Plug, plugAttrs map[string]interface{}, slot *interfaces.Slot, slotAttrs map[string]interface{}) error { + spec.AddSnippet(desktopConnectedPlugAppArmor) + return nil +} + +func (iface *desktopInterface) MountConnectedPlug(spec *mount.Specification, plug *interfaces.Plug, plugAttrs map[string]interface{}, slot *interfaces.Slot, slotAttrs map[string]interface{}) error { + if !release.OnClassic { + // There is nothing to expose on an all-snaps system + return nil + } + + for _, dir := range desktopFontconfigDirs { + if !osutil.IsDirectory(dir) { + continue + } + spec.AddMountEntry(mount.Entry{ + Name: "/var/lib/snapd/hostfs" + dir, + Dir: dir, + Options: []string{"bind", "ro"}, + }) + } + return nil +} + func init() { - registerIface(&commonInterface{ - name: "desktop", - summary: desktopSummary, - implicitOnClassic: true, - baseDeclarationSlots: desktopBaseDeclarationSlots, - connectedPlugAppArmor: desktopConnectedPlugAppArmor, - reservedForOS: true, - }) + registerIface(&desktopInterface{}) } diff --git a/interfaces/builtin/desktop_test.go b/interfaces/builtin/desktop_test.go index 6ec4f7ff5c1..c15b4fc56cf 100644 --- a/interfaces/builtin/desktop_test.go +++ b/interfaces/builtin/desktop_test.go @@ -25,6 +25,9 @@ import ( "github.com/snapcore/snapd/interfaces" "github.com/snapcore/snapd/interfaces/apparmor" "github.com/snapcore/snapd/interfaces/builtin" + "github.com/snapcore/snapd/interfaces/mount" + "github.com/snapcore/snapd/osutil" + "github.com/snapcore/snapd/release" "github.com/snapcore/snapd/snap" "github.com/snapcore/snapd/testutil" ) @@ -91,6 +94,40 @@ func (s *DesktopInterfaceSuite) TestAppArmorSpec(c *C) { c.Assert(spec.SecurityTags(), HasLen, 0) } +func (s *DesktopInterfaceSuite) TestMountSpec(c *C) { + restore := release.MockOnClassic(false) + defer restore() + + // On all-snaps systems, no mount entries are added + spec := &mount.Specification{} + c.Assert(spec.AddConnectedPlug(s.iface, s.plug, nil, s.coreSlot, nil), IsNil) + c.Check(spec.MountEntries(), HasLen, 0) + + // On classic systems, a number of font related directories + // are bind mounted from the host system if they exist. + release.OnClassic = true + spec = &mount.Specification{} + c.Assert(spec.AddConnectedPlug(s.iface, s.plug, nil, s.coreSlot, nil), IsNil) + expectedMountPoints := []string{ + "/usr/share/fonts", + "/usr/local/share/fonts", + "/var/cache/fontconfig", + } + expected := 0 + for _, dir := range expectedMountPoints { + if osutil.IsDirectory(dir) { + expected += 1 + } + } + entries := spec.MountEntries() + c.Check(entries, HasLen, expected) + for _, entry := range entries { + c.Check(expectedMountPoints, testutil.Contains, entry.Dir) + c.Check(entry.Name, Equals, "/var/lib/snapd/hostfs"+entry.Dir) + c.Check(entry.Options, DeepEquals, []string{"bind", "ro"}) + } +} + func (s *DesktopInterfaceSuite) TestStaticInfo(c *C) { si := interfaces.StaticInfoOf(s.iface) c.Assert(si.ImplicitOnCore, Equals, false) From 36f4877a59f45d7e02b8040de66cb90b9a1a65e0 Mon Sep 17 00:00:00 2001 From: James Henstridge Date: Thu, 14 Sep 2017 19:27:39 +0800 Subject: [PATCH 2/5] interfaces: changes from jdstrand's review --- interfaces/builtin/desktop.go | 1 + interfaces/builtin/desktop_test.go | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/interfaces/builtin/desktop.go b/interfaces/builtin/desktop.go index 1bd30cc7168..b966036d7d9 100644 --- a/interfaces/builtin/desktop.go +++ b/interfaces/builtin/desktop.go @@ -150,6 +150,7 @@ func (iface *desktopInterface) SanitizeSlot(slot *interfaces.Slot) error { } func (iface *desktopInterface) AutoConnect(*interfaces.Plug, *interfaces.Slot) bool { + // allow what declarations allowed return true } diff --git a/interfaces/builtin/desktop_test.go b/interfaces/builtin/desktop_test.go index c15b4fc56cf..64dc81e7b5f 100644 --- a/interfaces/builtin/desktop_test.go +++ b/interfaces/builtin/desktop_test.go @@ -105,7 +105,8 @@ func (s *DesktopInterfaceSuite) TestMountSpec(c *C) { // On classic systems, a number of font related directories // are bind mounted from the host system if they exist. - release.OnClassic = true + restore = release.MockOnClassic(true) + defer restore() spec = &mount.Specification{} c.Assert(spec.AddConnectedPlug(s.iface, s.plug, nil, s.coreSlot, nil), IsNil) expectedMountPoints := []string{ From ff3c33ef56b2c527e66a6fbbbc17413bf9391cf6 Mon Sep 17 00:00:00 2001 From: James Henstridge Date: Thu, 14 Sep 2017 19:54:00 +0800 Subject: [PATCH 3/5] interfaces, dirs: respect GlobalRootDir --- dirs/dirs.go | 8 +++++ interfaces/builtin/desktop.go | 17 ++++++----- interfaces/builtin/desktop_test.go | 47 ++++++++++++++++++------------ 3 files changed, 46 insertions(+), 26 deletions(-) diff --git a/dirs/dirs.go b/dirs/dirs.go index dc6755c0d15..db6f5767b10 100644 --- a/dirs/dirs.go +++ b/dirs/dirs.go @@ -87,6 +87,10 @@ var ( CompletionHelper string CompletersDir string CompleteSh string + + SystemFontsDir string + SystemLocalFontsDir string + SystemFontconfigCacheDir string ) const ( @@ -224,4 +228,8 @@ func SetRootDir(rootdir string) { CompletionHelper = filepath.Join(CoreLibExecDir, "etelpmoc.sh") CompletersDir = filepath.Join(rootdir, "/usr/share/bash-completion/completions/") CompleteSh = filepath.Join(SnapMountDir, "core/current/usr/lib/snapd/complete.sh") + + SystemFontsDir = filepath.Join(rootdir, "/usr/share/fonts") + SystemLocalFontsDir = filepath.Join(rootdir, "/usr/local/share/fonts") + SystemFontconfigCacheDir = filepath.Join(rootdir, "/var/cache/fontconfig") } diff --git a/interfaces/builtin/desktop.go b/interfaces/builtin/desktop.go index b966036d7d9..6345d565bb6 100644 --- a/interfaces/builtin/desktop.go +++ b/interfaces/builtin/desktop.go @@ -20,6 +20,7 @@ package builtin import ( + "github.com/snapcore/snapd/dirs" "github.com/snapcore/snapd/interfaces" "github.com/snapcore/snapd/interfaces/apparmor" "github.com/snapcore/snapd/interfaces/mount" @@ -125,12 +126,6 @@ dbus (send) deny /{dev,run,var/run}/shm/lttng-ust-* rw, ` -var desktopFontconfigDirs = []string{ - "/usr/share/fonts", - "/usr/local/share/fonts", - "/var/cache/fontconfig", -} - type desktopInterface struct{} func (iface *desktopInterface) Name() string { @@ -165,13 +160,19 @@ func (iface *desktopInterface) MountConnectedPlug(spec *mount.Specification, plu return nil } - for _, dir := range desktopFontconfigDirs { + fontconfigDirs := []string{ + dirs.SystemFontsDir, + dirs.SystemLocalFontsDir, + dirs.SystemFontconfigCacheDir, + } + + for _, dir := range fontconfigDirs { if !osutil.IsDirectory(dir) { continue } spec.AddMountEntry(mount.Entry{ Name: "/var/lib/snapd/hostfs" + dir, - Dir: dir, + Dir: dirs.StripRootDir(dir), Options: []string{"bind", "ro"}, }) } diff --git a/interfaces/builtin/desktop_test.go b/interfaces/builtin/desktop_test.go index 64dc81e7b5f..c3a36e0bd25 100644 --- a/interfaces/builtin/desktop_test.go +++ b/interfaces/builtin/desktop_test.go @@ -20,13 +20,16 @@ package builtin_test import ( + "os" + "path/filepath" + . "gopkg.in/check.v1" + "github.com/snapcore/snapd/dirs" "github.com/snapcore/snapd/interfaces" "github.com/snapcore/snapd/interfaces/apparmor" "github.com/snapcore/snapd/interfaces/builtin" "github.com/snapcore/snapd/interfaces/mount" - "github.com/snapcore/snapd/osutil" "github.com/snapcore/snapd/release" "github.com/snapcore/snapd/snap" "github.com/snapcore/snapd/testutil" @@ -59,6 +62,10 @@ func (s *DesktopInterfaceSuite) SetUpTest(c *C) { s.coreSlot = MockSlot(c, desktopCoreYaml, nil, "desktop") } +func (s *DesktopInterfaceSuite) TearDownTest(c *C) { + dirs.SetRootDir("/") +} + func (s *DesktopInterfaceSuite) TestName(c *C) { c.Assert(s.iface.Name(), Equals, "desktop") } @@ -95,6 +102,12 @@ func (s *DesktopInterfaceSuite) TestAppArmorSpec(c *C) { } func (s *DesktopInterfaceSuite) TestMountSpec(c *C) { + tmpdir := c.MkDir() + dirs.SetRootDir(tmpdir) + c.Assert(os.MkdirAll(filepath.Join(tmpdir, "/usr/share/fonts"), 0777), IsNil) + c.Assert(os.MkdirAll(filepath.Join(tmpdir, "/usr/local/share/fonts"), 0777), IsNil) + c.Assert(os.MkdirAll(filepath.Join(tmpdir, "/var/cache/fontconfig"), 0777), IsNil) + restore := release.MockOnClassic(false) defer restore() @@ -109,24 +122,22 @@ func (s *DesktopInterfaceSuite) TestMountSpec(c *C) { defer restore() spec = &mount.Specification{} c.Assert(spec.AddConnectedPlug(s.iface, s.plug, nil, s.coreSlot, nil), IsNil) - expectedMountPoints := []string{ - "/usr/share/fonts", - "/usr/local/share/fonts", - "/var/cache/fontconfig", - } - expected := 0 - for _, dir := range expectedMountPoints { - if osutil.IsDirectory(dir) { - expected += 1 - } - } + entries := spec.MountEntries() - c.Check(entries, HasLen, expected) - for _, entry := range entries { - c.Check(expectedMountPoints, testutil.Contains, entry.Dir) - c.Check(entry.Name, Equals, "/var/lib/snapd/hostfs"+entry.Dir) - c.Check(entry.Options, DeepEquals, []string{"bind", "ro"}) - } + c.Assert(entries, HasLen, 3) + + const hostfs = "/var/lib/snapd/hostfs" + c.Check(entries[0].Name, Equals, hostfs + dirs.SystemFontsDir) + c.Check(entries[0].Dir, Equals, "/usr/share/fonts") + c.Check(entries[0].Options, DeepEquals, []string{"bind", "ro"}) + + c.Check(entries[1].Name, Equals, hostfs + dirs.SystemLocalFontsDir) + c.Check(entries[1].Dir, Equals, "/usr/local/share/fonts") + c.Check(entries[1].Options, DeepEquals, []string{"bind", "ro"}) + + c.Check(entries[2].Name, Equals, hostfs + dirs.SystemFontconfigCacheDir) + c.Check(entries[2].Dir, Equals, "/var/cache/fontconfig") + c.Check(entries[2].Options, DeepEquals, []string{"bind", "ro"}) } func (s *DesktopInterfaceSuite) TestStaticInfo(c *C) { From cb60ba4fac8375885a01d04430eb091b022f8c7d Mon Sep 17 00:00:00 2001 From: James Henstridge Date: Thu, 14 Sep 2017 20:28:08 +0800 Subject: [PATCH 4/5] cmd/snap-confine: allow mounting of fonts --- cmd/snap-confine/snap-confine.apparmor.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd/snap-confine/snap-confine.apparmor.in b/cmd/snap-confine/snap-confine.apparmor.in index d943703a6b8..a2bc1c0d2dd 100644 --- a/cmd/snap-confine/snap-confine.apparmor.in +++ b/cmd/snap-confine/snap-confine.apparmor.in @@ -242,6 +242,10 @@ audit deny mount /** -> /snap/bin/**, # Allow the content interface to bind fonts from the host filesystem mount options=(ro bind) /var/lib/snapd/hostfs/usr/share/fonts/ -> /snap/*/*/**, + # Allow the desktop interface to bind fonts from the host filesystem + mount options=(ro bind) /var/lib/snapd/hostfs/usr/share/fonts -> /usr/share/fonts, + mount options=(ro bind) /var/lib/snapd/hostfs/usr/local/share/fonts -> /usr/local/share/fonts, + mount options=(ro bind) /var/lib/snapd/hostfs/var/cache/fontconfig -> /var/cache/fontconfig, # nvidia handling, glob needs /usr/** and the launcher must be # able to bind mount the nvidia dir From 1d76910ecae4993c0716faf0ce79a5ac9273e4a5 Mon Sep 17 00:00:00 2001 From: James Henstridge Date: Fri, 15 Sep 2017 00:09:56 +0800 Subject: [PATCH 5/5] interfaces: fix formatting --- interfaces/builtin/desktop_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interfaces/builtin/desktop_test.go b/interfaces/builtin/desktop_test.go index c3a36e0bd25..2d0554ee9c9 100644 --- a/interfaces/builtin/desktop_test.go +++ b/interfaces/builtin/desktop_test.go @@ -127,15 +127,15 @@ func (s *DesktopInterfaceSuite) TestMountSpec(c *C) { c.Assert(entries, HasLen, 3) const hostfs = "/var/lib/snapd/hostfs" - c.Check(entries[0].Name, Equals, hostfs + dirs.SystemFontsDir) + c.Check(entries[0].Name, Equals, hostfs+dirs.SystemFontsDir) c.Check(entries[0].Dir, Equals, "/usr/share/fonts") c.Check(entries[0].Options, DeepEquals, []string{"bind", "ro"}) - c.Check(entries[1].Name, Equals, hostfs + dirs.SystemLocalFontsDir) + c.Check(entries[1].Name, Equals, hostfs+dirs.SystemLocalFontsDir) c.Check(entries[1].Dir, Equals, "/usr/local/share/fonts") c.Check(entries[1].Options, DeepEquals, []string{"bind", "ro"}) - c.Check(entries[2].Name, Equals, hostfs + dirs.SystemFontconfigCacheDir) + c.Check(entries[2].Name, Equals, hostfs+dirs.SystemFontconfigCacheDir) c.Check(entries[2].Dir, Equals, "/var/cache/fontconfig") c.Check(entries[2].Options, DeepEquals, []string{"bind", "ro"}) }