Skip to content

Commit c88d390

Browse files
committed
Merge branch 'ocelot-vcap-fixes'
Vladimir Oltean says: ==================== Ocelot VCAP fixes Changes in v2: fix the NPDs and UAFs caused by filter->trap_list in a more robust way that actually does not introduce bugs of its own (1/5) This series fixes issues found while running tools/testing/selftests/net/forwarding/tc_actions.sh on the ocelot switch: - NULL pointer dereference when failing to offload a filter - NULL pointer dereference after deleting a trap - filters still having effect after being deleted - dropped packets still being seen by software - statistics counters showing double the amount of hits - statistics counters showing inexistent hits - invalid configurations not rejected ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 4e70734 + 93a8417 commit c88d390

File tree

5 files changed

+22
-16
lines changed

5 files changed

+22
-16
lines changed

drivers/net/dsa/ocelot/felix.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ static int felix_update_trapping_destinations(struct dsa_switch *ds,
403403
{
404404
struct ocelot *ocelot = ds->priv;
405405
struct felix *felix = ocelot_to_felix(ocelot);
406+
struct ocelot_vcap_block *block_vcap_is2;
406407
struct ocelot_vcap_filter *trap;
407408
enum ocelot_mask_mode mask_mode;
408409
unsigned long port_mask;
@@ -422,9 +423,13 @@ static int felix_update_trapping_destinations(struct dsa_switch *ds,
422423
/* We are sure that "cpu" was found, otherwise
423424
* dsa_tree_setup_default_cpu() would have failed earlier.
424425
*/
426+
block_vcap_is2 = &ocelot->block[VCAP_IS2];
425427

426428
/* Make sure all traps are set up for that destination */
427-
list_for_each_entry(trap, &ocelot->traps, trap_list) {
429+
list_for_each_entry(trap, &block_vcap_is2->rules, list) {
430+
if (!trap->is_trap)
431+
continue;
432+
428433
/* Figure out the current trapping destination */
429434
if (using_tag_8021q) {
430435
/* Redirect to the tag_8021q CPU port. If timestamps

drivers/net/ethernet/mscc/ocelot.c

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1622,7 +1622,7 @@ int ocelot_trap_add(struct ocelot *ocelot, int port,
16221622
trap->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
16231623
trap->action.port_mask = 0;
16241624
trap->take_ts = take_ts;
1625-
list_add_tail(&trap->trap_list, &ocelot->traps);
1625+
trap->is_trap = true;
16261626
new = true;
16271627
}
16281628

@@ -1634,10 +1634,8 @@ int ocelot_trap_add(struct ocelot *ocelot, int port,
16341634
err = ocelot_vcap_filter_replace(ocelot, trap);
16351635
if (err) {
16361636
trap->ingress_port_mask &= ~BIT(port);
1637-
if (!trap->ingress_port_mask) {
1638-
list_del(&trap->trap_list);
1637+
if (!trap->ingress_port_mask)
16391638
kfree(trap);
1640-
}
16411639
return err;
16421640
}
16431641

@@ -1657,11 +1655,8 @@ int ocelot_trap_del(struct ocelot *ocelot, int port, unsigned long cookie)
16571655
return 0;
16581656

16591657
trap->ingress_port_mask &= ~BIT(port);
1660-
if (!trap->ingress_port_mask) {
1661-
list_del(&trap->trap_list);
1662-
1658+
if (!trap->ingress_port_mask)
16631659
return ocelot_vcap_filter_del(ocelot, trap);
1664-
}
16651660

16661661
return ocelot_vcap_filter_replace(ocelot, trap);
16671662
}

drivers/net/ethernet/mscc/ocelot_flower.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -280,9 +280,10 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
280280
filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
281281
break;
282282
case FLOW_ACTION_TRAP:
283-
if (filter->block_id != VCAP_IS2) {
283+
if (filter->block_id != VCAP_IS2 ||
284+
filter->lookup != 0) {
284285
NL_SET_ERR_MSG_MOD(extack,
285-
"Trap action can only be offloaded to VCAP IS2");
286+
"Trap action can only be offloaded to VCAP IS2 lookup 0");
286287
return -EOPNOTSUPP;
287288
}
288289
if (filter->goto_target != -1) {
@@ -295,7 +296,7 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
295296
filter->action.cpu_copy_ena = true;
296297
filter->action.cpu_qu_num = 0;
297298
filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
298-
list_add_tail(&filter->trap_list, &ocelot->traps);
299+
filter->is_trap = true;
299300
break;
300301
case FLOW_ACTION_POLICE:
301302
if (filter->block_id == PSFP_BLOCK_ID) {
@@ -878,8 +879,6 @@ int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
878879

879880
ret = ocelot_flower_parse(ocelot, port, ingress, f, filter);
880881
if (ret) {
881-
if (!list_empty(&filter->trap_list))
882-
list_del(&filter->trap_list);
883882
kfree(filter);
884883
return ret;
885884
}

drivers/net/ethernet/mscc/ocelot_vcap.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,6 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
374374
OCELOT_VCAP_BIT_0);
375375
vcap_key_set(vcap, &data, VCAP_IS2_HK_IGR_PORT_MASK, 0,
376376
~filter->ingress_port_mask);
377-
vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_FIRST, OCELOT_VCAP_BIT_ANY);
378377
vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_HOST_MATCH,
379378
OCELOT_VCAP_BIT_ANY);
380379
vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L2_MC, filter->dmac_mc);
@@ -1217,6 +1216,8 @@ int ocelot_vcap_filter_add(struct ocelot *ocelot,
12171216
struct ocelot_vcap_filter *tmp;
12181217

12191218
tmp = ocelot_vcap_block_find_filter_by_index(block, i);
1219+
/* Read back the filter's counters before moving it */
1220+
vcap_entry_get(ocelot, i - 1, tmp);
12201221
vcap_entry_set(ocelot, i, tmp);
12211222
}
12221223

@@ -1250,7 +1251,11 @@ int ocelot_vcap_filter_del(struct ocelot *ocelot,
12501251
struct ocelot_vcap_filter del_filter;
12511252
int i, index;
12521253

1254+
/* Need to inherit the block_id so that vcap_entry_set()
1255+
* does not get confused and knows where to install it.
1256+
*/
12531257
memset(&del_filter, 0, sizeof(del_filter));
1258+
del_filter.block_id = filter->block_id;
12541259

12551260
/* Gets index of the filter */
12561261
index = ocelot_vcap_block_get_filter_index(block, filter);
@@ -1265,6 +1270,8 @@ int ocelot_vcap_filter_del(struct ocelot *ocelot,
12651270
struct ocelot_vcap_filter *tmp;
12661271

12671272
tmp = ocelot_vcap_block_find_filter_by_index(block, i);
1273+
/* Read back the filter's counters before moving it */
1274+
vcap_entry_get(ocelot, i + 1, tmp);
12681275
vcap_entry_set(ocelot, i, tmp);
12691276
}
12701277

include/soc/mscc/ocelot_vcap.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,6 @@ struct ocelot_vcap_id {
681681

682682
struct ocelot_vcap_filter {
683683
struct list_head list;
684-
struct list_head trap_list;
685684

686685
enum ocelot_vcap_filter_type type;
687686
int block_id;
@@ -695,6 +694,7 @@ struct ocelot_vcap_filter {
695694
struct ocelot_vcap_stats stats;
696695
/* For VCAP IS1 and IS2 */
697696
bool take_ts;
697+
bool is_trap;
698698
unsigned long ingress_port_mask;
699699
/* For VCAP ES0 */
700700
struct ocelot_vcap_port ingress_port;

0 commit comments

Comments
 (0)