f89950
From 03df255180677b86eb058866be668063fcc6f598 Mon Sep 17 00:00:00 2001
f89950
From: Phil Sutter <phil@nwl.cc>
f89950
Date: Fri, 6 Oct 2017 12:48:50 +0200
f89950
Subject: [PATCH] Use flock() for --concurrent option
f89950
f89950
The previous locking mechanism was not atomic, hence it was possible
f89950
that a killed ebtables process would leave the lock file in place which
f89950
in turn made future ebtables processes wait indefinitely for the lock to
f89950
become free.
f89950
f89950
Fix this by using flock(). This also simplifies code quite a bit because
f89950
there is no need for a custom signal handler or an __exit routine
f89950
anymore.
f89950
f89950
Signed-off-by: Phil Sutter <phil@nwl.cc>
f89950
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
f89950
Signed-off-by: Phil Sutter <psutter@redhat.com>
f89950
---
f89950
 ebtables.c |  8 --------
f89950
 libebtc.c  | 49 +++++--------------------------------------------
f89950
 2 files changed, 5 insertions(+), 52 deletions(-)
f89950
f89950
diff --git a/ebtables.c b/ebtables.c
f89950
index 62f1ba80063d8..f7dfccf4b2f31 100644
f89950
--- a/ebtables.c
f89950
+++ b/ebtables.c
f89950
@@ -528,12 +528,6 @@ void ebt_early_init_once()
f89950
 	ebt_iterate_targets(merge_target);
f89950
 }
f89950
 
f89950
-/* signal handler, installed when the option --concurrent is specified. */
f89950
-static void sighandler(int signum)
f89950
-{
f89950
-	exit(-1);
f89950
-}
f89950
-
f89950
 /* We use exec_style instead of #ifdef's because ebtables.so is a shared object. */
f89950
 int do_command(int argc, char *argv[], int exec_style,
f89950
                struct ebt_u_replace *replace_)
f89950
@@ -1047,8 +1041,6 @@ big_iface_length:
f89950
 			strcpy(replace->filename, optarg);
f89950
 			break;
f89950
 		case 13 : /* concurrent */
f89950
-			signal(SIGINT, sighandler);
f89950
-			signal(SIGTERM, sighandler);
f89950
 			use_lockfd = 1;
f89950
 			break;
f89950
 		case 1 :
f89950
diff --git a/libebtc.c b/libebtc.c
f89950
index b0814213b6b06..ab3429577a1f1 100644
f89950
--- a/libebtc.c
f89950
+++ b/libebtc.c
f89950
@@ -31,6 +31,7 @@
f89950
 #include "include/ethernetdb.h"
f89950
 #include <unistd.h>
f89950
 #include <fcntl.h>
f89950
+#include <sys/file.h>
f89950
 #include <sys/wait.h>
f89950
 #include <sys/stat.h>
f89950
 #include <sys/types.h>
f89950
@@ -137,58 +138,18 @@ void ebt_list_extensions()
f89950
 #define LOCKDIR "/run"
f89950
 #define LOCKFILE LOCKDIR"/ebtables.lock"
f89950
 #endif
f89950
-static int lockfd = -1, locked;
f89950
 int use_lockfd;
f89950
 /* Returns 0 on success, -1 when the file is locked by another process
f89950
  * or -2 on any other error. */
f89950
 static int lock_file()
f89950
 {
f89950
-	int try = 0;
f89950
-	int ret = 0;
f89950
-	sigset_t sigset;
f89950
-
f89950
-tryagain:
f89950
-	/* the SIGINT handler will call unlock_file. To make sure the state
f89950
-	 * of the variable locked is correct, we need to temporarily mask the
f89950
-	 * SIGINT interrupt. */
f89950
-	sigemptyset(&sigset);
f89950
-	sigaddset(&sigset, SIGINT);
f89950
-	sigprocmask(SIG_BLOCK, &sigset, NULL);
f89950
-	lockfd = open(LOCKFILE, O_CREAT | O_EXCL | O_WRONLY, 00600);
f89950
-	if (lockfd < 0) {
f89950
-		if (errno == EEXIST)
f89950
-			ret = -1;
f89950
-		else if (try == 1)
f89950
-			ret = -2;
f89950
-		else {
f89950
-			if (mkdir(LOCKDIR, 00700))
f89950
-				ret = -2;
f89950
-			else {
f89950
-				try = 1;
f89950
-				goto tryagain;
f89950
-			}
f89950
-		}
f89950
-	} else {
f89950
-		close(lockfd);
f89950
-		locked = 1;
f89950
-	}
f89950
-	sigprocmask(SIG_UNBLOCK, &sigset, NULL);
f89950
-	return ret;
f89950
-}
f89950
+	int fd = open(LOCKFILE, O_CREAT, 00600);
f89950
 
f89950
-void unlock_file()
f89950
-{
f89950
-	if (locked) {
f89950
-		remove(LOCKFILE);
f89950
-		locked = 0;
f89950
-	}
f89950
+	if (fd < 0)
f89950
+		return -2;
f89950
+	return flock(fd, LOCK_EX);
f89950
 }
f89950
 
f89950
-void __attribute__ ((destructor)) onexit()
f89950
-{
f89950
-	if (use_lockfd)
f89950
-		unlock_file();
f89950
-}
f89950
 /* Get the table from the kernel or from a binary file
f89950
  * init: 1 = ask the kernel for the initial contents of a table, i.e. the
f89950
  *           way it looks when the table is insmod'ed
f89950
-- 
f89950
2.13.1
f89950