github.com/anonymouse64/snapd@v0.0.0-20210824153203-04c4c42d842d/interfaces/apparmor/spec_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016-2018 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package apparmor_test
    21  
    22  import (
    23  	"strings"
    24  
    25  	. "gopkg.in/check.v1"
    26  
    27  	"github.com/snapcore/snapd/interfaces"
    28  	"github.com/snapcore/snapd/interfaces/apparmor"
    29  	"github.com/snapcore/snapd/interfaces/ifacetest"
    30  	"github.com/snapcore/snapd/snap"
    31  	"github.com/snapcore/snapd/snap/snaptest"
    32  	"github.com/snapcore/snapd/testutil"
    33  )
    34  
    35  type specSuite struct {
    36  	testutil.BaseTest
    37  	iface    *ifacetest.TestInterface
    38  	spec     *apparmor.Specification
    39  	plugInfo *snap.PlugInfo
    40  	plug     *interfaces.ConnectedPlug
    41  	slotInfo *snap.SlotInfo
    42  	slot     *interfaces.ConnectedSlot
    43  }
    44  
    45  var _ = Suite(&specSuite{
    46  	iface: &ifacetest.TestInterface{
    47  		InterfaceName: "test",
    48  		AppArmorConnectedPlugCallback: func(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
    49  			spec.AddSnippet("connected-plug")
    50  			return nil
    51  		},
    52  		AppArmorConnectedSlotCallback: func(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
    53  			spec.AddSnippet("connected-slot")
    54  			return nil
    55  		},
    56  		AppArmorPermanentPlugCallback: func(spec *apparmor.Specification, plug *snap.PlugInfo) error {
    57  			spec.AddSnippet("permanent-plug")
    58  			return nil
    59  		},
    60  		AppArmorPermanentSlotCallback: func(spec *apparmor.Specification, slot *snap.SlotInfo) error {
    61  			spec.AddSnippet("permanent-slot")
    62  			return nil
    63  		},
    64  	},
    65  	plugInfo: &snap.PlugInfo{
    66  		Snap:      &snap.Info{SuggestedName: "snap1"},
    67  		Name:      "name",
    68  		Interface: "test",
    69  		Apps: map[string]*snap.AppInfo{
    70  			"app1": {
    71  				Snap: &snap.Info{
    72  					SuggestedName: "snap1",
    73  				},
    74  				Name: "app1"}},
    75  	},
    76  	slotInfo: &snap.SlotInfo{
    77  		Snap:      &snap.Info{SuggestedName: "snap2"},
    78  		Name:      "name",
    79  		Interface: "test",
    80  		Apps: map[string]*snap.AppInfo{
    81  			"app2": {
    82  				Snap: &snap.Info{
    83  					SuggestedName: "snap2",
    84  				},
    85  				Name: "app2"}},
    86  	},
    87  })
    88  
    89  func (s *specSuite) SetUpTest(c *C) {
    90  	s.BaseTest.SetUpTest(c)
    91  	s.BaseTest.AddCleanup(snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {}))
    92  
    93  	s.spec = &apparmor.Specification{}
    94  	s.plug = interfaces.NewConnectedPlug(s.plugInfo, nil, nil)
    95  	s.slot = interfaces.NewConnectedSlot(s.slotInfo, nil, nil)
    96  }
    97  
    98  func (s *specSuite) TearDownTest(c *C) {
    99  	s.BaseTest.TearDownTest(c)
   100  }
   101  
   102  // The spec.Specification can be used through the interfaces.Specification interface
   103  func (s *specSuite) TestSpecificationIface(c *C) {
   104  	var r interfaces.Specification = s.spec
   105  	c.Assert(r.AddConnectedPlug(s.iface, s.plug, s.slot), IsNil)
   106  	c.Assert(r.AddConnectedSlot(s.iface, s.plug, s.slot), IsNil)
   107  	c.Assert(r.AddPermanentPlug(s.iface, s.plugInfo), IsNil)
   108  	c.Assert(r.AddPermanentSlot(s.iface, s.slotInfo), IsNil)
   109  	c.Assert(s.spec.Snippets(), DeepEquals, map[string][]string{
   110  		"snap.snap1.app1": {"connected-plug", "permanent-plug"},
   111  		"snap.snap2.app2": {"connected-slot", "permanent-slot"},
   112  	})
   113  }
   114  
   115  // AddSnippet adds a snippet for the given security tag.
   116  func (s *specSuite) TestAddSnippet(c *C) {
   117  	restore := apparmor.SetSpecScope(s.spec, []string{"snap.demo.command", "snap.demo.service"})
   118  	defer restore()
   119  
   120  	// Add two snippets in the context we are in.
   121  	s.spec.AddSnippet("snippet 1")
   122  	s.spec.AddSnippet("snippet 2")
   123  
   124  	// The snippets were recorded correctly.
   125  	c.Assert(s.spec.UpdateNS(), HasLen, 0)
   126  	c.Assert(s.spec.Snippets(), DeepEquals, map[string][]string{
   127  		"snap.demo.command": {"snippet 1", "snippet 2"},
   128  		"snap.demo.service": {"snippet 1", "snippet 2"},
   129  	})
   130  	c.Assert(s.spec.SnippetsForTag("snap.demo.command"), DeepEquals, []string{"snippet 1", "snippet 2"})
   131  	c.Assert(s.spec.SnippetForTag("snap.demo.command"), Equals, "snippet 1\nsnippet 2")
   132  	c.Assert(s.spec.SecurityTags(), DeepEquals, []string{"snap.demo.command", "snap.demo.service"})
   133  }
   134  
   135  // AddDeduplicatedSnippet adds a snippet for the given security tag.
   136  func (s *specSuite) TestAddDeduplicatedSnippet(c *C) {
   137  	restore := apparmor.SetSpecScope(s.spec, []string{"snap.demo.command", "snap.demo.service"})
   138  	defer restore()
   139  
   140  	// Add two snippets in the context we are in.
   141  	s.spec.AddDeduplicatedSnippet("dedup snippet 1")
   142  	s.spec.AddDeduplicatedSnippet("dedup snippet 1")
   143  	s.spec.AddDeduplicatedSnippet("dedup snippet 2")
   144  	s.spec.AddDeduplicatedSnippet("dedup snippet 2")
   145  
   146  	// The snippets were recorded correctly.
   147  	c.Assert(s.spec.UpdateNS(), HasLen, 0)
   148  	c.Assert(s.spec.Snippets(), DeepEquals, map[string][]string{
   149  		"snap.demo.command": {"dedup snippet 1", "dedup snippet 2"},
   150  		"snap.demo.service": {"dedup snippet 1", "dedup snippet 2"},
   151  	})
   152  	c.Assert(s.spec.SnippetsForTag("snap.demo.command"), DeepEquals, []string{"dedup snippet 1", "dedup snippet 2"})
   153  	c.Assert(s.spec.SnippetForTag("snap.demo.command"), Equals, "dedup snippet 1\ndedup snippet 2")
   154  	c.Assert(s.spec.SecurityTags(), DeepEquals, []string{"snap.demo.command", "snap.demo.service"})
   155  }
   156  
   157  func (s *specSuite) TestAddParametricSnippet(c *C) {
   158  	restore := apparmor.SetSpecScope(s.spec, []string{"snap.demo.command", "snap.demo.service"})
   159  	defer restore()
   160  
   161  	s.spec.AddParametricSnippet([]string{"prefix ", " postfix"}, "param1")
   162  	s.spec.AddParametricSnippet([]string{"prefix ", " postfix"}, "param1")
   163  	s.spec.AddParametricSnippet([]string{"prefix ", " postfix"}, "param2")
   164  	s.spec.AddParametricSnippet([]string{"prefix ", " postfix"}, "param2")
   165  	s.spec.AddParametricSnippet([]string{"other "}, "param")
   166  	c.Assert(s.spec.SnippetsForTag("snap.demo.command"), DeepEquals, []string{
   167  		"other param",
   168  		"prefix {param1,param2} postfix",
   169  	})
   170  	c.Assert(s.spec.SnippetForTag("snap.demo.command"), Equals, "other param\nprefix {param1,param2} postfix")
   171  	c.Assert(s.spec.Snippets(), DeepEquals, map[string][]string{
   172  		"snap.demo.command": {"other param", "prefix {param1,param2} postfix"},
   173  		"snap.demo.service": {"other param", "prefix {param1,param2} postfix"},
   174  	})
   175  }
   176  
   177  // All of AddSnippet, AddDeduplicatedSnippet, AddParameticSnippet work correctly together.
   178  func (s *specSuite) TestAddSnippetAndAddDeduplicatedAndParamSnippet(c *C) {
   179  	restore := apparmor.SetSpecScope(s.spec, []string{"snap.demo.command", "snap.demo.service"})
   180  	defer restore()
   181  
   182  	// Add three snippets in the context we are in.
   183  	s.spec.AddSnippet("normal")
   184  	s.spec.AddDeduplicatedSnippet("dedup")
   185  	s.spec.AddParametricSnippet([]string{""}, "param")
   186  
   187  	// The snippets were recorded correctly.
   188  	c.Assert(s.spec.UpdateNS(), HasLen, 0)
   189  	c.Assert(s.spec.Snippets(), DeepEquals, map[string][]string{
   190  		"snap.demo.command": {"normal", "dedup", "param"},
   191  		"snap.demo.service": {"normal", "dedup", "param"},
   192  	})
   193  	c.Assert(s.spec.SnippetsForTag("snap.demo.command"), DeepEquals, []string{"normal", "dedup", "param"})
   194  	c.Assert(s.spec.SnippetForTag("snap.demo.command"), Equals, "normal\ndedup\nparam")
   195  	c.Assert(s.spec.SecurityTags(), DeepEquals, []string{"snap.demo.command", "snap.demo.service"})
   196  }
   197  
   198  // Define tags but don't add any snippets.
   199  func (s *specSuite) TestTagsButNoSnippets(c *C) {
   200  	restore := apparmor.SetSpecScope(s.spec, []string{"snap.demo.command", "snap.demo.service"})
   201  	defer restore()
   202  
   203  	c.Assert(s.spec.UpdateNS(), HasLen, 0)
   204  	c.Assert(s.spec.Snippets(), DeepEquals, map[string][]string{})
   205  	c.Assert(s.spec.SnippetsForTag("snap.demo.command"), DeepEquals, []string(nil))
   206  	c.Assert(s.spec.SnippetForTag("snap.demo.command"), Equals, "")
   207  	c.Assert(s.spec.SecurityTags(), DeepEquals, []string(nil))
   208  }
   209  
   210  // Don't define any tags but add snippets.
   211  func (s *specSuite) TestNoTagsButWithSnippets(c *C) {
   212  	restore := apparmor.SetSpecScope(s.spec, []string{})
   213  	defer restore()
   214  
   215  	s.spec.AddSnippet("normal")
   216  	s.spec.AddDeduplicatedSnippet("dedup")
   217  	s.spec.AddParametricSnippet([]string{""}, "param")
   218  
   219  	c.Assert(s.spec.UpdateNS(), HasLen, 0)
   220  	c.Assert(s.spec.Snippets(), DeepEquals, map[string][]string{})
   221  	c.Assert(s.spec.SnippetsForTag("snap.demo.command"), DeepEquals, []string(nil))
   222  	c.Assert(s.spec.SnippetForTag("snap.demo.command"), Equals, "")
   223  	c.Assert(s.spec.SecurityTags(), DeepEquals, []string(nil))
   224  }
   225  
   226  // Don't define any tags or snippets.
   227  func (s *specSuite) TestsNoTagsOrSnippets(c *C) {
   228  	restore := apparmor.SetSpecScope(s.spec, []string{})
   229  	defer restore()
   230  
   231  	c.Assert(s.spec.UpdateNS(), HasLen, 0)
   232  	c.Assert(s.spec.Snippets(), DeepEquals, map[string][]string{})
   233  	c.Assert(s.spec.SnippetsForTag("snap.demo.command"), DeepEquals, []string(nil))
   234  	c.Assert(s.spec.SnippetForTag("snap.demo.command"), Equals, "")
   235  	c.Assert(s.spec.SecurityTags(), DeepEquals, []string(nil))
   236  }
   237  
   238  // AddUpdateNS adds a snippet for the snap-update-ns profile for a given snap.
   239  func (s *specSuite) TestAddUpdateNS(c *C) {
   240  	restore := apparmor.SetSpecScope(s.spec, []string{"snap.demo.command", "snap.demo.service"})
   241  	defer restore()
   242  
   243  	// Add a two snap-update-ns snippets in the context we are in.
   244  	s.spec.AddUpdateNS("s-u-n snippet 1")
   245  	s.spec.AddUpdateNS("s-u-n snippet 2")
   246  
   247  	// Check the order of the snippets can be retrieved.
   248  	idx, ok := s.spec.UpdateNSIndexOf("s-u-n snippet 2")
   249  	c.Assert(ok, Equals, true)
   250  	c.Check(idx, Equals, 1)
   251  
   252  	// The snippets were recorded correctly and in the right place.
   253  	c.Assert(s.spec.UpdateNS(), DeepEquals, []string{
   254  		"s-u-n snippet 1", "s-u-n snippet 2",
   255  	})
   256  	c.Assert(s.spec.SnippetForTag("snap.demo.command"), Equals, "")
   257  	c.Assert(s.spec.SecurityTags(), HasLen, 0)
   258  }
   259  
   260  const snapWithLayout = `
   261  name: vanguard
   262  version: 0
   263  apps:
   264    vanguard:
   265      command: vanguard
   266  layout:
   267    /usr/foo:
   268      bind: $SNAP/usr/foo
   269    /var/tmp:
   270      type: tmpfs
   271      mode: 1777
   272    /var/cache/mylink:
   273      symlink: $SNAP_DATA/link/target
   274    /etc/foo.conf:
   275      bind-file: $SNAP/foo.conf
   276  `
   277  
   278  func (s *specSuite) TestApparmorSnippetsFromLayout(c *C) {
   279  	snapInfo := snaptest.MockInfo(c, snapWithLayout, &snap.SideInfo{Revision: snap.R(42)})
   280  	restore := apparmor.SetSpecScope(s.spec, []string{"snap.vanguard.vanguard"})
   281  	defer restore()
   282  
   283  	s.spec.AddLayout(snapInfo)
   284  	c.Assert(s.spec.Snippets(), DeepEquals, map[string][]string{
   285  		"snap.vanguard.vanguard": {
   286  			"# Layout path: /etc/foo.conf\n/etc/foo.conf mrwklix,",
   287  			"# Layout path: /usr/foo\n/usr/foo{,/**} mrwklix,",
   288  			"# Layout path: /var/cache/mylink\n# (no extra permissions required for symlink)",
   289  			"# Layout path: /var/tmp\n/var/tmp{,/**} mrwklix,",
   290  		},
   291  	})
   292  	updateNS := s.spec.UpdateNS()
   293  
   294  	profile0 := `  # Layout /etc/foo.conf: bind-file $SNAP/foo.conf
   295    mount options=(bind, rw) /snap/vanguard/42/foo.conf -> /etc/foo.conf,
   296    mount options=(rprivate) -> /etc/foo.conf,
   297    umount /etc/foo.conf,
   298    # Writable mimic /etc
   299    # .. permissions for traversing the prefix that is assumed to exist
   300    / r,
   301    # .. variant with mimic at /etc/
   302    # Allow reading the mimic directory, it must exist in the first place.
   303    /etc/ r,
   304    # Allow setting the read-only directory aside via a bind mount.
   305    /tmp/.snap/etc/ rw,
   306    mount options=(rbind, rw) /etc/ -> /tmp/.snap/etc/,
   307    # Allow mounting tmpfs over the read-only directory.
   308    mount fstype=tmpfs options=(rw) tmpfs -> /etc/,
   309    # Allow creating empty files and directories for bind mounting things
   310    # to reconstruct the now-writable parent directory.
   311    /tmp/.snap/etc/*/ rw,
   312    /etc/*/ rw,
   313    mount options=(rbind, rw) /tmp/.snap/etc/*/ -> /etc/*/,
   314    /tmp/.snap/etc/* rw,
   315    /etc/* rw,
   316    mount options=(bind, rw) /tmp/.snap/etc/* -> /etc/*,
   317    # Allow unmounting the auxiliary directory.
   318    # TODO: use fstype=tmpfs here for more strictness (LP: #1613403)
   319    mount options=(rprivate) -> /tmp/.snap/etc/,
   320    umount /tmp/.snap/etc/,
   321    # Allow unmounting the destination directory as well as anything
   322    # inside.  This lets us perform the undo plan in case the writable
   323    # mimic fails.
   324    mount options=(rprivate) -> /etc/,
   325    mount options=(rprivate) -> /etc/*,
   326    mount options=(rprivate) -> /etc/*/,
   327    umount /etc/,
   328    umount /etc/*,
   329    umount /etc/*/,
   330    # Writable mimic /snap/vanguard/42
   331    /snap/ r,
   332    /snap/vanguard/ r,
   333    # .. variant with mimic at /snap/vanguard/42/
   334    /snap/vanguard/42/ r,
   335    /tmp/.snap/snap/vanguard/42/ rw,
   336    mount options=(rbind, rw) /snap/vanguard/42/ -> /tmp/.snap/snap/vanguard/42/,
   337    mount fstype=tmpfs options=(rw) tmpfs -> /snap/vanguard/42/,
   338    /tmp/.snap/snap/vanguard/42/*/ rw,
   339    /snap/vanguard/42/*/ rw,
   340    mount options=(rbind, rw) /tmp/.snap/snap/vanguard/42/*/ -> /snap/vanguard/42/*/,
   341    /tmp/.snap/snap/vanguard/42/* rw,
   342    /snap/vanguard/42/* rw,
   343    mount options=(bind, rw) /tmp/.snap/snap/vanguard/42/* -> /snap/vanguard/42/*,
   344    mount options=(rprivate) -> /tmp/.snap/snap/vanguard/42/,
   345    umount /tmp/.snap/snap/vanguard/42/,
   346    mount options=(rprivate) -> /snap/vanguard/42/,
   347    mount options=(rprivate) -> /snap/vanguard/42/*,
   348    mount options=(rprivate) -> /snap/vanguard/42/*/,
   349    umount /snap/vanguard/42/,
   350    umount /snap/vanguard/42/*,
   351    umount /snap/vanguard/42/*/,
   352  `
   353  	// Find the slice that describes profile0 by looking for the first unique
   354  	// line of the next profile.
   355  	start := 0
   356  	end, _ := s.spec.UpdateNSIndexOf("  # Layout /usr/foo: bind $SNAP/usr/foo\n")
   357  	c.Assert(strings.Join(updateNS[start:end], ""), Equals, profile0)
   358  
   359  	profile1 := `  # Layout /usr/foo: bind $SNAP/usr/foo
   360    mount options=(rbind, rw) /snap/vanguard/42/usr/foo/ -> /usr/foo/,
   361    mount options=(rprivate) -> /usr/foo/,
   362    umount /usr/foo/,
   363    # Writable mimic /usr
   364    # .. variant with mimic at /usr/
   365    /usr/ r,
   366    /tmp/.snap/usr/ rw,
   367    mount options=(rbind, rw) /usr/ -> /tmp/.snap/usr/,
   368    mount fstype=tmpfs options=(rw) tmpfs -> /usr/,
   369    /tmp/.snap/usr/*/ rw,
   370    /usr/*/ rw,
   371    mount options=(rbind, rw) /tmp/.snap/usr/*/ -> /usr/*/,
   372    /tmp/.snap/usr/* rw,
   373    /usr/* rw,
   374    mount options=(bind, rw) /tmp/.snap/usr/* -> /usr/*,
   375    mount options=(rprivate) -> /tmp/.snap/usr/,
   376    umount /tmp/.snap/usr/,
   377    mount options=(rprivate) -> /usr/,
   378    mount options=(rprivate) -> /usr/*,
   379    mount options=(rprivate) -> /usr/*/,
   380    umount /usr/,
   381    umount /usr/*,
   382    umount /usr/*/,
   383    # Writable mimic /snap/vanguard/42/usr
   384    # .. variant with mimic at /snap/vanguard/42/usr/
   385    /snap/vanguard/42/usr/ r,
   386    /tmp/.snap/snap/vanguard/42/usr/ rw,
   387    mount options=(rbind, rw) /snap/vanguard/42/usr/ -> /tmp/.snap/snap/vanguard/42/usr/,
   388    mount fstype=tmpfs options=(rw) tmpfs -> /snap/vanguard/42/usr/,
   389    /tmp/.snap/snap/vanguard/42/usr/*/ rw,
   390    /snap/vanguard/42/usr/*/ rw,
   391    mount options=(rbind, rw) /tmp/.snap/snap/vanguard/42/usr/*/ -> /snap/vanguard/42/usr/*/,
   392    /tmp/.snap/snap/vanguard/42/usr/* rw,
   393    /snap/vanguard/42/usr/* rw,
   394    mount options=(bind, rw) /tmp/.snap/snap/vanguard/42/usr/* -> /snap/vanguard/42/usr/*,
   395    mount options=(rprivate) -> /tmp/.snap/snap/vanguard/42/usr/,
   396    umount /tmp/.snap/snap/vanguard/42/usr/,
   397    mount options=(rprivate) -> /snap/vanguard/42/usr/,
   398    mount options=(rprivate) -> /snap/vanguard/42/usr/*,
   399    mount options=(rprivate) -> /snap/vanguard/42/usr/*/,
   400    umount /snap/vanguard/42/usr/,
   401    umount /snap/vanguard/42/usr/*,
   402    umount /snap/vanguard/42/usr/*/,
   403  `
   404  	// Find the slice that describes profile1 by looking for the first unique
   405  	// line of the next profile.
   406  	start = end
   407  	end, _ = s.spec.UpdateNSIndexOf("  # Layout /var/cache/mylink: symlink $SNAP_DATA/link/target\n")
   408  	c.Assert(strings.Join(updateNS[start:end], ""), Equals, profile1)
   409  
   410  	profile2 := `  # Layout /var/cache/mylink: symlink $SNAP_DATA/link/target
   411    /var/cache/mylink rw,
   412    # Writable mimic /var/cache
   413    # .. variant with mimic at /var/
   414    /var/ r,
   415    /tmp/.snap/var/ rw,
   416    mount options=(rbind, rw) /var/ -> /tmp/.snap/var/,
   417    mount fstype=tmpfs options=(rw) tmpfs -> /var/,
   418    /tmp/.snap/var/*/ rw,
   419    /var/*/ rw,
   420    mount options=(rbind, rw) /tmp/.snap/var/*/ -> /var/*/,
   421    /tmp/.snap/var/* rw,
   422    /var/* rw,
   423    mount options=(bind, rw) /tmp/.snap/var/* -> /var/*,
   424    mount options=(rprivate) -> /tmp/.snap/var/,
   425    umount /tmp/.snap/var/,
   426    mount options=(rprivate) -> /var/,
   427    mount options=(rprivate) -> /var/*,
   428    mount options=(rprivate) -> /var/*/,
   429    umount /var/,
   430    umount /var/*,
   431    umount /var/*/,
   432    # .. variant with mimic at /var/cache/
   433    /var/cache/ r,
   434    /tmp/.snap/var/cache/ rw,
   435    mount options=(rbind, rw) /var/cache/ -> /tmp/.snap/var/cache/,
   436    mount fstype=tmpfs options=(rw) tmpfs -> /var/cache/,
   437    /tmp/.snap/var/cache/*/ rw,
   438    /var/cache/*/ rw,
   439    mount options=(rbind, rw) /tmp/.snap/var/cache/*/ -> /var/cache/*/,
   440    /tmp/.snap/var/cache/* rw,
   441    /var/cache/* rw,
   442    mount options=(bind, rw) /tmp/.snap/var/cache/* -> /var/cache/*,
   443    mount options=(rprivate) -> /tmp/.snap/var/cache/,
   444    umount /tmp/.snap/var/cache/,
   445    mount options=(rprivate) -> /var/cache/,
   446    mount options=(rprivate) -> /var/cache/*,
   447    mount options=(rprivate) -> /var/cache/*/,
   448    umount /var/cache/,
   449    umount /var/cache/*,
   450    umount /var/cache/*/,
   451  `
   452  	// Find the slice that describes profile2 by looking for the first unique
   453  	// line of the next profile.
   454  	start = end
   455  	end, _ = s.spec.UpdateNSIndexOf("  # Layout /var/tmp: type tmpfs, mode: 01777\n")
   456  	c.Assert(strings.Join(updateNS[start:end], ""), Equals, profile2)
   457  
   458  	profile3 := `  # Layout /var/tmp: type tmpfs, mode: 01777
   459    mount fstype=tmpfs tmpfs -> /var/tmp/,
   460    mount options=(rprivate) -> /var/tmp/,
   461    umount /var/tmp/,
   462    # Writable mimic /var
   463  `
   464  	// Find the slice that describes profile2 by looking till the end of the list.
   465  	start = end
   466  	c.Assert(strings.Join(updateNS[start:], ""), Equals, profile3)
   467  	c.Assert(strings.Join(updateNS, ""), DeepEquals, strings.Join([]string{profile0, profile1, profile2, profile3}, ""))
   468  }
   469  
   470  const snapTrivial = `
   471  name: some-snap
   472  version: 0
   473  apps:
   474    app:
   475      command: app-command
   476  `
   477  
   478  func (s *specSuite) TestApparmorOvernameSnippetsNotInstanceKeyed(c *C) {
   479  	snapInfo := snaptest.MockInfo(c, snapTrivial, &snap.SideInfo{Revision: snap.R(42)})
   480  	restore := apparmor.SetSpecScope(s.spec, []string{"snap.some-snap.app"})
   481  	defer restore()
   482  
   483  	s.spec.AddOvername(snapInfo)
   484  	c.Assert(s.spec.Snippets(), HasLen, 0)
   485  	// non instance-keyed snaps require no extra snippets
   486  	c.Assert(s.spec.UpdateNS(), HasLen, 0)
   487  }
   488  
   489  func (s *specSuite) TestApparmorOvernameSnippets(c *C) {
   490  	snapInfo := snaptest.MockInfo(c, snapTrivial, &snap.SideInfo{Revision: snap.R(42)})
   491  	snapInfo.InstanceKey = "instance"
   492  
   493  	restore := apparmor.SetSpecScope(s.spec, []string{"snap.some-snap_instace.app"})
   494  	defer restore()
   495  
   496  	s.spec.AddOvername(snapInfo)
   497  	c.Assert(s.spec.Snippets(), HasLen, 0)
   498  
   499  	updateNS := s.spec.UpdateNS()
   500  	c.Assert(updateNS, HasLen, 1)
   501  
   502  	profile := `  # Allow parallel instance snap mount namespace adjustments
   503    mount options=(rw rbind) /snap/some-snap_instance/ -> /snap/some-snap/,
   504    mount options=(rw rbind) /var/snap/some-snap_instance/ -> /var/snap/some-snap/,
   505  `
   506  	c.Assert(updateNS[0], Equals, profile)
   507  }
   508  
   509  func (s *specSuite) TestUsesPtraceTrace(c *C) {
   510  	c.Assert(s.spec.UsesPtraceTrace(), Equals, false)
   511  	s.spec.SetUsesPtraceTrace()
   512  	c.Assert(s.spec.UsesPtraceTrace(), Equals, true)
   513  }
   514  
   515  func (s *specSuite) TestSuppressPtraceTrace(c *C) {
   516  	c.Assert(s.spec.SuppressPtraceTrace(), Equals, false)
   517  	s.spec.SetSuppressPtraceTrace()
   518  	c.Assert(s.spec.SuppressPtraceTrace(), Equals, true)
   519  }
   520  
   521  func (s *specSuite) TestSetSuppressHomeIx(c *C) {
   522  	c.Assert(s.spec.SuppressHomeIx(), Equals, false)
   523  	s.spec.SetSuppressHomeIx()
   524  	c.Assert(s.spec.SuppressHomeIx(), Equals, true)
   525  }