linux/include/net/tc_act/tc_pedit.h
Paolo Abeni 8b796475fd net/sched: act_pedit: really ensure the skb is writable
Currently pedit tries to ensure that the accessed skb offset
is writable via skb_unclone(). The action potentially allows
touching any skb bytes, so it may end-up modifying shared data.

The above causes some sporadic MPTCP self-test failures, due to
this code:

	tc -n $ns2 filter add dev ns2eth$i egress \
		protocol ip prio 1000 \
		handle 42 fw \
		action pedit munge offset 148 u8 invert \
		pipe csum tcp \
		index 100

The above modifies a data byte outside the skb head and the skb is
a cloned one, carrying a TCP output packet.

This change addresses the issue by keeping track of a rough
over-estimate highest skb offset accessed by the action and ensuring
such offset is really writable.

Note that this may cause performance regressions in some scenarios,
but hopefully pedit is not in the critical path.

Fixes: db2c24175d ("act_pedit: access skb->data safely")
Acked-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Tested-by: Geliang Tang <geliang.tang@suse.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Link: https://lore.kernel.org/r/1fcf78e6679d0a287dd61bb0f04730ce33b3255d.1652194627.git.pabeni@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2022-05-11 15:06:42 -07:00

69 lines
1.5 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __NET_TC_PED_H
#define __NET_TC_PED_H
#include <net/act_api.h>
#include <linux/tc_act/tc_pedit.h>
struct tcf_pedit_key_ex {
enum pedit_header_type htype;
enum pedit_cmd cmd;
};
struct tcf_pedit {
struct tc_action common;
unsigned char tcfp_nkeys;
unsigned char tcfp_flags;
u32 tcfp_off_max_hint;
struct tc_pedit_key *tcfp_keys;
struct tcf_pedit_key_ex *tcfp_keys_ex;
};
#define to_pedit(a) ((struct tcf_pedit *)a)
static inline bool is_tcf_pedit(const struct tc_action *a)
{
#ifdef CONFIG_NET_CLS_ACT
if (a->ops && a->ops->id == TCA_ID_PEDIT)
return true;
#endif
return false;
}
static inline int tcf_pedit_nkeys(const struct tc_action *a)
{
return to_pedit(a)->tcfp_nkeys;
}
static inline u32 tcf_pedit_htype(const struct tc_action *a, int index)
{
if (to_pedit(a)->tcfp_keys_ex)
return to_pedit(a)->tcfp_keys_ex[index].htype;
return TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK;
}
static inline u32 tcf_pedit_cmd(const struct tc_action *a, int index)
{
if (to_pedit(a)->tcfp_keys_ex)
return to_pedit(a)->tcfp_keys_ex[index].cmd;
return __PEDIT_CMD_MAX;
}
static inline u32 tcf_pedit_mask(const struct tc_action *a, int index)
{
return to_pedit(a)->tcfp_keys[index].mask;
}
static inline u32 tcf_pedit_val(const struct tc_action *a, int index)
{
return to_pedit(a)->tcfp_keys[index].val;
}
static inline u32 tcf_pedit_offset(const struct tc_action *a, int index)
{
return to_pedit(a)->tcfp_keys[index].off;
}
#endif /* __NET_TC_PED_H */