Skip to content

Commit

Permalink
criu: use unique table names for nftables based locking
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
ZeyadYasser authored and avagin committed Sep 3, 2021
1 parent ca3e3c5 commit 9838d34
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 24 deletions.
1 change: 1 addition & 0 deletions criu/include/netfilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
6 changes: 3 additions & 3 deletions criu/kerndat.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
31 changes: 24 additions & 7 deletions criu/net.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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);
Expand Down
63 changes: 49 additions & 14 deletions criu/netfilter.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}

0 comments on commit 9838d34

Please sign in to comment.