Received: by 2002:ac0:a5a6:0:0:0:0:0 with SMTP id m35-v6csp3810054imm; Tue, 11 Sep 2018 02:23:59 -0700 (PDT) X-Google-Smtp-Source: ANB0VdbR7TTZfewCpfx7gxFuCFCw7yDFFcw0EU/WiAFN4TtReN60xcwwTdNe14RGDmNeWzcsOh7y X-Received: by 2002:a17:902:27a8:: with SMTP id d37-v6mr3958303plb.290.1536657839503; Tue, 11 Sep 2018 02:23:59 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1536657839; cv=none; d=google.com; s=arc-20160816; b=SH9l0YBqtX8wZVN2lSIvbe+weqt/iBZOFVw2eQM9MtNhWxQWueVyTwG03GTjULvRjq UDVbVqIK5AxiQFC5vFuHC7MnSgJsB12ssQHeOqHVTBukNX5BXqqnmK6jA8yYcZzJ/aOm bWC+ErMBffjsbYA9dvybXpy0OCiqiFKp54BGz3hsCbvYj5NkaC2u1T+P8now2eIYxXbY +yh4FYmtXraTKnkkQKSec+adTuZ3c//TDydfxCCWQ5pnYoBd82Bl1Bp8hloZHGUS0B2e v3WhEblini8koWVBIi+zoR20MSwXfygbXG9nVXYbUF7LwcLLwe2y7ZEF6ItsdlT1cLUT ckkA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:in-reply-to:message-id:date:subject:cc:to :from; bh=/ueJgXD2vYvlKWLiynnv3aI+dGLxzwY99l7VeoZGNZs=; b=NQNc+di7+rUnaUztmZhKQeabqamVt/zqTjIzz3iR7R9MFkY0cxIOebUzNIBopy6Mnj xpR1uVu0Ogz16koUY1MDEUX0wZ34IK4irqQfpJcztE7gnduIBjfk8ycjvAasAm9su1z3 h07oNHTbsH+k5aepIGBZY1mn17WFRL/3S1l0V6sf4+YoKP0tjPdsMLqAQjwXEhcNHFeg jCbsAVZLM5LBz2dbnWdKWrtnsjyP8TKtymAaAAVjxlMHW2U9Tf+jxqN4/EIfHF+E9P6r y212lhlZ4BWfNC9yX98Z/yJLfDl6VUB36p5KCdXFK/LYS6/5oPO1A+GZu1MQCR2JDmiP Cs0g== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id v61-v6si18408166plb.448.2018.09.11.02.23.42; Tue, 11 Sep 2018 02:23:59 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727002AbeIKOUZ (ORCPT + 99 others); Tue, 11 Sep 2018 10:20:25 -0400 Received: from nautica.notk.org ([91.121.71.147]:54637 "EHLO nautica.notk.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726563AbeIKOUZ (ORCPT ); Tue, 11 Sep 2018 10:20:25 -0400 Received: by nautica.notk.org (Postfix, from userid 1001) id BF201C009; Tue, 11 Sep 2018 11:21:57 +0200 (CEST) From: Dominique Martinet To: Doron Roberts-Kedes , Tom Herbert , Dave Watson Cc: Dominique Martinet , "David S. Miller" , netdev@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2] kcm: remove any offset before parsing messages Date: Tue, 11 Sep 2018 11:21:43 +0200 Message-Id: <1536657703-27577-1-git-send-email-asmadeus@codewreck.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: 1534855906-22870-1-git-send-email-asmadeus@codewreck.org Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 --- Hmm, while trying to benchmark this, I sometimes got hangs in kcm_wait_data() for the last packet somehow? The sender program was done (exited (zombie) so I assumed the sender socket flushed), but the receiver was in kcm_wait_data in kcm_recvmsg indicating it parsed a header but there was no skb to peek at? But the sock is locked so this shouldn't be racy... I can get it fairly often with this patch and small messages with an offset, but I think it's just because the pull changes some timing - I can't hit it with just the clone, and I can hit it with a pull without clone as well.... And I don't see how pulling a cloned skb can impact the original socket, but I'm a bit fuzzy on this. (it's interesting that I didn't seem to hit this race when pulling in strparser, that shouldn't be any different) I'll look at that a bit more, but there have been no activity here for a while and I don't have the energy to keep pushing in the strparser direction, so take this patch more as a change of direction and a bit as a 'bump' on the subject - I think it's important but I have too much on my plate right now to keep pushing if there is no interest from the authors. net/kcm/kcmsock.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index 571d824e4e24..36c438b95955 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -381,8 +381,32 @@ static int kcm_parse_func_strparser(struct strparser *strp, struct sk_buff *skb) { struct kcm_psock *psock = container_of(strp, struct kcm_psock, strp); struct bpf_prog *prog = psock->bpf_prog; + struct sk_buff *clone_skb = NULL; + struct strp_msg *stm; + int rc; + + stm = strp_msg(skb); + if (stm->offset) { + skb = clone_skb = skb_clone(skb, GFP_ATOMIC); + if (!clone_skb) + return -ENOMEM; + + if (!pskb_pull(clone_skb, stm->offset)) { + rc = -ENOMEM; + goto out; + } + + /* reset cloned skb's offset for bpf programs using it */ + stm = strp_msg(clone_skb); + stm->offset = 0; + } + + rc = (*prog->bpf_func)(skb, prog->insnsi); +out: + if (clone_skb) + kfree_skb(clone_skb); - return (*prog->bpf_func)(skb, prog->insnsi); + return rc; } static int kcm_read_sock_done(struct strparser *strp, int err) -- 2.17.1