func (s *policySuite) TestSnapDeclAllowDenyConnection(c *C) { tests := []struct { iface string expected string // "" => no error }{ {"random", ""}, {"snap-plug-allow", ""}, {"snap-plug-deny", `connection denied by plug rule of interface "snap-plug-deny" for "plug-snap" snap`}, {"snap-plug-not-allow", `connection not allowed by plug rule of interface "snap-plug-not-allow" for "plug-snap" snap`}, {"snap-slot-allow", ""}, {"snap-slot-deny", `connection denied by slot rule of interface "snap-slot-deny" for "slot-snap" snap`}, {"snap-slot-not-allow", `connection not allowed by slot rule of interface "snap-slot-not-allow" for "slot-snap" snap`}, {"base-deny-snap-slot-allow", ""}, {"base-deny-snap-plug-allow", ""}, {"snap-slot-deny-snap-plug-allow", ""}, {"base-allow-snap-slot-not-allow", `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.Check() if t.expected == "" { c.Check(err, IsNil) } else { c.Check(err, ErrorMatches, t.expected) } } }
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"`) }
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) }
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) }
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) } } }
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) }
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) }
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.*") }
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 }
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 }