Skip to content

Commit 8b79647

Browse files
Paolo Abenikuba-moo
authored andcommitted
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: db2c241 ("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>
1 parent 3cc5c6a commit 8b79647

2 files changed

Lines changed: 23 additions & 4 deletions

File tree

include/net/tc_act/tc_pedit.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ struct tcf_pedit {
1414
struct tc_action common;
1515
unsigned char tcfp_nkeys;
1616
unsigned char tcfp_flags;
17+
u32 tcfp_off_max_hint;
1718
struct tc_pedit_key *tcfp_keys;
1819
struct tcf_pedit_key_ex *tcfp_keys_ex;
1920
};

net/sched/act_pedit.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
149149
struct nlattr *pattr;
150150
struct tcf_pedit *p;
151151
int ret = 0, err;
152-
int ksize;
152+
int i, ksize;
153153
u32 index;
154154

155155
if (!nla) {
@@ -228,6 +228,18 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
228228
p->tcfp_nkeys = parm->nkeys;
229229
}
230230
memcpy(p->tcfp_keys, parm->keys, ksize);
231+
p->tcfp_off_max_hint = 0;
232+
for (i = 0; i < p->tcfp_nkeys; ++i) {
233+
u32 cur = p->tcfp_keys[i].off;
234+
235+
/* The AT option can read a single byte, we can bound the actual
236+
* value with uchar max.
237+
*/
238+
cur += (0xff & p->tcfp_keys[i].offmask) >> p->tcfp_keys[i].shift;
239+
240+
/* Each key touches 4 bytes starting from the computed offset */
241+
p->tcfp_off_max_hint = max(p->tcfp_off_max_hint, cur + 4);
242+
}
231243

232244
p->tcfp_flags = parm->flags;
233245
goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
@@ -308,13 +320,18 @@ static int tcf_pedit_act(struct sk_buff *skb, const struct tc_action *a,
308320
struct tcf_result *res)
309321
{
310322
struct tcf_pedit *p = to_pedit(a);
323+
u32 max_offset;
311324
int i;
312325

313-
if (skb_unclone(skb, GFP_ATOMIC))
314-
return p->tcf_action;
315-
316326
spin_lock(&p->tcf_lock);
317327

328+
max_offset = (skb_transport_header_was_set(skb) ?
329+
skb_transport_offset(skb) :
330+
skb_network_offset(skb)) +
331+
p->tcfp_off_max_hint;
332+
if (skb_ensure_writable(skb, min(skb->len, max_offset)))
333+
goto unlock;
334+
318335
tcf_lastuse_update(&p->tcf_tm);
319336

320337
if (p->tcfp_nkeys > 0) {
@@ -403,6 +420,7 @@ static int tcf_pedit_act(struct sk_buff *skb, const struct tc_action *a,
403420
p->tcf_qstats.overlimits++;
404421
done:
405422
bstats_update(&p->tcf_bstats, skb);
423+
unlock:
406424
spin_unlock(&p->tcf_lock);
407425
return p->tcf_action;
408426
}

0 commit comments

Comments
 (0)