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