File iptables-batch-lock.patch of Package iptables

From: Matthias Gerstner <matthias.gerstner@suse.com>
Date: 2017-06-26T10:53:24+0000

- fix a locking issue of iptables-batch which can cause it to spuriously fail
  when other programs modify the iptables rules in parallel (bnc#1045130).
  This can especially affect SuSEfirewall2 during startup.

---
 iptables/iptables-batch.c |   21 +++++++++++++++++++++
 iptables/xshared.c        |    8 +++++++-
 2 files changed, 28 insertions(+), 1 deletion(-)

Index: iptables-1.8.11/iptables/iptables-batch.c
===================================================================
--- iptables-1.8.11.orig/iptables/iptables-batch.c
+++ iptables-1.8.11/iptables/iptables-batch.c
@@ -44,6 +44,7 @@
 #include <iptables.h>
 #endif
 #include <xtables.h>
+#include "xshared.h"
 
 #ifdef IP6T
 #define prog_name ip6tables_globals.program_name
@@ -403,6 +404,26 @@ main(int argc, char *argv[])
 	tables[3].name = "raw";
 	tables[3].handle = NULL;
 	current_table = &tables[0];
+	/*
+	 * We need to lock the complete batch processing against parallel
+	 * modification by other processes. Otherwise, we can end up with
+	 * EAGAIN errors.
+	 *
+	 * The do_command{4,6} function already locks itself, but the complete
+	 * call sequence needs to be locked until the commit is performed.
+	 *
+	 * Sadly, the xtables_lock() implementation is not very cooperative.
+	 * There is no unlock() equivalent. The lock file descriptor is simply
+	 * left open until the process exits. Thus, we would have deadlocks
+	 * when calling do_command{4,6} the second time.
+	 *
+	 * To prevent this, part of this patch adds logic to avoid taking the
+	 * lock a second time in the same process in xtables_lock()
+	 */
+	if (!xtables_lock_or_exit(-1)) {
+		fprintf(stderr, "failed to acquire the xtables lock\n");
+		exit(1);
+	}
 
 	while((r = getline(&iline, &llen, fp)) != -1)
 	{
Index: iptables-1.8.11/iptables/xshared.c
===================================================================
--- iptables-1.8.11.orig/iptables/xshared.c
+++ iptables-1.8.11/iptables/xshared.c
@@ -255,10 +255,14 @@ static void alarm_ignore(int i) {
 
 static int xtables_lock(int wait)
 {
+	static bool already_locked = false;
 	struct sigaction sigact_alarm;
 	const char *lock_file;
 	int fd;
 
+	if (already_locked)
+		/* Avoid deadlocks, see iptables-batch.c */
+		return true;
 	lock_file = getenv("XTABLES_LOCKFILE");
 	if (lock_file == NULL || lock_file[0] == '\0')
 		lock_file = XT_LOCK_NAME;
@@ -278,8 +282,10 @@ static int xtables_lock(int wait)
 		alarm(wait);
 	}
 
-	if (flock(fd, LOCK_EX | (wait ? 0 : LOCK_NB)) == 0)
+	if (flock(fd, LOCK_EX | (wait ? 0 : LOCK_NB)) == 0) {
+		already_locked = true;
 		return fd;
+	}
 
 	if (errno == EINTR) {
 		errno = EWOULDBLOCK;
openSUSE Build Service is sponsored by