iptables: add file lock to prevent concurrent overwrite

the kernel can only prevent the concurrency of s/getsockopt, but
iptables will call these interfaces multiple times at a time. We
need to wait for one iptables to complete before executing the second
one, otherwise the data will be overwritten.

iptables flow:
get current iptables entries [1] -> add new entry 2 [1,2] -> set to kernel [1,2]
get current iptables entries [1] -> add new entry 3 [1,3] -> set to kernel [1,3]
entry 2 is lost

Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
This commit is contained in:
zhanghongyu 2025-08-20 20:05:59 +08:00 committed by Xiang Xiao
parent 859fc54c96
commit 2b0a4a20f5
2 changed files with 62 additions and 1 deletions

View file

@ -29,4 +29,9 @@ config SYSTEM_IPTABLES_STACKSIZE
int "iptables & ip6tables stack size"
default DEFAULT_TASK_STACKSIZE
config SYSTEM_IPTABLES_LOCK_FILE_PATH
string "File lock path to prevent concurrent overwrite"
default "/tmp/iptables.lock"
depends on FS_LOCK_BUCKET_SIZE > 0
endif

View file

@ -26,6 +26,7 @@
#include <nuttx/config.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <nuttx/net/netfilter/ip_tables.h>
@ -33,17 +34,62 @@
#include "iptables.h"
#include "netutils/netlib.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#if CONFIG_FS_LOCK_BUCKET_SIZE == 0
# define iptables_lock() 0
# define iptables_unlock(fd) (void)(fd)
#endif
/****************************************************************************
* Private Types
****************************************************************************/
typedef CODE int
(*iptables_command_func_t)(FAR const struct iptables_args_s *args);
(*iptables_command_func_t)(FAR const struct iptables_args_s *args);
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: iptables_lock / iptables_unlock
*
* Description:
* Lock and unlock iptables to prevent concurrent overwrite.
*
****************************************************************************/
#if CONFIG_FS_LOCK_BUCKET_SIZE > 0
static int iptables_lock(void)
{
struct flock lock;
int lockfd;
lockfd = open(CONFIG_SYSTEM_IPTABLES_LOCK_FILE_PATH, O_CREAT | O_RDWR,
0666);
if (lockfd < 0)
{
return lockfd;
}
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
fcntl(lockfd, F_SETLKW, &lock);
return lockfd;
}
static int iptables_unlock(int lockfd)
{
return close(lockfd);
}
#endif
/****************************************************************************
* Name: iptables_addr2str
*
@ -485,6 +531,7 @@ static int iptables_apply(FAR const struct iptables_args_s *args,
int main(int argc, FAR char *argv[])
{
struct iptables_args_s args;
int lock;
int ret = iptables_parse(&args, argc, argv);
if (ret < 0 || args.cmd == COMMAND_INVALID)
@ -493,6 +540,13 @@ int main(int argc, FAR char *argv[])
return ret;
}
lock = iptables_lock();
if (lock < 0)
{
printf("Failed to lock iptables!\n");
return lock;
}
#ifdef CONFIG_NET_IPFILTER
if (args.table == NULL || strcmp(args.table, XT_TABLE_NAME_FILTER) == 0)
{
@ -520,5 +574,7 @@ int main(int argc, FAR char *argv[])
printf("Unknown table: %s\n", args.table);
}
iptables_unlock(lock);
return ret;
}