Skip to content

Commit 1a5360d

Browse files
committed
interfaces/builtin: add lsm self-attr syscall allowances
Add lsm_get_self_attr to interfaces that read AppArmor current labels and add lsm_set_self_attr where AppArmor allows writing process attr/exec. Include seccomp coverage updates in tests for system-observe, cups-control, docker-support, and kubernetes-support flavors. No syscall addition for browser-support: it explicitly denies access to /proc/.../attr/{,apparmor/}current. No explicit syscall addition for lxd-support: its seccomp policy is @unrestricted. The k8s-support interface has both get and set per advice from John Johansen. Jira: https://warthogs.atlassian.net/browse/AA-1000 Signed-off-by: Zygmunt Krynicki <me@zygoon.pl>
1 parent 6755a6f commit 1a5360d

File tree

8 files changed

+58
-0
lines changed

8 files changed

+58
-0
lines changed

interfaces/builtin/cups_control.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"github.com/snapcore/snapd/dirs"
2727
"github.com/snapcore/snapd/interfaces"
2828
"github.com/snapcore/snapd/interfaces/apparmor"
29+
"github.com/snapcore/snapd/interfaces/seccomp"
2930
"github.com/snapcore/snapd/osutil"
3031
"github.com/snapcore/snapd/release"
3132
"github.com/snapcore/snapd/snap"
@@ -117,6 +118,10 @@ dbus (receive)
117118
peer=(label=###SLOT_SECURITY_TAGS###),
118119
`
119120

121+
const cupsControlPermanentSlotSecComp = `
122+
lsm_get_self_attr
123+
`
124+
120125
type cupsControlInterface struct {
121126
commonInterface
122127
}
@@ -167,6 +172,13 @@ func (iface *cupsControlInterface) AppArmorConnectedPlug(spec *apparmor.Specific
167172
return nil
168173
}
169174

175+
func (iface *cupsControlInterface) SecCompPermanentSlot(spec *seccomp.Specification, slot *snap.SlotInfo) error {
176+
if !implicitSystemPermanentSlot(slot) {
177+
spec.AddSnippet(cupsControlPermanentSlotSecComp)
178+
}
179+
return nil
180+
}
181+
170182
func (iface *cupsControlInterface) AutoConnect(plug *snap.PlugInfo, slot *snap.SlotInfo) bool {
171183
cupsdConf := filepath.Join(dirs.GlobalRootDir, "/etc/cups/cupsd.conf")
172184
_, hostSystemHasCupsd, _ := osutil.RegularFileExists(cupsdConf)

interfaces/builtin/cups_control_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/snapcore/snapd/interfaces"
3030
"github.com/snapcore/snapd/interfaces/apparmor"
3131
"github.com/snapcore/snapd/interfaces/builtin"
32+
"github.com/snapcore/snapd/interfaces/seccomp"
3233
"github.com/snapcore/snapd/release"
3334
"github.com/snapcore/snapd/snap"
3435
"github.com/snapcore/snapd/testutil"
@@ -197,6 +198,38 @@ func (s *cupsControlSuite) TestAppArmorSpecClassic(c *C) {
197198
c.Assert(spec.SnippetForTag("snap.provider.app"), testutil.Contains, "peer=(label=\"snap.consumer.app\"")
198199
}
199200

201+
func (s *cupsControlSuite) TestSecCompSpecCore(c *C) {
202+
restore := release.MockOnClassic(false)
203+
defer restore()
204+
205+
// core to consumer on core is empty for PermanentSlot
206+
spec := seccomp.NewSpecification(s.coreSlot.AppSet())
207+
c.Assert(spec.AddPermanentSlot(s.iface, s.coreSlotInfo), IsNil)
208+
c.Assert(spec.SecurityTags(), HasLen, 0)
209+
210+
// provider to consumer on core gets permanent slot seccomp policy
211+
spec = seccomp.NewSpecification(s.providerSlot.AppSet())
212+
c.Assert(spec.AddPermanentSlot(s.iface, s.providerSlotInfo), IsNil)
213+
c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.provider.app"})
214+
c.Assert(spec.SnippetForTag("snap.provider.app"), testutil.Contains, "lsm_get_self_attr\n")
215+
}
216+
217+
func (s *cupsControlSuite) TestSecCompSpecClassic(c *C) {
218+
restore := release.MockOnClassic(true)
219+
defer restore()
220+
221+
// core to consumer on classic is empty for PermanentSlot
222+
spec := seccomp.NewSpecification(s.coreSlot.AppSet())
223+
c.Assert(spec.AddPermanentSlot(s.iface, s.coreSlotInfo), IsNil)
224+
c.Assert(spec.SecurityTags(), HasLen, 0)
225+
226+
// provider to consumer on classic gets permanent slot seccomp policy
227+
spec = seccomp.NewSpecification(s.providerSlot.AppSet())
228+
c.Assert(spec.AddPermanentSlot(s.iface, s.providerSlotInfo), IsNil)
229+
c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.provider.app"})
230+
c.Assert(spec.SnippetForTag("snap.provider.app"), testutil.Contains, "lsm_get_self_attr\n")
231+
}
232+
200233
func (s *cupsControlSuite) TestAutoConnect(c *C) {
201234
tmpdir := c.MkDir()
202235
dirs.SetRootDir(tmpdir)

interfaces/builtin/docker_support.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,8 @@ keyctl
312312
# /snap/docker/VERSION/bin/docker-runc
313313
pivot_root
314314
315+
lsm_set_self_attr
316+
315317
# ptrace can be abused to break out of the seccomp sandbox
316318
# but is required by the Docker daemon.
317319
ptrace

interfaces/builtin/docker_support_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ func (s *DockerSupportInterfaceSuite) TestSecCompSpec(c *C) {
239239
spec := seccomp.NewSpecification(appSet)
240240
c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.slot), IsNil)
241241
c.Check(spec.SnippetForTag("snap.docker.app"), testutil.Contains, "# Calls the Docker daemon itself requires\n")
242+
c.Check(spec.SnippetForTag("snap.docker.app"), testutil.Contains, "lsm_set_self_attr\n")
242243
}
243244

244245
func (s *DockerSupportInterfaceSuite) TestKModSpec(c *C) {

interfaces/builtin/kubernetes_support.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,9 @@ mount
252252
umount
253253
umount2
254254
255+
lsm_get_self_attr
256+
lsm_set_self_attr
257+
255258
unshare
256259
setns - CLONE_NEWNET
257260

interfaces/builtin/kubernetes_support_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ func (s *KubernetesSupportInterfaceSuite) TestSecCompConnectedPlug(c *C) {
225225
c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.kubernetes-support.default"})
226226
c.Check(spec.SnippetForTag("snap.kubernetes-support.default"), testutil.Contains, "# Allow running as the kubelet service\n")
227227
c.Check(spec.SnippetForTag("snap.kubernetes-support.default"), testutil.Contains, "# Allow using the 'autobind' feature of bind() (eg, for journald).\n")
228+
c.Check(spec.SnippetForTag("snap.kubernetes-support.default"), testutil.Contains, "lsm_get_self_attr\n")
228229

229230
// kubeproxy should have the autobind rules
230231
spec = seccomp.NewSpecification(s.plugKubeproxy.AppSet())
@@ -233,6 +234,7 @@ func (s *KubernetesSupportInterfaceSuite) TestSecCompConnectedPlug(c *C) {
233234
c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.kubernetes-support.kubeproxy"})
234235
c.Check(spec.SnippetForTag("snap.kubernetes-support.kubeproxy"), Not(testutil.Contains), "# Allow running as the kubelet service\n")
235236
c.Check(spec.SnippetForTag("snap.kubernetes-support.kubeproxy"), testutil.Contains, "# Allow using the 'autobind' feature of bind() (eg, for journald).\n")
237+
c.Check(spec.SnippetForTag("snap.kubernetes-support.kubeproxy"), Not(testutil.Contains), "lsm_get_self_attr\n")
236238

237239
// kubelet should have its rules and the autobind rules
238240
spec = seccomp.NewSpecification(s.plugKubelet.AppSet())
@@ -241,6 +243,7 @@ func (s *KubernetesSupportInterfaceSuite) TestSecCompConnectedPlug(c *C) {
241243
c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.kubernetes-support.kubelet"})
242244
c.Check(spec.SnippetForTag("snap.kubernetes-support.kubelet"), testutil.Contains, "# Allow running as the kubelet service\n")
243245
c.Check(spec.SnippetForTag("snap.kubernetes-support.kubelet"), testutil.Contains, "# Allow using the 'autobind' feature of bind() (eg, for journald).\n")
246+
c.Check(spec.SnippetForTag("snap.kubernetes-support.kubelet"), testutil.Contains, "lsm_get_self_attr\n")
244247

245248
// kube-autobind-unix should have the autobind rules
246249
spec = seccomp.NewSpecification(s.plugKubeAutobind.AppSet())
@@ -249,6 +252,7 @@ func (s *KubernetesSupportInterfaceSuite) TestSecCompConnectedPlug(c *C) {
249252
c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.kubernetes-support.kube-autobind-unix"})
250253
c.Check(spec.SnippetForTag("snap.kubernetes-support.kube-autobind-unix"), Not(testutil.Contains), "# Allow running as the kubelet service\n")
251254
c.Check(spec.SnippetForTag("snap.kubernetes-support.kube-autobind-unix"), testutil.Contains, "# Allow using the 'autobind' feature of bind() (eg, for journald).\n")
255+
c.Check(spec.SnippetForTag("snap.kubernetes-support.kube-autobind-unix"), Not(testutil.Contains), "lsm_get_self_attr\n")
252256
}
253257

254258
func (s *KubernetesSupportInterfaceSuite) TestUDevConnectedPlug(c *C) {

interfaces/builtin/system_observe.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@ const systemObserveConnectedPlugSecComp = `
208208
# it gives privileged read access to all processes on the system and should
209209
# only be used with trusted apps.
210210
211+
lsm_get_self_attr
212+
211213
# ptrace can be used to break out of the seccomp sandbox, but ps requests
212214
# 'ptrace (trace)' from apparmor. 'ps' does not need the ptrace syscall though,
213215
# so we deny the ptrace here to make sure we are always safe. Note: may

interfaces/builtin/system_observe_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ func (s *SystemObserveInterfaceSuite) TestUsedSecuritySystems(c *C) {
103103
err = seccompSpec.AddConnectedPlug(s.iface, s.plug, s.slot)
104104
c.Assert(err, IsNil)
105105
c.Assert(seccompSpec.SecurityTags(), DeepEquals, []string{"snap.other.app2"})
106+
c.Check(seccompSpec.SnippetForTag("snap.other.app2"), testutil.Contains, "lsm_get_self_attr\n")
106107
c.Check(seccompSpec.SnippetForTag("snap.other.app2"), testutil.Contains, "ptrace\n")
107108
}
108109

0 commit comments

Comments
 (0)