File iptables-batch-lock.patch of Package iptables.5107

Index: iptables-1.4.21/iptables/iptables-batch.c
===================================================================
--- iptables-1.4.21.orig/iptables/iptables-batch.c
+++ iptables-1.4.21/iptables/iptables-batch.c
@@ -352,6 +352,9 @@ main(int argc, char *argv[])
 	int nargc = 0;
 	char* nargv[256];
 	FILE* fp = stdin;
+	const struct timeval wait_interval = {
+		.tv_sec = 1,
+	};
 
 #ifdef IP6T
 	prog_name = "ip6tables-batch";
@@ -404,6 +407,30 @@ main(int argc, char *argv[])
 	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's no unlock() equivalent. The lock file descriptor is smiply
+	 * left open until the process exits. Thus we'd 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(-1, &wait_interval) != true )
+	{
+		fprintf(stderr, "failed to acquire the xtables lock\n");
+		exit(1);
+	}
+
 	while((r = getline(&iline, &llen, fp)) != -1)
 	{
 		if(llen < 1 || !*iline)
Index: iptables-1.4.21/iptables/xshared.c
===================================================================
--- iptables-1.4.21.orig/iptables/xshared.c
+++ iptables-1.4.21/iptables/xshared.c
@@ -246,8 +246,14 @@ void xs_init_match(struct xtables_match
 bool xtables_lock(bool wait)
 {
 	int i = 0, ret, xt_socket;
+	static bool already_locked = false;
 	struct sockaddr_un xt_addr;
 
+	if( already_locked ) {
+		// avoid dead-locks, see iptables-batch.c
+		return true;
+	}
+
 	memset(&xt_addr, 0, sizeof(xt_addr));
 	xt_addr.sun_family = AF_UNIX;
 	strcpy(xt_addr.sun_path+1, XT_SOCKET_NAME);
@@ -259,8 +265,10 @@ bool xtables_lock(bool wait)
 	while (1) {
 		ret = bind(xt_socket, (struct sockaddr*)&xt_addr,
 			   offsetof(struct sockaddr_un, sun_path)+XT_SOCKET_LEN);
-		if (ret == 0)
+		if (ret == 0) {
+			already_locked = true;
 			return true;
+		}
 		else if (wait == false)
 			return false;
 		if (++i % 2 == 0)
openSUSE Build Service is sponsored by