Commit a7cd39e0 authored by Pieter Jansen van Vuuren's avatar Pieter Jansen van Vuuren Committed by David S. Miller

nfp: fix unchecked flow dissector use

Previously flow dissectors were referenced without first checking that
they are in use and correctly populated by TC. This patch fixes this by
checking each flow dissector key before referencing them.

Fixes: 5571e8c9 ("nfp: extend flower matching capabilities")
Signed-off-by: default avatarPieter Jansen van Vuuren <pieter.jansenvanvuuren@netronome.com>
Reviewed-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: default avatarSimon Horman <simon.horman@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 77146b5d
...@@ -45,6 +45,7 @@ nfp_flower_compile_meta_tci(struct nfp_flower_meta_two *frame, ...@@ -45,6 +45,7 @@ nfp_flower_compile_meta_tci(struct nfp_flower_meta_two *frame,
struct flow_dissector_key_vlan *flow_vlan; struct flow_dissector_key_vlan *flow_vlan;
u16 tmp_tci; u16 tmp_tci;
memset(frame, 0, sizeof(struct nfp_flower_meta_two));
/* Populate the metadata frame. */ /* Populate the metadata frame. */
frame->nfp_flow_key_layer = key_type; frame->nfp_flow_key_layer = key_type;
frame->mask_id = ~0; frame->mask_id = ~0;
...@@ -54,21 +55,20 @@ nfp_flower_compile_meta_tci(struct nfp_flower_meta_two *frame, ...@@ -54,21 +55,20 @@ nfp_flower_compile_meta_tci(struct nfp_flower_meta_two *frame,
return; return;
} }
flow_vlan = skb_flow_dissector_target(flow->dissector, if (dissector_uses_key(flow->dissector, FLOW_DISSECTOR_KEY_VLAN)) {
FLOW_DISSECTOR_KEY_VLAN, flow_vlan = skb_flow_dissector_target(flow->dissector,
flow->key); FLOW_DISSECTOR_KEY_VLAN,
flow->key);
/* Populate the tci field. */ /* Populate the tci field. */
if (!flow_vlan->vlan_id) { if (flow_vlan->vlan_id) {
tmp_tci = 0; tmp_tci = FIELD_PREP(NFP_FLOWER_MASK_VLAN_PRIO,
} else { flow_vlan->vlan_priority) |
tmp_tci = FIELD_PREP(NFP_FLOWER_MASK_VLAN_PRIO, FIELD_PREP(NFP_FLOWER_MASK_VLAN_VID,
flow_vlan->vlan_priority) | flow_vlan->vlan_id) |
FIELD_PREP(NFP_FLOWER_MASK_VLAN_VID, NFP_FLOWER_MASK_VLAN_CFI;
flow_vlan->vlan_id) | frame->tci = cpu_to_be16(tmp_tci);
NFP_FLOWER_MASK_VLAN_CFI; }
} }
frame->tci = cpu_to_be16(tmp_tci);
} }
static void static void
...@@ -99,17 +99,18 @@ nfp_flower_compile_mac(struct nfp_flower_mac_mpls *frame, ...@@ -99,17 +99,18 @@ nfp_flower_compile_mac(struct nfp_flower_mac_mpls *frame,
bool mask_version) bool mask_version)
{ {
struct fl_flow_key *target = mask_version ? flow->mask : flow->key; struct fl_flow_key *target = mask_version ? flow->mask : flow->key;
struct flow_dissector_key_eth_addrs *flow_mac; struct flow_dissector_key_eth_addrs *addr;
flow_mac = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_ETH_ADDRS,
target);
memset(frame, 0, sizeof(struct nfp_flower_mac_mpls)); memset(frame, 0, sizeof(struct nfp_flower_mac_mpls));
/* Populate mac frame. */ if (dissector_uses_key(flow->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
ether_addr_copy(frame->mac_dst, &flow_mac->dst[0]); addr = skb_flow_dissector_target(flow->dissector,
ether_addr_copy(frame->mac_src, &flow_mac->src[0]); FLOW_DISSECTOR_KEY_ETH_ADDRS,
target);
/* Populate mac frame. */
ether_addr_copy(frame->mac_dst, &addr->dst[0]);
ether_addr_copy(frame->mac_src, &addr->src[0]);
}
if (mask_version) if (mask_version)
frame->mpls_lse = cpu_to_be32(~0); frame->mpls_lse = cpu_to_be32(~0);
...@@ -121,14 +122,17 @@ nfp_flower_compile_tport(struct nfp_flower_tp_ports *frame, ...@@ -121,14 +122,17 @@ nfp_flower_compile_tport(struct nfp_flower_tp_ports *frame,
bool mask_version) bool mask_version)
{ {
struct fl_flow_key *target = mask_version ? flow->mask : flow->key; struct fl_flow_key *target = mask_version ? flow->mask : flow->key;
struct flow_dissector_key_ports *flow_tp; struct flow_dissector_key_ports *tp;
flow_tp = skb_flow_dissector_target(flow->dissector, memset(frame, 0, sizeof(struct nfp_flower_tp_ports));
FLOW_DISSECTOR_KEY_PORTS,
target);
frame->port_src = flow_tp->src; if (dissector_uses_key(flow->dissector, FLOW_DISSECTOR_KEY_PORTS)) {
frame->port_dst = flow_tp->dst; tp = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_PORTS,
target);
frame->port_src = tp->src;
frame->port_dst = tp->dst;
}
} }
static void static void
...@@ -137,25 +141,27 @@ nfp_flower_compile_ipv4(struct nfp_flower_ipv4 *frame, ...@@ -137,25 +141,27 @@ nfp_flower_compile_ipv4(struct nfp_flower_ipv4 *frame,
bool mask_version) bool mask_version)
{ {
struct fl_flow_key *target = mask_version ? flow->mask : flow->key; struct fl_flow_key *target = mask_version ? flow->mask : flow->key;
struct flow_dissector_key_ipv4_addrs *flow_ipv4; struct flow_dissector_key_ipv4_addrs *addr;
struct flow_dissector_key_basic *flow_basic; struct flow_dissector_key_basic *basic;
flow_ipv4 = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_IPV4_ADDRS,
target);
flow_basic = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_BASIC,
target);
/* Populate IPv4 frame. */
frame->reserved = 0;
frame->ipv4_src = flow_ipv4->src;
frame->ipv4_dst = flow_ipv4->dst;
frame->proto = flow_basic->ip_proto;
/* Wildcard TOS/TTL for now. */ /* Wildcard TOS/TTL for now. */
frame->tos = 0; memset(frame, 0, sizeof(struct nfp_flower_ipv4));
frame->ttl = 0;
if (dissector_uses_key(flow->dissector,
FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
addr = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_IPV4_ADDRS,
target);
frame->ipv4_src = addr->src;
frame->ipv4_dst = addr->dst;
}
if (dissector_uses_key(flow->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
basic = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_BASIC,
target);
frame->proto = basic->ip_proto;
}
} }
static void static void
...@@ -164,26 +170,27 @@ nfp_flower_compile_ipv6(struct nfp_flower_ipv6 *frame, ...@@ -164,26 +170,27 @@ nfp_flower_compile_ipv6(struct nfp_flower_ipv6 *frame,
bool mask_version) bool mask_version)
{ {
struct fl_flow_key *target = mask_version ? flow->mask : flow->key; struct fl_flow_key *target = mask_version ? flow->mask : flow->key;
struct flow_dissector_key_ipv6_addrs *flow_ipv6; struct flow_dissector_key_ipv6_addrs *addr;
struct flow_dissector_key_basic *flow_basic; struct flow_dissector_key_basic *basic;
flow_ipv6 = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_IPV6_ADDRS,
target);
flow_basic = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_BASIC,
target);
/* Populate IPv6 frame. */
frame->reserved = 0;
frame->ipv6_src = flow_ipv6->src;
frame->ipv6_dst = flow_ipv6->dst;
frame->proto = flow_basic->ip_proto;
/* Wildcard LABEL/TOS/TTL for now. */ /* Wildcard LABEL/TOS/TTL for now. */
frame->ipv6_flow_label_exthdr = 0; memset(frame, 0, sizeof(struct nfp_flower_ipv6));
frame->tos = 0;
frame->ttl = 0; if (dissector_uses_key(flow->dissector,
FLOW_DISSECTOR_KEY_IPV6_ADDRS)) {
addr = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_IPV6_ADDRS,
target);
frame->ipv6_src = addr->src;
frame->ipv6_dst = addr->dst;
}
if (dissector_uses_key(flow->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
basic = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_BASIC,
target);
frame->proto = basic->ip_proto;
}
} }
int nfp_flower_compile_flow_match(struct tc_cls_flower_offload *flow, int nfp_flower_compile_flow_match(struct tc_cls_flower_offload *flow,
......
...@@ -105,35 +105,40 @@ static int ...@@ -105,35 +105,40 @@ static int
nfp_flower_calculate_key_layers(struct nfp_fl_key_ls *ret_key_ls, nfp_flower_calculate_key_layers(struct nfp_fl_key_ls *ret_key_ls,
struct tc_cls_flower_offload *flow) struct tc_cls_flower_offload *flow)
{ {
struct flow_dissector_key_control *mask_enc_ctl; struct flow_dissector_key_basic *mask_basic = NULL;
struct flow_dissector_key_basic *mask_basic; struct flow_dissector_key_basic *key_basic = NULL;
struct flow_dissector_key_basic *key_basic;
u32 key_layer_two; u32 key_layer_two;
u8 key_layer; u8 key_layer;
int key_size; int key_size;
mask_enc_ctl = skb_flow_dissector_target(flow->dissector, if (dissector_uses_key(flow->dissector,
FLOW_DISSECTOR_KEY_ENC_CONTROL, FLOW_DISSECTOR_KEY_ENC_CONTROL)) {
flow->mask); struct flow_dissector_key_control *mask_enc_ctl =
skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_ENC_CONTROL,
flow->mask);
/* We are expecting a tunnel. For now we ignore offloading. */
if (mask_enc_ctl->addr_type)
return -EOPNOTSUPP;
}
if (dissector_uses_key(flow->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
mask_basic = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_BASIC,
flow->mask);
mask_basic = skb_flow_dissector_target(flow->dissector, key_basic = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_BASIC, FLOW_DISSECTOR_KEY_BASIC,
flow->mask); flow->key);
}
key_basic = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_BASIC,
flow->key);
key_layer_two = 0; key_layer_two = 0;
key_layer = NFP_FLOWER_LAYER_PORT | NFP_FLOWER_LAYER_MAC; key_layer = NFP_FLOWER_LAYER_PORT | NFP_FLOWER_LAYER_MAC;
key_size = sizeof(struct nfp_flower_meta_one) + key_size = sizeof(struct nfp_flower_meta_one) +
sizeof(struct nfp_flower_in_port) + sizeof(struct nfp_flower_in_port) +
sizeof(struct nfp_flower_mac_mpls); sizeof(struct nfp_flower_mac_mpls);
/* We are expecting a tunnel. For now we ignore offloading. */ if (mask_basic && mask_basic->n_proto) {
if (mask_enc_ctl->addr_type)
return -EOPNOTSUPP;
if (mask_basic->n_proto) {
/* Ethernet type is present in the key. */ /* Ethernet type is present in the key. */
switch (key_basic->n_proto) { switch (key_basic->n_proto) {
case cpu_to_be16(ETH_P_IP): case cpu_to_be16(ETH_P_IP):
...@@ -166,7 +171,7 @@ nfp_flower_calculate_key_layers(struct nfp_fl_key_ls *ret_key_ls, ...@@ -166,7 +171,7 @@ nfp_flower_calculate_key_layers(struct nfp_fl_key_ls *ret_key_ls,
} }
} }
if (mask_basic->ip_proto) { if (mask_basic && mask_basic->ip_proto) {
/* Ethernet type is present in the key. */ /* Ethernet type is present in the key. */
switch (key_basic->ip_proto) { switch (key_basic->ip_proto) {
case IPPROTO_TCP: case IPPROTO_TCP:
......
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