interface: add firewall-control from ubuntu-core-security #720

Merged
merged 5 commits into from Mar 24, 2016
@@ -25,6 +25,7 @@ import (
var allInterfaces = []interfaces.Interface{
&BoolFileInterface{},
+ NewFirewallControlInterface(),
@zyga

zyga Mar 23, 2016

Contributor

Please add a test for this to all_test.go

NewNetworkInterface(),
NewNetworkBindInterface(),
}
@@ -33,6 +33,7 @@ var _ = Suite(&AllSuite{})
func (s *AllSuite) TestInterfaces(c *C) {
all := builtin.Interfaces()
c.Check(all, Contains, &builtin.BoolFileInterface{})
+ c.Check(all, DeepContains, builtin.NewFirewallControlInterface())
c.Check(all, DeepContains, builtin.NewNetworkInterface())
c.Check(all, DeepContains, builtin.NewNetworkBindInterface())
}
@@ -0,0 +1,119 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package builtin
+
+import (
+ "github.com/ubuntu-core/snappy/interfaces"
+)
+
+// http://bazaar.launchpad.net/~ubuntu-security/ubuntu-core-security/trunk/view/head:/data/apparmor/policygroups/ubuntu-core/16.04/firewall-control
+const firewallControlConnectedPlugAppArmor = `
+# Description: Can configure firewall. This is restricted because it gives
+# privileged access to networking and should only be used with trusted apps.
+# Usage: reserved
+
+#include <abstractions/nameservice>
+
+capability net_admin,
+
+/{,usr/}{,s}bin/iptables{,-save,-restore} ixr,
+/{,usr/}{,s}bin/ip6tables{,-save,-restore} ixr,
+/{,usr/}{,s}bin/iptables-apply ixr,
+/{,usr/}{,s}bin/xtables-multi ixr, # ip[6]tables*
+
+# ping - child profile would be nice but seccomp causes problems with that
+/{,usr/}{,s}bin/ping ixr,
+/{,usr/}{,s}bin/ping6 ixr,
+capability net_raw,
+capability setuid,
+network inet raw,
+network inet6 raw,
+
+# iptables (note, we don't want to allow loading modules, but
+# we can allow reading @{PROC}/sys/kernel/modprobe). Also,
+# snappy needs to have iptable_filter and ip6table_filter loaded,
+# they don't autoload.
+unix (bind) type=stream addr="@xtables",
+@{PROC}/sys/kernel/modprobe r,
+
+@{PROC}/@{pid}/net/ r,
+@{PROC}/@{pid}/net/** r,
+
+# sysctl
+/{,usr/}{,s}bin/sysctl ixr,
+@{PROC}/sys/ r,
+@{PROC}/sys/net/ r,
+@{PROC}/sys/net/core/ r,
+@{PROC}/sys/net/core/** r,
+@{PROC}/sys/net/ipv{4,6}/ r,
+@{PROC}/sys/net/ipv{4,6}/** r,
+@{PROC}/sys/net/netfilter/ r,
+@{PROC}/sys/net/netfilter/** r,
+@{PROC}/sys/net/nf_conntrack_max r,
+
+# various firewall related sysctl files
+@{PROC}/sys/net/ipv4/conf/*/rp_filter w,
+@{PROC}/sys/net/ipv{4,6}/conf/*/accept_source_route w,
+@{PROC}/sys/net/ipv{4,6}/conf/*/accept_redirects w,
+@{PROC}/sys/net/ipv4/icmp_echo_ignore_broadcasts w,
+@{PROC}/sys/net/ipv4/icmp_ignore_bogus_error_responses w,
+@{PROC}/sys/net/ipv4/icmp_echo_ignore_all w,
+@{PROC}/sys/net/ipv4/ip_forward w,
+@{PROC}/sys/net/ipv4/conf/*/log_martians w,
+@{PROC}/sys/net/ipv4/tcp_syncookies w,
+@{PROC}/sys/net/ipv6/conf/*/forwarding w,
+`
+
+// http://bazaar.launchpad.net/~ubuntu-security/ubuntu-core-security/trunk/view/head:/data/seccomp/policygroups/ubuntu-core/16.04/firewall-control
+const firewallControlConnectedPlugSecComp = `
+# Description: Can configure firewall. This is restricted because it gives
+# privileged access to networking and should only be used with trusted apps.
+# Usage: reserved
+
+# for connecting to xtables abstract socket
+bind
+connect
+getsockname
+getsockopt
+recv
+recvfrom
+recvmsg
+recvmmsg
+send
+sendmmsg
+sendmsg
+sendto
+setsockopt
+socket
+
+# for ping and ping6
+capset
+setuid
+`
+
+// NewFirewallControlInterface returns a new "firewall-control" interface.
+func NewFirewallControlInterface() interfaces.Interface {
+ return &commonInterface{
+ name: "firewall-control",
+ connectedPlugAppArmor: firewallControlConnectedPlugAppArmor,
+ connectedPlugSecComp: firewallControlConnectedPlugSecComp,
+ reservedForOS: true,
+ }
+}
@@ -0,0 +1,128 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package builtin_test
+
+import (
+ . "gopkg.in/check.v1"
+
+ "github.com/ubuntu-core/snappy/interfaces"
+ "github.com/ubuntu-core/snappy/interfaces/builtin"
+ "github.com/ubuntu-core/snappy/snap"
+)
+
+type FirewallControlInterfaceSuite struct {
+ iface interfaces.Interface
+ slot *interfaces.Slot
+ plug *interfaces.Plug
+}
+
+var _ = Suite(&FirewallControlInterfaceSuite{
+ iface: builtin.NewFirewallControlInterface(),
+ slot: &interfaces.Slot{
+ SlotInfo: &snap.SlotInfo{
+ Snap: &snap.Info{Name: "ubuntu-core"},
+ Name: "firewall-control",
+ Interface: "firewall-control",
+ },
+ },
+ plug: &interfaces.Plug{
+ PlugInfo: &snap.PlugInfo{
+ Snap: &snap.Info{Name: "other"},
+ Name: "firewall-control",
+ Interface: "firewall-control",
+ },
+ },
+})
+
+func (s *FirewallControlInterfaceSuite) TestName(c *C) {
+ c.Assert(s.iface.Name(), Equals, "firewall-control")
+}
+
+func (s *FirewallControlInterfaceSuite) TestSanitizeSlot(c *C) {
+ err := s.iface.SanitizeSlot(s.slot)
+ c.Assert(err, IsNil)
+ err = s.iface.SanitizeSlot(&interfaces.Slot{SlotInfo: &snap.SlotInfo{
+ Snap: &snap.Info{Name: "some-snap"},
+ Name: "firewall-control",
+ Interface: "firewall-control",
+ }})
+ c.Assert(err, ErrorMatches, "firewall-control slots are reserved for the operating system snap")
+}
+
+func (s *FirewallControlInterfaceSuite) TestSanitizePlug(c *C) {
+ err := s.iface.SanitizePlug(s.plug)
+ c.Assert(err, IsNil)
+}
+
+func (s *FirewallControlInterfaceSuite) TestSanitizeIncorrectInterface(c *C) {
+ c.Assert(func() { s.iface.SanitizeSlot(&interfaces.Slot{SlotInfo: &snap.SlotInfo{Interface: "other"}}) },
+ PanicMatches, `slot is not of interface "firewall-control"`)
+ c.Assert(func() { s.iface.SanitizePlug(&interfaces.Plug{PlugInfo: &snap.PlugInfo{Interface: "other"}}) },
+ PanicMatches, `plug is not of interface "firewall-control"`)
+}
+
+func (s *FirewallControlInterfaceSuite) TestUnusedSecuritySystems(c *C) {
+ systems := [...]interfaces.SecuritySystem{interfaces.SecurityAppArmor,
+ interfaces.SecuritySecComp, interfaces.SecurityDBus,
+ interfaces.SecurityUDev}
+ for _, system := range systems {
+ snippet, err := s.iface.PermanentPlugSnippet(s.plug, system)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.PermanentSlotSnippet(s.slot, system)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.ConnectedSlotSnippet(s.plug, s.slot, system)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+ }
+ snippet, err := s.iface.ConnectedPlugSnippet(s.plug, s.slot, interfaces.SecurityDBus)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.ConnectedPlugSnippet(s.plug, s.slot, interfaces.SecurityUDev)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, IsNil)
+}
+
+func (s *FirewallControlInterfaceSuite) TestUsedSecuritySystems(c *C) {
+ // connected plugs have a non-nil security snippet for apparmor
+ snippet, err := s.iface.ConnectedPlugSnippet(s.plug, s.slot, interfaces.SecurityAppArmor)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, Not(IsNil))
+ // connected plugs have a non-nil security snippet for seccomp
+ snippet, err = s.iface.ConnectedPlugSnippet(s.plug, s.slot, interfaces.SecuritySecComp)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, Not(IsNil))
+}
+
+func (s *FirewallControlInterfaceSuite) TestUnexpectedSecuritySystems(c *C) {
+ snippet, err := s.iface.PermanentPlugSnippet(s.plug, "foo")
+ c.Assert(err, Equals, interfaces.ErrUnknownSecurity)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.ConnectedPlugSnippet(s.plug, s.slot, "foo")
+ c.Assert(err, Equals, interfaces.ErrUnknownSecurity)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.PermanentSlotSnippet(s.slot, "foo")
+ c.Assert(err, Equals, interfaces.ErrUnknownSecurity)
+ c.Assert(snippet, IsNil)
+ snippet, err = s.iface.ConnectedSlotSnippet(s.plug, s.slot, "foo")
+ c.Assert(err, Equals, interfaces.ErrUnknownSecurity)
+ c.Assert(snippet, IsNil)
+}