Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 46 additions & 8 deletions net/ipv6/datagram.c
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,18 @@ void ip6_datagram_recv_common_ctl(struct sock *sk, struct msghdr *msg,
}
}

static u16 ipv6_get_exthdr_len(const struct sk_buff *skb, const u8 *ptr)
{
u16 len;

if (ptr + 2 > skb_tail_pointer(skb))
return 0;

len = (ptr[1] + 1) << 3;

return (len <= skb_tail_pointer(skb) - ptr) ? len : 0;
}

void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg,
struct sk_buff *skb)
{
Expand All @@ -625,7 +637,10 @@ void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg,
/* HbH is allowed only once */
if (np->rxopt.bits.hopopts && (opt->flags & IP6SKB_HOPBYHOP)) {
u8 *ptr = nh + sizeof(struct ipv6hdr);
put_cmsg(msg, SOL_IPV6, IPV6_HOPOPTS, (ptr[1]+1)<<3, ptr);
u16 len = ipv6_get_exthdr_len(skb, ptr);

if (len)
put_cmsg(msg, SOL_IPV6, IPV6_HOPOPTS, len, ptr);
}

if (opt->lastopt &&
Expand All @@ -646,26 +661,37 @@ void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg,
unsigned int len;
u8 *ptr = nh + off;

if (ptr + 2 > skb_tail_pointer(skb))
return;

switch (nexthdr) {
case IPPROTO_DSTOPTS:
nexthdr = ptr[0];
len = (ptr[1] + 1) << 3;
len = ipv6_get_exthdr_len(skb, ptr);
if (!len)
return;
if (np->rxopt.bits.dstopts)
put_cmsg(msg, SOL_IPV6, IPV6_DSTOPTS, len, ptr);
break;
case IPPROTO_ROUTING:
nexthdr = ptr[0];
len = (ptr[1] + 1) << 3;
len = ipv6_get_exthdr_len(skb, ptr);
if (!len)
return;
if (np->rxopt.bits.srcrt)
put_cmsg(msg, SOL_IPV6, IPV6_RTHDR, len, ptr);
break;
case IPPROTO_AH:
nexthdr = ptr[0];
len = (ptr[1] + 2) << 2;
if (ptr + len > skb_tail_pointer(skb))
return;
break;
default:
nexthdr = ptr[0];
len = (ptr[1] + 1) << 3;
len = ipv6_get_exthdr_len(skb, ptr);
if (!len)
return;
break;
}

Expand All @@ -687,19 +713,31 @@ void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg,
}
if (np->rxopt.bits.ohopopts && (opt->flags & IP6SKB_HOPBYHOP)) {
u8 *ptr = nh + sizeof(struct ipv6hdr);
put_cmsg(msg, SOL_IPV6, IPV6_2292HOPOPTS, (ptr[1]+1)<<3, ptr);
u16 len = ipv6_get_exthdr_len(skb, ptr);

if (len)
put_cmsg(msg, SOL_IPV6, IPV6_2292HOPOPTS, len, ptr);
}
if (np->rxopt.bits.odstopts && opt->dst0) {
u8 *ptr = nh + opt->dst0;
put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr);
u16 len = ipv6_get_exthdr_len(skb, ptr);

if (len)
put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, len, ptr);
}
if (np->rxopt.bits.osrcrt && opt->srcrt) {
struct ipv6_rt_hdr *rthdr = (struct ipv6_rt_hdr *)(nh + opt->srcrt);
put_cmsg(msg, SOL_IPV6, IPV6_2292RTHDR, (rthdr->hdrlen+1) << 3, rthdr);
u16 len = ipv6_get_exthdr_len(skb, (u8 *)rthdr);

if (len)
put_cmsg(msg, SOL_IPV6, IPV6_2292RTHDR, len, rthdr);
}
if (np->rxopt.bits.odstopts && opt->dst1) {
u8 *ptr = nh + opt->dst1;
put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr);
u16 len = ipv6_get_exthdr_len(skb, ptr);

if (len)
put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, len, ptr);
}
if (np->rxopt.bits.rxorigdstaddr) {
struct sockaddr_in6 sin6;
Expand Down
8 changes: 4 additions & 4 deletions net/netfilter/nfnetlink_cthelper.c
Original file line number Diff line number Diff line change
Expand Up @@ -609,10 +609,10 @@ nfnl_cthelper_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
goto out;
}
}
}
if (cb->args[1]) {
cb->args[1] = 0;
goto restart;
if (cb->args[1]) {
cb->args[1] = 0;
goto restart;
}
}
out:
rcu_read_unlock();
Expand Down
Loading