Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
Already on GitHub? Sign in to your account
interface: add firewall-control from ubuntu-core-security #720
Merged
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
5276990
interface: add firewall-control from ubuntu-core-security
jdstrand ed97899
Merge branch 'master' into firewall-control
jdstrand efff91e
interface: adjust firewall-control for testsuite changes
jdstrand f085757
interface: adjust all.go for firewall-control
jdstrand c2a53cb
interface: add test for firewall-control to all_test.go
jdstrand
Jump to file or symbol
Failed to load files and symbols.
| @@ -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) | ||
| +} |
Please add a test for this to
all_test.go