From e9d24a2ba33b2dd72c1f787da60abc5fb70ad51b Mon Sep 17 00:00:00 2001 From: Zeyad Yasser Date: Thu, 1 Jul 2021 21:30:42 +0200 Subject: [PATCH] cr-check: add check for nftables based network locking Nftables based network locking/unlocking will be added later. Nftables sets will be used to load the connection tuples that will be locked, to be able to store those tuples we need to check "Set Concatenations" support. https://wiki.nftables.org/wiki-nftables/index.php/Concatenations v2: fix 'has_nftables_concat=true' when adding CRIU table fails v3: add better message when CRIU is build without libnftables support v4: run make indent Signed-off-by: Zeyad Yasser --- criu/cr-check.c | 12 ++++++++++++ criu/include/kerndat.h | 1 + criu/include/netfilter.h | 8 ++++++++ criu/kerndat.c | 41 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+) diff --git a/criu/cr-check.c b/criu/cr-check.c index 8fab51ca4..3575fb3b3 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -1362,6 +1362,16 @@ static int check_ns_pid(void) return 0; } +static int check_network_lock_nftables(void) +{ + if (!kdat.has_nftables_concat) { + pr_warn("Nftables based locking requires libnftables and set concatenations support\n"); + return -1; + } + + return 0; +} + static int (*chk_feature)(void); /* @@ -1479,6 +1489,7 @@ int cr_check(void) ret |= check_pidfd_store(); ret |= check_ns_pid(); ret |= check_apparmor_stacking(); + ret |= check_network_lock_nftables(); } /* @@ -1590,6 +1601,7 @@ static struct feature_list feature_list[] = { { "pidfd_store", check_pidfd_store }, { "ns_pid", check_ns_pid }, { "apparmor_stacking", check_apparmor_stacking }, + { "network_lock_nftables", check_network_lock_nftables }, { NULL, NULL }, }; diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index b2f5d4305..80bad7f11 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -73,6 +73,7 @@ struct kerndat_s { bool has_pidfd_open; bool has_pidfd_getfd; bool has_nspid; + bool has_nftables_concat; }; extern struct kerndat_s kdat; diff --git a/criu/include/netfilter.h b/criu/include/netfilter.h index 35ef26205..5f58c41b7 100644 --- a/criu/include/netfilter.h +++ b/criu/include/netfilter.h @@ -10,4 +10,12 @@ extern int nf_unlock_connection_info(struct inet_sk_info *); extern void preload_netfilter_modules(void); +#if defined(CONFIG_HAS_NFTABLES_LIB_API_0) +#define NFT_RUN_CMD(nft, cmd) nft_run_cmd_from_buffer(nft, cmd, strlen(cmd)) +#elif defined(CONFIG_HAS_NFTABLES_LIB_API_1) +#define NFT_RUN_CMD(nft, cmd) nft_run_cmd_from_buffer(nft, cmd) +#else +#define NFT_RUN_CMD(nft, cmd) BUILD_BUG_ON(1) +#endif + #endif /* __CR_NETFILTER_H__ */ diff --git a/criu/kerndat.c b/criu/kerndat.c index 4d28dac98..da3732261 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -14,6 +14,10 @@ #include #include +#if defined(CONFIG_HAS_NFTABLES_LIB_API_0) || defined(CONFIG_HAS_NFTABLES_LIB_API_1) +#include +#endif + #include "common/config.h" #include "int.h" #include "log.h" @@ -1146,6 +1150,39 @@ close: return ret; } +static int kerndat_has_nftables_concat(void) +{ +#if defined(CONFIG_HAS_NFTABLES_LIB_API_0) || defined(CONFIG_HAS_NFTABLES_LIB_API_1) + struct nft_ctx *nft; + int ret = 0; + + nft = nft_ctx_new(NFT_CTX_DEFAULT); + if (!nft) + return -1; + + if (NFT_RUN_CMD(nft, "add table inet CRIU")) { + ret = -1; + goto nft_ctx_free_out; + } + + if (NFT_RUN_CMD(nft, "add set inet CRIU 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_ctx_free_out: + nft_ctx_free(nft); + return ret; +#else + pr_warn("CRIU was built without libnftables support\n"); + kdat.has_nftables_concat = false; + return 0; +#endif +} + int kerndat_init(void) { int ret; @@ -1293,6 +1330,10 @@ int kerndat_init(void) pr_err("kerndat_has_nspid failed when initializing kerndat.\n"); ret = -1; } + if (!ret && kerndat_has_nftables_concat()) { + pr_err("kerndat_has_nftables_concat failed when initializing kerndat.\n"); + ret = -1; + } kerndat_lsm(); kerndat_mmap_min_addr();