callers of tcf_gact_goto_chain_index() can potentially read an old value of the chain index, or even dereference a NULL 'goto_chain' pointer, because 'goto_chain' and 'tcfa_action' are read in the traffic path without caring of concurrent write in the control path. The most recent value of chain index can be read also from a->tcfa_action (it's encoded there together with TC_ACT_GOTO_CHAIN bits), so we don't really need to dereference 'goto_chain': just read the chain id from the control action.
Showing the changes to include/net (1 of 1 file). Show all
Unified · Split
| @@ -56,7 +56,7 @@ static inline bool is_tcf_gact_goto_chain(const struct tc_action *a) · 55 unmodified lines | ||
| 56 | 56 | |
| 57 | 57 | static inline u32 tcf_gact_goto_chain_index(const struct tc_action *a) |
| 58 | 58 | { |
| 59 | − return a->goto_chain->index; | |
| 59 | + return READ_ONCE(a->tcfa_action) & TC_ACT_EXT_VAL_MASK; | |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | 62 | #endif /* __NET_TC_GACT_H */ |