iptables.c: lock the xtables.lock
authorAlexander Couzens <lynxis@fe80.eu>
Fri, 17 May 2019 09:14:46 +0000 (11:14 +0200)
committerJo-Philipp Wich <jo@mein.io>
Thu, 22 Aug 2019 09:29:42 +0000 (11:29 +0200)
When using fw3 together with other applications or scripts a race
conditions might occur. When fw3 is preparing the new tables, another
application can use the executable `iptables` which modifies the
kernel-tables.  libxtables will notify this and fails when fw3 is
committing the changes resulting in a failed firewall.

Now waits in a while loop until the lock is gone, activate the lock
itself and applies changes.

To reproduce the bug the following two scripts should run in parrallel,
after a few seconds the latter stop and leaves a broken firewall:

    while true; do iptables -N locking; done

and

    while [ "$(iptables -w -L OUTPUT | wc -l)" -gt 2 ]; do fw3 reload; done

The following message will appear

        Warning: iptc_commit(): Resource temporarily unavailable

and connectivity is gone.

Tested in an LXC and Qemu container.

Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
[fixed waiting for unlock and commit message]
Signed-off-by: Paul Spooren <mail@aparcar.org>
iptables.c

index a095621dc30873a2cb068d2ace6e59bc0d111e97..559fe7defef3be85c4eb2934884caf549f932bc5 100644 (file)
@@ -55,6 +55,8 @@
 
 #include "iptables.h"
 
+#define XT_LOCK_NAME "/var/run/xtables.lock"
+static int xt_lock_fd = -1;
 
 struct fw3_ipt_rule {
        struct fw3_ipt_handle *h;
@@ -168,6 +170,11 @@ fw3_ipt_open(enum fw3_family family, enum fw3_table table)
 
        xtables_init();
 
+       while (!fw3_lock_path(&xt_lock_fd, XT_LOCK_NAME)) {
+               warn("Currently busy xtables.lock - wait 1 second");
+               sleep(1);
+       }
+
        if (family == FW3_FAMILY_V6)
        {
 #ifndef DISABLE_IPV6
@@ -192,6 +199,7 @@ fw3_ipt_open(enum fw3_family family, enum fw3_table table)
        if (!h->handle)
        {
                free(h);
+               fw3_unlock_path(&xt_lock_fd, XT_LOCK_NAME);
                return NULL;
        }
 
@@ -561,6 +569,7 @@ fw3_ipt_commit(struct fw3_ipt_handle *h)
 void
 fw3_ipt_close(struct fw3_ipt_handle *h)
 {
+       fw3_unlock_path(&xt_lock_fd, XT_LOCK_NAME);
        free(h);
 }