xref: /openbmc/linux/net/ipv4/ip_options.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
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  
ip_options_build(struct sk_buff * skb,struct ip_options * opt,__be32 daddr,struct rtable * rt)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  
__ip_options_echo(struct net * net,struct ip_options * dopt,struct sk_buff * skb,const struct ip_options * sopt)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  
ip_options_fragment(struct sk_buff * skb)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   */
spec_dst_fill(__be32 * spec_dst,struct sk_buff * skb)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  
__ip_options_compile(struct net * net,struct ip_options * opt,struct sk_buff * skb,__be32 * info)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  
ip_options_compile(struct net * net,struct ip_options * opt,struct sk_buff * skb)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  
ip_options_undo(struct ip_options * opt)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  
ip_options_get(struct net * net,struct ip_options_rcu ** optp,sockptr_t data,int optlen)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  
ip_forward_options(struct sk_buff * skb)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  
ip_options_rcv_srr(struct sk_buff * skb,struct net_device * dev)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