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.8/iptables/iptables-batch.c
===================================================================
--- iptables-1.8.8.orig/iptables/iptables-batch.c
+++ iptables-1.8.8/iptables/iptables-batch.c
@@ -403,6 +403,27 @@ 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()
+	 */
+	const struct timeval wait_interval = {.tv_sec = 1};
+	if (!xtables_lock_or_exit(-1, &wait_interval)) {
+		fprintf(stderr, "failed to acquire the xtables lock\n");
+		exit(1);
+	}
 
 	while((r = getline(&iline, &llen, fp)) != -1)
 	{
Index: iptables-1.8.8/iptables/xshared.c
===================================================================
--- iptables-1.8.8.orig/iptables/xshared.c
+++ iptables-1.8.8/iptables/xshared.c
@@ -262,10 +262,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;
@@ -285,8 +289,10 @@ static int xtables_lock(int wait)
 		alarm(wait);
 	}
 
-	if (flock(fd, LOCK_EX) == 0)
+	if (flock(fd, LOCK_EX) == 0) {
+		already_locked = true;
 		return fd;
+	}
 
 	if (errno == EINTR) {
 		errno = EWOULDBLOCK;
openSUSE Build Service is sponsored by