Skip to content

Commit 072222b

Browse files
martinetddavem330
authored andcommitted
kcm: remove any offset before parsing messages
The current code assumes kcm users know they need to look for the strparser offset within their bpf program, which is not documented anywhere and examples laying around do not do. The actual recv function does handle the offset well, so we can create a temporary clone of the skb and pull that one up as required for parsing. The pull itself has a cost if we are pulling beyond the head data, measured to 2-3% latency in a noisy VM with a local client stressing that path. The clone's impact seemed too small to measure. This bug can be exhibited easily by implementing a "trivial" kcm parser taking the first bytes as size, and on the client sending at least two such packets in a single write(). Note that bpf sockmap has the same problem, both for parse and for recv, so it would pulling twice or a real pull within the strparser logic if anyone cares about that. Signed-off-by: Dominique Martinet <asmadeus@codewreck.org> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent c734809 commit 072222b

File tree

1 file changed

+25
-1
lines changed

1 file changed

+25
-1
lines changed

net/kcm/kcmsock.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,8 +381,32 @@ static int kcm_parse_func_strparser(struct strparser *strp, struct sk_buff *skb)
381381
{
382382
struct kcm_psock *psock = container_of(strp, struct kcm_psock, strp);
383383
struct bpf_prog *prog = psock->bpf_prog;
384+
struct sk_buff *clone_skb = NULL;
385+
struct strp_msg *stm;
386+
int rc;
387+
388+
stm = strp_msg(skb);
389+
if (stm->offset) {
390+
skb = clone_skb = skb_clone(skb, GFP_ATOMIC);
391+
if (!clone_skb)
392+
return -ENOMEM;
393+
394+
if (!pskb_pull(clone_skb, stm->offset)) {
395+
rc = -ENOMEM;
396+
goto out;
397+
}
398+
399+
/* reset cloned skb's offset for bpf programs using it */
400+
stm = strp_msg(clone_skb);
401+
stm->offset = 0;
402+
}
403+
404+
rc = (*prog->bpf_func)(skb, prog->insnsi);
405+
out:
406+
if (clone_skb)
407+
kfree_skb(clone_skb);
384408

385-
return (*prog->bpf_func)(skb, prog->insnsi);
409+
return rc;
386410
}
387411

388412
static int kcm_read_sock_done(struct strparser *strp, int err)

0 commit comments

Comments
 (0)