From 9838d34ded282d94654fd986ca7c38fe0915d08c Mon Sep 17 00:00:00 2001 From: Zeyad Yasser Date: Thu, 12 Aug 2021 22:07:00 +0200 Subject: [PATCH] criu: use unique table names for nftables based locking During network locking CRIU creates an nftables table to add needed rules. If more than one instance of CRIU run in parallel, those tables' names would conflict. Solution is to append root task pid to the nftables table name as a postfix (e.g. inet CRIU-3231). We also need to use `create table` instead of `add table` because using `create` returns an error in case table name already exists so we could detect conflicts if they happen. Signed-off-by: Zeyad Yasser --- criu/include/netfilter.h | 1 + criu/kerndat.c | 6 ++-- criu/net.c | 31 +++++++++++++++----- criu/netfilter.c | 63 +++++++++++++++++++++++++++++++--------- 4 files changed, 77 insertions(+), 24 deletions(-) diff --git a/criu/include/netfilter.h b/criu/include/netfilter.h index c2ac7a0df6..005573a4f2 100644 --- a/criu/include/netfilter.h +++ b/criu/include/netfilter.h @@ -12,6 +12,7 @@ extern void preload_netfilter_modules(void); extern int nftables_init_connection_lock(void); extern int nftables_lock_connection(struct inet_sk_desc *); +extern int nftables_get_table(char *table, int n); #if defined(CONFIG_HAS_NFTABLES_LIB_API_0) #define NFT_RUN_CMD(nft, cmd) nft_run_cmd_from_buffer(nft, cmd, strlen(cmd)) diff --git a/criu/kerndat.c b/criu/kerndat.c index da3732261d..b2e5650cfe 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -1160,18 +1160,18 @@ static int kerndat_has_nftables_concat(void) if (!nft) return -1; - if (NFT_RUN_CMD(nft, "add table inet CRIU")) { + if (NFT_RUN_CMD(nft, "create table inet CRIU-kerndat-test")) { ret = -1; goto nft_ctx_free_out; } - if (NFT_RUN_CMD(nft, "add set inet CRIU conn { type ipv4_addr . inet_service ;}")) + if (NFT_RUN_CMD(nft, "add set inet CRIU-kerndat-test conn { type ipv4_addr . inet_service ;}")) kdat.has_nftables_concat = false; else kdat.has_nftables_concat = true; /* Clean up */ - NFT_RUN_CMD(nft, "delete table inet CRIU"); + NFT_RUN_CMD(nft, "delete table inet CRIU-kerndat-test"); nft_ctx_free_out: nft_ctx_free(nft); diff --git a/criu/net.c b/criu/net.c index fd4d781bd6..7b45f0633f 100644 --- a/criu/net.c +++ b/criu/net.c @@ -3020,30 +3020,41 @@ static inline int nftables_lock_network_internal(void) #if defined(CONFIG_HAS_NFTABLES_LIB_API_0) || defined(CONFIG_HAS_NFTABLES_LIB_API_1) struct nft_ctx *nft; int ret = 0; + char table[32]; + char buf[128]; + + if (nftables_get_table(table, sizeof(table))) + return -1; nft = nft_ctx_new(NFT_CTX_DEFAULT); if (!nft) return -1; - if (NFT_RUN_CMD(nft, "add table inet CRIU")) + snprintf(buf, sizeof(buf), "create table %s", table); + if (NFT_RUN_CMD(nft, buf)) goto err2; - if (NFT_RUN_CMD(nft, "add chain inet CRIU output { type filter hook output priority 0; policy drop; }")) + snprintf(buf, sizeof(buf), "add chain %s output { type filter hook output priority 0; policy drop; }", table); + if (NFT_RUN_CMD(nft, buf)) goto err1; - if (NFT_RUN_CMD(nft, "add rule inet CRIU output meta mark " __stringify(SOCCR_MARK) " accept")) + snprintf(buf, sizeof(buf), "add rule %s output meta mark " __stringify(SOCCR_MARK) " accept", table); + if (NFT_RUN_CMD(nft, buf)) goto err1; - if (NFT_RUN_CMD(nft, "add chain inet CRIU input { type filter hook input priority 0; policy drop; }")) + snprintf(buf, sizeof(buf), "add chain %s input { type filter hook input priority 0; policy drop; }", table); + if (NFT_RUN_CMD(nft, buf)) goto err1; - if (NFT_RUN_CMD(nft, "add rule inet CRIU input meta mark " __stringify(SOCCR_MARK) " accept")) + snprintf(buf, sizeof(buf), "add rule %s input meta mark " __stringify(SOCCR_MARK) " accept", table); + if (NFT_RUN_CMD(nft, buf)) goto err1; goto out; err1: - NFT_RUN_CMD(nft, "delete table inet CRIU"); + snprintf(buf, sizeof(buf), "delete table %s", table); + NFT_RUN_CMD(nft, buf); err2: ret = -1; pr_err("Locking network failed using nftables\n"); @@ -3104,12 +3115,18 @@ static inline int nftables_network_unlock(void) #if defined(CONFIG_HAS_NFTABLES_LIB_API_0) || defined(CONFIG_HAS_NFTABLES_LIB_API_1) int ret = 0; struct nft_ctx *nft; + char table[32]; + char buf[128]; + + if (nftables_get_table(table, sizeof(table))) + return -1; nft = nft_ctx_new(NFT_CTX_DEFAULT); if (!nft) return -1; - if (NFT_RUN_CMD(nft, "delete table inet CRIU")) + snprintf(buf, sizeof(buf), "delete table %s", table); + if (NFT_RUN_CMD(nft, buf)) ret = -1; nft_ctx_free(nft); diff --git a/criu/netfilter.c b/criu/netfilter.c index 90944b4316..2212fd9f23 100644 --- a/criu/netfilter.c +++ b/criu/netfilter.c @@ -18,10 +18,11 @@ #include "sockets.h" #include "sk-inet.h" #include "kerndat.h" +#include "pstree.h" static char buf[512]; -#define NFTABLES_CONN_CMD "add element inet CRIU conns%c { %s . %d . %s . %d }" +#define NFTABLES_CONN_CMD "add element %s conns%c { %s . %d . %s . %d }" /* * Need to configure simple netfilter rules for blocking connections @@ -157,50 +158,71 @@ int nftables_init_connection_lock(void) #if defined(CONFIG_HAS_NFTABLES_LIB_API_0) || defined(CONFIG_HAS_NFTABLES_LIB_API_1) struct nft_ctx *nft; int ret = 0; + char table[32]; + + if (nftables_get_table(table, sizeof(table))) + return -1; nft = nft_ctx_new(NFT_CTX_DEFAULT); if (!nft) return -1; - if (NFT_RUN_CMD(nft, "add table inet CRIU")) + snprintf(buf, sizeof(buf), "create table %s", table); + if (NFT_RUN_CMD(nft, buf)) goto err2; - if (NFT_RUN_CMD(nft, "add chain inet CRIU output { type filter hook output priority 0; }")) + snprintf(buf, sizeof(buf), "add chain %s output { type filter hook output priority 0; }", table); + if (NFT_RUN_CMD(nft, buf)) goto err1; - if (NFT_RUN_CMD(nft, "add rule inet CRIU output meta mark " __stringify(SOCCR_MARK) " accept")) + snprintf(buf, sizeof(buf), "add rule %s output meta mark " __stringify(SOCCR_MARK) " accept", table); + if (NFT_RUN_CMD(nft, buf)) goto err1; - if (NFT_RUN_CMD(nft, "add chain inet CRIU input { type filter hook input priority 0; }")) + snprintf(buf, sizeof(buf), "add chain %s input { type filter hook input priority 0; }", table); + if (NFT_RUN_CMD(nft, buf)) goto err1; - if (NFT_RUN_CMD(nft, "add rule inet CRIU input meta mark " __stringify(SOCCR_MARK) " accept")) + snprintf(buf, sizeof(buf), "add rule %s input meta mark " __stringify(SOCCR_MARK) " accept", table); + if (NFT_RUN_CMD(nft, buf)) goto err1; /* IPv4 */ - if (NFT_RUN_CMD(nft, "add set inet CRIU conns4 { type ipv4_addr . inet_service . ipv4_addr . inet_service ; }")) + snprintf(buf, sizeof(buf), "add set %s conns4 { type ipv4_addr . inet_service . ipv4_addr . inet_service; }", + table); + if (NFT_RUN_CMD(nft, buf)) goto err1; - if (NFT_RUN_CMD(nft, "add rule inet CRIU output ip saddr . tcp sport . ip daddr . tcp dport @conns4 drop")) + snprintf(buf, sizeof(buf), "add rule %s output ip saddr . tcp sport . ip daddr . tcp dport @conns4 drop", + table); + if (NFT_RUN_CMD(nft, buf)) goto err1; - if (NFT_RUN_CMD(nft, "add rule inet CRIU input ip saddr . tcp sport . ip daddr . tcp dport @conns4 drop")) + snprintf(buf, sizeof(buf), "add rule %s input ip saddr . tcp sport . ip daddr . tcp dport @conns4 drop", table); + if (NFT_RUN_CMD(nft, buf)) goto err1; /* IPv6 */ - if (NFT_RUN_CMD(nft, "add set inet CRIU conns6 { type ipv6_addr . inet_service . ipv6_addr . inet_service ; }")) + snprintf(buf, sizeof(buf), "add set %s conns6 { type ipv6_addr . inet_service . ipv6_addr . inet_service; }", + table); + if (NFT_RUN_CMD(nft, buf)) goto err1; - if (NFT_RUN_CMD(nft, "add rule inet CRIU output ip6 saddr . tcp sport . ip6 daddr . tcp dport @conns6 drop")) + snprintf(buf, sizeof(buf), "add rule %s output ip6 saddr . tcp sport . ip6 daddr . tcp dport @conns6 drop", + table); + if (NFT_RUN_CMD(nft, buf)) goto err1; - if (NFT_RUN_CMD(nft, "add rule inet CRIU input ip6 saddr . tcp sport . ip6 daddr . tcp dport @conns6 drop")) + snprintf(buf, sizeof(buf), "add rule %s input ip6 saddr . tcp sport . ip6 daddr . tcp dport @conns6 drop", + table); + if (NFT_RUN_CMD(nft, buf)) goto err1; goto out; err1: - NFT_RUN_CMD(nft, "delete table inet CRIU"); + snprintf(buf, sizeof(buf), "delete table %s", table); + NFT_RUN_CMD(nft, buf); pr_err("Locking network failed using nftables\n"); err2: ret = -1; @@ -219,6 +241,10 @@ static int nftables_lock_connection_raw(int family, u32 *src_addr, u16 src_port, struct nft_ctx *nft; int ret = 0; char sip[INET_ADDR_LEN], dip[INET_ADDR_LEN]; + char table[32]; + + if (nftables_get_table(table, sizeof(table))) + return -1; if (family == AF_INET6 && ipv6_addr_mapped(dst_addr)) { family = AF_INET; @@ -240,7 +266,7 @@ static int nftables_lock_connection_raw(int family, u32 *src_addr, u16 src_port, if (!nft) return -1; - snprintf(buf, sizeof(buf), NFTABLES_CONN_CMD, family == AF_INET ? '4' : '6', dip, (int)dst_port, sip, + snprintf(buf, sizeof(buf), NFTABLES_CONN_CMD, table, family == AF_INET ? '4' : '6', dip, (int)dst_port, sip, (int)src_port); pr_debug("\tRunning nftables [%s]\n", buf); @@ -270,3 +296,12 @@ int nftables_lock_connection(struct inet_sk_desc *sk) return ret; } + +int nftables_get_table(char *table, int n) +{ + if (snprintf(table, n, "inet CRIU-%d", root_item->pid->real) < 0) { + pr_err("Cannot generate CRIU's nftables table name\n"); + return -1; + } + return 0; +}