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