Skip to content
This repository was archived by the owner on Aug 5, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions doc/security.rst
Original file line number Diff line number Diff line change
Expand Up @@ -239,3 +239,55 @@ The signing tool uses a 2048bit RSA private key (``REFKIT_DB_KEY``) and a
PEM formatted X.509 signature (``REFKIT_DB_CERT``). When deploying the DB
keys on the device, use the DER formatted X.509. See ``meta-refkit/files/secureboot/gen-keys-helper.sh`` for more details on how the test keys can be created.

Firewall support
================

Default firewall is nftables. The default firewall ruleset itself is
quite basic: only incoming IPv4 and IPv6 traffic is filtered.
Applications must by themselves request the permissions they need by
dropping an nftables script to directory ``/usr/lib/firewall/services/``
or ``/etc/firewall/services/``. The nftables script should be named with
the package name to avoid file name conflicts.

There are two main ways for writing the script. First way is the
fastest, and is suitable for applications and services which only need
to have certain TCP or UDP port ranges open. The service has a chain
which contains the rules for processing the packet. The chain is then
added as a jump target to tcp map (``tcp_service_map``) or udp map
(``udp_service_map``), which map from port numbers or well-known
services to the chains. In this example, tcp port 22 (ssh) is mapped to
chain ``openssh-sshd``, which then accepts connections from LAN
interfaces. The interface definitions are included from
``zones.ruleset``.

.. code:: nft

#!/usr/sbin/nft

table inet filter {
include "zones.ruleset"
chain openssh-sshd {
iif @ZONE_LAN accept;
}
}

add element inet filter tcp_service_map {ssh : jump openssh-sshd};

The second way is to set up a new input chain with priority 0 and policy
``accept``. The chain must tag packets belonging to the service there
with mark ``accept_packet``. This method is especially suitable for
services which require network traffic other than tcp or udp, such as
ICMP packets. It carries a performance penalty, however. The following
example is equivalent with the previous example.

.. code:: nft

#!/usr/sbin/nft

table inet filter {
include "zones.ruleset"
chain openssh-sshd {
type filter hook input priority 0; policy accept;
tcp dport ssh iif @ZONE_LAN mark set $accept_packet;
}
}
2 changes: 1 addition & 1 deletion meta-intel
Submodule meta-intel updated from 7e8f98 to 86c55b
1 change: 1 addition & 0 deletions meta-iotqa/conf/test/qemu.mask
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ oeqa.runtime.connectivity.bluetooth.btcheck
oeqa.runtime.connectivity.wifi.wifi_connect
oeqa.runtime.peripherals.mraa.mraa_gpio
oeqa.runtime.multimedia.audio.alsa
oeqa.runtime.sanity.nftables
1 change: 1 addition & 0 deletions meta-iotqa/conf/test/refkit-image-common.manifest
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ oeqa.runtime.peripherals.mraa.mraa_hello
oeqa.runtime.peripherals.mraa.mraa_gpio
oeqa.runtime.multimedia.audio.alsa
oeqa.runtime.peripherals.upm.upm
oeqa.runtime.sanity.nftables
11 changes: 5 additions & 6 deletions meta-iotqa/lib/oeqa/runtime/core/iotivity/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,10 @@ def setUpClass(cls):
# Set up firewall
port_range_cmd = "cat /proc/sys/net/ipv4/ip_local_port_range"
(status, output) = cls.tc.target.run(port_range_cmd)
port_range = "%s:%s" % tuple(output.split())
port_range = output.split()

iptables_cmd = "/usr/sbin/ip6tables -w -A INPUT -s fe80::/10 \
-p udp -m udp --dport %s -j ACCEPT"
cls.tc.target.run(iptables_cmd % "5683")
cls.tc.target.run(iptables_cmd % "5684")
cls.tc.target.run(iptables_cmd % port_range)
cls.tc.target.run("/usr/sbin/nft add chain inet filter iotivity { type filter hook input priority 0\; }")
cls.tc.target.run("/usr/sbin/nft add rule inet filter iotivity ip6 saddr fe80::/10 udp dport {5683, 5684, %s-%s} mark set 1" % (port_range[0], port_range[1]))

# Start server
resource_cmd = "/opt/iotivity/examples/resource/cpp/%s > /tmp/%s &"
Expand All @@ -57,5 +54,7 @@ def setUpClass(cls):
@classmethod
def tearDownClass(cls):

cls.tc.target.run("/usr/sbin/nft flush chain inet filter iotivity")
cls.tc.target.run("/usr/sbin/nft delete chain inet filter iotivity")
remove_user("iotivity-tester")
cls.tc.target.run("killall simpleserver simpleclient")
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,10 @@ def setUpClass(cls):
# Setup firewall accept for multicast
(status, output) = cls.tc.target.run("cat /proc/sys/net/ipv4/ip_local_port_range")
port_range = output.split()
cls.tc.target.run("/usr/sbin/iptables -w -A INPUT -p udp --dport 5683 -j ACCEPT")
cls.tc.target.run("/usr/sbin/iptables -w -A INPUT -p udp --dport 5684 -j ACCEPT")
cls.tc.target.run("/usr/sbin/ip6tables -w -A INPUT -s fe80::/10 -p udp -m udp --dport 5683 -j ACCEPT")
cls.tc.target.run("/usr/sbin/ip6tables -w -A INPUT -s fe80::/10 -p udp -m udp --dport 5684 -j ACCEPT")
cls.tc.target.run("/usr/sbin/ip6tables -w -A INPUT -s fe80::/10 -p udp -m udp --dport %s:%s -j ACCEPT" % (port_range[0], port_range[1]))

cls.tc.target.run("/usr/sbin/nft add chain inet filter iotivity { type filter hook input priority 0\; }")
cls.tc.target.run("/usr/sbin/nft add rule inet filter iotivity udp dport {5683, 5684} mark set 1")
cls.tc.target.run("/usr/sbin/nft add rule inet filter iotivity ip6 saddr fe80::/10 udp dport {5683, 5684, %s-%s} mark set 1" % (port_range[0], port_range[1]))

@classmethod
def tearDownClass(cls):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,8 @@ def setUpClass(cls):
add_group("tester", target=cls.tc.targets[1])
add_user("iotivity-tester", "tester", target=cls.tc.targets[1])
# Setup firewall accept for multicast, on both sides
run_as("root", "/usr/sbin/iptables -w -A INPUT -p udp --dport 5683 -j ACCEPT", target=cls.tc.targets[0])
run_as("root", "/usr/sbin/iptables -w -A INPUT -p udp --dport 5684 -j ACCEPT", target=cls.tc.targets[0])
run_as("root", "/usr/sbin/iptables -w -A INPUT -p udp --dport 5683 -j ACCEPT", target=cls.tc.targets[1])
run_as("root", "/usr/sbin/iptables -w -A INPUT -p udp --dport 5684 -j ACCEPT", target=cls.tc.targets[1])
run_as("root", "/usr/sbin/nft add rule inet filter input udp dport {5683, 5684} accept", target=cls.tc.targets[0])
run_as("root", "/usr/sbin/nft add rule inet filter input udp dport {5683, 5684} accept", target=cls.tc.targets[1])
# check if image contains iotivity example applications
(status, output) = run_as("root", "ls /opt/iotivity/examples/resource/", target=cls.tc.targets[0])
if "cpp" in output:
Expand Down
6 changes: 2 additions & 4 deletions meta-iotqa/lib/oeqa/runtime/core/iotivity/iotvt_wifi.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,8 @@ def setUpClass(cls):
add_group("tester", target=cls.tc.targets[1])
add_user("iotivity-tester", "tester", target=cls.tc.targets[1])
# Setup firewall accept for multicast, on both sides
run_as("root", "/usr/sbin/iptables -w -A INPUT -p udp --dport 5683 -j ACCEPT", target=cls.tc.targets[0])
run_as("root", "/usr/sbin/iptables -w -A INPUT -p udp --dport 5684 -j ACCEPT", target=cls.tc.targets[0])
run_as("root", "/usr/sbin/iptables -w -A INPUT -p udp --dport 5683 -j ACCEPT", target=cls.tc.targets[1])
run_as("root", "/usr/sbin/iptables -w -A INPUT -p udp --dport 5684 -j ACCEPT", target=cls.tc.targets[1])
run_as("root", "/usr/sbin/nft add rule inet filter input udp dport {5683, 5684} accept", target=cls.tc.targets[0])
run_as("root", "/usr/sbin/nft add rule inet filter input udp dport {5683, 5684} accept", target=cls.tc.targets[1])

# check if image contains iotivity example applications
(status, output) = run_as("root", "ls /opt/iotivity/examples/resource/", target=cls.tc.targets[0])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,9 @@ def setUp(self):
# Set firewall rules
(status, output) = self.target.run("cat /proc/sys/net/ipv4/ip_local_port_range")
port_range = output.split()
self.target.run("/usr/sbin/iptables -w -A INPUT -p udp --dport 5683 -j ACCEPT")
self.target.run("/usr/sbin/iptables -w -A INPUT -p udp --dport 5684 -j ACCEPT")
self.target.run("/usr/sbin/ip6tables -w -A INPUT -s fe80::/10 -p udp -m udp --dport 5683 -j ACCEPT")
self.target.run("/usr/sbin/ip6tables -w -A INPUT -s fe80::/10 -p udp -m udp --dport 5684 -j ACCEPT")
self.target.run("/usr/sbin/ip6tables -w -A INPUT -s fe80::/10 -p udp -m udp --dport %s:%s -j ACCEPT" % (port_range[0], port_range[1]))
self.target.run("/usr/sbin/nft add chain inet filter iotivity { type filter hook input priority 0\; }")
self.target.run("/usr/sbin/nft add rule inet filter iotivity udp dport {5683, 5684} mark set 1")
self.target.run("/usr/sbin/nft add rule inet filter iotivity ip6 saddr fe80::/10 udp dport {5683, 5684, %s-%s} mark set 1" % (port_range[0], port_range[1]))


def test_apprt_iotivitynode(self):
Expand Down Expand Up @@ -261,13 +259,9 @@ def tearDown(self):
@fn tearDown
@param self
'''
(status, output) = self.target.run("cat /proc/sys/net/ipv4/ip_local_port_range")
port_range = output.split()
self.target.run("/usr/sbin/iptables -w -D INPUT -p udp --dport 5683 -j ACCEPT")
self.target.run("/usr/sbin/iptables -w -D INPUT -p udp --dport 5684 -j ACCEPT")
self.target.run("/usr/sbin/ip6tables -w -D INPUT -s fe80::/10 -p udp -m udp --dport 5683 -j ACCEPT")
self.target.run("/usr/sbin/ip6tables -w -D INPUT -s fe80::/10 -p udp -m udp --dport 5684 -j ACCEPT")
self.target.run("/usr/sbin/ip6tables -w -D INPUT -s fe80::/10 -p udp -m udp --dport %s:%s -j ACCEPT" % (port_range[0], port_range[1]))

self.target.run("/usr/sbin/nft flush chain inet filter iotivity")
self.target.run("/usr/sbin/nft delete chain inet filter iotivity")
sys.stdout.write("\nClean test files in device, eg: tests grunt-build")
sys.stdout.flush()
self.target_path = '/usr/lib/node_modules/iotivity-node/'
Expand Down Expand Up @@ -295,4 +289,3 @@ def tearDown(self):
# @}
# @}
##

6 changes: 4 additions & 2 deletions meta-iotqa/lib/oeqa/runtime/programming/nodejs/mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ def test_mqtt(self):
@param return
'''
# Enable the port 1883
self.target.run('ip6tables -A INPUT -p tcp --dport 1883 -j ACCEPT')
self.target.run("/usr/sbin/nft add chain inet filter mqtt { type filter hook input priority 0\; }")
self.target.run("/usr/sbin/nft add rule inet filter mqtt tcp dport 1883 mark set 1")
(status, output) = self.target.run("node /tmp/mqtt/mqtt.js")
self.assertEqual(status, 0)
self.assertTrue('error' not in output.lower())
Expand All @@ -82,4 +83,5 @@ def tearDown(self):
os.system('rm -rf %s >/dev/null 2>&1' % os.path.join(target_file, 'node_modules'))
self.target.run('rm -rf /tmp/node_modules')
self.target.run('rm -rf /tmp/mqtt')
self.target.run('ip6tables -D INPUT -p tcp --dport 1883 -j ACCEPT')
self.target.run("/usr/sbin/nft flush chain inet filter mqtt")
self.target.run("/usr/sbin/nft delete chain inet filter mqtt")
6 changes: 4 additions & 2 deletions meta-iotqa/lib/oeqa/runtime/programming/nodejs/rest_apis.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ def setUpClass(cls):
'chmod +x /tmp/nodeunit-master/bin/nodeunit'
)

cls.tc.target.run("/usr/sbin/iptables -w -A INPUT -p udp --dport 5683 -j ACCEPT")
cls.tc.target.run("/usr/sbin/nft add chain inet filter rest_api { type filter hook input priority 0\; }")
cls.tc.target.run("/usr/sbin/nft add rule inet filter rest_api udp dport 5683 accept")
cls.tc.target.run('/opt/iotivity/examples/resource/c/SimpleClientServer/ocserver -o 0')
for api, api_js in cls.rest_api_js_files.items():
cls.tc.target.run('cd %s; node %s' % (cls.target_rest_api_dir, api_js) )
Expand Down Expand Up @@ -1502,4 +1503,5 @@ def tearDownClass(cls):
cls.tc.target.run('rm -f /tmp/master.tar')
cls.tc.target.run('rm -rf /tmp/modules')

cls.tc.target.run("/usr/sbin/iptables -w -D INPUT -p udp --dport 5683 -j ACCEPT")
cls.tc.target.run("/usr/sbin/nft flush chain inet filter rest_api")
cls.tc.target.run("/usr/sbin/nft delete chain inet filter rest_api")
64 changes: 64 additions & 0 deletions meta-iotqa/lib/oeqa/runtime/sanity/nftables.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import os
import subprocess
from time import sleep
from oeqa.oetest import oeRuntimeTest

class NftablesTest(oeRuntimeTest):

def check_ssh_connection(self):
'''Check SSH connection to DUT port 2222'''
process = subprocess.Popen(("ssh -o UserKnownHostsFile=/dev/null " \
"-o ConnectTimeout=3 " \
"-o StrictHostKeyChecking=no root@" + \
self.target.ip +" -p 2222 ls").split(),
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
output, err = process.communicate()
output = output.decode("utf-8")
returncode = process.returncode
return returncode, output

def add_test_table(self):
self.target.run("nft add table ip test")
self.target.run("nft add chain ip test input {type filter hook input priority 0\;}")
self.target.run("nft add chain ip test donothing")
self.target.run("nft add chain ip test prerouting {type nat hook prerouting priority 0 \;}")
self.target.run("nft add chain ip test postrouting {type nat hook postrouting priority 100 \;}")

def delete_test_table(self):
self.target.run("nft delete table ip test")

def test_reject(self):
'''Test rejecting SSH with nftables'''
self.add_test_table()
self.target.run("nft add rule ip test input tcp dport 2222 reject")
self.target.run("nft add rule ip test input goto donothing")
returncode, output = self.check_ssh_connection()
self.delete_test_table()
self.assertIn("Connection refused", output, msg="Error message: %s" % output)

def test_drop(self):
'''Test dropping SSH with nftables'''
self.add_test_table()
self.target.run("nft add rule ip test input tcp dport 2222 drop")
self.target.run("nft add rule ip test input goto donothing")
returncode, output = self.check_ssh_connection()
self.delete_test_table()
self.assertIn("Connection timed out", output, msg="Error message: %s" % output)

def test_redirect(self):
'''Test redirecting port'''
# Check that SSH can't connect to port 2222
returncode, output = self.check_ssh_connection()
self.assertNotEqual(returncode, 0, msg="Error message: %s" % output)

self.add_test_table()
self.target.run("nft add rule ip test prerouting tcp dport 2222 redirect to 22")
# Check that SSH can connect to port 2222
returncode, output = self.check_ssh_connection()
self.assertEqual(returncode, 0, msg="Error message: %s" % output)

self.delete_test_table()
# Check that SSH can't connect to port 2222
returncode, output = self.check_ssh_connection()
self.assertNotEqual(returncode, 0, msg="Error message: %s" % output)
14 changes: 14 additions & 0 deletions meta-refkit-core/conf/distro/include/refkit-config.inc
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ REFKIT_IMAGE_MODE_VALID ??= "development production"
KERNEL_FEATURES_append_refkit-config = " \
${@ bb.utils.contains('DISTRO_FEATURES', 'dm-verity', ' features/device-mapper/dm-verity.scc', '', d) } \
${@ bb.utils.contains('DISTRO_FEATURES', 'tpm1.2', ' features/tpm/tpm.scc', '', d) } \
${@ bb.utils.contains('DISTRO_FEATURES', 'refkit-firewall', ' features/nf_tables/nf_tables.scc', '', d) } \
"

# Use UEFI-based "dsk" image format for machines supporting UEFI.
Expand Down Expand Up @@ -132,6 +133,10 @@ PACKAGECONFIG_pn-gstreamer1.0-plugins-bad_refkit-config ?= ""
# Enable OpenCL.
PACKAGECONFIG_append_pn-opencv_refkit-config = " opencl"

# Use nftables instead of iptables.
PACKAGECONFIG_remove_pn-connman_refkit-config = "iptables"
PACKAGECONFIG_append_pn-connman_refkit-config = " nftables"

#########################################################################
# Changes that normally are better suited for a .bbappend have
# to be done here if the corresponding .bb file is not guaranteed
Expand All @@ -154,3 +159,12 @@ SYSTEMD_AUTO_ENABLE_forcevariable_pn-trousers_refkit-config = "enable"
# usbutils depends directly on libusb1, not the obsolete compatibility. This removes dependency on libusb-compat.
DEPENDS_remove_pn-libgphoto2_refkit-config = "virtual/libusb0"
DEPENDS_append_pn-libgphoto2_refkit-config = " libusb1"

# remove readline dependency from nftables
DEPENDS_remove_pn-nftables_refkit-config = "readline"
EXTRA_OECONF_append_pn-nftables_refkit-config = " --without-cli"

# make nftables require a settings package
VIRTUAL-RUNTIME_nftables-settings ?= "nftables-settings-default"
RDEPENDS_nftables_append_refkit-config = " ${VIRTUAL-RUNTIME_nftables-settings}"

17 changes: 6 additions & 11 deletions meta-refkit-core/recipes-connectivity/avahi/avahi_%.bbappend
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ FILES_${PN}_append_refkit-config = " \
"

# add firewall support
RDEPENDS_${PN}_append_refkit-firewall += " iptables"
RDEPENDS_${PN}_append_refkit-firewall += " nftables"

SRC_URI_append_refkit-firewall = "\
file://${PN}-ipv4.conf \
file://${PN}-ipv6.conf \
file://avahi.ruleset \
"

do_install_append_refkit-config() {
Expand All @@ -25,15 +24,11 @@ do_install_append_refkit-config() {

}
do_install_append_refkit-firewall() {
install -d ${D}${systemd_unitdir}/system/avahi-daemon.socket.d
install -m 0644 ${WORKDIR}/${PN}-ipv4.conf ${D}${systemd_unitdir}/system/avahi-daemon.socket.d
if ${@bb.utils.contains('DISTRO_FEATURES', 'ipv6', 'true', 'false', d)}; then
install -m 0644 ${WORKDIR}/${PN}-ipv6.conf ${D}${systemd_unitdir}/system/avahi-daemon.socket.d
fi
install -d ${D}${libdir}/firewall/services
install -m 0644 ${WORKDIR}/avahi.ruleset ${D}${libdir}/firewall/services/

}

FILES_${PN}_append_refkit-firewall = " \
${systemd_unitdir}/system/avahi-daemon.socket.d/${PN}-ipv4.conf \
${@bb.utils.contains('DISTRO_FEATURES', 'ipv6', \
'${systemd_unitdir}/system/avahi-daemon.socket.d/${PN}-ipv6.conf', '', d)} \
${libdir}/firewall/services/avahi.ruleset \
"

This file was deleted.

This file was deleted.

12 changes: 12 additions & 0 deletions meta-refkit-core/recipes-connectivity/avahi/files/avahi.ruleset
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/sbin/nft

table inet filter {
include "zones.ruleset"

chain avahi {
# allow multicast for clients in ZONE_LAN
iif @ZONE_LAN accept;
}
}

add element inet filter udp_service_map {5353 : jump avahi};
Loading