Skip to content

Commit 8794fd5

Browse files
author
Charles
committed
interfaces/builtin: add xdg-permission-store interface
Provide a dedicated super-privileged interface for xdg-desktop-portal PermissionStore access.
1 parent 6bf401f commit 8794fd5

4 files changed

Lines changed: 195 additions & 0 deletions

File tree

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// -*- Mode: Go; indent-tabs-mode: t -*-
2+
3+
/*
4+
* Copyright (C) 2026 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 builtin
21+
22+
const xdgPermissionStoreSummary = `allows access to the xdg desktop portal PermissionStore service`
23+
24+
const xdgPermissionStoreBaseDeclarationPlugs = `
25+
xdg-permission-store:
26+
allow-installation: false
27+
deny-auto-connection: true
28+
`
29+
30+
const xdgPermissionStoreBaseDeclarationSlots = `
31+
xdg-permission-store:
32+
allow-installation:
33+
slot-snap-type:
34+
- core
35+
deny-auto-connection: true
36+
`
37+
38+
const xdgPermissionStoreConnectedPlugAppArmor = `
39+
# Description: Allow access to xdg-desktop-portal's PermissionStore service.
40+
41+
#include <abstractions/dbus-session-strict>
42+
43+
dbus (receive, send)
44+
bus=session
45+
interface=org.freedesktop.impl.portal.PermissionStore
46+
path=/org/freedesktop/impl/portal/PermissionStore
47+
peer=(label=unconfined),
48+
dbus (receive, send)
49+
bus=session
50+
interface=org.freedesktop.DBus.Properties
51+
path=/org/freedesktop/impl/portal/PermissionStore
52+
peer=(label=unconfined),
53+
dbus (receive, send)
54+
bus=session
55+
interface=org.freedesktop.DBus.Peer
56+
path=/org/freedesktop/impl/portal/PermissionStore
57+
peer=(label=unconfined),
58+
dbus (receive, send)
59+
bus=session
60+
interface=org.freedesktop.DBus.Introspectable
61+
path=/org/freedesktop/impl/portal/PermissionStore
62+
peer=(label=unconfined),
63+
`
64+
65+
func init() {
66+
registerIface(&commonInterface{
67+
name: "xdg-permission-store",
68+
summary: xdgPermissionStoreSummary,
69+
implicitOnCore: true,
70+
implicitOnClassic: true,
71+
baseDeclarationPlugs: xdgPermissionStoreBaseDeclarationPlugs,
72+
baseDeclarationSlots: xdgPermissionStoreBaseDeclarationSlots,
73+
connectedPlugAppArmor: xdgPermissionStoreConnectedPlugAppArmor,
74+
})
75+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// -*- Mode: Go; indent-tabs-mode: t -*-
2+
3+
/*
4+
* Copyright (C) 2026 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 builtin_test
21+
22+
import (
23+
. "gopkg.in/check.v1"
24+
25+
"github.com/snapcore/snapd/interfaces"
26+
"github.com/snapcore/snapd/interfaces/apparmor"
27+
"github.com/snapcore/snapd/interfaces/builtin"
28+
"github.com/snapcore/snapd/snap"
29+
"github.com/snapcore/snapd/testutil"
30+
)
31+
32+
type XdgPermissionStoreInterfaceSuite struct {
33+
iface interfaces.Interface
34+
slot *interfaces.ConnectedSlot
35+
slotInfo *snap.SlotInfo
36+
plug *interfaces.ConnectedPlug
37+
plugInfo *snap.PlugInfo
38+
}
39+
40+
var _ = Suite(&XdgPermissionStoreInterfaceSuite{
41+
iface: builtin.MustInterface("xdg-permission-store"),
42+
})
43+
44+
func (s *XdgPermissionStoreInterfaceSuite) SetUpTest(c *C) {
45+
const coreYaml = `name: core
46+
version: 0
47+
type: os
48+
slots:
49+
xdg-permission-store:
50+
interface: xdg-permission-store
51+
`
52+
s.slot, s.slotInfo = MockConnectedSlot(c, coreYaml, nil, "xdg-permission-store")
53+
54+
const consumerYaml = `name: consumer
55+
version: 0
56+
apps:
57+
app:
58+
plugs: [xdg-permission-store]
59+
`
60+
s.plug, s.plugInfo = MockConnectedPlug(c, consumerYaml, nil, "xdg-permission-store")
61+
}
62+
63+
func (s *XdgPermissionStoreInterfaceSuite) TestName(c *C) {
64+
c.Assert(s.iface.Name(), Equals, "xdg-permission-store")
65+
}
66+
67+
func (s *XdgPermissionStoreInterfaceSuite) TestSanitize(c *C) {
68+
c.Assert(interfaces.BeforePreparePlug(s.iface, s.plugInfo), IsNil)
69+
c.Assert(interfaces.BeforePrepareSlot(s.iface, s.slotInfo), IsNil)
70+
}
71+
72+
func (s *XdgPermissionStoreInterfaceSuite) TestAppArmorConnectedPlug(c *C) {
73+
appSet, err := interfaces.NewSnapAppSet(s.plug.Snap(), nil)
74+
c.Assert(err, IsNil)
75+
spec := apparmor.NewSpecification(appSet)
76+
c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.slot), IsNil)
77+
c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app"})
78+
c.Check(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "#include <abstractions/dbus-session-strict>")
79+
c.Check(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "path=/org/freedesktop/impl/portal/PermissionStore")
80+
c.Check(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "interface=org.freedesktop.impl.portal.PermissionStore")
81+
c.Check(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "interface=org.freedesktop.DBus.Properties")
82+
c.Check(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "interface=org.freedesktop.DBus.Peer")
83+
c.Check(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "interface=org.freedesktop.DBus.Introspectable")
84+
c.Check(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "peer=(label=unconfined)")
85+
}
86+
87+
func (s *XdgPermissionStoreInterfaceSuite) TestAppArmorConnectedSlot(c *C) {
88+
appSet, err := interfaces.NewSnapAppSet(s.slot.Snap(), nil)
89+
c.Assert(err, IsNil)
90+
spec := apparmor.NewSpecification(appSet)
91+
c.Assert(spec.AddConnectedSlot(s.iface, s.plug, s.slot), IsNil)
92+
c.Assert(spec.SecurityTags(), HasLen, 0)
93+
}
94+
95+
func (s *XdgPermissionStoreInterfaceSuite) TestAppArmorPermanentSlot(c *C) {
96+
spec := &apparmor.Specification{}
97+
c.Assert(spec.AddPermanentSlot(s.iface, s.slotInfo), IsNil)
98+
c.Assert(spec.SecurityTags(), HasLen, 0)
99+
}
100+
101+
func (s *XdgPermissionStoreInterfaceSuite) TestStaticInfo(c *C) {
102+
si := interfaces.StaticInfoOf(s.iface)
103+
c.Check(si.ImplicitOnCore, Equals, true)
104+
c.Check(si.ImplicitOnClassic, Equals, true)
105+
c.Check(si.Summary, Equals, "allows access to the xdg desktop portal PermissionStore service")
106+
c.Check(si.BaseDeclarationPlugs, testutil.Contains, "xdg-permission-store")
107+
c.Check(si.BaseDeclarationPlugs, testutil.Contains, "allow-installation: false")
108+
c.Check(si.BaseDeclarationPlugs, testutil.Contains, "deny-auto-connection: true")
109+
c.Check(si.BaseDeclarationSlots, testutil.Contains, "xdg-permission-store")
110+
c.Check(si.BaseDeclarationSlots, testutil.Contains, "deny-auto-connection: true")
111+
}
112+
113+
func (s *XdgPermissionStoreInterfaceSuite) TestInterfaces(c *C) {
114+
c.Check(builtin.Interfaces(), testutil.DeepContains, s.iface)
115+
}

interfaces/policy/basedeclaration_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,6 +1102,7 @@ func (s *baseDeclSuite) TestPlugInstallation(c *C) {
11021102
"uinput": true,
11031103
"unity8": true,
11041104
"ubuntu-pro-control": true,
1105+
"xdg-permission-store": true,
11051106
"userns": true,
11061107
"xilinx-dma": true,
11071108
"snap-fde-control": true,
@@ -1425,6 +1426,7 @@ func (s *baseDeclSuite) TestValidity(c *C) {
14251426
"system-files": true,
14261427
"tee": true,
14271428
"ubuntu-pro-control": true,
1429+
"xdg-permission-store": true,
14281430
"udisks2": true,
14291431
"uinput": true,
14301432
"unity8": true,

tests/lib/snaps/test-snapd-policy-app-consumer/meta/snap.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,9 @@ apps:
302302
x11:
303303
command: bin/run
304304
plugs: [ x11 ]
305+
xdg-permission-store:
306+
command: bin/run
307+
plugs: [ xdg-permission-store ]
305308
xilinx-dma:
306309
command: bin/run
307310
plugs: [ xilinx-dma ]

0 commit comments

Comments
 (0)