Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
Bug 945762 - net-firewall/iptables - init script's reload()'s explicit -F, -X break atomicity
Summary: net-firewall/iptables - init script's reload()'s explicit -F, -X break atomicity
Status: RESOLVED FIXED
Alias: None
Product: Gentoo Linux
Classification: Unclassified
Component: Current packages (show other bugs)
Hardware: All Linux
: Normal normal
Assignee: Gentoo's Team for Core System packages
URL:
Whiteboard:
Keywords: PullRequest
Depends on:
Blocks:
 
Reported: 2024-12-02 19:32 UTC by Hank Leininger
Modified: 2024-12-08 07:16 UTC (History)
1 user (show)

See Also:
Package list:
Runtime testing required: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Hank Leininger 2024-12-02 19:32:10 UTC
iptables-restore <iptables_save has a nice atomic property, it'll parse the rules and swap them in all at once (...per-table and COMMIT command, at least).

However, Gentoo's /etc/init.d/iptables script, since it was first added in 2004, has this behavior in its reload():

reload() {
...
        for a in $(cat ${iptables_proc}) ; do
                ${iptables_bin} --wait ${iptables_lock_wait_time} -F -t $a
...
                ${iptables_bin} --wait ${iptables_lock_wait_time} -X -t $a
...
        start

start() in turn uses iptables-restore to import the cooked save file, as created by save() or generated externally.

As a result, there is a race during which tables have been flushed and deleted, before they have been repopulated by "start".

If the default policy is ACCEPT, then that creates a tiny window when shields are down.

If the default policy is DROP, then this will drop all traffic during the brief window.

As I read its manpage, iptables-restore will take care of flushing any table it is replacing, so manually/explicitly doing so ahead of time should be overkill. 

..._except_ if there is a table not referenced in the policy-to-load: suppose it only contains a *filter section for some reason; skipping -F/-X would mean that an existing *raw or *nat for example, are left behind.

So, I think we could do something more like:

  for a in $(cat ${iptables_proc}) ; do
    grep -q "^\*${a}$" "${iptables_save}" || ${iptables_bin} --wait ${iptables_lock_wait_time} -F -t $a
    ...

As in: we only nuke tables that are not about to be reloaded.

Maybe we could test out an atomic_reload() function first if people want to be able to get this exercised w/o changing the default behavior.
Comment 1 Hank Leininger 2024-12-03 00:25:43 UTC
See PR for an implementation that only -F/-X's tables that are not listed in the save file, if any. (iptables-save produces empty sections for the main tables even when they have no rules, but we could anticipate some tool cooking up a save file and omitting unused tables.)

Note that our systemd files for iptables-restore and ip6tables-restore make no attempt at -F/-X, they simply call *-restore and call it a day.
Comment 2 Larry the Git Cow gentoo-dev 2024-12-08 07:16:45 UTC
The bug has been closed via the following commit(s):

https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=2198b9a1fd9d0d66b4e0e37915dfcd5c052a1160

commit 2198b9a1fd9d0d66b4e0e37915dfcd5c052a1160
Author:     Hank Leininger <hlein@korelogic.com>
AuthorDate: 2024-12-03 00:13:17 +0000
Commit:     Sam James <sam@gentoo.org>
CommitDate: 2024-12-08 07:15:43 +0000

    net-firewall/iptables: fix race condition in init script
    
    When doing a reload, we only need to flush+delete any table that is
    _not_ included in what we are about to feed iptables-restore, which
    does its own flush.
    
    Signed-off-by: Hank Leininger <hlein@korelogic.com>
    Closes: https://bugs.gentoo.org/945762
    Closes: https://github.com/gentoo/gentoo/pull/39573
    Signed-off-by: Sam James <sam@gentoo.org>

 net-firewall/iptables/files/iptables-r4.init    | 167 ++++++++++++++++++++++
 net-firewall/iptables/iptables-1.8.11-r1.ebuild | 176 ++++++++++++++++++++++++
 2 files changed, 343 insertions(+)