From patchwork Thu Jan 4 23:55:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lawrence Brakmo X-Patchwork-Id: 855865 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=fb.com header.i=@fb.com header.b="Z3Nc/BYS"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3zCPp46d9Rz9s7n for ; Fri, 5 Jan 2018 10:56:12 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751379AbeADX4G (ORCPT ); Thu, 4 Jan 2018 18:56:06 -0500 Received: from mx0a-00082601.pphosted.com ([67.231.145.42]:36724 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751155AbeADXzi (ORCPT ); Thu, 4 Jan 2018 18:55:38 -0500 Received: from pps.filterd (m0109334.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id w04Nr7iu023086 for ; Thu, 4 Jan 2018 15:55:37 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=facebook; bh=bGxeQJtipnMkyb4LnBdsVp7zgKdtz1qkHRw0Hjnwv3I=; b=Z3Nc/BYS+uzCPyrIfbkgq1Ps0KRliWlw6GN6N1jpLj/0kxfqC40391qn/gx9cQpVvTKZ 9v3SzefUmClpKJ7KV2ywewU3gxx3tQco2x15qn9GHBHGn7xx1iPCYvOCHDnLOY7HYDLO ZutfOYKS0UcoESbW/3ZeGg21ytjC1f/jeaI= Received: from mail.thefacebook.com ([199.201.64.23]) by mx0a-00082601.pphosted.com with ESMTP id 2f9t0g0q7m-4 (version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT) for ; Thu, 04 Jan 2018 15:55:37 -0800 Received: from mx-out.facebook.com (192.168.52.123) by PRN-CHUB01.TheFacebook.com (192.168.16.11) with Microsoft SMTP Server id 14.3.361.1; Thu, 4 Jan 2018 15:55:36 -0800 Received: by dev15893.prn1.facebook.com (Postfix, from userid 10340) id 0EB84C244A4; Thu, 4 Jan 2018 15:55:35 -0800 (PST) Smtp-Origin-Hostprefix: dev From: Lawrence Brakmo Smtp-Origin-Hostname: dev15893.prn1.facebook.com To: netdev CC: Kernel Team , Blake Matheny , Alexei Starovoitov , Daniel Borkmann , Eric Dumazet , Neal Cardwell , Yuchung Cheng Smtp-Origin-Cluster: prn1c29 Subject: [PATCH bpf-next v4 03/11] bpf: Add write access to tcp_sock and sock fields Date: Thu, 4 Jan 2018 15:55:25 -0800 Message-ID: <20180104235533.3672006-4-brakmo@fb.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20180104235533.3672006-1-brakmo@fb.com> References: <20180104235533.3672006-1-brakmo@fb.com> X-FB-Internal: Safe MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2018-01-04_11:, , signatures=0 X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This patch adds a macro, SOCK_OPS_SET_FIELD, for writing to struct tcp_sock or struct sock fields. This required adding a new field "temp" to struct bpf_sock_ops_kern for temporary storage that is used by sock_ops_convert_ctx_access. It is used to store and recover the contents of a register, so the register can be used to store the address of the sk. Since we cannot overwrite the dst_reg because it contains the pointer to ctx, nor the src_reg since it contains the value we want to store, we need an extra register to contain the address of the sk. Also adds the macro SOCK_OPS_GET_OR_SET_FIELD that calls one of the GET or SET macros depending on the value of the TYPE field. Signed-off-by: Lawrence Brakmo --- include/linux/filter.h | 3 +++ include/net/tcp.h | 2 +- net/core/filter.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/include/linux/filter.h b/include/linux/filter.h index 2b0df27..2e6e889 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -1005,6 +1005,9 @@ struct bpf_sock_ops_kern { u32 replylong[4]; }; u32 is_fullsock; + u64 temp; /* Used by sock_ops_convert_ctx_access + * as temporary storaage of a register + */ }; #endif /* __LINUX_FILTER_H__ */ diff --git a/include/net/tcp.h b/include/net/tcp.h index 6939e69..108d16a 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -2010,7 +2010,7 @@ static inline int tcp_call_bpf(struct sock *sk, int op) struct bpf_sock_ops_kern sock_ops; int ret; - memset(&sock_ops, 0, sizeof(sock_ops)); + memset(&sock_ops, 0, offsetof(struct bpf_sock_ops_kern, temp)); if (sk_fullsock(sk)) { sock_ops.is_fullsock = 1; sock_owned_by_me(sk); diff --git a/net/core/filter.c b/net/core/filter.c index 7064862..978ac78 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -4470,6 +4470,54 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type, offsetof(OBJ, OBJ_FIELD)); \ } while (0) +/* Helper macro for adding write access to tcp_sock or sock fields. + * The macro is called with two registers, dst_reg which contains a pointer + * to ctx (context) and src_reg which contains the value that should be + * stored. However, we need an additional register since we cannot overwrite + * dst_reg because it may be used later in the program. + * Instead we "borrow" one of the other register. We first save its value + * into a new (temp) field in bpf_sock_ops_kern, use it, and then restore + * it at the end of the macro. + */ +#define SOCK_OPS_SET_FIELD(BPF_FIELD, OBJ_FIELD, OBJ) \ + do { \ + int reg = BPF_REG_9; \ + BUILD_BUG_ON(FIELD_SIZEOF(OBJ, OBJ_FIELD) > \ + FIELD_SIZEOF(struct bpf_sock_ops, BPF_FIELD)); \ + if (si->dst_reg == reg || si->src_reg == reg) \ + reg--; \ + if (si->dst_reg == reg || si->src_reg == reg) \ + reg--; \ + *insn++ = BPF_STX_MEM(BPF_DW, si->dst_reg, reg, \ + offsetof(struct bpf_sock_ops_kern, \ + temp)); \ + *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF( \ + struct bpf_sock_ops_kern, \ + is_fullsock), \ + reg, si->dst_reg, \ + offsetof(struct bpf_sock_ops_kern, \ + is_fullsock)); \ + *insn++ = BPF_JMP_IMM(BPF_JEQ, reg, 0, 2); \ + *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF( \ + struct bpf_sock_ops_kern, sk),\ + reg, si->dst_reg, \ + offsetof(struct bpf_sock_ops_kern, sk));\ + *insn++ = BPF_STX_MEM(BPF_FIELD_SIZEOF(OBJ, OBJ_FIELD), \ + reg, si->src_reg, \ + offsetof(OBJ, OBJ_FIELD)); \ + *insn++ = BPF_LDX_MEM(BPF_DW, reg, si->dst_reg, \ + offsetof(struct bpf_sock_ops_kern, \ + temp)); \ + } while (0) + +#define SOCK_OPS_GET_OR_SET_FIELD(BPF_FIELD, OBJ_FIELD, OBJ, TYPE) \ + do { \ + if (TYPE == BPF_WRITE) \ + SOCK_OPS_SET_FIELD(BPF_FIELD, OBJ_FIELD, OBJ); \ + else \ + SOCK_OPS_GET_FIELD(BPF_FIELD, OBJ_FIELD, OBJ); \ + } while (0) + case offsetof(struct bpf_sock_ops, snd_cwnd): SOCK_OPS_GET_FIELD(snd_cwnd, snd_cwnd, struct tcp_sock); break;