xref: /openbmc/linux/net/ipv4/ip_options.c (revision 0c6dfa75)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * INET		An implementation of the TCP/IP protocol suite for the LINUX
4  *		operating system.  INET is implemented using the  BSD Socket
5  *		interface as the means of communication with the user level.
6  *
7  *		The options processing module for ip.c
8  *
9  * Authors:	A.N.Kuznetsov
10  *
11  */
12 
13 #define pr_fmt(fmt) "IPv4: " fmt
14 
15 #include <linux/capability.h>
16 #include <linux/module.h>
17 #include <linux/slab.h>
18 #include <linux/types.h>
19 #include <linux/uaccess.h>
20 #include <asm/unaligned.h>
21 #include <linux/skbuff.h>
22 #include <linux/ip.h>
23 #include <linux/icmp.h>
24 #include <linux/netdevice.h>
25 #include <linux/rtnetlink.h>
26 #include <net/sock.h>
27 #include <net/ip.h>
28 #include <net/icmp.h>
29 #include <net/route.h>
30 #include <net/cipso_ipv4.h>
31 #include <net/ip_fib.h>
32 
33 /*
34  * Write options to IP header, record destination address to
35  * source route option, address of outgoing interface
36  * (we should already know it, so that this  function is allowed be
37  * called only after routing decision) and timestamp,
38  * if we originate this datagram.
39  *
40  * daddr is real destination address, next hop is recorded in IP header.
41  * saddr is address of outgoing interface.
42  */
43 
44 void ip_options_build(struct sk_buff *skb, struct ip_options *opt,
45 		      __be32 daddr, struct rtable *rt)
46 {
47 	unsigned char *iph = skb_network_header(skb);
48 
49 	memcpy(&(IPCB(skb)->opt), opt, sizeof(struct ip_options));
50 	memcpy(iph + sizeof(struct iphdr), opt->__data, opt->optlen);
51 	opt = &(IPCB(skb)->opt);
52 
53 	if (opt->srr)
54 		memcpy(iph + opt->srr + iph[opt->srr + 1] - 4, &daddr, 4);
55 
56 	if (opt->rr_needaddr)
57 		ip_rt_get_source(iph + opt->rr + iph[opt->rr + 2] - 5, skb, rt);
58 	if (opt->ts_needaddr)
59 		ip_rt_get_source(iph + opt->ts + iph[opt->ts + 2] - 9, skb, rt);
60 	if (opt->ts_needtime) {
61 		__be32 midtime;
62 
63 		midtime = inet_current_timestamp();
64 		memcpy(iph + opt->ts + iph[opt->ts + 2] - 5, &midtime, 4);
65 	}
66 }
67 
68 /*
69  * Provided (sopt, skb) points to received options,
70  * build in dopt compiled option set appropriate for answering.
71  * i.e. invert SRR option, copy anothers,
72  * and grab room in RR/TS options.
73  *
74  * NOTE: dopt cannot point to skb.
75  */
76 
77 int __ip_options_echo(struct net *net, struct ip_options *dopt,
78 		      struct sk_buff *skb, const struct ip_options *sopt)
79 {
80 	unsigned char *sptr, *dptr;
81 	int soffset, doffset;
82 	int	optlen;
83 
84 	memset(dopt, 0, sizeof(struct ip_options));
85 
86 	if (sopt->optlen == 0)
87 		return 0;
88 
89 	sptr = skb_network_header(skb);
90 	dptr = dopt->__data;
91 
92 	if (sopt->rr) {
93 		optlen  = sptr[sopt->rr+1];
94 		soffset = sptr[sopt->rr+2];
95 		dopt->rr = dopt->optlen + sizeof(struct iphdr);
96 		memcpy(dptr, sptr+sopt->rr, optlen);
97 		if (sopt->rr_needaddr && soffset <= optlen) {
98 			if (soffset + 3 > optlen)
99 				return -EINVAL;
100 			dptr[2] = soffset + 4;
101 			dopt->rr_needaddr = 1;
102 		}
103 		dptr += optlen;
104 		dopt->optlen += optlen;
105 	}
106 	if (sopt->ts) {
107 		optlen = sptr[sopt->ts+1];
108 		soffset = sptr[sopt->ts+2];
109 		dopt->ts = dopt->optlen + sizeof(struct iphdr);
110 		memcpy(dptr, sptr+sopt->ts, optlen);
111 		if (soffset <= optlen) {
112 			if (sopt->ts_needaddr) {
113 				if (soffset + 3 > optlen)
114 					return -EINVAL;
115 				dopt->ts_needaddr = 1;
116 				soffset += 4;
117 			}
118 			if (sopt->ts_needtime) {
119 				if (soffset + 3 > optlen)
120 					return -EINVAL;
121 				if ((dptr[3]&0xF) != IPOPT_TS_PRESPEC) {
122 					dopt->ts_needtime = 1;
123 					soffset += 4;
124 				} else {
125 					dopt->ts_needtime = 0;
126 
127 					if (soffset + 7 <= optlen) {
128 						__be32 addr;
129 
130 						memcpy(&addr, dptr+soffset-1, 4);
131 						if (inet_addr_type(net, addr) != RTN_UNICAST) {
132 							dopt->ts_needtime = 1;
133 							soffset += 8;
134 						}
135 					}
136 				}
137 			}
138 			dptr[2] = soffset;
139 		}
140 		dptr += optlen;
141 		dopt->optlen += optlen;
142 	}
143 	if (sopt->srr) {
144 		unsigned char *start = sptr+sopt->srr;
145 		__be32 faddr;
146 
147 		optlen  = start[1];
148 		soffset = start[2];
149 		doffset = 0;
150 		if (soffset > optlen)
151 			soffset = optlen + 1;
152 		soffset -= 4;
153 		if (soffset > 3) {
154 			memcpy(&faddr, &start[soffset-1], 4);
155 			for (soffset -= 4, doffset = 4; soffset > 3; soffset -= 4, doffset += 4)
156 				memcpy(&dptr[doffset-1], &start[soffset-1], 4);
157 			/*
158 			 * RFC1812 requires to fix illegal source routes.
159 			 */
160 			if (memcmp(&ip_hdr(skb)->saddr,
161 				   &start[soffset + 3], 4) == 0)
162 				doffset -= 4;
163 		}
164 		if (doffset > 3) {
165 			dopt->faddr = faddr;
166 			dptr[0] = start[0];
167 			dptr[1] = doffset+3;
168 			dptr[2] = 4;
169 			dptr += doffset+3;
170 			dopt->srr = dopt->optlen + sizeof(struct iphdr);
171 			dopt->optlen += doffset+3;
172 			dopt->is_strictroute = sopt->is_strictroute;
173 		}
174 	}
175 	if (sopt->cipso) {
176 		optlen  = sptr[sopt->cipso+1];
177 		dopt->cipso = dopt->optlen+sizeof(struct iphdr);
178 		memcpy(dptr, sptr+sopt->cipso, optlen);
179 		dptr += optlen;
180 		dopt->optlen += optlen;
181 	}
182 	while (dopt->optlen & 3) {
183 		*dptr++ = IPOPT_END;
184 		dopt->optlen++;
185 	}
186 	return 0;
187 }
188 
189 /*
190  *	Options "fragmenting", just fill options not
191  *	allowed in fragments with NOOPs.
192  *	Simple and stupid 8), but the most efficient way.
193  */
194 
195 void ip_options_fragment(struct sk_buff *skb)
196 {
197 	unsigned char *optptr = skb_network_header(skb) + sizeof(struct iphdr);
198 	struct ip_options *opt = &(IPCB(skb)->opt);
199 	int  l = opt->optlen;
200 	int  optlen;
201 
202 	while (l > 0) {
203 		switch (*optptr) {
204 		case IPOPT_END:
205 			return;
206 		case IPOPT_NOOP:
207 			l--;
208 			optptr++;
209 			continue;
210 		}
211 		optlen = optptr[1];
212 		if (optlen < 2 || optlen > l)
213 		  return;
214 		if (!IPOPT_COPIED(*optptr))
215 			memset(optptr, IPOPT_NOOP, optlen);
216 		l -= optlen;
217 		optptr += optlen;
218 	}
219 	opt->ts = 0;
220 	opt->rr = 0;
221 	opt->rr_needaddr = 0;
222 	opt->ts_needaddr = 0;
223 	opt->ts_needtime = 0;
224 }
225 
226 /* helper used by ip_options_compile() to call fib_compute_spec_dst()
227  * at most one time.
228  */
229 static void spec_dst_fill(__be32 *spec_dst, struct sk_buff *skb)
230 {
231 	if (*spec_dst == htonl(INADDR_ANY))
232 		*spec_dst = fib_compute_spec_dst(skb);
233 }
234 
235 /*
236  * Verify options and fill pointers in struct options.
237  * Caller should clear *opt, and set opt->data.
238  * If opt == NULL, then skb->data should point to IP header.
239  */
240 
241 int __ip_options_compile(struct net *net,
242 			 struct ip_options *opt, struct sk_buff *skb,
243 			 __be32 *info)
244 {
245 	__be32 spec_dst = htonl(INADDR_ANY);
246 	unsigned char *pp_ptr = NULL;
247 	struct rtable *rt = NULL;
248 	unsigned char *optptr;
249 	unsigned char *iph;
250 	int optlen, l;
251 
252 	if (skb) {
253 		rt = skb_rtable(skb);
254 		optptr = (unsigned char *)&(ip_hdr(skb)[1]);
255 	} else
256 		optptr = opt->__data;
257 	iph = optptr - sizeof(struct iphdr);
258 
259 	for (l = opt->optlen; l > 0; ) {
260 		switch (*optptr) {
261 		case IPOPT_END:
262 			for (optptr++, l--; l > 0; optptr++, l--) {
263 				if (*optptr != IPOPT_END) {
264 					*optptr = IPOPT_END;
265 					opt->is_changed = 1;
266 				}
267 			}
268 			goto eol;
269 		case IPOPT_NOOP:
270 			l--;
271 			optptr++;
272 			continue;
273 		}
274 		if (unlikely(l < 2)) {
275 			pp_ptr = optptr;
276 			goto error;
277 		}
278 		optlen = optptr[1];
279 		if (optlen < 2 || optlen > l) {
280 			pp_ptr = optptr;
281 			goto error;
282 		}
283 		switch (*optptr) {
284 		case IPOPT_SSRR:
285 		case IPOPT_LSRR:
286 			if (optlen < 3) {
287 				pp_ptr = optptr + 1;
288 				goto error;
289 			}
290 			if (optptr[2] < 4) {
291 				pp_ptr = optptr + 2;
292 				goto error;
293 			}
294 			/* NB: cf RFC-1812 5.2.4.1 */
295 			if (opt->srr) {
296 				pp_ptr = optptr;
297 				goto error;
298 			}
299 			if (!skb) {
300 				if (optptr[2] != 4 || optlen < 7 || ((optlen-3) & 3)) {
301 					pp_ptr = optptr + 1;
302 					goto error;
303 				}
304 				memcpy(&opt->faddr, &optptr[3], 4);
305 				if (optlen > 7)
306 					memmove(&optptr[3], &optptr[7], optlen-7);
307 			}
308 			opt->is_strictroute = (optptr[0] == IPOPT_SSRR);
309 			opt->srr = optptr - iph;
310 			break;
311 		case IPOPT_RR:
312 			if (opt->rr) {
313 				pp_ptr = optptr;
314 				goto error;
315 			}
316 			if (optlen < 3) {
317 				pp_ptr = optptr + 1;
318 				goto error;
319 			}
320 			if (optptr[2] < 4) {
321 				pp_ptr = optptr + 2;
322 				goto error;
323 			}
324 			if (optptr[2] <= optlen) {
325 				if (optptr[2]+3 > optlen) {
326 					pp_ptr = optptr + 2;
327 					goto error;
328 				}
329 				if (rt) {
330 					spec_dst_fill(&spec_dst, skb);
331 					memcpy(&optptr[optptr[2]-1], &spec_dst, 4);
332 					opt->is_changed = 1;
333 				}
334 				optptr[2] += 4;
335 				opt->rr_needaddr = 1;
336 			}
337 			opt->rr = optptr - iph;
338 			break;
339 		case IPOPT_TIMESTAMP:
340 			if (opt->ts) {
341 				pp_ptr = optptr;
342 				goto error;
343 			}
344 			if (optlen < 4) {
345 				pp_ptr = optptr + 1;
346 				goto error;
347 			}
348 			if (optptr[2] < 5) {
349 				pp_ptr = optptr + 2;
350 				goto error;
351 			}
352 			if (optptr[2] <= optlen) {
353 				unsigned char *timeptr = NULL;
354 				if (optptr[2]+3 > optlen) {
355 					pp_ptr = optptr + 2;
356 					goto error;
357 				}
358 				switch (optptr[3]&0xF) {
359 				case IPOPT_TS_TSONLY:
360 					if (skb)
361 						timeptr = &optptr[optptr[2]-1];
362 					opt->ts_needtime = 1;
363 					optptr[2] += 4;
364 					break;
365 				case IPOPT_TS_TSANDADDR:
366 					if (optptr[2]+7 > optlen) {
367 						pp_ptr = optptr + 2;
368 						goto error;
369 					}
370 					if (rt)  {
371 						spec_dst_fill(&spec_dst, skb);
372 						memcpy(&optptr[optptr[2]-1], &spec_dst, 4);
373 						timeptr = &optptr[optptr[2]+3];
374 					}
375 					opt->ts_needaddr = 1;
376 					opt->ts_needtime = 1;
377 					optptr[2] += 8;
378 					break;
379 				case IPOPT_TS_PRESPEC:
380 					if (optptr[2]+7 > optlen) {
381 						pp_ptr = optptr + 2;
382 						goto error;
383 					}
384 					{
385 						__be32 addr;
386 						memcpy(&addr, &optptr[optptr[2]-1], 4);
387 						if (inet_addr_type(net, addr) == RTN_UNICAST)
388 							break;
389 						if (skb)
390 							timeptr = &optptr[optptr[2]+3];
391 					}
392 					opt->ts_needtime = 1;
393 					optptr[2] += 8;
394 					break;
395 				default:
396 					if (!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) {
397 						pp_ptr = optptr + 3;
398 						goto error;
399 					}
400 					break;
401 				}
402 				if (timeptr) {
403 					__be32 midtime;
404 
405 					midtime = inet_current_timestamp();
406 					memcpy(timeptr, &midtime, 4);
407 					opt->is_changed = 1;
408 				}
409 			} else if ((optptr[3]&0xF) != IPOPT_TS_PRESPEC) {
410 				unsigned int overflow = optptr[3]>>4;
411 				if (overflow == 15) {
412 					pp_ptr = optptr + 3;
413 					goto error;
414 				}
415 				if (skb) {
416 					optptr[3] = (optptr[3]&0xF)|((overflow+1)<<4);
417 					opt->is_changed = 1;
418 				}
419 			}
420 			opt->ts = optptr - iph;
421 			break;
422 		case IPOPT_RA:
423 			if (optlen < 4) {
424 				pp_ptr = optptr + 1;
425 				goto error;
426 			}
427 			if (optptr[2] == 0 && optptr[3] == 0)
428 				opt->router_alert = optptr - iph;
429 			break;
430 		case IPOPT_CIPSO:
431 			if ((!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) || opt->cipso) {
432 				pp_ptr = optptr;
433 				goto error;
434 			}
435 			opt->cipso = optptr - iph;
436 			if (cipso_v4_validate(skb, &optptr)) {
437 				pp_ptr = optptr;
438 				goto error;
439 			}
440 			break;
441 		case IPOPT_SEC:
442 		case IPOPT_SID:
443 		default:
444 			if (!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) {
445 				pp_ptr = optptr;
446 				goto error;
447 			}
448 			break;
449 		}
450 		l -= optlen;
451 		optptr += optlen;
452 	}
453 
454 eol:
455 	if (!pp_ptr)
456 		return 0;
457 
458 error:
459 	if (info)
460 		*info = htonl((pp_ptr-iph)<<24);
461 	return -EINVAL;
462 }
463 EXPORT_SYMBOL(__ip_options_compile);
464 
465 int ip_options_compile(struct net *net,
466 		       struct ip_options *opt, struct sk_buff *skb)
467 {
468 	int ret;
469 	__be32 info;
470 
471 	ret = __ip_options_compile(net, opt, skb, &info);
472 	if (ret != 0 && skb)
473 		icmp_send(skb, ICMP_PARAMETERPROB, 0, info);
474 	return ret;
475 }
476 EXPORT_SYMBOL(ip_options_compile);
477 
478 /*
479  *	Undo all the changes done by ip_options_compile().
480  */
481 
482 void ip_options_undo(struct ip_options *opt)
483 {
484 	if (opt->srr) {
485 		unsigned char *optptr = opt->__data + opt->srr - sizeof(struct iphdr);
486 
487 		memmove(optptr + 7, optptr + 3, optptr[1] - 7);
488 		memcpy(optptr + 3, &opt->faddr, 4);
489 	}
490 	if (opt->rr_needaddr) {
491 		unsigned char *optptr = opt->__data + opt->rr - sizeof(struct iphdr);
492 
493 		optptr[2] -= 4;
494 		memset(&optptr[optptr[2] - 1], 0, 4);
495 	}
496 	if (opt->ts) {
497 		unsigned char *optptr = opt->__data + opt->ts - sizeof(struct iphdr);
498 
499 		if (opt->ts_needtime) {
500 			optptr[2] -= 4;
501 			memset(&optptr[optptr[2] - 1], 0, 4);
502 			if ((optptr[3] & 0xF) == IPOPT_TS_PRESPEC)
503 				optptr[2] -= 4;
504 		}
505 		if (opt->ts_needaddr) {
506 			optptr[2] -= 4;
507 			memset(&optptr[optptr[2] - 1], 0, 4);
508 		}
509 	}
510 }
511 
512 int ip_options_get(struct net *net, struct ip_options_rcu **optp,
513 		   sockptr_t data, int optlen)
514 {
515 	struct ip_options_rcu *opt;
516 
517 	opt = kzalloc(sizeof(struct ip_options_rcu) + ((optlen + 3) & ~3),
518 		       GFP_KERNEL);
519 	if (!opt)
520 		return -ENOMEM;
521 	if (optlen && copy_from_sockptr(opt->opt.__data, data, optlen)) {
522 		kfree(opt);
523 		return -EFAULT;
524 	}
525 
526 	while (optlen & 3)
527 		opt->opt.__data[optlen++] = IPOPT_END;
528 	opt->opt.optlen = optlen;
529 	if (optlen && ip_options_compile(net, &opt->opt, NULL)) {
530 		kfree(opt);
531 		return -EINVAL;
532 	}
533 	kfree(*optp);
534 	*optp = opt;
535 	return 0;
536 }
537 
538 void ip_forward_options(struct sk_buff *skb)
539 {
540 	struct   ip_options *opt	= &(IPCB(skb)->opt);
541 	unsigned char *optptr;
542 	struct rtable *rt = skb_rtable(skb);
543 	unsigned char *raw = skb_network_header(skb);
544 
545 	if (opt->rr_needaddr) {
546 		optptr = (unsigned char *)raw + opt->rr;
547 		ip_rt_get_source(&optptr[optptr[2]-5], skb, rt);
548 		opt->is_changed = 1;
549 	}
550 	if (opt->srr_is_hit) {
551 		int srrptr, srrspace;
552 
553 		optptr = raw + opt->srr;
554 
555 		for ( srrptr = optptr[2], srrspace = optptr[1];
556 		     srrptr <= srrspace;
557 		     srrptr += 4
558 		     ) {
559 			if (srrptr + 3 > srrspace)
560 				break;
561 			if (memcmp(&opt->nexthop, &optptr[srrptr-1], 4) == 0)
562 				break;
563 		}
564 		if (srrptr + 3 <= srrspace) {
565 			opt->is_changed = 1;
566 			ip_hdr(skb)->daddr = opt->nexthop;
567 			ip_rt_get_source(&optptr[srrptr-1], skb, rt);
568 			optptr[2] = srrptr+4;
569 		} else {
570 			net_crit_ratelimited("%s(): Argh! Destination lost!\n",
571 					     __func__);
572 		}
573 		if (opt->ts_needaddr) {
574 			optptr = raw + opt->ts;
575 			ip_rt_get_source(&optptr[optptr[2]-9], skb, rt);
576 			opt->is_changed = 1;
577 		}
578 	}
579 	if (opt->is_changed) {
580 		opt->is_changed = 0;
581 		ip_send_check(ip_hdr(skb));
582 	}
583 }
584 
585 int ip_options_rcv_srr(struct sk_buff *skb, struct net_device *dev)
586 {
587 	struct ip_options *opt = &(IPCB(skb)->opt);
588 	int srrspace, srrptr;
589 	__be32 nexthop;
590 	struct iphdr *iph = ip_hdr(skb);
591 	unsigned char *optptr = skb_network_header(skb) + opt->srr;
592 	struct rtable *rt = skb_rtable(skb);
593 	struct rtable *rt2;
594 	unsigned long orefdst;
595 	int err;
596 
597 	if (!rt)
598 		return 0;
599 
600 	if (skb->pkt_type != PACKET_HOST)
601 		return -EINVAL;
602 	if (rt->rt_type == RTN_UNICAST) {
603 		if (!opt->is_strictroute)
604 			return 0;
605 		icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl(16<<24));
606 		return -EINVAL;
607 	}
608 	if (rt->rt_type != RTN_LOCAL)
609 		return -EINVAL;
610 
611 	for (srrptr = optptr[2], srrspace = optptr[1]; srrptr <= srrspace; srrptr += 4) {
612 		if (srrptr + 3 > srrspace) {
613 			icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl((opt->srr+2)<<24));
614 			return -EINVAL;
615 		}
616 		memcpy(&nexthop, &optptr[srrptr-1], 4);
617 
618 		orefdst = skb->_skb_refdst;
619 		skb_dst_set(skb, NULL);
620 		err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, dev);
621 		rt2 = skb_rtable(skb);
622 		if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) {
623 			skb_dst_drop(skb);
624 			skb->_skb_refdst = orefdst;
625 			return -EINVAL;
626 		}
627 		refdst_drop(orefdst);
628 		if (rt2->rt_type != RTN_LOCAL)
629 			break;
630 		/* Superfast 8) loopback forward */
631 		iph->daddr = nexthop;
632 		opt->is_changed = 1;
633 	}
634 	if (srrptr <= srrspace) {
635 		opt->srr_is_hit = 1;
636 		opt->nexthop = nexthop;
637 		opt->is_changed = 1;
638 	}
639 	return 0;
640 }
641 EXPORT_SYMBOL(ip_options_rcv_srr);
642