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

Martin Doucha mdoucha@suse.cz
Mon Nov 13 11:59:31 CET 2023


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 */
> +

-- 
Martin Doucha   mdoucha@suse.cz
SW Quality Engineer
SUSE LINUX, s.r.o.
CORSO IIa
Krizikova 148/34
186 00 Prague 8
Czech Republic



More information about the ltp mailing list