Categories
DSSP2

Report 21 to 28 Dec. 2019

  • Added an FC spec for some emacs elpa helper scripts. Debian apt post installation scriptlet prompted this. Not sure if eventually i want to label that this way but for now this will keep apt happy.
  • Removed some macro access to capabilities for “common_user”. These macros are also called for prefixed domains and not only for “subj.common_subj” access. Therefore I shouldnt imply access to caps here.
  • I reverted a commit that actually opened up a LOT of bad access. These “subj.common_subj.all_macro_templates” reference “subj_type_attribute” from the calling namespace. If that type attribute does not exist there then it will use the name space of the macro. In this care it allows all callers for “chfn.run” access to various process perms for “subj.common_subj.subj_type_attribute”
  • One one of my systems fstrim does a “write” access check on mounpoints suchs as /boot and others (I guess the filesystems mounted on there don’t support “discared” even though the are storage) Anyhow, that is speculation and i dontaudited audit_access there.
  • Googler wants to execute uname.
  • Some changes to screen. Initially i gave “screen home” a private type for “.screenrc”, and screen read access. I opened this up for also make it apply to “screenlog” and “hardcopy”. So I ended giving “manage” access to screen for “screen home” files.. People might want screen to “write” to .screenrc so this is a little bit more tolerant/liberal.
  • Added a basic policy to “radeontop”. This is probably one of the simplest policy modules in dssp2 standard.

… And that wraps it up for this week.

Categories
DSSP2

DSSP2 Trivia

What happened here?

Categories
DSSP2

Leveraging Secmark on Agnus for termy.id

I have a login shell account on my Agnus host that I basically use for shared confined shell access. It is not quite a minimal login shell but not far from it. The user can connect with Termy as well as SSH with SFTP access, it has a systemd –user instance, and it has access to emacs, git client, screen.

Emacs and git can optionally be used to connect to the network, but I did not want that to be an all-or-nothing proposition. So I decided to leverage Secmark so that Emacs Termy instance (Eww) can be used to browse “allowed_web” and so that Git client Termy instance can be used to connect to “allowed_git” (this only includes Git access via git:// an https:// — so no ssh:// access). Also DNS access is restricted to “allowed_dns”. Local DNS is currently “allowed_dns”, defensec.nl is currently “allowed_web” and “allowed_git”. So Termy can use Emacs Eww to browse this blog , and git can be used to access the dssp2.git repositories. I can easily manage the “allowed_web”, “allowed_git”, and “allowed_dns” hosts. And I might extend Emacs access to for example mail with “allowed_mail”, IRC “allowed_irc”, etc.

The mysecmark.cil policy module that I use for this:

(block allowed_dns (blockinherit net.packet.obj_template))
(block allowed_git (blockinherit net.packet.obj_template))
(block allowed_web (blockinherit net.packet.obj_template))

(typeattribute secmark_constrained_subj_type_attribute)
(typeattributeset secmark_constrained_subj_type_attribute (emacs.termy.subj git.client.termy.subj screen.termy.subj termy_server.termy.subj systemd.termy.subj emacs.client.termy.subj passwd.termy.subj))

(typeattribute dns_client_minus_secmark_constrained_type_attribute)
(typeattributeset dns_client_minus_secmark_constrained_type_attribute (and dns.client_subj_type_attribute (not secmark_constrained_subj_type_attribute)))

(call sys.invalid.packet_send (dns_client_minus_secmark_constrained_type_attribute))
(call sys.invalid.packet_recv (dns_client_minus_secmark_constrained_type_attribute))

(call allowed_dns.packet_recv (dns.client_subj_type_attribute))
(call allowed_dns.packet_send (dns.client_subj_type_attribute))

(call allowed_git.packet_recv (dns.client_subj_type_attribute))
(call allowed_git.packet_send (dns.client_subj_type_attribute))

(call allowed_web.packet_recv (dns.client_subj_type_attribute))
(call allowed_web.packet_send (dns.client_subj_type_attribute))

(call sys.invalid.dontaudit_packet_recv (secmark_constrained_subj_type_attribute))
(call sys.invalid.dontaudit_packet_send (secmark_constrained_subj_type_attribute))

The /etc/sysconfig/nftables.secmark configuration I use for this:

table inet mysecmark {

    secmark allowed_dns {
        "sys.id:sys.role:allowed_dns.packet:s0"
    }

    secmark allowed_git {
        "sys.id:sys.role:allowed_git.packet:s0"
    }

    secmark allowed_web {
        "sys.id:sys.role:allowed_web.packet:s0"
    }

    map secmapping4_out {
        type ipv4_addr . inet_service : secmark
        elements = { 192.168.1.1 . 53 : "allowed_dns", 80.100.19.56 . 9418 : "allowed_git", 80.100.19.56 . 80 : "allowed_web", 80.100.19.56 . 443 : "allowed_web" }
    }

    map secmapping6_out {
        type ipv6_addr . inet_service : secmark
        elements = { fd18:5480:168d::1 . 53 : "allowed_dns", 2001:985:d55d::711 . 9418 : "allowed_git", 2001:985:d55d::711 . 80 : "allowed_web", 2001:985:d55d::711 . 443 : "allowed_web" }
    }

    chain input {
        type filter hook input priority -225;

        # label new incoming packets and add to connection
        ct state new ct secmark set meta secmark

        # set label for est/rel packets from connection
        ct state established,related meta secmark set ct secmark
    }

    chain output {
        type filter hook output priority 225;

        # label new outgoing packets and add to connection
        ct state new meta secmark set ip daddr . tcp dport map @secmapping4_out
        ct state new meta secmark set ip daddr . udp dport map @secmapping4_out
        ct state new meta secmark set ip6 daddr . tcp dport map @secmapping6_out
        ct state new meta secmark set ip6 daddr . udp dport map @secmapping6_out
        ct state new ct secmark set meta secmark

        # set label for est/rel packets from connection
        ct state established,related meta secmark set ct secmark
    }
}

The /etc/systemd/system/nftables.secmark.service I use for this:

# /etc/systemd/system/nftables.secmark.service
[Unit]
Description=Netfilter Tables
Documentation=man:nft(8)
Wants=network-pre.target
Before=network-pre.target

[Service]
Type=oneshot
ProtectSystem=full
ProtectHome=true
ExecStart=/sbin/nft -f /etc/sysconfig/nftables.secmark
ExecReload=/sbin/nft 'flush table inet mysecmark; include "/etc/sysconfig/nftables.secmark";'
ExecStop=/sbin/nft flush table inet mysecmark
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
Categories
DSSP2

Another pointless example of NFT, Secmark and DSSP2-Standard

I was just playing with things to get a little bit more used to the NFT syntax. In the example below I only allow the firefox instances of users in the wheel group to access the local DNS server and the rt.com website. Everything else is allowed.

#!/usr/sbin/nft -f

# nft -f <file>

#(in dns (block client (blockinherit net.packet.obj_template)))
#(block rt (block client (blockinherit net.packet.obj_template)))
#(typeattribute dns_clients_minus_wheel_seamonkey)
#(typeattributeset dns_clients_minus_wheel_seamonkey (and dns.client_subj_type_attribute (not seamonkey.wheel.subj)))
#(call sys.invalid.packet_send (dns_clients_minus_wheel_seamonkey))
#(call sys.invalid.packet_recv (dns_clients_minus_wheel_seamonkey))
#(call dns.client.packet_recv (dns.client_subj_type_attribute))
#(call dns.client.packet_send (dns.client_subj_type_attribute))
#(call rt.client.packet_recv (dns.client_subj_type_attribute))
#(call rt.client.packet_send (dns.client_subj_type_attribute))

# setsebool sys.recv_and_send_invalid_packets off

table inet mysecmark {

    secmark dns_client {
        "sys.id:sys.role:dns.client.packet:s0"
    }
    secmark rt_client {
        "sys.id:sys.role:rt.client.packet:s0"
    }

    map secmapping_4_out {
        type ipv4_addr . inet_service : secmark
        elements = { 192.168.1.1 . 53 : "dns_client", 207.244.80.166 . 80 : "rt_client", 207.244.80.166 . 443 : "rt_client", 92.223.126.251 . 80 : "rt_client", 92.223.126.251 . 443 : "rt_client" }
    }

    map secmapping_6_out {
        type ipv6_addr . inet_service : secmark
        elements = { fd18:5480:168d::1 . 53 : "dns_client", 2001:1af8:4700:b220::112 . 80 : "rt_client", 2001:1af8:4700:b220::112 . 443 : "rt_client", 2a03:90c0:9997::9997 . 80 : "rt_client", 2a03:90c0:9997::9997 . 443 : "rt_client" }
    }

    chain input {
        type filter hook input priority -225;

        # label new incoming packets and add to connection
        ct state new ct secmark set meta secmark

        # set label for est/rel packets from connection
        ct state established,related meta secmark set ct secmark
    }

    chain output {
        type filter hook output priority 225;

        # label new outgoing packets and add to connection
        ct state new meta secmark set ip daddr . tcp dport map @secmapping_4_out
        ct state new meta secmark set ip daddr . udp dport map @secmapping_4_out
        ct state new meta secmark set ip6 daddr . tcp dport map @secmapping_6_out
        ct state new meta secmark set ip6 daddr . udp dport map @secmapping_6_out
        ct state new ct secmark set meta secmark

        # set label for est/rel packets from connection
        ct state established,related meta secmark set ct secmark
    }
}

This stuff is more powerful than systemd IPAddressAllow= and IPaddressDeny= though (If BPF is not disabled due to Kernel Lock-down in the first place), as you can also leverage other attributes like protocol, source and destination port and address.

Demo time:

Categories
DSSP2

Per-process firewalling with DSSP2-standard and NFTables using Secmark filtering

NFTables 0.9.3 was recently released with Secmark filtering support (Thanks!). Secmark with DSSP2-standard allows for per-process network filtering.

DSSP2-standard by default allows processes to send and receive “invalid” packets with the sys.recv_and_send_invalid_packets boolean. This means that processes can send and receive packets that are not associated with a valid label.

This makes it easier to configure your firewall because you will not lose connectivity in enforcing mode while you label your packets and associate your packets with nodes and ports. Access to valid packet labels is ofcourse denied by default. Associate your packet types with allow rules.

Here is a simple example that creates four packet types: two client packet types and two server packet types. One server and client packet type for IRC and one server and client packet type for ICMP. The IRC client and server packet types are associated with port 4567 but in this example they are not associated with any specific nodes (IP addresses).

In the example there are no rules associated with the packet types yet and so access to these packets is blocked by default.

!/usr/sbin/nft -f

# nft -f <file>

# echo "(block icmp (block client (blockinherit net.packet.obj_template)) (block server (blockinherit net.packet.obj_template)))" > icmp_packet.ci>
# echo "(in irc (block client (blockinherit net.packet.obj_template)) (block server (blockinherit net.packet.obj_template)))" > irc_packet.cil && >

table inet mysecmark {

    secmark icmp_client {
        "sys.id:sys.role:icmp.client.packet:s0"
    }

    secmark icmp_server {
        "sys.id:sys.role:icmp.server.packet:s0"
    }

    secmark irc_client {
        "sys.id:sys.role:irc.client.packet:s0"
    }

    secmark irc_server {
        "sys.id:sys.role:irc.server.packet:s0"
    }

    map secmapping_in {
        type inet_service : secmark
        elements = { 4567 : "irc_server" }

    }

    map secmapping_out {
        type inet_service : secmark
        elements = { 4567 : "irc_client" }
    }

    chain input {
        type filter hook input priority -225;

        # label new incoming packets and add to connection
        ct state new meta secmark set tcp dport map @secmapping_in
        ct state new meta secmark set udp dport map @secmapping_in
        ct state new ip protocol icmp meta secmark set "icmp_server"
        ct state new ip6 nexthdr icmpv6 meta secmark set "icmp_server"
        ct state new ct secmark set meta secmark

        # set label for est/rel packets from connection
        ct state established,related meta secmark set ct secmark
    }

    chain output {
        type filter hook output priority 225;

        # label new outgoing packets and add to connection
        ct state new meta secmark set tcp dport map @secmapping_out
        ct state new meta secmark set udp dport map @secmapping_out
        ct state new ip protocol icmp meta secmark set "icmp_client"
        ct state new ip6 nexthdr icmpv6 meta secmark set "icmp_client"
        ct state new ct secmark set meta secmark

        # set label for est/rel packets from connection
        ct state established,related meta secmark set ct secmark
    }
}

You can simply load the above table with sudo nft -f <file>. This should not interfere with existing tables. So you can for example use this alongside Firewalld as that maintains its own “Firewalld” table. Make sure you declare the packet types referenced in the table:

echo "(block icmp (block client (blockinherit net.packet.obj_template)) (block server (blockinherit net.packet.obj_template)))" > icmp_packet.cil && sudo semodule -i icmp_packet.cil

echo "(in irc (block client (blockinherit net.packet.obj_template)) (block server (blockinherit net.packet.obj_template)))" > irc_packet.cil && sudo semodule -i irc_packet.cil

Once you have created packet types for all your network requirements and you have associated these packet types with the appropriate rules, You can disable the sys.recv_and_send_invalid_packets boolean so that all traffic that is not explicitly allowed will be denied.

If you want to undo your Secmark configuration then simply delete the mysecmark table:

nft delete table inet mysecmark

And remove the custom modules:

sudo semodule -r icmp_packet irc_packet