Skip to content

Commit

Permalink
o/hookstate/ctlcmd: add distinct exit codes for cases when pid is not a
Browse files Browse the repository at this point in the history
snap, or pid is a classic snap.
  • Loading branch information
jhenstridge committed Aug 27, 2020
1 parent 27c3ee6 commit 260dff9
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 11 deletions.
29 changes: 22 additions & 7 deletions overlord/hookstate/ctlcmd/is_connected.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/snapcore/snapd/overlord/ifacestate"
"github.com/snapcore/snapd/overlord/snapstate"
"github.com/snapcore/snapd/sandbox/cgroup"
"github.com/snapcore/snapd/snap"
)

var cgroupSnapNameFromPid = cgroup.SnapNameFromPid
Expand All @@ -37,7 +38,7 @@ type isConnectedCommand struct {
Positional struct {
PlugOrSlotSpec string `positional-args:"true" positional-arg-name:"<plug|slot>"`
} `positional-args:"true" required:"true"`
Pid int `long:"pid" description:"Process ID for a connected process"`
Pid int `long:"pid" description:"Process ID for a plausibly connected process"`
}

var shortIsConnectedHelp = i18n.G(`Return success if the given plug or slot is connected, and failure otherwise`)
Expand All @@ -51,6 +52,12 @@ $ echo $?
Snaps can only query their own plugs and slots - snap name is implicit and
implied by the snapctl execution context.
The --pid option can be used to determine whether a plug or slot is
connected to the snap identified by the given process ID. In this
mode, additional failure exit codes may be returned: 10 if the other
process is not snap confined, or 11 if the other snap is not connected
but uses classic confinement.
`)

func init() {
Expand Down Expand Up @@ -91,12 +98,16 @@ func (c *isConnectedCommand) Execute(args []string) error {
return fmt.Errorf("internal error: cannot get connections: %s", err)
}

var otherSnapName string
var otherSnap *snap.Info
if c.Pid != 0 {
otherSnapName, err = cgroupSnapNameFromPid(c.Pid)
// FIXME: should we treat non-snap processes as connected?
name, err := cgroupSnapNameFromPid(c.Pid)
if err != nil {
// Indicate that this pid is not a snap
return &UnsuccessfulError{ExitCode: 10}
}
otherSnap, err = snapstate.CurrentInfo(st, name)
if err != nil {
return fmt.Errorf("internal error: cannot get snap name for pid %d: %s", c.Pid, err)
return fmt.Errorf("internal error: cannot get snap info for pid %d: %s", c.Pid, err)
}
}

Expand All @@ -115,8 +126,8 @@ func (c *isConnectedCommand) Execute(args []string) error {

matchingPlug := connRef.PlugRef.Snap == snapName && connRef.PlugRef.Name == plugOrSlot
matchingSlot := connRef.SlotRef.Snap == snapName && connRef.SlotRef.Name == plugOrSlot
if otherSnapName != "" {
if matchingPlug && connRef.SlotRef.Snap == otherSnapName || matchingSlot && connRef.PlugRef.Snap == otherSnapName {
if otherSnap != nil {
if matchingPlug && connRef.SlotRef.Snap == otherSnap.InstanceName() || matchingSlot && connRef.PlugRef.Snap == otherSnap.InstanceName() {
return nil
}
} else {
Expand All @@ -126,5 +137,9 @@ func (c *isConnectedCommand) Execute(args []string) error {
}
}

if otherSnap != nil && otherSnap.Confinement == snap.ClassicConfinement {
return &UnsuccessfulError{ExitCode: 11}
}

return &UnsuccessfulError{ExitCode: 1}
}
32 changes: 28 additions & 4 deletions overlord/hookstate/ctlcmd/is_connected_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,12 @@ var isConnectedTests = []struct {
exitCode: 1,
}, {
// snap1:plug1 is not connected to a non-snap pid
args: []string{"is-connected", "--pid", "42", "plug1"},
err: "internal error: cannot get snap name for pid 42: Not a snap",
args: []string{"is-connected", "--pid", "42", "plug1"},
exitCode: 10,
}, {
// snap1:plug1 is not connected to snap4, but snap4 is classic
args: []string{"is-connected", "--pid", "1004", "plug1"},
exitCode: 11,
}, {
// snap1:slot1 is connected to snap3
args: []string{"is-connected", "--pid", "1003", "slot1"},
Expand All @@ -96,8 +100,12 @@ var isConnectedTests = []struct {
exitCode: 1,
}, {
// snap1:slot1 is not connected to a non-snap pid
args: []string{"is-connected", "--pid", "42", "slot1"},
err: "internal error: cannot get snap name for pid 42: Not a snap",
args: []string{"is-connected", "--pid", "42", "slot1"},
exitCode: 10,
}, {
// snap1:slot1 is not connected to snap4, but snap4 is classic
args: []string{"is-connected", "--pid", "1004", "slot1"},
exitCode: 11,
}}

func mockInstalledSnap(c *C, st *state.State, snapYaml string) {
Expand Down Expand Up @@ -126,6 +134,22 @@ plugs:
interface: x11
slots:
slot1:
interface: x11`)
mockInstalledSnap(c, s.st, `name: snap2
slots:
slot2:
interface: x11`)
mockInstalledSnap(c, s.st, `name: snap3
plugs:
plug4:
interface: x11
slots:
slot3:
interface: x11`)
mockInstalledSnap(c, s.st, `name: snap4
confinement: classic
slots:
slot4:
interface: x11`)
restore := ctlcmd.MockCgroupSnapNameFromPid(func(pid int) (string, error) {
switch {
Expand Down

0 comments on commit 260dff9

Please sign in to comment.