bugzilla-daemon at netfilter.org
2024-Jul-13  12:21 UTC
[Bug 1758] New: Design flaw in chain traversal
https://bugzilla.netfilter.org/show_bug.cgi?id=1758
            Bug ID: 1758
           Summary: Design flaw in chain traversal
           Product: nftables
           Version: unspecified
          Hardware: x86_64
                OS: Ubuntu
            Status: NEW
          Severity: major
          Priority: P5
         Component: kernel
          Assignee: pablo at netfilter.org
          Reporter: hadmut at danisch.de
Hi, 
when trying to migrate my old iptables/ufw rules to nftables I ran into a
subtile change in semantics which I do consider as a major design flaw. Let me
cite your documentation
https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains which says
NOTE: If a packet is accepted and there is another chain, bearing the same hook
type and with a later priority, then the packet will subsequently traverse this
other chain. Hence, an accept verdict ? be it by way of a rule or the default
chain policy ? isn?t necessarily final. However, the same is not true of
packets that are subjected to a drop verdict. Instead, drops take immediate
effect, with no further rules or chains being evaluated. 
which is a design flaw. 
Formerly, with iptables, there was one INPUT, OUTPUT, FORWARD chain, and
different tasks for different applications were implemented with subchains,
that were jumped into one after the other. All three final decisions accept,
reject, and drop were final and terminated processing, i.e. were reliable. 
But since nftables invented the hooks where chains are registered in order to
keeps different things apart, the logic is broken. 
Let me explain this. 
I followed common examples to write a simple firewall ruleset to protect a
machine to get into the nftables style (and not just copying my old rules), and
(a shortened excerpt just do demonstrate the problem) was something like
table inet firewall {
      set allowed_interfaces {
          type ifname
          elements = { "lo" }
      }
      set allowed_protocols {
          type inet_proto
          elements = { icmp, icmpv6 }
      }
      set allowed_tcp_dports {
          type inet_service
          elements = { ssh }
      }
      chain allow {
            ct state     established,related accept
            meta l4proto @allowed_protocols  accept
            iifname      @allowed_interfaces accept
            tcp dport    @allowed_tcp_dports accept
      }
      chain input {
            type filter hook input priority filter + 10;
            policy accept
            jump allow
            reject with icmpx type port-unreachable
      }
}
which, at a first glance, worked like expected. But then I noticed that the
virtual guest machine in LXD virtualization cannot resolve DNS queries anymore. 
The reason: LXD itself installs a ruleset like (again, just an excerpt to show
the problem)
table inet lxd {
     chain in.lxdbr0 {
                type filter hook input priority filter; policy accept;
                iifname "lxdbr0" tcp dport 53 accept
                iifname "lxdbr0" udp dport 53 accept
                iifname "lxdbr0" icmp type { destination-unreachable,
time-exceeded, parameter-problem } accept
                iifname "lxdbr0" udp dport 67 accept
                iifname "lxdbr0" icmpv6 type {
destination-unreachable,
packet-too-big, time-exceeded, parameter-problem, nd-router-solicit,
nd-neighbor-solicit, nd-neighbor-advert, mld2-listener-report } accept
                iifname "lxdbr0" udp dport 547 accept
        }
}
which becomes effectively useless and effectless, once my firewall ruleset is
loaded, since the accepted packages are then sent through my firewall ruleset
and thus rejected by the reject command. There is no way for me to cleanly
respect LXD tables, I would have to repeat all statements in my ruleset, and
thus continuously monitor LXD rulesets to copy its rules into mine. 
Rules like 
                iifname "lxdbr0" udp dport 53 accept
are completely useless here, since the have the very same effect as if they
just would not exist: The packet is accepted within the chain, and then sent
through the next chain (i.e. my firewall ruleset). 
As a consequence, any accept statement becomes completely useless and has no
effect in a ruleset (i.e. chains in a table) without a reject/drop, since an
accept only can override a reject/drop in (oder under) the very same chain, but
not against other chains. 
As a result, I do not see a clean way to both have my machine protected and
have LXD running correctly while keeping the rules apart. Under iptables, this
was working. 
My impression is, that this construction was made with constructive rules in
midn only, i.e. allow each program to manage its own tables for NAT, mangling,
tunneling, and things like that, but not with security and the final
"reject
anything that has not been permitted yet" rule. 
That's a major design flaw. 
A clean solution (which is common in other applications with cascaded black-,
and whitelists) would be to have a fourth terminal action besides accept,
reject, drop, i.e. "proceed", probably as a packet destination and as
a chain
policy, and as a default value of the policy. "proceed" would mean
"go on with
the next chain/table", while accept, reject, drop have to be final and
strictly
terminal. That's a common practice.
Therefore, the current practice to send an already accepted packet to the next
chain the same way as if it hadn't been accepted is design flaw and sets the
security on risk, since people who do not deeply understand the problem and are
not willing/able to copy all rulesets into the last one feel urged to omit
security reject rules in order to keep things up and running.
-- 
You are receiving this mail because:
You are watching all bug changes.
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://lists.netfilter.org/pipermail/netfilter-buglog/attachments/20240713/d93a5d31/attachment.html>
bugzilla-daemon at netfilter.org
2024-Jul-15  09:42 UTC
[Bug 1758] Design flaw in chain traversal
https://bugzilla.netfilter.org/show_bug.cgi?id=1758
Phil Sutter <phil at nwl.cc> changed:
           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
                 CC|                            |phil at nwl.cc
         Resolution|---                         |WONTFIX
--- Comment #1 from Phil Sutter <phil at nwl.cc> ---
Hi,
Please note that iptables works exactly the same way, you just don't have
the
flexibility to add arbitrary base chains.
Take security table for instance: A drop rule in its INPUT chain can't be
overridden from filter table, no matter what. Vice-versa: An accept rule in
security table's INPUT chain will not see any packet if filter table's
INPUT
chain dropped them already.
All this is hard to change: Nobody would expect a packet to no longer appear in
filter's INPUT chain after mangle's PREROUTING chain had an ACCEPT
verdict for
it.
You're free to design the basic ruleset layout of base and non-base chains
in
nftables. But you also have to define (and enforce) the rules of how different
actors add their ruleset snippets to it. A simpler way may be to use a
coordinating daemon such as firewalld.
The "major design flaw" is expecting nftables to implement
coordination between
concurrent users because its design supports them in the first place. We've
discussed this misunderstanding pretty extensively at netfilter workshops in
the past and haven't even found a feasible way to please users falling for
this, let alone compatibility to existing rulesets.
The substantial problem with the suggested "proceed" verdict is that
one has to
change the "accept" one which is not compatible. The alternative of
implementing a "really accept" is flawed in that it will only lead to
requests
for support of overriding it and thus back to square one.
We may continue discussing why things are the way they are, but please don't
expect this to change.
Cheers, Phil
-- 
You are receiving this mail because:
You are watching all bug changes.
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://lists.netfilter.org/pipermail/netfilter-buglog/attachments/20240715/c0529b50/attachment.html>
bugzilla-daemon at netfilter.org
2024-Jul-15  12:14 UTC
[Bug 1758] Design flaw in chain traversal
https://bugzilla.netfilter.org/show_bug.cgi?id=1758
marius at nuenneri.ch changed:
           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |marius at nuenneri.ch
--- Comment #2 from marius at nuenneri.ch ---
I also found this behaviour quite confusing.
Before I discovered this, I assumed there are two types of packet filters:
1. Exectute the statement on the first matching rule (like FreeBSD's ipfw)
2. Execute the statement on the last matching rule (like OpenBSD's pf).
Now I see that there is a third way
3. Execute a drop on the first matching rule, but an accept on the last
matching rule. 
OpenBSD's pf actually solves this by having a `quick` keyword, which makes a
rule terminate the rule evaluation and execute the statement.[1]
IMHO this makes a lot of sense for type 2 and 3 packet filters.
This matches the "really accept" that Phil is talking about, but I
don't
think people have requests to override it, and this has been the case in
OpenBSD for at least two decades.
I conclude that it would make sense to add the quick keyword to nftables.
[1] https://www.openbsd.org/faq/pf/filter.html
-- 
You are receiving this mail because:
You are watching all bug changes.
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://lists.netfilter.org/pipermail/netfilter-buglog/attachments/20240715/f4ee0cf2/attachment.html>
Maybe Matching Threads
- [Bug 1360] New: BUG: invalid expression type concat on invalid input "iifname . oifname p . q"
- [Bug 1195] New: 'list ruleset' of 'nft -f' outputs garbage while 'nft list ruleset' seems to work.
- [Bug 1413] New: Inconsistent EBUSY errors when adding a duplicate element to a map
- [Bug 1358] New: Error when atomically replacing rules with symbolic variables
- [Bug 1302] New: iptables v1.8.0 (nf_tables) has a problem inverting in-interface and maybe out