From 0305093a6621a40775cc4b4e38d62587dcd8c49d Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 17 Dec 2024 13:00:50 +0100 Subject: [PATCH] net: remember the name of the lock chain (nftables) Using libnftables the chain to lock the network is composed of ("CRIU-%d", real_pid). This leads to around 40 zdtm tests failing with errors like this: Error: No such file or directory; did you mean table 'CRIU-62' in family inet? delete table inet CRIU-86 The reason is that as soon as a process is running in a namespace the real PID can be anything and only the PID in the namespace is restored correctly. Relying on the real PID does not work for the chain name. Using the PID of the innermost namespace would lead to the chain be called 'CRIU-1' most of the time which is also not really unique. The uniqueness of the name was always problematic. With this change all tests are working again which rely on network locking if the nftables backend is used for network locking. Signed-off-by: Adrian Reber --- criu/cr-dump.c | 2 +- criu/cr-restore.c | 2 +- criu/image.c | 4 ++++ criu/include/net.h | 5 +++-- criu/net.c | 48 ++++++++++++++++++++++++++++++++++++------ images/inventory.proto | 1 + 6 files changed, 51 insertions(+), 11 deletions(-) diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 1bc5d934f5..31a8703de7 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -2195,7 +2195,7 @@ int cr_dump_tasks(pid_t pid) if (collect_pstree_ids()) goto err; - if (network_lock()) + if (network_lock(&he)) goto err; if (rpc_query_external_files()) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 646300bdb8..9437b2ebcd 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -2113,7 +2113,7 @@ static int restore_root_task(struct pstree_item *init) * the '--empty-ns net' mode no iptables C/R is done and we * need to return these rules by hands. */ - ret = network_lock_internal(); + ret = network_lock_internal(NULL); if (ret) goto out_kill; } diff --git a/criu/image.c b/criu/image.c index 9589167fb1..4b74eef130 100644 --- a/criu/image.c +++ b/criu/image.c @@ -25,6 +25,7 @@ bool img_common_magic = true; TaskKobjIdsEntry *root_ids; u32 root_cg_set; Lsmtype image_lsm; +char nft_lock_table[32]; struct inventory_plugin { struct list_head node; @@ -120,6 +121,9 @@ int check_img_inventory(bool restore) goto out_err; } } + + if (he->nft_lock_table) + strncpy(nft_lock_table, he->nft_lock_table, sizeof(nft_lock_table) - 1); } ret = 0; diff --git a/criu/include/net.h b/criu/include/net.h index 5e8a848620..0b0afb0b38 100644 --- a/criu/include/net.h +++ b/criu/include/net.h @@ -29,9 +29,10 @@ struct veth_pair { extern int collect_net_namespaces(bool for_dump); -extern int network_lock(void); +#include "images/inventory.pb-c.h" +extern int network_lock(InventoryEntry *he); extern void network_unlock(void); -extern int network_lock_internal(void); +extern int network_lock_internal(InventoryEntry *he); extern struct ns_desc net_ns_desc; diff --git a/criu/net.c b/criu/net.c index eee3311087..8b34bd6ded 100644 --- a/criu/net.c +++ b/criu/net.c @@ -229,6 +229,8 @@ static const char *unix_conf_entries[] = { "max_dgram_qlen", }; +extern char nft_lock_table[32]; + /* * MAX_CONF_UNIX_PATH = (sizeof(CONF_UNIX_FMT) - strlen("%s")) * + MAX_CONF_UNIX_OPT_PATH @@ -3066,21 +3068,34 @@ static int iptables_restore(bool ipv6, char *buf, int size) return ret; } -static inline int nftables_lock_network_internal(void) +static inline int nftables_lock_network_internal(InventoryEntry *he) { #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]; + FILE *fp; if (nftables_get_table(table, sizeof(table))) return -1; + if (he) { + he->nft_lock_table = strdup(table); + } + nft = nft_ctx_new(NFT_CTX_DEFAULT); if (!nft) return -1; + fp = fdopen(log_get_fd(), "w"); + if (!fp) { + pr_perror("fdopen() failed"); + goto err3; + } + nft_ctx_set_output(nft, fp); + nft_ctx_set_error(nft, fp); + snprintf(buf, sizeof(buf), "create table %s", table); if (NFT_RUN_CMD(nft, buf)) goto err2; @@ -3107,6 +3122,9 @@ static inline int nftables_lock_network_internal(void) snprintf(buf, sizeof(buf), "delete table %s", table); NFT_RUN_CMD(nft, buf); err2: + fflush(fp); + fclose(fp); +err3: ret = -1; pr_err("Locking network failed using nftables\n"); out: @@ -3143,7 +3161,7 @@ static int iptables_network_lock_internal(void) return ret; } -int network_lock_internal(void) +int network_lock_internal(InventoryEntry *he) { int ret = 0, nsret; @@ -3156,7 +3174,7 @@ int network_lock_internal(void) if (opts.network_lock_method == NETWORK_LOCK_IPTABLES) ret = iptables_network_lock_internal(); else if (opts.network_lock_method == NETWORK_LOCK_NFTABLES) - ret = nftables_lock_network_internal(); + ret = nftables_lock_network_internal(he); if (restore_ns(nsret, &net_ns_desc)) ret = -1; @@ -3171,18 +3189,34 @@ static inline int nftables_network_unlock(void) struct nft_ctx *nft; char table[32]; char buf[128]; + FILE *fp; - if (nftables_get_table(table, sizeof(table))) - return -1; + if (nft_lock_table[0] != 0) { + strncpy(table, nft_lock_table, sizeof(table)); + } else { + if (nftables_get_table(table, sizeof(table))) + return -1; + } nft = nft_ctx_new(NFT_CTX_DEFAULT); if (!nft) return -1; + fp = fdopen(log_get_fd(), "w"); + if (!fp) { + pr_perror("fdopen() failed"); + nft_ctx_free(nft); + return -1; + } + nft_ctx_set_output(nft, fp); + nft_ctx_set_error(nft, fp); + snprintf(buf, sizeof(buf), "delete table %s", table); if (NFT_RUN_CMD(nft, buf)) ret = -1; + fflush(fp); + fclose(fp); nft_ctx_free(nft); return ret; #else @@ -3263,7 +3297,7 @@ static int network_unlock_internal(void) return ret; } -int network_lock(void) +int network_lock(InventoryEntry *he) { pr_info("Lock network\n"); @@ -3277,7 +3311,7 @@ int network_lock(void) if (run_scripts(ACT_NET_LOCK)) return -1; - return network_lock_internal(); + return network_lock_internal(he); } void network_unlock(void) diff --git a/images/inventory.proto b/images/inventory.proto index 7f655031bc..5d416c202d 100644 --- a/images/inventory.proto +++ b/images/inventory.proto @@ -29,4 +29,5 @@ message inventory_entry { optional bool tcp_close = 10; optional uint32 network_lock_method = 11; optional plugins_entry plugins_entry = 12; + optional string nft_lock_table = 13; }