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