mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 10:49:33 +00:00
![Herbert Xu](/assets/img/avatar_default.png)
The SELinux hooks invoke ipv6_skip_exthdr() with an incorrect length final argument. However, the length argument turns out to be superfluous. I was just reading ipv6_skip_exthdr and it occured to me that we can get rid of len altogether. The only place where len is used is to check whether the skb has two bytes for ipv6_opt_hdr. This check is done by skb_header_pointer/skb_copy_bits anyway. Now it might appear that we've made the code slower by deferring the check to skb_copy_bits. However, this check should not trigger in the common case so this is OK. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
106 lines
3.2 KiB
C
106 lines
3.2 KiB
C
/*
|
|
* IPv6 library code, needed by static components when full IPv6 support is
|
|
* not configured or static.
|
|
*/
|
|
#include <net/ipv6.h>
|
|
|
|
/*
|
|
* find out if nexthdr is a well-known extension header or a protocol
|
|
*/
|
|
|
|
int ipv6_ext_hdr(u8 nexthdr)
|
|
{
|
|
/*
|
|
* find out if nexthdr is an extension header or a protocol
|
|
*/
|
|
return ( (nexthdr == NEXTHDR_HOP) ||
|
|
(nexthdr == NEXTHDR_ROUTING) ||
|
|
(nexthdr == NEXTHDR_FRAGMENT) ||
|
|
(nexthdr == NEXTHDR_AUTH) ||
|
|
(nexthdr == NEXTHDR_NONE) ||
|
|
(nexthdr == NEXTHDR_DEST) );
|
|
}
|
|
|
|
/*
|
|
* Skip any extension headers. This is used by the ICMP module.
|
|
*
|
|
* Note that strictly speaking this conflicts with RFC 2460 4.0:
|
|
* ...The contents and semantics of each extension header determine whether
|
|
* or not to proceed to the next header. Therefore, extension headers must
|
|
* be processed strictly in the order they appear in the packet; a
|
|
* receiver must not, for example, scan through a packet looking for a
|
|
* particular kind of extension header and process that header prior to
|
|
* processing all preceding ones.
|
|
*
|
|
* We do exactly this. This is a protocol bug. We can't decide after a
|
|
* seeing an unknown discard-with-error flavour TLV option if it's a
|
|
* ICMP error message or not (errors should never be send in reply to
|
|
* ICMP error messages).
|
|
*
|
|
* But I see no other way to do this. This might need to be reexamined
|
|
* when Linux implements ESP (and maybe AUTH) headers.
|
|
* --AK
|
|
*
|
|
* This function parses (probably truncated) exthdr set "hdr".
|
|
* "nexthdrp" initially points to some place,
|
|
* where type of the first header can be found.
|
|
*
|
|
* It skips all well-known exthdrs, and returns pointer to the start
|
|
* of unparsable area i.e. the first header with unknown type.
|
|
* If it is not NULL *nexthdr is updated by type/protocol of this header.
|
|
*
|
|
* NOTES: - if packet terminated with NEXTHDR_NONE it returns NULL.
|
|
* - it may return pointer pointing beyond end of packet,
|
|
* if the last recognized header is truncated in the middle.
|
|
* - if packet is truncated, so that all parsed headers are skipped,
|
|
* it returns NULL.
|
|
* - First fragment header is skipped, not-first ones
|
|
* are considered as unparsable.
|
|
* - ESP is unparsable for now and considered like
|
|
* normal payload protocol.
|
|
* - Note also special handling of AUTH header. Thanks to IPsec wizards.
|
|
*
|
|
* --ANK (980726)
|
|
*/
|
|
|
|
int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp)
|
|
{
|
|
u8 nexthdr = *nexthdrp;
|
|
|
|
while (ipv6_ext_hdr(nexthdr)) {
|
|
struct ipv6_opt_hdr _hdr, *hp;
|
|
int hdrlen;
|
|
|
|
if (nexthdr == NEXTHDR_NONE)
|
|
return -1;
|
|
hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
|
|
if (hp == NULL)
|
|
return -1;
|
|
if (nexthdr == NEXTHDR_FRAGMENT) {
|
|
unsigned short _frag_off, *fp;
|
|
fp = skb_header_pointer(skb,
|
|
start+offsetof(struct frag_hdr,
|
|
frag_off),
|
|
sizeof(_frag_off),
|
|
&_frag_off);
|
|
if (fp == NULL)
|
|
return -1;
|
|
|
|
if (ntohs(*fp) & ~0x7)
|
|
break;
|
|
hdrlen = 8;
|
|
} else if (nexthdr == NEXTHDR_AUTH)
|
|
hdrlen = (hp->hdrlen+2)<<2;
|
|
else
|
|
hdrlen = ipv6_optlen(hp);
|
|
|
|
nexthdr = hp->nexthdr;
|
|
start += hdrlen;
|
|
}
|
|
|
|
*nexthdrp = nexthdr;
|
|
return start;
|
|
}
|
|
|
|
EXPORT_SYMBOL(ipv6_ext_hdr);
|
|
EXPORT_SYMBOL(ipv6_skip_exthdr);
|