Commit 5af7fb6e authored by Alexander Duyck's avatar Alexander Duyck Committed by David S. Miller

flow-dissector: Fix alignment issue in __skb_flow_get_ports

This patch addresses a kernel unaligned access bug seen on a sparc64 system
with an igb adapter.  Specifically the __skb_flow_get_ports was returning a
be32 pointer which was then having the value directly returned.

In order to prevent this it is actually easier to simply not populate the
ports or address values when an skb is not present.  In this case the
assumption is that the data isn't needed and rather than slow down the
faster aligned accesses by making them have to assume the unaligned path on
architectures that don't support efficent unaligned access it makes more
sense to simply switch off the bits that were copying the source and
destination address/port for the case where we only care about the protocol
types and lengths which are normally 16 bit fields anyway.
Reported-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarAlexander Duyck <alexander.h.duyck@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8ea6e345
...@@ -100,6 +100,13 @@ bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow, ...@@ -100,6 +100,13 @@ bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow,
if (ip_is_fragment(iph)) if (ip_is_fragment(iph))
ip_proto = 0; ip_proto = 0;
/* skip the address processing if skb is NULL. The assumption
* here is that if there is no skb we are not looking for flow
* info but lengths and protocols.
*/
if (!skb)
break;
iph_to_flow_copy_addrs(flow, iph); iph_to_flow_copy_addrs(flow, iph);
break; break;
} }
...@@ -114,17 +121,15 @@ bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow, ...@@ -114,17 +121,15 @@ bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow,
return false; return false;
ip_proto = iph->nexthdr; ip_proto = iph->nexthdr;
flow->src = (__force __be32)ipv6_addr_hash(&iph->saddr);
flow->dst = (__force __be32)ipv6_addr_hash(&iph->daddr);
nhoff += sizeof(struct ipv6hdr); nhoff += sizeof(struct ipv6hdr);
/* skip the flow label processing if skb is NULL. The /* see comment above in IPv4 section */
* assumption here is that if there is no skb we are not
* looking for flow info as much as we are length.
*/
if (!skb) if (!skb)
break; break;
flow->src = (__force __be32)ipv6_addr_hash(&iph->saddr);
flow->dst = (__force __be32)ipv6_addr_hash(&iph->daddr);
flow_label = ip6_flowlabel(iph); flow_label = ip6_flowlabel(iph);
if (flow_label) { if (flow_label) {
/* Awesome, IPv6 packet has a flow label so we can /* Awesome, IPv6 packet has a flow label so we can
...@@ -231,9 +236,13 @@ bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow, ...@@ -231,9 +236,13 @@ bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow,
flow->n_proto = proto; flow->n_proto = proto;
flow->ip_proto = ip_proto; flow->ip_proto = ip_proto;
flow->ports = __skb_flow_get_ports(skb, nhoff, ip_proto, data, hlen);
flow->thoff = (u16) nhoff; flow->thoff = (u16) nhoff;
/* unless skb is set we don't need to record port info */
if (skb)
flow->ports = __skb_flow_get_ports(skb, nhoff, ip_proto,
data, hlen);
return true; return true;
} }
EXPORT_SYMBOL(__skb_flow_dissect); EXPORT_SYMBOL(__skb_flow_dissect);
...@@ -334,15 +343,16 @@ u32 __skb_get_poff(const struct sk_buff *skb, void *data, ...@@ -334,15 +343,16 @@ u32 __skb_get_poff(const struct sk_buff *skb, void *data,
switch (keys->ip_proto) { switch (keys->ip_proto) {
case IPPROTO_TCP: { case IPPROTO_TCP: {
const struct tcphdr *tcph; /* access doff as u8 to avoid unaligned access */
struct tcphdr _tcph; const u8 *doff;
u8 _doff;
tcph = __skb_header_pointer(skb, poff, sizeof(_tcph), doff = __skb_header_pointer(skb, poff + 12, sizeof(_doff),
data, hlen, &_tcph); data, hlen, &_doff);
if (!tcph) if (!doff)
return poff; return poff;
poff += max_t(u32, sizeof(struct tcphdr), tcph->doff * 4); poff += max_t(u32, sizeof(struct tcphdr), (*doff & 0xF0) >> 2);
break; break;
} }
case IPPROTO_UDP: case IPPROTO_UDP:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment