• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2020 SUSE LLC
4  * Author: Nicolai Stange <nstange@suse.de>
5  * LTP port: Martin Doucha <mdoucha@suse.cz>
6  */
7 
8 /*\
9  * CVE-2020-25705
10  *
11  * Test of ICMP rate limiting behavior that may be abused for DNS cache
12  * poisoning attack. Send a few batches of 100 packets to a closed UDP port
13  * and count the ICMP errors. If the number of errors is always the same
14  * for each batch (not randomized), the system is vulnerable. Send packets
15  * from multiple IP addresses to bypass per-address ICMP throttling.
16  *
17  * Fixed in:
18  *
19  *  commit b38e7819cae946e2edf869e604af1e65a5d241c5
20  *  Author: Eric Dumazet <edumazet@google.com>
21  *  Date:   Thu Oct 15 11:42:00 2020 -0700
22  *
23  *  icmp: randomize the global rate limiter
24  */
25 
26 #include <time.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30 #include <linux/errqueue.h>
31 
32 #include <sched.h>
33 #include <limits.h>
34 
35 #include "lapi/if_addr.h"
36 #include "tst_test.h"
37 #include "tst_netdevice.h"
38 
39 #define DSTNET 0xfa444e00 /* 250.68.78.0 */
40 #define SRCNET 0xfa444e40 /* 250.68.78.64 */
41 #define DSTADDR 0xfa444e02 /* 250.68.78.2 */
42 #define SRCADDR_BASE 0xfa444e41 /* 250.68.78.65 */
43 #define SRCADDR_COUNT 50
44 #define NETMASK 26
45 #define BATCH_COUNT 8
46 #define BUFSIZE 1024
47 
48 static int parentns = -1, childns = -1;
49 static int fds[SRCADDR_COUNT];
50 
setup(void)51 static void setup(void)
52 {
53 	struct sockaddr_in ipaddr = { .sin_family = AF_INET };
54 	uint32_t addr;
55 	int i;
56 	int real_uid = getuid();
57 	int real_gid = getgid();
58 
59 	for (i = 0; i < SRCADDR_COUNT; i++)
60 		fds[i] = -1;
61 
62 	SAFE_TRY_FILE_PRINTF("/proc/sys/user/max_user_namespaces", "%d", 10);
63 
64 	SAFE_UNSHARE(CLONE_NEWUSER);
65 	SAFE_UNSHARE(CLONE_NEWNET);
66 	SAFE_FILE_PRINTF("/proc/self/setgroups", "deny");
67 	SAFE_FILE_PRINTF("/proc/self/uid_map", "0 %d 1\n", real_uid);
68 	SAFE_FILE_PRINTF("/proc/self/gid_map", "0 %d 1\n", real_gid);
69 
70 	/*
71 	 * Create network namespace to hide the destination interface from
72 	 * the test process.
73 	 */
74 	parentns = SAFE_OPEN("/proc/self/ns/net", O_RDONLY);
75 	SAFE_UNSHARE(CLONE_NEWNET);
76 
77 	/* Do NOT close this FD, or both interfaces will be destroyed */
78 	childns = SAFE_OPEN("/proc/self/ns/net", O_RDONLY);
79 
80 	/* Configure child namespace */
81 	CREATE_VETH_PAIR("ltp_veth1", "ltp_veth2");
82 	NETDEV_ADD_ADDRESS_INET("ltp_veth2", htonl(DSTADDR), NETMASK,
83 		IFA_F_NOPREFIXROUTE);
84 	NETDEV_SET_STATE("ltp_veth2", 1);
85 	NETDEV_ADD_ROUTE_INET("ltp_veth2", 0, 0, htonl(SRCNET), NETMASK, 0);
86 
87 	/* Configure parent namespace */
88 	NETDEV_CHANGE_NS_FD("ltp_veth1", parentns);
89 	SAFE_SETNS(parentns, CLONE_NEWNET);
90 	addr = SRCADDR_BASE;
91 
92 	for (i = 0; i < SRCADDR_COUNT; i++, addr++) {
93 		NETDEV_ADD_ADDRESS_INET("ltp_veth1", htonl(addr), NETMASK,
94 			IFA_F_NOPREFIXROUTE);
95 	}
96 
97 	NETDEV_SET_STATE("ltp_veth1", 1);
98 	NETDEV_ADD_ROUTE_INET("ltp_veth1", 0, 0, htonl(DSTNET), NETMASK, 0);
99 	SAFE_FILE_PRINTF("/proc/sys/net/ipv4/conf/ltp_veth1/forwarding", "1");
100 
101 	/* Open test sockets */
102 	for (i = 0; i < SRCADDR_COUNT; i++) {
103 		ipaddr.sin_addr.s_addr = htonl(SRCADDR_BASE + i);
104 		fds[i] = SAFE_SOCKET(AF_INET, SOCK_DGRAM, 0);
105 		SAFE_SETSOCKOPT_INT(fds[i], IPPROTO_IP, IP_RECVERR, 1);
106 		SAFE_BIND(fds[i], (struct sockaddr *)&ipaddr, sizeof(ipaddr));
107 	}
108 }
109 
count_icmp_errors(int fd)110 static int count_icmp_errors(int fd)
111 {
112 	int error_count = 0;
113 	ssize_t len;
114 	char msgbuf[BUFSIZE], errbuf[BUFSIZE];
115 	struct sockaddr_in addr;
116 	struct cmsghdr *cmsg;
117 	struct sock_extended_err exterr;
118 	struct iovec iov = {
119 		.iov_base = msgbuf,
120 		.iov_len = BUFSIZE
121 	};
122 
123 	while (1) {
124 		struct msghdr msg = {
125 			.msg_name = (struct sockaddr *)&addr,
126 			.msg_namelen = sizeof(addr),
127 			.msg_iov = &iov,
128 			.msg_iovlen = 1,
129 			.msg_flags = 0,
130 			.msg_control = errbuf,
131 			.msg_controllen = BUFSIZE
132 		};
133 
134 		memset(errbuf, 0, BUFSIZE);
135 		errno = 0;
136 		len = recvmsg(fd, &msg, MSG_ERRQUEUE);
137 
138 		if (len == -1) {
139 			if (errno == EWOULDBLOCK || errno == EAGAIN)
140 				break;
141 
142 			tst_brk(TBROK | TERRNO, "recvmsg() failed");
143 		}
144 
145 		if (len < 0) {
146 			tst_brk(TBROK | TERRNO,
147 				"Invalid recvmsg() return value %zd", len);
148 		}
149 
150 		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
151 			cmsg = CMSG_NXTHDR(&msg, cmsg)) {
152 			if (cmsg->cmsg_level != SOL_IP)
153 				continue;
154 
155 			if (cmsg->cmsg_type != IP_RECVERR)
156 				continue;
157 
158 			memcpy(&exterr, CMSG_DATA(cmsg), sizeof(exterr));
159 
160 			if (exterr.ee_origin != SO_EE_ORIGIN_ICMP)
161 				tst_brk(TBROK, "Unexpected non-ICMP error");
162 
163 			if (exterr.ee_errno != ECONNREFUSED) {
164 				TST_ERR = exterr.ee_errno;
165 				tst_brk(TBROK | TTERRNO,
166 					"Unexpected ICMP error");
167 			}
168 
169 			error_count++;
170 		}
171 	}
172 
173 	return error_count;
174 }
175 
packet_batch(const struct sockaddr * addr,socklen_t addrsize)176 static int packet_batch(const struct sockaddr *addr, socklen_t addrsize)
177 {
178 	int i, j, error_count = 0;
179 	char data = 0;
180 
181 	for (i = 0; i < SRCADDR_COUNT; i++) {
182 		for (j = 0; j < 2; j++) {
183 			error_count += count_icmp_errors(fds[i]);
184 			TEST(sendto(fds[i], &data, sizeof(data), 0, addr,
185 				addrsize));
186 
187 			if (TST_RET == -1) {
188 				if (TST_ERR == ECONNREFUSED) {
189 					j--; /* flush ICMP errors and retry */
190 					continue;
191 				}
192 
193 				tst_brk(TBROK | TTERRNO, "sento() failed");
194 			}
195 
196 			if (TST_RET < 0) {
197 				tst_brk(TBROK | TTERRNO,
198 					"Invalid sento() return value %ld",
199 					TST_RET);
200 			}
201 		}
202 	}
203 
204 	/*
205 	 * Wait and collect pending ICMP errors. Waiting less than 2 seconds
206 	 * will make the test unreliable. Looping over each socket multiple
207 	 * times (with or without poll()) will cause kernel to silently
208 	 * discard ICMP errors, allowing the test to pass on vulnerable
209 	 * systems.
210 	 */
211 	sleep(2);
212 
213 	for (i = 0; i < SRCADDR_COUNT; i++)
214 		error_count += count_icmp_errors(fds[i]);
215 
216 	return error_count;
217 }
218 
run(void)219 static void run(void)
220 {
221 	int i, errors_baseline, errors;
222 	struct sockaddr_in addr = {
223 		.sin_family = AF_INET,
224 		.sin_port = TST_GET_UNUSED_PORT(AF_INET, SOCK_DGRAM),
225 		.sin_addr = { htonl(DSTADDR) }
226 	};
227 
228 	errors_baseline = packet_batch((struct sockaddr *)&addr, sizeof(addr));
229 	errors = errors_baseline;
230 	tst_res(TINFO, "Batch 0: Got %d ICMP errors", errors);
231 
232 	for (i = 1; i < BATCH_COUNT && errors == errors_baseline; i++) {
233 		errors = packet_batch((struct sockaddr *)&addr, sizeof(addr));
234 		tst_res(TINFO, "Batch %d: Got %d ICMP errors", i, errors);
235 	}
236 
237 	if (errors == errors_baseline) {
238 		tst_res(TFAIL,
239 			"ICMP rate limit not randomized, system is vulnerable");
240 		return;
241 	}
242 
243 	tst_res(TPASS, "ICMP rate limit is randomized");
244 }
245 
cleanup(void)246 static void cleanup(void)
247 {
248 	int i;
249 
250 	for (i = 0; i < SRCADDR_COUNT; i++)
251 		if (fds[i] >= 0)
252 			SAFE_CLOSE(fds[i]);
253 
254 	if (childns >= 0)
255 		SAFE_CLOSE(childns);
256 
257 	if (parentns >= 0)
258 		SAFE_CLOSE(parentns);
259 }
260 
261 static struct tst_test test = {
262 	.test_all = run,
263 	.setup = setup,
264 	.cleanup = cleanup,
265 	.needs_kconfigs = (const char *[]) {
266 		"CONFIG_VETH",
267 		"CONFIG_USER_NS=y",
268 		"CONFIG_NET_NS=y",
269 		NULL
270 	},
271 	.save_restore = (const char * const[]) {
272 		"?/proc/sys/user/max_user_namespaces",
273 		NULL,
274 	},
275 	.tags = (const struct tst_tag[]) {
276 		{"linux-git", "b38e7819cae9"},
277 		{"CVE", "2020-25705"},
278 		{}
279 	}
280 };
281