diff mbox series

[v1] Add test for CVE-2023-31248 and Add AUTOCONF rule for nftables tests.

Message ID 080648612d41f8f09275c40beafe625d5e3614ca.1699753620.git.souta.kawahara@miraclelinux.com
State Rejected
Headers show
Series [v1] Add test for CVE-2023-31248 and Add AUTOCONF rule for nftables tests. | expand

Commit Message

河原颯太 Nov. 13, 2023, 6:02 a.m. UTC
Fixes #1058

Signed-off-by: Souta Kawahara <souta.kawahara@miraclelinux.com>
---
 ci/debian.cross-compile.sh     |   1 +
 ci/debian.sh                   |   1 +
 ci/fedora.sh                   |   1 +
 ci/tumbleweed.sh               |   1 +
 configure.ac                   |   2 +
 include/mk/config.mk.in        |   2 +
 m4/ltp-libnftnl.m4             |   9 ++
 runtest/cve                    |   1 +
 testcases/cve/.gitignore       |   1 +
 testcases/cve/Makefile         |   2 +
 testcases/cve/cve-2023-31248.c | 200 +++++++++++++++++++++++++++++++++
 11 files changed, 221 insertions(+)
 create mode 100644 m4/ltp-libnftnl.m4
 create mode 100644 testcases/cve/cve-2023-31248.c

Comments

Martin Doucha Nov. 13, 2023, 10:59 a.m. UTC | #1
Hi,
I have a nearly complete reproducer that uses the internal tst_netlink 
API, without any external dependencies. I'm planning to finish it and 
submit tomorrow.

On 13. 11. 23 7:02, Souta Kawahara wrote:
> Fixes #1058
> 
> Signed-off-by: Souta Kawahara <souta.kawahara@miraclelinux.com>
> ---
>   ci/debian.cross-compile.sh     |   1 +
>   ci/debian.sh                   |   1 +
>   ci/fedora.sh                   |   1 +
>   ci/tumbleweed.sh               |   1 +
>   configure.ac                   |   2 +
>   include/mk/config.mk.in        |   2 +
>   m4/ltp-libnftnl.m4             |   9 ++
>   runtest/cve                    |   1 +
>   testcases/cve/.gitignore       |   1 +
>   testcases/cve/Makefile         |   2 +
>   testcases/cve/cve-2023-31248.c | 200 +++++++++++++++++++++++++++++++++
>   11 files changed, 221 insertions(+)
>   create mode 100644 m4/ltp-libnftnl.m4
>   create mode 100644 testcases/cve/cve-2023-31248.c
> 
> diff --git a/ci/debian.cross-compile.sh b/ci/debian.cross-compile.sh
> index 95cf11da2..6b71bb428 100755
> --- a/ci/debian.cross-compile.sh
> +++ b/ci/debian.cross-compile.sh
> @@ -21,4 +21,5 @@ apt install -y --no-install-recommends \
>   	gcc-${gcc_arch}-linux-gnu \
>   	libc6-dev-${ARCH}-cross \
>   	libmnl-dev:$ARCH \
> +	libnftnl-dev:$ARCH \
>   	libtirpc-dev:$ARCH
> diff --git a/ci/debian.sh b/ci/debian.sh
> index 96b55a35b..33b69c2b5 100755
> --- a/ci/debian.sh
> +++ b/ci/debian.sh
> @@ -38,6 +38,7 @@ $apt \
>   	libkeyutils-dev \
>   	libkeyutils1 \
>   	libmnl-dev \
> +	libnftnl-dev \
>   	libnuma-dev \
>   	libnuma1 \
>   	libselinux1-dev \
> diff --git a/ci/fedora.sh b/ci/fedora.sh
> index 623dbb5cb..887bcf7f0 100755
> --- a/ci/fedora.sh
> +++ b/ci/fedora.sh
> @@ -24,4 +24,5 @@ $yum \
>   
>   # CentOS 8 fixes
>   $yum libmnl-devel || $yum libmnl
> +$yum libnftnl-devel || $yum libnftnl
>   $yum rubygem-asciidoctor || true
> diff --git a/ci/tumbleweed.sh b/ci/tumbleweed.sh
> index 42d62c0e0..ca9923e7f 100755
> --- a/ci/tumbleweed.sh
> +++ b/ci/tumbleweed.sh
> @@ -21,6 +21,7 @@ $zyp \
>   	libaio-devel \
>   	libcap-devel \
>   	libmnl-devel \
> +	libnftnl-devel \
>   	libnuma-devel \
>   	libopenssl-devel \
>   	libselinux-devel \
> diff --git a/configure.ac b/configure.ac
> index 3fa350f9e..7da51c16e 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -382,6 +382,7 @@ LTP_CHECK_FORTIFY_SOURCE
>   LTP_CHECK_KERNEL_DEVEL
>   LTP_CHECK_KEYUTILS_SUPPORT
>   LTP_CHECK_LIBMNL
> +LTP_CHECK_LIBNFTNL
>   LTP_CHECK_LINUX_PTRACE
>   LTP_CHECK_LINUXRANDOM
>   LTP_CHECK_NOMMU_LINUX
> @@ -441,6 +442,7 @@ libaio: ${have_libaio:-no} (aio: ${have_aio:-no})
>   libcap: $cap_libs (newer: ${has_newer_libcap:-no})
>   libcrypto: ${have_libcrypto:-no} (sha: ${have_sha:-no})
>   libmnl: ${have_libmnl:-yes}
> +libnftnl: ${have_libnftnl:-yes}
>   libnuma: ${have_libnuma:-no} (headers: ${have_numa_headers:-yes}, v2 headers: ${have_numa_headers_v2:-no})
>   libtirpc: ${have_libtirpc:-no}
>   glibc SUN-RPC: ${have_rpc_glibc:-no}
> diff --git a/include/mk/config.mk.in b/include/mk/config.mk.in
> index 145b887fa..5d6794025 100644
> --- a/include/mk/config.mk.in
> +++ b/include/mk/config.mk.in
> @@ -58,6 +58,8 @@ KEYUTILS_LIBS		:= @KEYUTILS_LIBS@
>   HAVE_FTS_H		:= @HAVE_FTS_H@
>   LIBMNL_LIBS		:= @LIBMNL_LIBS@
>   LIBMNL_CFLAGS		:= @LIBMNL_CFLAGS@
> +LIBNFTNL_LIBS		:= @LIBNFTNL_LIBS@
> +LIBNFTNL_CFLAGS		:= @LIBNFTNL_CFLAGS@
>   
>   prefix			:= @prefix@
>   
> diff --git a/m4/ltp-libnftnl.m4 b/m4/ltp-libnftnl.m4
> new file mode 100644
> index 000000000..ae0cadb65
> --- /dev/null
> +++ b/m4/ltp-libnftnl.m4
> @@ -0,0 +1,9 @@
> +dnl SPDX-License-Identifier: GPL-2.0-or-later
> +dnl Copyright (c) 2023 Cybertrust Japan Co., Ltd.
> +dnl Author: Souta Kawahara <souta.kawahara@miraclelinux.com>
> +
> +AC_DEFUN([LTP_CHECK_LIBNFTNL], [
> +    PKG_CHECK_MODULES([LIBNFTNL], [libnftnl >= 1.1.8], [
> +        AC_DEFINE([HAVE_LIBNFTNL], [1], [Define to 1 if you have libnftnl library and headers])
> +	], [have_libnftnl=no])
> +])
> diff --git a/runtest/cve b/runtest/cve
> index 569558af2..1aa61a9b6 100644
> --- a/runtest/cve
> +++ b/runtest/cve
> @@ -86,6 +86,7 @@ cve-2022-2590 dirtyc0w_shmem
>   cve-2022-23222 bpf_prog07
>   cve-2023-1829 tcindex01
>   cve-2023-0461 setsockopt10
> +cve-2023-31248 cve-2023-31248
>   # Tests below may cause kernel memory leak
>   cve-2020-25704 perf_event_open03
>   cve-2022-0185 fsconfig03
> diff --git a/testcases/cve/.gitignore b/testcases/cve/.gitignore
> index 3a2b2bed6..c02b75c78 100644
> --- a/testcases/cve/.gitignore
> +++ b/testcases/cve/.gitignore
> @@ -13,3 +13,4 @@ cve-2017-17053
>   cve-2022-4378
>   icmp_rate_limit01
>   tcindex01
> +cve-2023-31248
> diff --git a/testcases/cve/Makefile b/testcases/cve/Makefile
> index 01b9b9ccb..698f5fe26 100644
> --- a/testcases/cve/Makefile
> +++ b/testcases/cve/Makefile
> @@ -13,6 +13,8 @@ cve-2016-7042:	LDLIBS += $(KEYUTILS_LIBS)
>   
>   cve-2014-0196 cve-2016-7117 cve-2017-2671 cve-2017-17052 cve-2017-17053:  CFLAGS += -pthread
>   cve-2014-0196 cve-2016-7117 cve-2017-2671:  LDLIBS += -lrt
> +cve-2023-31248: CFLAGS += $(LIBMNL_CFLAGS) $(LIBNFTNL_CFLAGS)
> +cve-2023-31248: LDLIBS += $(LIBMNL_LIBS) $(LIBNFTNL_LIBS)
>   
>   ifneq ($(ANDROID),1)
>   cve-2014-0196:  LDLIBS += -lutil
> diff --git a/testcases/cve/cve-2023-31248.c b/testcases/cve/cve-2023-31248.c
> new file mode 100644
> index 000000000..4b2fd5cc5
> --- /dev/null
> +++ b/testcases/cve/cve-2023-31248.c
> @@ -0,0 +1,200 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2023 Cybertrust Japan Co., Ltd.
> + * Author: Souta Kawahara <soute.kawahara@miraclelinux.com>
> + */
> +
> +/*\
> + * CVE-2023-31248.
> + *
> + * This test add a rule to jump to a deleted chain.
> + * If vulnerable, the operation passed and the rule eventually leads to use-after-free.
> + *
> + * The bug was fixed in:
> + *
> + *  commit 515ad530795c118f012539ed76d02bacfd426d89
> + *  Author: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
> + *  Date:   Wed Jul 05 09:12:55 2023 -0300
> + *
> + *  netfilter: nf_tables: do not ignore genmask when looking up chain by id
> + */
> +
> +#include "tst_test.h"
> +
> +#if defined(HAVE_LIBMNL) && defined(HAVE_LIBNFTNL)
> +
> +#include <sched.h>
> +#include <arpa/inet.h>
> +
> +#include <linux/netfilter.h>
> +#include <linux/netfilter/nf_tables.h>
> +
> +#include <libmnl/libmnl.h>
> +#include <libnftnl/table.h>
> +#include <libnftnl/chain.h>
> +#include <libnftnl/rule.h>
> +#include <libnftnl/expr.h>
> +
> +#define TABLE_NAME "ltp_table"
> +#define VICTIM_CHAIN_NAME "victim_chain"
> +#define TRIGGER_CHAIN_NAME "trigger_chain"
> +#define VICTIM_ID 0x1111
> +
> +static struct mnl_socket *nl;
> +static struct nftnl_table *table;
> +static struct nftnl_chain *victim_chain, *trigger_chain;
> +static struct nftnl_rule *rule;
> +static struct nftnl_expr *expr;
> +
> +static inline int callbacks(const struct mnl_socket *nl, char *buf, size_t sbuf, int seq, int rseq)
> +{
> +	int ret;
> +
> +	while (rseq < seq) {
> +		ret = mnl_socket_recvfrom(nl, buf, sbuf);
> +		if (ret <= 0)
> +			return ret;
> +		ret = mnl_cb_run(buf, ret, rseq, mnl_socket_get_portid(nl), NULL, NULL);
> +		if (ret < 0)
> +			return ret;
> +		rseq++;
> +	}
> +	return 0;
> +}
> +
> +static void setup(void)
> +{
> +	tst_setup_netns();
> +
> +	nl = mnl_socket_open(NETLINK_NETFILTER);
> +	if (nl == NULL)
> +		tst_brk(TBROK, "mnl_socket_open faild (errno=%d): %s", errno, strerror(errno));
> +	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
> +		tst_brk(TBROK, "mnl_socket_bind faild (errno=%d): %s", errno, strerror(errno));
> +
> +	table = nftnl_table_alloc();
> +	if (table == NULL)
> +		tst_brk(TBROK, "nftnl_table_alloc faild (errno=%d): %s", errno, strerror(errno));
> +	victim_chain = nftnl_chain_alloc();
> +	if (victim_chain == NULL)
> +		tst_brk(TBROK, "nftnl_chain_alloc faild (errno=%d): %s", errno, strerror(errno));
> +	trigger_chain = nftnl_chain_alloc();
> +	if (trigger_chain == NULL)
> +		tst_brk(TBROK, "nftnl_chain_alloc faild (errno=%d): %s", errno, strerror(errno));
> +	rule = nftnl_rule_alloc();
> +	if (rule == NULL)
> +		tst_brk(TBROK, "nftnl_rule_alloc faild (errno=%d): %s", errno, strerror(errno));
> +	expr = nftnl_expr_alloc("immediate");
> +	if (expr == NULL)
> +		tst_brk(TBROK, "nftnl_expr_alloc faild (errno=%d): %s", errno, strerror(errno));
> +}
> +
> +static void run(void)
> +{
> +	struct mnl_nlmsg_batch *batch;
> +	struct nlmsghdr *nlh;
> +	char buf[MNL_SOCKET_BUFFER_SIZE];
> +	int ret, rseq, seq = 0;
> +
> +	nftnl_table_set_u32(table, NFTNL_TABLE_FAMILY, NFPROTO_IPV4);
> +	nftnl_table_set_str(table, NFTNL_TABLE_NAME, TABLE_NAME);
> +
> +	nftnl_chain_set_str(victim_chain, NFTNL_CHAIN_TABLE, TABLE_NAME);
> +	nftnl_chain_set_str(victim_chain, NFTNL_CHAIN_NAME, VICTIM_CHAIN_NAME);
> +	nftnl_chain_set_u32(victim_chain, NFTNL_CHAIN_ID, VICTIM_ID);
> +
> +	nftnl_chain_set_str(trigger_chain, NFTNL_CHAIN_TABLE, TABLE_NAME);
> +	nftnl_chain_set_str(trigger_chain, NFTNL_CHAIN_NAME, TRIGGER_CHAIN_NAME);
> +
> +	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT);
> +	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_VERDICT, NFT_GOTO);
> +	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_CHAIN_ID, VICTIM_ID);
> +
> +	nftnl_rule_set_u32(rule, NFTNL_RULE_FAMILY, NFPROTO_IPV4);
> +	nftnl_rule_set_str(rule, NFTNL_RULE_TABLE, TABLE_NAME);
> +	nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN, TRIGGER_CHAIN_NAME);
> +
> +	nftnl_rule_add_expr(rule, expr);
> +
> +	batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
> +	nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
> +	mnl_nlmsg_batch_next(batch);
> +	rseq = seq;
> +
> +	nlh = nftnl_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
> +			NFT_MSG_NEWTABLE, NFPROTO_IPV4, NLM_F_ACK | NLM_F_CREATE, seq++);
> +	nftnl_table_nlmsg_build_payload(nlh, table);
> +	mnl_nlmsg_batch_next(batch);
> +
> +	nlh = nftnl_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
> +			NFT_MSG_NEWCHAIN, NFPROTO_IPV4, NLM_F_ACK | NLM_F_CREATE, seq++);
> +	nftnl_chain_nlmsg_build_payload(nlh, victim_chain);
> +	mnl_nlmsg_batch_next(batch);
> +
> +	nlh = nftnl_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
> +			NFT_MSG_DELCHAIN, NFPROTO_IPV4, NLM_F_ACK, seq++);
> +	nftnl_chain_nlmsg_build_payload(nlh, victim_chain);
> +	mnl_nlmsg_batch_next(batch);
> +
> +	nlh = nftnl_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
> +			NFT_MSG_NEWCHAIN, NFPROTO_IPV4, NLM_F_ACK | NLM_F_CREATE, seq++);
> +	nftnl_chain_nlmsg_build_payload(nlh, trigger_chain);
> +	mnl_nlmsg_batch_next(batch);
> +
> +	nlh = nftnl_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
> +			NFT_MSG_NEWRULE, NFPROTO_IPV4, NLM_F_ACK | NLM_F_CREATE, seq++);
> +	nftnl_rule_nlmsg_build_payload(nlh, rule);
> +	mnl_nlmsg_batch_next(batch);
> +
> +	nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq);
> +	mnl_nlmsg_batch_next(batch);
> +
> +	ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch));
> +	if (ret == -1)
> +		tst_brk(TBROK, "mnl_socket_sendto faild (errno=%d): %s", errno, strerror(errno));
> +	mnl_nlmsg_batch_stop(batch);
> +
> +	TEST(callbacks(nl, buf, sizeof(buf), seq, rseq));
> +	if ((TST_RET < 0) && (TST_ERR == ENOENT))
> +		tst_res(TPASS | TTERRNO, "The operation expectedly failed");
> +	else
> +		tst_res(TFAIL, "The operation unexpectedly passed");
> +}
> +
> +static void cleanup(void)
> +{
> +	if (rule)
> +		nftnl_rule_free(rule);
> +	if (trigger_chain)
> +		nftnl_chain_free(trigger_chain);
> +	if (victim_chain)
> +		nftnl_chain_free(victim_chain);
> +	if (table)
> +		nftnl_table_free(table);
> +
> +	if (nl)
> +		mnl_socket_close(nl);
> +}
> +
> +static struct tst_test test = {
> +	.setup = setup,
> +	.test_all = run,
> +	.cleanup = cleanup,
> +	.needs_kconfigs = (const char *[]) {
> +		"CONFIG_NF_TABLES",
> +		"CONFIG_NF_TABLES_IPV4",
> +		"CONFIG_USER_NS=y",
> +		"CONFIG_NET_NS=y",
> +		NULL
> +	},
> +	.tags = (const struct tst_tag[]) {
> +		{"linux-git", "515ad530795c"},
> +		{"CVE", "2023-31248"},
> +		{}
> +	}
> +};
> +
> +#else
> +	TST_TEST_TCONF("libmnl and libnftnl(>= 1.1.8) libraries and headers are required.");
> +#endif /* HAVE_LIBMNL && HAVE_LIBNFTNL */
> +
diff mbox series

Patch

diff --git a/ci/debian.cross-compile.sh b/ci/debian.cross-compile.sh
index 95cf11da2..6b71bb428 100755
--- a/ci/debian.cross-compile.sh
+++ b/ci/debian.cross-compile.sh
@@ -21,4 +21,5 @@  apt install -y --no-install-recommends \
 	gcc-${gcc_arch}-linux-gnu \
 	libc6-dev-${ARCH}-cross \
 	libmnl-dev:$ARCH \
+	libnftnl-dev:$ARCH \
 	libtirpc-dev:$ARCH
diff --git a/ci/debian.sh b/ci/debian.sh
index 96b55a35b..33b69c2b5 100755
--- a/ci/debian.sh
+++ b/ci/debian.sh
@@ -38,6 +38,7 @@  $apt \
 	libkeyutils-dev \
 	libkeyutils1 \
 	libmnl-dev \
+	libnftnl-dev \
 	libnuma-dev \
 	libnuma1 \
 	libselinux1-dev \
diff --git a/ci/fedora.sh b/ci/fedora.sh
index 623dbb5cb..887bcf7f0 100755
--- a/ci/fedora.sh
+++ b/ci/fedora.sh
@@ -24,4 +24,5 @@  $yum \
 
 # CentOS 8 fixes
 $yum libmnl-devel || $yum libmnl
+$yum libnftnl-devel || $yum libnftnl
 $yum rubygem-asciidoctor || true
diff --git a/ci/tumbleweed.sh b/ci/tumbleweed.sh
index 42d62c0e0..ca9923e7f 100755
--- a/ci/tumbleweed.sh
+++ b/ci/tumbleweed.sh
@@ -21,6 +21,7 @@  $zyp \
 	libaio-devel \
 	libcap-devel \
 	libmnl-devel \
+	libnftnl-devel \
 	libnuma-devel \
 	libopenssl-devel \
 	libselinux-devel \
diff --git a/configure.ac b/configure.ac
index 3fa350f9e..7da51c16e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -382,6 +382,7 @@  LTP_CHECK_FORTIFY_SOURCE
 LTP_CHECK_KERNEL_DEVEL
 LTP_CHECK_KEYUTILS_SUPPORT
 LTP_CHECK_LIBMNL
+LTP_CHECK_LIBNFTNL
 LTP_CHECK_LINUX_PTRACE
 LTP_CHECK_LINUXRANDOM
 LTP_CHECK_NOMMU_LINUX
@@ -441,6 +442,7 @@  libaio: ${have_libaio:-no} (aio: ${have_aio:-no})
 libcap: $cap_libs (newer: ${has_newer_libcap:-no})
 libcrypto: ${have_libcrypto:-no} (sha: ${have_sha:-no})
 libmnl: ${have_libmnl:-yes}
+libnftnl: ${have_libnftnl:-yes}
 libnuma: ${have_libnuma:-no} (headers: ${have_numa_headers:-yes}, v2 headers: ${have_numa_headers_v2:-no})
 libtirpc: ${have_libtirpc:-no}
 glibc SUN-RPC: ${have_rpc_glibc:-no}
diff --git a/include/mk/config.mk.in b/include/mk/config.mk.in
index 145b887fa..5d6794025 100644
--- a/include/mk/config.mk.in
+++ b/include/mk/config.mk.in
@@ -58,6 +58,8 @@  KEYUTILS_LIBS		:= @KEYUTILS_LIBS@
 HAVE_FTS_H		:= @HAVE_FTS_H@
 LIBMNL_LIBS		:= @LIBMNL_LIBS@
 LIBMNL_CFLAGS		:= @LIBMNL_CFLAGS@
+LIBNFTNL_LIBS		:= @LIBNFTNL_LIBS@
+LIBNFTNL_CFLAGS		:= @LIBNFTNL_CFLAGS@
 
 prefix			:= @prefix@
 
diff --git a/m4/ltp-libnftnl.m4 b/m4/ltp-libnftnl.m4
new file mode 100644
index 000000000..ae0cadb65
--- /dev/null
+++ b/m4/ltp-libnftnl.m4
@@ -0,0 +1,9 @@ 
+dnl SPDX-License-Identifier: GPL-2.0-or-later
+dnl Copyright (c) 2023 Cybertrust Japan Co., Ltd.
+dnl Author: Souta Kawahara <souta.kawahara@miraclelinux.com>
+
+AC_DEFUN([LTP_CHECK_LIBNFTNL], [
+    PKG_CHECK_MODULES([LIBNFTNL], [libnftnl >= 1.1.8], [
+        AC_DEFINE([HAVE_LIBNFTNL], [1], [Define to 1 if you have libnftnl library and headers])
+	], [have_libnftnl=no])
+])
diff --git a/runtest/cve b/runtest/cve
index 569558af2..1aa61a9b6 100644
--- a/runtest/cve
+++ b/runtest/cve
@@ -86,6 +86,7 @@  cve-2022-2590 dirtyc0w_shmem
 cve-2022-23222 bpf_prog07
 cve-2023-1829 tcindex01
 cve-2023-0461 setsockopt10
+cve-2023-31248 cve-2023-31248
 # Tests below may cause kernel memory leak
 cve-2020-25704 perf_event_open03
 cve-2022-0185 fsconfig03
diff --git a/testcases/cve/.gitignore b/testcases/cve/.gitignore
index 3a2b2bed6..c02b75c78 100644
--- a/testcases/cve/.gitignore
+++ b/testcases/cve/.gitignore
@@ -13,3 +13,4 @@  cve-2017-17053
 cve-2022-4378
 icmp_rate_limit01
 tcindex01
+cve-2023-31248
diff --git a/testcases/cve/Makefile b/testcases/cve/Makefile
index 01b9b9ccb..698f5fe26 100644
--- a/testcases/cve/Makefile
+++ b/testcases/cve/Makefile
@@ -13,6 +13,8 @@  cve-2016-7042:	LDLIBS += $(KEYUTILS_LIBS)
 
 cve-2014-0196 cve-2016-7117 cve-2017-2671 cve-2017-17052 cve-2017-17053:  CFLAGS += -pthread
 cve-2014-0196 cve-2016-7117 cve-2017-2671:  LDLIBS += -lrt
+cve-2023-31248: CFLAGS += $(LIBMNL_CFLAGS) $(LIBNFTNL_CFLAGS)
+cve-2023-31248: LDLIBS += $(LIBMNL_LIBS) $(LIBNFTNL_LIBS)
 
 ifneq ($(ANDROID),1)
 cve-2014-0196:  LDLIBS += -lutil
diff --git a/testcases/cve/cve-2023-31248.c b/testcases/cve/cve-2023-31248.c
new file mode 100644
index 000000000..4b2fd5cc5
--- /dev/null
+++ b/testcases/cve/cve-2023-31248.c
@@ -0,0 +1,200 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 Cybertrust Japan Co., Ltd.
+ * Author: Souta Kawahara <soute.kawahara@miraclelinux.com>
+ */
+
+/*\
+ * CVE-2023-31248.
+ *
+ * This test add a rule to jump to a deleted chain.
+ * If vulnerable, the operation passed and the rule eventually leads to use-after-free.
+ *
+ * The bug was fixed in:
+ *
+ *  commit 515ad530795c118f012539ed76d02bacfd426d89
+ *  Author: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
+ *  Date:   Wed Jul 05 09:12:55 2023 -0300
+ *
+ *  netfilter: nf_tables: do not ignore genmask when looking up chain by id
+ */
+
+#include "tst_test.h"
+
+#if defined(HAVE_LIBMNL) && defined(HAVE_LIBNFTNL)
+
+#include <sched.h>
+#include <arpa/inet.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter/nf_tables.h>
+
+#include <libmnl/libmnl.h>
+#include <libnftnl/table.h>
+#include <libnftnl/chain.h>
+#include <libnftnl/rule.h>
+#include <libnftnl/expr.h>
+
+#define TABLE_NAME "ltp_table"
+#define VICTIM_CHAIN_NAME "victim_chain"
+#define TRIGGER_CHAIN_NAME "trigger_chain"
+#define VICTIM_ID 0x1111
+
+static struct mnl_socket *nl;
+static struct nftnl_table *table;
+static struct nftnl_chain *victim_chain, *trigger_chain;
+static struct nftnl_rule *rule;
+static struct nftnl_expr *expr;
+
+static inline int callbacks(const struct mnl_socket *nl, char *buf, size_t sbuf, int seq, int rseq)
+{
+	int ret;
+
+	while (rseq < seq) {
+		ret = mnl_socket_recvfrom(nl, buf, sbuf);
+		if (ret <= 0)
+			return ret;
+		ret = mnl_cb_run(buf, ret, rseq, mnl_socket_get_portid(nl), NULL, NULL);
+		if (ret < 0)
+			return ret;
+		rseq++;
+	}
+	return 0;
+}
+
+static void setup(void)
+{
+	tst_setup_netns();
+
+	nl = mnl_socket_open(NETLINK_NETFILTER);
+	if (nl == NULL)
+		tst_brk(TBROK, "mnl_socket_open faild (errno=%d): %s", errno, strerror(errno));
+	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
+		tst_brk(TBROK, "mnl_socket_bind faild (errno=%d): %s", errno, strerror(errno));
+
+	table = nftnl_table_alloc();
+	if (table == NULL)
+		tst_brk(TBROK, "nftnl_table_alloc faild (errno=%d): %s", errno, strerror(errno));
+	victim_chain = nftnl_chain_alloc();
+	if (victim_chain == NULL)
+		tst_brk(TBROK, "nftnl_chain_alloc faild (errno=%d): %s", errno, strerror(errno));
+	trigger_chain = nftnl_chain_alloc();
+	if (trigger_chain == NULL)
+		tst_brk(TBROK, "nftnl_chain_alloc faild (errno=%d): %s", errno, strerror(errno));
+	rule = nftnl_rule_alloc();
+	if (rule == NULL)
+		tst_brk(TBROK, "nftnl_rule_alloc faild (errno=%d): %s", errno, strerror(errno));
+	expr = nftnl_expr_alloc("immediate");
+	if (expr == NULL)
+		tst_brk(TBROK, "nftnl_expr_alloc faild (errno=%d): %s", errno, strerror(errno));
+}
+
+static void run(void)
+{
+	struct mnl_nlmsg_batch *batch;
+	struct nlmsghdr *nlh;
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	int ret, rseq, seq = 0;
+
+	nftnl_table_set_u32(table, NFTNL_TABLE_FAMILY, NFPROTO_IPV4);
+	nftnl_table_set_str(table, NFTNL_TABLE_NAME, TABLE_NAME);
+
+	nftnl_chain_set_str(victim_chain, NFTNL_CHAIN_TABLE, TABLE_NAME);
+	nftnl_chain_set_str(victim_chain, NFTNL_CHAIN_NAME, VICTIM_CHAIN_NAME);
+	nftnl_chain_set_u32(victim_chain, NFTNL_CHAIN_ID, VICTIM_ID);
+
+	nftnl_chain_set_str(trigger_chain, NFTNL_CHAIN_TABLE, TABLE_NAME);
+	nftnl_chain_set_str(trigger_chain, NFTNL_CHAIN_NAME, TRIGGER_CHAIN_NAME);
+
+	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT);
+	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_VERDICT, NFT_GOTO);
+	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_CHAIN_ID, VICTIM_ID);
+
+	nftnl_rule_set_u32(rule, NFTNL_RULE_FAMILY, NFPROTO_IPV4);
+	nftnl_rule_set_str(rule, NFTNL_RULE_TABLE, TABLE_NAME);
+	nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN, TRIGGER_CHAIN_NAME);
+
+	nftnl_rule_add_expr(rule, expr);
+
+	batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
+	nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
+	mnl_nlmsg_batch_next(batch);
+	rseq = seq;
+
+	nlh = nftnl_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
+			NFT_MSG_NEWTABLE, NFPROTO_IPV4, NLM_F_ACK | NLM_F_CREATE, seq++);
+	nftnl_table_nlmsg_build_payload(nlh, table);
+	mnl_nlmsg_batch_next(batch);
+
+	nlh = nftnl_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
+			NFT_MSG_NEWCHAIN, NFPROTO_IPV4, NLM_F_ACK | NLM_F_CREATE, seq++);
+	nftnl_chain_nlmsg_build_payload(nlh, victim_chain);
+	mnl_nlmsg_batch_next(batch);
+
+	nlh = nftnl_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
+			NFT_MSG_DELCHAIN, NFPROTO_IPV4, NLM_F_ACK, seq++);
+	nftnl_chain_nlmsg_build_payload(nlh, victim_chain);
+	mnl_nlmsg_batch_next(batch);
+
+	nlh = nftnl_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
+			NFT_MSG_NEWCHAIN, NFPROTO_IPV4, NLM_F_ACK | NLM_F_CREATE, seq++);
+	nftnl_chain_nlmsg_build_payload(nlh, trigger_chain);
+	mnl_nlmsg_batch_next(batch);
+
+	nlh = nftnl_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
+			NFT_MSG_NEWRULE, NFPROTO_IPV4, NLM_F_ACK | NLM_F_CREATE, seq++);
+	nftnl_rule_nlmsg_build_payload(nlh, rule);
+	mnl_nlmsg_batch_next(batch);
+
+	nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq);
+	mnl_nlmsg_batch_next(batch);
+
+	ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch));
+	if (ret == -1)
+		tst_brk(TBROK, "mnl_socket_sendto faild (errno=%d): %s", errno, strerror(errno));
+	mnl_nlmsg_batch_stop(batch);
+
+	TEST(callbacks(nl, buf, sizeof(buf), seq, rseq));
+	if ((TST_RET < 0) && (TST_ERR == ENOENT))
+		tst_res(TPASS | TTERRNO, "The operation expectedly failed");
+	else
+		tst_res(TFAIL, "The operation unexpectedly passed");
+}
+
+static void cleanup(void)
+{
+	if (rule)
+		nftnl_rule_free(rule);
+	if (trigger_chain)
+		nftnl_chain_free(trigger_chain);
+	if (victim_chain)
+		nftnl_chain_free(victim_chain);
+	if (table)
+		nftnl_table_free(table);
+
+	if (nl)
+		mnl_socket_close(nl);
+}
+
+static struct tst_test test = {
+	.setup = setup,
+	.test_all = run,
+	.cleanup = cleanup,
+	.needs_kconfigs = (const char *[]) {
+		"CONFIG_NF_TABLES",
+		"CONFIG_NF_TABLES_IPV4",
+		"CONFIG_USER_NS=y",
+		"CONFIG_NET_NS=y",
+		NULL
+	},
+	.tags = (const struct tst_tag[]) {
+		{"linux-git", "515ad530795c"},
+		{"CVE", "2023-31248"},
+		{}
+	}
+};
+
+#else
+	TST_TEST_TCONF("libmnl and libnftnl(>= 1.1.8) libraries and headers are required.");
+#endif /* HAVE_LIBMNL && HAVE_LIBNFTNL */
+