From patchwork Thu Sep 8 00:02:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joanne Koong X-Patchwork-Id: 12969487 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 64963ECAAD3 for ; Thu, 8 Sep 2022 00:07:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230064AbiIHAHo (ORCPT ); Wed, 7 Sep 2022 20:07:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37164 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230054AbiIHAHn (ORCPT ); Wed, 7 Sep 2022 20:07:43 -0400 Received: from 69-171-232-181.mail-mxout.facebook.com (69-171-232-181.mail-mxout.facebook.com [69.171.232.181]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 39625AF4A6 for ; Wed, 7 Sep 2022 17:07:41 -0700 (PDT) Received: by devbig010.atn6.facebook.com (Postfix, from userid 115148) id 1B5C511703794; Wed, 7 Sep 2022 17:07:27 -0700 (PDT) From: Joanne Koong To: bpf@vger.kernel.org Cc: daniel@iogearbox.net, martin.lau@kernel.org, andrii@kernel.org, ast@kernel.org, Kernel-team@fb.com, Joanne Koong Subject: [PATCH bpf-next v1 3/8] bpf: Add bpf_dynptr_is_null and bpf_dynptr_is_rdonly Date: Wed, 7 Sep 2022 17:02:49 -0700 Message-Id: <20220908000254.3079129-4-joannelkoong@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220908000254.3079129-1-joannelkoong@gmail.com> References: <20220908000254.3079129-1-joannelkoong@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net Add two new helper functions: bpf_dynptr_is_null and bpf_dynptr_is_rdonly. bpf_dynptr_is_null returns true if the dynptr is null / invalid (determined by whether ptr->data is NULL), else false if the dynptr is a valid dynptr. bpf_dynptr_is_rdonly returns true if the dynptr is read-only, else false if the dynptr is read-writable. Signed-off-by: Joanne Koong --- include/uapi/linux/bpf.h | 20 ++++++++++++++++++ kernel/bpf/helpers.c | 37 +++++++++++++++++++++++++++++++--- scripts/bpf_doc.py | 3 +++ tools/include/uapi/linux/bpf.h | 20 ++++++++++++++++++ 4 files changed, 77 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 3b054553be30..90b6d0744df2 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -5467,6 +5467,24 @@ union bpf_attr { * Return * 0 on success, -EINVAL if the dynptr is invalid, -ERANGE if * trying to trim more bytes than the size of the dynptr. + * + * bool bpf_dynptr_is_null(struct bpf_dynptr *ptr) + * Description + * Determine whether a dynptr is null / invalid. + * + * *ptr* must be an initialized dynptr. + * Return + * True if the dynptr is null, else false. + * + * bool bpf_dynptr_is_rdonly(struct bpf_dynptr *ptr) + * Description + * Determine whether a dynptr is read-only. + * + * *ptr* must be an initialized dynptr. If *ptr* + * is a null dynptr, this will return false. + * Return + * True if the dynptr is read-only and a valid dynptr, + * else false. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5683,6 +5701,8 @@ union bpf_attr { FN(dynptr_data_rdonly), \ FN(dynptr_advance), \ FN(dynptr_trim), \ + FN(dynptr_is_null), \ + FN(dynptr_is_rdonly), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 9f356105ab49..8729383d0966 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1398,7 +1398,7 @@ static const struct bpf_func_proto bpf_kptr_xchg_proto = { #define DYNPTR_SIZE_MASK 0xFFFFFF #define DYNPTR_RDONLY_BIT BIT(31) -static bool bpf_dynptr_is_rdonly(struct bpf_dynptr_kern *ptr) +static bool __bpf_dynptr_is_rdonly(struct bpf_dynptr_kern *ptr) { return ptr->size & DYNPTR_RDONLY_BIT; } @@ -1539,7 +1539,7 @@ BPF_CALL_5(bpf_dynptr_write, struct bpf_dynptr_kern *, dst, u32, offset, void *, enum bpf_dynptr_type type; int err; - if (!dst->data || bpf_dynptr_is_rdonly(dst)) + if (!dst->data || __bpf_dynptr_is_rdonly(dst)) return -EINVAL; err = bpf_dynptr_check_off_len(dst, offset, len); @@ -1592,7 +1592,7 @@ void *__bpf_dynptr_data(struct bpf_dynptr_kern *ptr, u32 offset, u32 len, bool w if (err) return 0; - if (writable && bpf_dynptr_is_rdonly(ptr)) + if (writable && __bpf_dynptr_is_rdonly(ptr)) return 0; type = bpf_dynptr_get_type(ptr); @@ -1705,6 +1705,33 @@ static const struct bpf_func_proto bpf_dynptr_trim_proto = { .arg2_type = ARG_ANYTHING, }; +BPF_CALL_1(bpf_dynptr_is_null, struct bpf_dynptr_kern *, ptr) +{ + return !ptr->data; +} + +static const struct bpf_func_proto bpf_dynptr_is_null_proto = { + .func = bpf_dynptr_is_null, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_DYNPTR, +}; + +BPF_CALL_1(bpf_dynptr_is_rdonly, struct bpf_dynptr_kern *, ptr) +{ + if (!ptr->data) + return 0; + + return __bpf_dynptr_is_rdonly(ptr); +} + +static const struct bpf_func_proto bpf_dynptr_is_rdonly_proto = { + .func = bpf_dynptr_is_rdonly, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_DYNPTR, +}; + const struct bpf_func_proto bpf_get_current_task_proto __weak; const struct bpf_func_proto bpf_get_current_task_btf_proto __weak; const struct bpf_func_proto bpf_probe_read_user_proto __weak; @@ -1781,6 +1808,10 @@ bpf_base_func_proto(enum bpf_func_id func_id) return &bpf_dynptr_advance_proto; case BPF_FUNC_dynptr_trim: return &bpf_dynptr_trim_proto; + case BPF_FUNC_dynptr_is_null: + return &bpf_dynptr_is_null_proto; + case BPF_FUNC_dynptr_is_rdonly: + return &bpf_dynptr_is_rdonly_proto; default: break; } diff --git a/scripts/bpf_doc.py b/scripts/bpf_doc.py index d5c389df6045..ecd227c2ea34 100755 --- a/scripts/bpf_doc.py +++ b/scripts/bpf_doc.py @@ -691,6 +691,7 @@ class PrinterHelpers(Printer): 'int', 'long', 'unsigned long', + 'bool', '__be16', '__be32', @@ -761,6 +762,8 @@ class PrinterHelpers(Printer): header = '''\ /* This is auto-generated file. See bpf_doc.py for details. */ +#include + /* Forward declarations of BPF structs */''' print(header) diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 3b054553be30..90b6d0744df2 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -5467,6 +5467,24 @@ union bpf_attr { * Return * 0 on success, -EINVAL if the dynptr is invalid, -ERANGE if * trying to trim more bytes than the size of the dynptr. + * + * bool bpf_dynptr_is_null(struct bpf_dynptr *ptr) + * Description + * Determine whether a dynptr is null / invalid. + * + * *ptr* must be an initialized dynptr. + * Return + * True if the dynptr is null, else false. + * + * bool bpf_dynptr_is_rdonly(struct bpf_dynptr *ptr) + * Description + * Determine whether a dynptr is read-only. + * + * *ptr* must be an initialized dynptr. If *ptr* + * is a null dynptr, this will return false. + * Return + * True if the dynptr is read-only and a valid dynptr, + * else false. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5683,6 +5701,8 @@ union bpf_attr { FN(dynptr_data_rdonly), \ FN(dynptr_advance), \ FN(dynptr_trim), \ + FN(dynptr_is_null), \ + FN(dynptr_is_rdonly), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper