Skip to content

Commit 982b527

Browse files
jessegrossdavem330
authored andcommitted
openvswitch: Fix mask generation for nested attributes.
Masks were added to OVS flows in a way that was backwards compatible with userspace programs that did not generate masks. As a result, it is possible that we may receive flows that do not have a mask and we need to synthesize one. Generating a mask requires iterating over attributes and descending into nested attributes. For each level we need to know the size to generate the correct mask. We do this with a linked table of attribute types. Although the logic to handle these nested attributes was there in concept, there are a number of bugs in practice. Examples include incomplete links between tables, variable length attributes being treated as nested and missing sanity checks. Signed-off-by: Jesse Gross <[email protected]> Acked-by: Pravin B Shelar <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 892aa01 commit 982b527

File tree

1 file changed

+59
-23
lines changed

1 file changed

+59
-23
lines changed

net/openvswitch/flow_netlink.c

Lines changed: 59 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct ovs_len_tbl {
5757
};
5858

5959
#define OVS_ATTR_NESTED -1
60+
#define OVS_ATTR_VARIABLE -2
6061

6162
static void update_range(struct sw_flow_match *match,
6263
size_t offset, size_t size, bool is_mask)
@@ -304,6 +305,10 @@ size_t ovs_key_attr_size(void)
304305
+ nla_total_size(28); /* OVS_KEY_ATTR_ND */
305306
}
306307

308+
static const struct ovs_len_tbl ovs_vxlan_ext_key_lens[OVS_VXLAN_EXT_MAX + 1] = {
309+
[OVS_VXLAN_EXT_GBP] = { .len = sizeof(u32) },
310+
};
311+
307312
static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = {
308313
[OVS_TUNNEL_KEY_ATTR_ID] = { .len = sizeof(u64) },
309314
[OVS_TUNNEL_KEY_ATTR_IPV4_SRC] = { .len = sizeof(u32) },
@@ -315,8 +320,9 @@ static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1]
315320
[OVS_TUNNEL_KEY_ATTR_TP_SRC] = { .len = sizeof(u16) },
316321
[OVS_TUNNEL_KEY_ATTR_TP_DST] = { .len = sizeof(u16) },
317322
[OVS_TUNNEL_KEY_ATTR_OAM] = { .len = 0 },
318-
[OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_NESTED },
319-
[OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = OVS_ATTR_NESTED },
323+
[OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_VARIABLE },
324+
[OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = OVS_ATTR_NESTED,
325+
.next = ovs_vxlan_ext_key_lens },
320326
};
321327

322328
/* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */
@@ -349,6 +355,13 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
349355
[OVS_KEY_ATTR_CT_LABEL] = { .len = sizeof(struct ovs_key_ct_label) },
350356
};
351357

358+
static bool check_attr_len(unsigned int attr_len, unsigned int expected_len)
359+
{
360+
return expected_len == attr_len ||
361+
expected_len == OVS_ATTR_NESTED ||
362+
expected_len == OVS_ATTR_VARIABLE;
363+
}
364+
352365
static bool is_all_zero(const u8 *fp, size_t size)
353366
{
354367
int i;
@@ -388,7 +401,7 @@ static int __parse_flow_nlattrs(const struct nlattr *attr,
388401
}
389402

390403
expected_len = ovs_key_lens[type].len;
391-
if (nla_len(nla) != expected_len && expected_len != OVS_ATTR_NESTED) {
404+
if (!check_attr_len(nla_len(nla), expected_len)) {
392405
OVS_NLERR(log, "Key %d has unexpected len %d expected %d",
393406
type, nla_len(nla), expected_len);
394407
return -EINVAL;
@@ -473,29 +486,50 @@ static int genev_tun_opt_from_nlattr(const struct nlattr *a,
473486
return 0;
474487
}
475488

476-
static const struct nla_policy vxlan_opt_policy[OVS_VXLAN_EXT_MAX + 1] = {
477-
[OVS_VXLAN_EXT_GBP] = { .type = NLA_U32 },
478-
};
479-
480-
static int vxlan_tun_opt_from_nlattr(const struct nlattr *a,
489+
static int vxlan_tun_opt_from_nlattr(const struct nlattr *attr,
481490
struct sw_flow_match *match, bool is_mask,
482491
bool log)
483492
{
484-
struct nlattr *tb[OVS_VXLAN_EXT_MAX+1];
493+
struct nlattr *a;
494+
int rem;
485495
unsigned long opt_key_offset;
486496
struct vxlan_metadata opts;
487-
int err;
488497

489498
BUILD_BUG_ON(sizeof(opts) > sizeof(match->key->tun_opts));
490499

491-
err = nla_parse_nested(tb, OVS_VXLAN_EXT_MAX, a, vxlan_opt_policy);
492-
if (err < 0)
493-
return err;
494-
495500
memset(&opts, 0, sizeof(opts));
501+
nla_for_each_nested(a, attr, rem) {
502+
int type = nla_type(a);
496503

497-
if (tb[OVS_VXLAN_EXT_GBP])
498-
opts.gbp = nla_get_u32(tb[OVS_VXLAN_EXT_GBP]);
504+
if (type > OVS_VXLAN_EXT_MAX) {
505+
OVS_NLERR(log, "VXLAN extension %d out of range max %d",
506+
type, OVS_VXLAN_EXT_MAX);
507+
return -EINVAL;
508+
}
509+
510+
if (!check_attr_len(nla_len(a),
511+
ovs_vxlan_ext_key_lens[type].len)) {
512+
OVS_NLERR(log, "VXLAN extension %d has unexpected len %d expected %d",
513+
type, nla_len(a),
514+
ovs_vxlan_ext_key_lens[type].len);
515+
return -EINVAL;
516+
}
517+
518+
switch (type) {
519+
case OVS_VXLAN_EXT_GBP:
520+
opts.gbp = nla_get_u32(a);
521+
break;
522+
default:
523+
OVS_NLERR(log, "Unknown VXLAN extension attribute %d",
524+
type);
525+
return -EINVAL;
526+
}
527+
}
528+
if (rem) {
529+
OVS_NLERR(log, "VXLAN extension message has %d unknown bytes.",
530+
rem);
531+
return -EINVAL;
532+
}
499533

500534
if (!is_mask)
501535
SW_FLOW_KEY_PUT(match, tun_opts_len, sizeof(opts), false);
@@ -528,8 +562,8 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
528562
return -EINVAL;
529563
}
530564

531-
if (ovs_tunnel_key_lens[type].len != nla_len(a) &&
532-
ovs_tunnel_key_lens[type].len != OVS_ATTR_NESTED) {
565+
if (!check_attr_len(nla_len(a),
566+
ovs_tunnel_key_lens[type].len)) {
533567
OVS_NLERR(log, "Tunnel attr %d has unexpected len %d expected %d",
534568
type, nla_len(a), ovs_tunnel_key_lens[type].len);
535569
return -EINVAL;
@@ -1052,10 +1086,13 @@ static void nlattr_set(struct nlattr *attr, u8 val,
10521086

10531087
/* The nlattr stream should already have been validated */
10541088
nla_for_each_nested(nla, attr, rem) {
1055-
if (tbl && tbl[nla_type(nla)].len == OVS_ATTR_NESTED)
1056-
nlattr_set(nla, val, tbl[nla_type(nla)].next);
1057-
else
1089+
if (tbl[nla_type(nla)].len == OVS_ATTR_NESTED) {
1090+
if (tbl[nla_type(nla)].next)
1091+
tbl = tbl[nla_type(nla)].next;
1092+
nlattr_set(nla, val, tbl);
1093+
} else {
10581094
memset(nla_data(nla), val, nla_len(nla));
1095+
}
10591096
}
10601097
}
10611098

@@ -1922,8 +1959,7 @@ static int validate_set(const struct nlattr *a,
19221959
key_len /= 2;
19231960

19241961
if (key_type > OVS_KEY_ATTR_MAX ||
1925-
(ovs_key_lens[key_type].len != key_len &&
1926-
ovs_key_lens[key_type].len != OVS_ATTR_NESTED))
1962+
!check_attr_len(key_len, ovs_key_lens[key_type].len))
19271963
return -EINVAL;
19281964

19291965
if (masked && !validate_masked(nla_data(ovs_key), key_len))

0 commit comments

Comments
 (0)