Example #1
0
func (s *policySuite) TestSnapDeclAllowDenyAutoConnection(c *C) {
	tests := []struct {
		iface    string
		expected string // "" => no error
	}{
		{"random", ""},
		{"auto-snap-plug-allow", ""},
		{"auto-snap-plug-deny", `auto-connection denied by plug rule of interface "auto-snap-plug-deny" for "plug-snap" snap`},
		{"auto-snap-plug-not-allow", `auto-connection not allowed by plug rule of interface "auto-snap-plug-not-allow" for "plug-snap" snap`},
		{"auto-snap-slot-allow", ""},
		{"auto-snap-slot-deny", `auto-connection denied by slot rule of interface "auto-snap-slot-deny" for "slot-snap" snap`},
		{"auto-snap-slot-not-allow", `auto-connection not allowed by slot rule of interface "auto-snap-slot-not-allow" for "slot-snap" snap`},
		{"auto-base-deny-snap-slot-allow", ""},
		{"auto-base-deny-snap-plug-allow", ""},
		{"auto-snap-slot-deny-snap-plug-allow", ""},
		{"auto-base-allow-snap-slot-not-allow", `auto-connection not allowed.*`},
	}

	for _, t := range tests {
		cand := policy.ConnectCandidate{
			Plug:                s.plugSnap.Plugs[t.iface],
			Slot:                s.slotSnap.Slots[t.iface],
			PlugSnapDeclaration: s.plugDecl,
			SlotSnapDeclaration: s.slotDecl,
			BaseDeclaration:     s.baseDecl,
		}

		err := cand.CheckAutoConnect()
		if t.expected == "" {
			c.Check(err, IsNil)
		} else {
			c.Check(err, ErrorMatches, t.expected)
		}
	}
}
Example #2
0
func (c *autoConnectChecker) check(plug *interfaces.Plug, slot *interfaces.Slot) bool {
	var plugDecl *asserts.SnapDeclaration
	if plug.Snap.SnapID != "" {
		var err error
		plugDecl, err = c.snapDeclaration(plug.Snap.SnapID)
		if err != nil {
			logger.Noticef("error: cannot find snap declaration for %q: %v", plug.Snap.Name(), err)
			return false
		}
	}

	var slotDecl *asserts.SnapDeclaration
	if slot.Snap.SnapID != "" {
		var err error
		slotDecl, err = c.snapDeclaration(slot.Snap.SnapID)
		if err != nil {
			logger.Noticef("error: cannot find snap declaration for %q: %v", slot.Snap.Name(), err)
			return false
		}
	}

	// check the connection against the declarations' rules
	ic := policy.ConnectCandidate{
		Plug:                plug.PlugInfo,
		PlugSnapDeclaration: plugDecl,
		Slot:                slot.SlotInfo,
		SlotSnapDeclaration: slotDecl,
		BaseDeclaration:     c.baseDecl,
	}

	return ic.CheckAutoConnect() == nil
}
Example #3
0
func (s *policySuite) TestInterfaceMismatch(c *C) {
	cand := policy.ConnectCandidate{
		Plug:            s.plugSnap.Plugs["mismatchy"],
		Slot:            s.slotSnap.Slots["mismatchy"],
		BaseDeclaration: s.baseDecl,
	}

	c.Check(cand.Check(), ErrorMatches, `cannot connect mismatched plug interface "bar" to slot interface "baz"`)
}
Example #4
0
func (s *policySuite) TestBaselineDefaultIsAllow(c *C) {
	cand := policy.ConnectCandidate{
		Plug:            s.plugSnap.Plugs["random"],
		Slot:            s.slotSnap.Slots["random"],
		BaseDeclaration: s.baseDecl,
	}

	c.Check(cand.Check(), IsNil)
	c.Check(cand.CheckAutoConnect(), IsNil)
}
Example #5
0
func (s *policySuite) TestDollarPlugPublisherIDCheckConnection(c *C) {
	// no known publishers
	cand := policy.ConnectCandidate{
		Plug:            s.plugSnap.Plugs["same-plug-publisher-id"],
		Slot:            s.randomSnap.Slots["same-plug-publisher-id"],
		BaseDeclaration: s.baseDecl,
	}
	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")

	// no slot-side declaration
	cand = policy.ConnectCandidate{
		Plug:                s.plugSnap.Plugs["same-plug-publisher-id"],
		PlugSnapDeclaration: s.plugDecl,
		Slot:                s.randomSnap.Slots["same-plug-publisher-id"],
		BaseDeclaration:     s.baseDecl,
	}
	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")

	// slot-side declaration, wrong publisher-id
	cand = policy.ConnectCandidate{
		Plug:                s.plugSnap.Plugs["same-plug-publisher-id"],
		PlugSnapDeclaration: s.plugDecl,
		Slot:                s.randomSnap.Slots["same-plug-publisher-id"],
		SlotSnapDeclaration: s.randomDecl,
		BaseDeclaration:     s.baseDecl,
	}
	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")

	// slot publisher id == plug publisher id
	samePubSlotSnap := snaptest.MockInfo(c, `
name: same-pub-slot-snap
slots:
  same-plug-publisher-id:
`, nil)

	a, err := asserts.Decode([]byte(`type: snap-declaration
authority-id: canonical
series: 16
snap-name: same-pub-slot-snap
snap-id: samepublslotsnapidididididididid
publisher-id: plug-publisher
timestamp: 2016-09-30T12:00:00Z
sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij

AXNpZw==`))
	c.Assert(err, IsNil)
	samePubSlotDecl := a.(*asserts.SnapDeclaration)

	cand = policy.ConnectCandidate{
		Plug:                s.plugSnap.Plugs["same-plug-publisher-id"],
		PlugSnapDeclaration: s.plugDecl,
		Slot:                samePubSlotSnap.Slots["same-plug-publisher-id"],
		SlotSnapDeclaration: samePubSlotDecl,
		BaseDeclaration:     s.baseDecl,
	}
	c.Check(cand.Check(), IsNil)
}
Example #6
0
func (s *policySuite) TestSlotPublisherIDCheckConnection(c *C) {
	// no slot-side declaration
	cand := policy.ConnectCandidate{
		Plug:                s.plugSnap.Plugs["checked-slot-publisher-id"],
		PlugSnapDeclaration: s.plugDecl,
		Slot:                s.randomSnap.Slots["checked-slot-publisher-id"],
		BaseDeclaration:     s.baseDecl,
	}
	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")

	// slot-side declaration, wrong publisher-id
	cand = policy.ConnectCandidate{
		Plug:                s.plugSnap.Plugs["checked-slot-publisher-id"],
		PlugSnapDeclaration: s.plugDecl,
		Slot:                s.randomSnap.Slots["checked-slot-publisher-id"],
		SlotSnapDeclaration: s.randomDecl,
		BaseDeclaration:     s.baseDecl,
	}
	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")

	// right publisher-id
	cand = policy.ConnectCandidate{
		Plug:                s.plugSnap.Plugs["checked-slot-publisher-id"],
		PlugSnapDeclaration: s.plugDecl,
		Slot:                s.slotSnap.Slots["checked-slot-publisher-id"],
		SlotSnapDeclaration: s.slotDecl,
		BaseDeclaration:     s.baseDecl,
	}
	c.Check(cand.Check(), IsNil)
}
Example #7
0
func (s *policySuite) TestPlugSnapIDCheckConnection(c *C) {
	// no plug-side declaration
	cand := policy.ConnectCandidate{
		Plug:                s.randomSnap.Plugs["precise-plug-snap-id"],
		Slot:                s.slotSnap.Slots["precise-plug-snap-id"],
		SlotSnapDeclaration: s.slotDecl,
		BaseDeclaration:     s.baseDecl,
	}
	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")

	// plug-side declaration, wrong snap-id
	cand = policy.ConnectCandidate{
		Plug:                s.randomSnap.Plugs["precise-plug-snap-id"],
		PlugSnapDeclaration: s.randomDecl,
		Slot:                s.slotSnap.Slots["precise-plug-snap-id"],
		SlotSnapDeclaration: s.slotDecl,
		BaseDeclaration:     s.baseDecl,
	}
	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")

	// right snap-id
	cand = policy.ConnectCandidate{
		Plug:                s.plugSnap.Plugs["precise-plug-snap-id"],
		PlugSnapDeclaration: s.plugDecl,
		Slot:                s.slotSnap.Slots["precise-plug-snap-id"],
		SlotSnapDeclaration: s.slotDecl,
		BaseDeclaration:     s.baseDecl,
	}
	c.Check(cand.Check(), IsNil)
}
Example #8
0
func (s *policySuite) TestSnapTypeCheckConnection(c *C) {
	gadgetSnap := snaptest.MockInfo(c, `
name: gadget
type: gadget
plugs:
   gadgethelp:
slots:
   trustedhelp:
`, nil)

	coreSnap := snaptest.MockInfo(c, `
name: core
type: os
slots:
   gadgethelp:
   trustedhelp:
`, nil)

	cand := policy.ConnectCandidate{
		Plug:            gadgetSnap.Plugs["gadgethelp"],
		Slot:            coreSnap.Slots["gadgethelp"],
		BaseDeclaration: s.baseDecl,
	}
	c.Check(cand.Check(), IsNil)

	cand = policy.ConnectCandidate{
		Plug:            s.plugSnap.Plugs["gadgethelp"],
		Slot:            coreSnap.Slots["gadgethelp"],
		BaseDeclaration: s.baseDecl,
	}
	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")

	for _, trustedSide := range []*snap.Info{coreSnap, gadgetSnap} {
		cand = policy.ConnectCandidate{
			Plug:                s.plugSnap.Plugs["trustedhelp"],
			PlugSnapDeclaration: s.plugDecl,
			Slot:                trustedSide.Slots["trustedhelp"],
			BaseDeclaration:     s.baseDecl,
		}
		c.Check(cand.Check(), IsNil)
	}

	cand = policy.ConnectCandidate{
		Plug:                s.plugSnap.Plugs["trustedhelp"],
		PlugSnapDeclaration: s.plugDecl,
		Slot:                s.slotSnap.Slots["trustedhelp"],
		BaseDeclaration:     s.baseDecl,
	}
	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
}
Example #9
0
func (s *policySuite) TestSlotOnClassicCheckConnection(c *C) {
	r1 := release.MockOnClassic(false)
	defer r1()
	r2 := release.MockReleaseInfo(&release.ReleaseInfo)
	defer r2()

	tests := []struct {
		distro string // "" => not classic
		iface  string
		err    string // "" => no error
	}{
		{"ubuntu", "slot-on-classic-true", ""},
		{"", "slot-on-classic-true", `connection not allowed by slot rule of interface "slot-on-classic-true"`},
		{"", "slot-on-classic-false", ""},
		{"ubuntu", "slot-on-classic-false", "connection not allowed.*"},
		{"ubuntu", "slot-on-classic-distros", ""},
		{"debian", "slot-on-classic-distros", ""},
		{"", "slot-on-classic-distros", "connection not allowed.*"},
		{"other", "slot-on-classic-distros", "connection not allowed.*"},
	}

	for _, t := range tests {
		if t.distro == "" {
			release.OnClassic = false
		} else {
			release.OnClassic = true
			release.ReleaseInfo = release.OS{
				ID: t.distro,
			}
		}
		cand := policy.ConnectCandidate{
			Plug:            s.plugSnap.Plugs[t.iface],
			Slot:            s.slotSnap.Slots[t.iface],
			BaseDeclaration: s.baseDecl,
		}
		err := cand.Check()
		if t.err == "" {
			c.Check(err, IsNil)
		} else {
			c.Check(err, ErrorMatches, t.err)
		}
	}
}
Example #10
0
func (s *policySuite) TestBaseDeclAllowDenyConnection(c *C) {
	tests := []struct {
		iface    string
		expected string // "" => no error
	}{
		{"base-plug-allow", ""},
		{"base-plug-deny", `connection denied by plug rule of interface "base-plug-deny"`},
		{"base-plug-not-allow", `connection not allowed by plug rule of interface "base-plug-not-allow"`},
		{"base-slot-allow", ""},
		{"base-slot-deny", `connection denied by slot rule of interface "base-slot-deny"`},
		{"base-slot-not-allow", `connection not allowed by slot rule of interface "base-slot-not-allow"`},
		{"base-plug-not-allow-slots", `connection not allowed.*`},
		{"base-slot-not-allow-slots", `connection not allowed.*`},
		{"base-plug-not-allow-plugs", `connection not allowed.*`},
		{"base-slot-not-allow-plugs", `connection not allowed.*`},
		{"plug-or-p1-s1", ""},
		{"plug-or-p2-s2", ""},
		{"plug-or-p1-s2", "connection not allowed by plug rule.*"},
		{"slot-or-p1-s1", ""},
		{"slot-or-p2-s2", ""},
		{"slot-or-p1-s2", "connection not allowed by slot rule.*"},
	}

	for _, t := range tests {
		cand := policy.ConnectCandidate{
			Plug:            s.plugSnap.Plugs[t.iface],
			Slot:            s.slotSnap.Slots[t.iface],
			BaseDeclaration: s.baseDecl,
		}

		err := cand.Check()
		if t.expected == "" {
			c.Check(err, IsNil)
		} else {
			c.Check(err, ErrorMatches, t.expected)
		}
	}
}
Example #11
0
func (m *InterfaceManager) doConnect(task *state.Task, _ *tomb.Tomb) error {
	st := task.State()
	st.Lock()
	defer st.Unlock()

	plugRef, slotRef, err := getPlugAndSlotRefs(task)
	if err != nil {
		return err
	}

	conns, err := getConns(st)
	if err != nil {
		return err
	}

	connRef, err := m.repo.ResolveConnect(plugRef.Snap, plugRef.Name, slotRef.Snap, slotRef.Name)
	if err != nil {
		return err
	}
	plug := m.repo.Plug(connRef.PlugRef.Snap, connRef.PlugRef.Name)
	if plug == nil {
		return fmt.Errorf("snap %q has no %q plug", connRef.PlugRef.Snap, connRef.PlugRef.Name)
	}
	var plugDecl *asserts.SnapDeclaration
	if plug.Snap.SnapID != "" {
		var err error
		plugDecl, err = assertstate.SnapDeclaration(st, plug.Snap.SnapID)
		if err != nil {
			return fmt.Errorf("cannot find snap declaration for %q: %v", plug.Snap.Name(), err)
		}
	}

	slot := m.repo.Slot(connRef.SlotRef.Snap, connRef.SlotRef.Name)
	if slot == nil {
		return fmt.Errorf("snap %q has no %q slot", connRef.SlotRef.Snap, connRef.SlotRef.Name)
	}
	var slotDecl *asserts.SnapDeclaration
	if slot.Snap.SnapID != "" {
		var err error
		slotDecl, err = assertstate.SnapDeclaration(st, slot.Snap.SnapID)
		if err != nil {
			return fmt.Errorf("cannot find snap declaration for %q: %v", slot.Snap.Name(), err)
		}
	}

	baseDecl, err := assertstate.BaseDeclaration(st)
	if err != nil {
		return fmt.Errorf("internal error: cannot find base declaration: %v", err)
	}

	// check the connection against the declarations' rules
	ic := policy.ConnectCandidate{
		Plug:                plug.PlugInfo,
		PlugSnapDeclaration: plugDecl,
		Slot:                slot.SlotInfo,
		SlotSnapDeclaration: slotDecl,
		BaseDeclaration:     baseDecl,
	}

	err = ic.Check()
	if err != nil {
		return err
	}

	err = m.repo.Connect(connRef)
	if err != nil {
		return err
	}

	var plugSnapst snapstate.SnapState
	if err := snapstate.Get(st, connRef.PlugRef.Snap, &plugSnapst); err != nil {
		return err
	}

	var slotSnapst snapstate.SnapState
	if err := snapstate.Get(st, connRef.SlotRef.Snap, &slotSnapst); err != nil {
		return err
	}

	if err := setupSnapSecurity(task, slot.Snap, slotSnapst.DevModeAllowed(), m.repo); err != nil {
		return err
	}
	if err := setupSnapSecurity(task, plug.Snap, plugSnapst.DevModeAllowed(), m.repo); err != nil {
		return err
	}

	conns[connRef.ID()] = connState{Interface: plug.Interface}
	setConns(st, conns)

	return nil
}
Example #12
0
func (m *InterfaceManager) doConnect(task *state.Task, _ *tomb.Tomb) error {
	st := task.State()
	st.Lock()
	defer st.Unlock()

	plugRef, slotRef, err := getPlugAndSlotRefs(task)
	if err != nil {
		return err
	}

	conns, err := getConns(st)
	if err != nil {
		return err
	}

	connRef, err := m.repo.ResolveConnect(plugRef.Snap, plugRef.Name, slotRef.Snap, slotRef.Name)
	if err != nil {
		return err
	}
	plug := m.repo.Plug(connRef.PlugRef.Snap, connRef.PlugRef.Name)
	if plug == nil {
		return fmt.Errorf("snap %q has no %q plug", connRef.PlugRef.Snap, connRef.PlugRef.Name)
	}
	var plugDecl *asserts.SnapDeclaration
	if plug.Snap.SnapID != "" {
		var err error
		plugDecl, err = assertstate.SnapDeclaration(st, plug.Snap.SnapID)
		if err != nil {
			return fmt.Errorf("cannot find snap declaration for %q: %v", plug.Snap.Name(), err)
		}
	}

	slot := m.repo.Slot(connRef.SlotRef.Snap, connRef.SlotRef.Name)
	if slot == nil {
		return fmt.Errorf("snap %q has no %q slot", connRef.SlotRef.Snap, connRef.SlotRef.Name)
	}
	var slotDecl *asserts.SnapDeclaration
	if slot.Snap.SnapID != "" {
		var err error
		slotDecl, err = assertstate.SnapDeclaration(st, slot.Snap.SnapID)
		if err != nil {
			return fmt.Errorf("cannot find snap declaration for %q: %v", slot.Snap.Name(), err)
		}
	}

	baseDecl, err := assertstate.BaseDeclaration(st)
	if err != nil {
		return fmt.Errorf("internal error: cannot find base declaration: %v", err)
	}

	// check the connection against the declarations' rules
	ic := policy.ConnectCandidate{
		Plug:                plug.PlugInfo,
		PlugSnapDeclaration: plugDecl,
		Slot:                slot.SlotInfo,
		SlotSnapDeclaration: slotDecl,
		BaseDeclaration:     baseDecl,
	}

	// if either of plug or slot snaps don't have a declaration it
	// means they were installed with "dangerous", so the security
	// check should be skipped at this point.
	if plugDecl != nil && slotDecl != nil {
		err = ic.Check()
		if err != nil {
			return err
		}
	}

	err = m.repo.Connect(connRef)
	if err != nil {
		return err
	}

	var plugSnapst snapstate.SnapState
	if err := snapstate.Get(st, connRef.PlugRef.Snap, &plugSnapst); err != nil {
		return err
	}

	var slotSnapst snapstate.SnapState
	if err := snapstate.Get(st, connRef.SlotRef.Snap, &slotSnapst); err != nil {
		return err
	}

	slotOpts := confinementOptions(slotSnapst.Flags)
	if err := setupSnapSecurity(task, slot.Snap, slotOpts, m.repo); err != nil {
		return err
	}
	plugOpts := confinementOptions(plugSnapst.Flags)
	if err := setupSnapSecurity(task, plug.Snap, plugOpts, m.repo); err != nil {
		return err
	}

	conns[connRef.ID()] = connState{Interface: plug.Interface}
	setConns(st, conns)

	return nil
}