From patchwork Thu Apr 28 21:10:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Joanne Koong X-Patchwork-Id: 12831151 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 BF5DBC433F5 for ; Thu, 28 Apr 2022 21:12:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1352112AbiD1VPg convert rfc822-to-8bit (ORCPT ); Thu, 28 Apr 2022 17:15:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55820 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1352127AbiD1VPg (ORCPT ); Thu, 28 Apr 2022 17:15:36 -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 4C50180BE6 for ; Thu, 28 Apr 2022 14:11:59 -0700 (PDT) Received: by devbig010.atn6.facebook.com (Postfix, from userid 115148) id 12737BAF4BB8; Thu, 28 Apr 2022 14:11:44 -0700 (PDT) From: Joanne Koong To: bpf@vger.kernel.org Cc: andrii@kernel.org, memxor@gmail.com, ast@kernel.org, daniel@iogearbox.net, toke@redhat.com, Joanne Koong Subject: [PATCH bpf-next v3 0/6] Dynamic pointers Date: Thu, 28 Apr 2022 14:10:53 -0700 Message-Id: <20220428211059.4065379-1-joannelkoong@gmail.com> X-Mailer: git-send-email 2.30.2 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net This patchset implements the basics of dynamic pointers in bpf. A dynamic pointer (struct bpf_dynptr) is a pointer that stores extra metadata alongside the address it points to. This abstraction is useful in bpf, given that every memory access in a bpf program must be safe. The verifier and bpf helper functions can use the metadata to enforce safety guarantees for things such as dynamically sized strings and kernel heap allocations. From the program side, the bpf_dynptr is an opaque struct and the verifier will enforce that its contents are never written to by the program. It can only be written to through specific bpf helper functions. There are several uses cases for dynamic pointers in bpf programs. A list of some are: dynamically sized ringbuf reservations without any extra memcpys, dynamic string parsing and memory comparisons, dynamic memory allocations that can be persisted in a map, and dynamic parsing of sk_buff and xdp_md packet data. At a high-level, the patches are as follows: 1/6 - Adds MEM_UNINIT as a bpf_type_flag 2/6 - Adds verifier support for dynptrs and implements malloc dynptrs 3/6 - Adds dynptr support for ring buffers 4/6 - Adds bpf_dynptr_read and bpf_dynptr_write 5/6 - Adds dynptr data slices (ptr to underlying dynptr memory) 6/6 - Tests to check that verifier rejects certain fail cases and passes certain success cases This is the first dynptr patchset in a larger series. The next series of patches will add persisting dynamic memory allocations in maps, parsing packet data through dynptrs, convenience helpers for using dynptrs as iterators, and more helper functions for interacting with strings and memory dynamically. Changelog: ---------- v3 -> v2: v2: https://lore.kernel.org/bpf/20220416063429.3314021-1-joannelkoong@gmail.com/ * Reorder patches (move ringbuffer patch to be right after the verifier + malloc dynptr patchset) * Remove local type dynptrs (Andrii + Alexei) * Mark stack slot as STACK_MISC after any writes into a dynptr instead of * explicitly prohibiting writes (Alexei) * Pass number of slots, not memory size to is_spi_bounds_valid (Kumar) * Check reference leaks by adding dynptr id to state->refs instead of checking stack slots (Alexei) v1 -> v2: v1: https://lore.kernel.org/bpf/20220402015826.3941317-1-joannekoong@fb.com/ 1/7 - * Remove ARG_PTR_TO_MAP_VALUE_UNINIT alias and use ARG_PTR_TO_MAP_VALUE | MEM_UNINIT directly (Andrii) * Drop arg_type_is_mem_ptr() wrapper function (Andrii) 2/7 - * Change name from MEM_RELEASE to OBJ_RELEASE (Andrii) * Use meta.release_ref instead of ref_obj_id != 0 to determine whether to release reference (Kumar) * Drop type_is_release_mem() wrapper function (Andrii) 3/7 - * Add checks for nested dynptrs edge-cases, which could lead to corrupt * writes of the dynptr stack variable. * Add u64 flags to bpf_dynptr_from_mem() and bpf_dynptr_alloc() (Andrii) * Rename from bpf_malloc/bpf_free to bpf_dynptr_alloc/bpf_dynptr_put (Alexei) * Support alloc flag __GFP_ZERO (Andrii) * Reserve upper 8 bits in dynptr size and offset fields instead of reserving just the upper 4 bits (Andrii) * Allow dynptr zero-slices (Andrii) * Use the highest bit for is_rdonly instead of the 28th bit (Andrii) * Rename check_* functions to is_* functions for better readability (Andrii) * Add comment for code that checks the spi bounds (Andrii) 4/7 - * Fix doc description for bpf_dynpt_read (Toke) * Move bpf_dynptr_check_off_len() from function patch 1 to here (Andrii) 5/7 - * When finding the id for the dynptr to associate the data slice with, look for dynptr arg instead of assuming it is BPF_REG_1. 6/7 - * Add __force when casting from unsigned long to void * (kernel test robot) * Expand on docs for ringbuf dynptr APIs (Andrii) 7/7 - * Use table approach for defining test programs and error messages (Andrii) * Print out full log if there’s an error (Andrii) * Use bpf_object__find_program_by_name() instead of specifying program name as a string (Andrii) * Add 6 extra cases: invalid_nested_dynptrs1, invalid_nested_dynptrs2, invalid_ref_mem1, invalid_ref_mem2, zero_slice_access, and test_alloc_zero_bytes * Add checking for edge cases (eg allocing with invalid flags) Joanne Koong (6): bpf: Add MEM_UNINIT as a bpf_type_flag bpf: Add verifier support for dynptrs and implement malloc dynptrs bpf: Dynptr support for ring buffers bpf: Add bpf_dynptr_read and bpf_dynptr_write bpf: Add dynptr data slices bpf: Dynptr tests include/linux/bpf.h | 103 +++- include/linux/bpf_verifier.h | 21 + include/uapi/linux/bpf.h | 96 +++ kernel/bpf/helpers.c | 169 +++++- kernel/bpf/ringbuf.c | 71 +++ kernel/bpf/verifier.c | 329 +++++++++- scripts/bpf_doc.py | 2 + tools/include/uapi/linux/bpf.h | 96 +++ .../testing/selftests/bpf/prog_tests/dynptr.c | 132 ++++ .../testing/selftests/bpf/progs/dynptr_fail.c | 574 ++++++++++++++++++ .../selftests/bpf/progs/dynptr_success.c | 218 +++++++ 11 files changed, 1774 insertions(+), 37 deletions(-) create mode 100644 tools/testing/selftests/bpf/prog_tests/dynptr.c create mode 100644 tools/testing/selftests/bpf/progs/dynptr_fail.c create mode 100644 tools/testing/selftests/bpf/progs/dynptr_success.c