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>
Seemingly Similar 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