All of lore.kernel.org
 help / color / mirror / Atom feed
From: Petr Vorel <pvorel@suse.cz>
To: ltp@lists.linux.it
Subject: [LTP] [PATCH v3 6/6] Add test for CVE 2020-25705
Date: Wed, 5 May 2021 12:04:21 +0200	[thread overview]
Message-ID: <YJJtpXWM4BxH2ffu@pevik> (raw)
In-Reply-To: <20210505081845.7024-6-mdoucha@suse.cz>

> Fixes #742

LGTM. Few unimportant comments below.

Reviewed-by: Petr Vorel <pvorel@suse.cz>

...
> diff --git a/testcases/cve/cve-2020-25705.c b/testcases/cve/cve-2020-25705.c
> new file mode 100644
> index 000000000..7d6bbafa8
> --- /dev/null
> +++ b/testcases/cve/cve-2020-25705.c
> @@ -0,0 +1,262 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2020 SUSE LLC
> + * Author: Nicolai Stange <nstange@suse.de>
> + * LTP port: Martin Doucha <mdoucha@suse.cz>
> + *
> + * CVE-2020-25705
> + *
> + * Test of ICMP rate limiting behavior that may be abused for DNS cache
> + * poisoning attack. Send a few batches of 100 packets to a closed UDP port
> + * and count the ICMP errors. If the number of errors is always the same
> + * for each batch (not randomized), the system is vulnerable. Send packets
> + * from multiple IP addresses to bypass per-address ICMP throttling.
We probably turn this into docparse during merge.

> + *
> + * Fixed in:
> + *
> + *  commit b38e7819cae946e2edf869e604af1e65a5d241c5
> + *  Author: Eric Dumazet <edumazet@google.com>
> + *  Date:   Thu Oct 15 11:42:00 2020 -0700
> + *
> + *  icmp: randomize the global rate limiter
> + */
> +
> +#include <sys/socket.h>
> +#include <netinet/in.h>
> +#include <arpa/inet.h>
> +#include <linux/if_addr.h>
> +#include <linux/errqueue.h>

#include <time.h>

to fix build failure on MUSL:

cve-2020-25705.c:262:1: warning: missing initializer for field 'needs_cmds' of 'struct tst_test' [-Wmissing-field-initializers]
https://travis-ci.org/github/pevik/ltp/jobs/769551152

> +#include <sched.h>
> +#include <limits.h>
> +#include "tst_test.h"
> +#include "tst_netdevice.h"
> +
> +#define DSTADDR 0xfa444e02 /* 250.68.78.2 */
> +#define SRCADDR_BASE 0xfa444e41 /* 250.68.78.65 */
> +#define SRCADDR_COUNT 50
> +#define BATCH_COUNT 8
> +#define BUFSIZE 1024
> +
> +static int parentns = -1, childns = -1;
> +static int fds[SRCADDR_COUNT];
> +
> +static void setup(void)
> +{
...
> +	/*
> +	 * Create network namespace to hide the destination interface from
> +	 * the test process.
> +	 */
> +	parentns = SAFE_OPEN("/proc/self/ns/net", O_RDONLY);
> +	SAFE_UNSHARE(CLONE_NEWNET);
> +
> +	/* Do NOT close this FD, or both interfaces will be destroyed */
> +	childns = SAFE_OPEN("/proc/self/ns/net", O_RDONLY);
> +
> +	/* Configure child namespace */
> +	CREATE_VETH_PAIR("ltp_veth1", "ltp_veth2");
> +	addr = DSTADDR;
> +	NETDEV_ADD_ADDRESS_INET("ltp_veth2", htonl(addr), 26,
> +		IFA_F_NOPREFIXROUTE);

I wonder if it'd be useful *later* (not bothering with it now) to allow tests
just declare .needs_netdevice = 1 and have generic network setup done (similarly
it's done in tst_net.sh). Or just define addresses a prefixes and do library to
do the setup.

> +	NETDEV_SET_STATE("ltp_veth2", 1);
> +	NETDEV_ADD_ROUTE_INET("ltp_veth2", 0, 0, htonl(0xfa444e40), 26,
nit: maybe define 0xfa444e40 (and 0xfa444e00) and 26 as constants?
> +		0);
> +
> +	/* Configure parent namespace */
> +	NETDEV_CHANGE_NS_FD("ltp_veth1", parentns);
> +	SAFE_SETNS(parentns, CLONE_NEWNET);
> +	addr = SRCADDR_BASE; /* 250.68.78.65 */
nit: maybe repeating the address in the comment is not needed.
> +
> +	for (i = 0; i < SRCADDR_COUNT; i++, addr++) {
> +		NETDEV_ADD_ADDRESS_INET("ltp_veth1", htonl(addr), 26,
> +			IFA_F_NOPREFIXROUTE);
> +	}
> +
> +	NETDEV_SET_STATE("ltp_veth1", 1);
> +	NETDEV_ADD_ROUTE_INET("ltp_veth1", 0, 0, htonl(0xfa444e00), 26, 0);

> +	SAFE_FILE_PRINTF("/proc/sys/net/ipv4/conf/ltp_veth1/forwarding", "1");
> +
> +	/* Open test sockets */
> +	for (i = 0; i < SRCADDR_COUNT; i++) {
> +		ipaddr.sin_addr.s_addr = htonl(SRCADDR_BASE + i);
> +		fds[i] = SAFE_SOCKET(AF_INET, SOCK_DGRAM, 0);
> +		SAFE_SETSOCKOPT_INT(fds[i], IPPROTO_IP, IP_RECVERR, 1);
> +		SAFE_BIND(fds[i], (struct sockaddr *)&ipaddr, sizeof(ipaddr));
> +	}
> +}
> +
> +static int count_icmp_errors(int fd)
> +{
> +	int error_count = 0;
> +	ssize_t len;
> +	char msgbuf[BUFSIZE], errbuf[BUFSIZE];
> +	struct sockaddr_in addr;
> +	struct cmsghdr *cmsg;
> +	struct sock_extended_err exterr;
> +	struct iovec iov = {
> +		.iov_base = msgbuf,
> +		.iov_len = BUFSIZE
> +	};
> +
> +	while (1) {
> +		struct msghdr msg = {
> +			.msg_name = (struct sockaddr *)&addr,
> +			.msg_namelen = sizeof(addr),
> +			.msg_iov = &iov,
> +			.msg_iovlen = 1,
> +			.msg_flags = 0,
> +			.msg_control = errbuf,
> +			.msg_controllen = BUFSIZE
> +		};
> +
> +		memset(errbuf, 0, BUFSIZE);
> +		errno = 0;
> +		len = recvmsg(fd, &msg, MSG_ERRQUEUE);
> +
> +		if (len == -1) {
> +			if (errno == EWOULDBLOCK || errno == EAGAIN)
> +				break;
> +
> +			tst_brk(TBROK | TERRNO, "recvmsg() failed");
> +		}
> +
> +		if (len < 0) {
> +			tst_brk(TBROK | TERRNO,
> +				"Invalid recvmsg() return value %zd", len);
> +		}
> +
> +		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
> +			cmsg = CMSG_NXTHDR(&msg, cmsg)) {
> +			if (cmsg->cmsg_level != SOL_IP)
> +				continue;
> +
> +			if (cmsg->cmsg_type != IP_RECVERR)
> +				continue;
> +
> +			memcpy(&exterr, CMSG_DATA(cmsg), sizeof(exterr));
> +
> +			if (exterr.ee_origin != SO_EE_ORIGIN_ICMP)
> +				tst_brk(TBROK, "Unexpected non-ICMP error");
> +
> +			if (exterr.ee_errno != ECONNREFUSED) {
> +				TST_ERR = exterr.ee_errno;
> +				tst_brk(TBROK | TTERRNO,
> +					"Unexpected ICMP error");
> +			}
> +
> +			error_count++;
> +		}
> +	}
> +
> +	return error_count;
> +}

FYI I tested the test on several VM. Very old kernel detects problem only on
more runs. But given it's 3.16 (and b38e7819cae9 is a fix for 4cdf507d5452 from
v3.18-rc1 we can ignore this).

Kind regards,
Petr

# ./cve-2020-25705
tst_kconfig.c:64: TINFO: Parsing kernel config '/boot/config-3.16.0-11-amd64'
tst_test.c:1313: TINFO: Timeout per run is 0h 05m 00s
cve-2020-25705.c:217: TINFO: Batch 0: Got 85 ICMP errors
cve-2020-25705.c:221: TINFO: Batch 1: Got 100 ICMP errors
cve-2020-25705.c:230: TPASS: ICMP rate limit is randomized

-i2
# ./cve-2020-25705 -i2
tst_kconfig.c:64: TINFO: Parsing kernel config '/boot/config-3.16.0-11-amd64'
tst_test.c:1313: TINFO: Timeout per run is 0h 05m 00s
cve-2020-25705.c:217: TINFO: Batch 0: Got 85 ICMP errors
cve-2020-25705.c:221: TINFO: Batch 1: Got 100 ICMP errors
cve-2020-25705.c:230: TPASS: ICMP rate limit is randomized
cve-2020-25705.c:217: TINFO: Batch 0: Got 100 ICMP errors
cve-2020-25705.c:221: TINFO: Batch 1: Got 100 ICMP errors
cve-2020-25705.c:221: TINFO: Batch 2: Got 100 ICMP errors
cve-2020-25705.c:221: TINFO: Batch 3: Got 100 ICMP errors
cve-2020-25705.c:221: TINFO: Batch 4: Got 100 ICMP errors
cve-2020-25705.c:221: TINFO: Batch 5: Got 100 ICMP errors
cve-2020-25705.c:221: TINFO: Batch 6: Got 100 ICMP errors
cve-2020-25705.c:221: TINFO: Batch 7: Got 100 ICMP errors
cve-2020-25705.c:226: TFAIL: ICMP rate limit not randomized, system is vulnerable

HINT: You _MAY_ be missing kernel fixes, see:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b38e7819cae9

HINT: You _MAY_ be vulnerable to CVE(s), see:

https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-25705

Summary:
passed   1
failed   1
broken   0
skipped  0
warnings 0

  reply	other threads:[~2021-05-05 10:04 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-05  8:18 [LTP] [PATCH v3 1/6] Add SAFE_REALLOC() helper function to LTP library Martin Doucha
2021-05-05  8:18 ` [LTP] [PATCH v3 2/6] Add SAFE_RECV() " Martin Doucha
2021-05-10  7:55   ` Petr Vorel
2021-05-05  8:18 ` [LTP] [PATCH v3 3/6] Add SAFE_IOCTL() variant for library code Martin Doucha
2021-05-05  9:12   ` Cyril Hrubis
2021-05-10  7:57   ` Petr Vorel
2021-05-05  8:18 ` [LTP] [PATCH v3 4/6] Add rtnetlink helper library Martin Doucha
2021-05-05 10:17   ` Petr Vorel
2021-05-05 10:25     ` Martin Doucha
2021-05-05 11:24       ` Petr Vorel
2021-05-05 11:26   ` Petr Vorel
2021-05-05 12:16     ` Cyril Hrubis
2021-05-05 20:20       ` Petr Vorel
2021-05-05 13:15     ` Martin Doucha
2021-05-05 20:24       ` Petr Vorel
2021-05-05 12:14   ` Cyril Hrubis
2021-05-10  9:07   ` Petr Vorel
2021-05-05  8:18 ` [LTP] [PATCH v3 5/6] Add helper functions for managing network interfaces Martin Doucha
2021-05-05 12:39   ` Cyril Hrubis
2021-05-05  8:18 ` [LTP] [PATCH v3 6/6] Add test for CVE 2020-25705 Martin Doucha
2021-05-05 10:04   ` Petr Vorel [this message]
2021-05-05 10:33     ` Martin Doucha
2021-05-05 11:13       ` Petr Vorel
2021-05-05 13:06   ` Cyril Hrubis
2021-05-05 15:54     ` Martin Doucha
2021-05-10  7:42 ` [LTP] [PATCH v3 1/6] Add SAFE_REALLOC() helper function to LTP library Petr Vorel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=YJJtpXWM4BxH2ffu@pevik \
    --to=pvorel@suse.cz \
    --cc=ltp@lists.linux.it \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.