On Sat, Apr 16, 2022 at 12:04:25PM IST, Joanne Koong wrote: > This patch adds 3 new APIs and the bulk of the verifier work for > supporting dynamic pointers in bpf. > > There are different types of dynptrs. This patch starts with the most > basic ones, ones that reference a program's local memory > (eg a stack variable) and ones that reference memory that is dynamically > allocated on behalf of the program. If the memory is dynamically > allocated by the program, the program *must* free it before the program > exits. This is enforced by the verifier. > > The added APIs are: > > long bpf_dynptr_from_mem(void *data, u32 size, u64 flags, struct bpf_dynptr *ptr); > long bpf_dynptr_alloc(u32 size, u64 flags, struct bpf_dynptr *ptr); > void bpf_dynptr_put(struct bpf_dynptr *ptr); > > This patch sets up the verifier to support dynptrs. Dynptrs will always > reside on the program's stack frame. As such, their state is tracked > in their corresponding stack slot, which includes the type of dynptr > (DYNPTR_LOCAL vs. DYNPTR_MALLOC). > > When the program passes in an uninitialized dynptr (ARG_PTR_TO_DYNPTR | > MEM_UNINIT), the stack slots corresponding to the frame pointer > where the dynptr resides at are marked as STACK_DYNPTR. For helper functions > that take in initialized dynptrs (such as the next patch in this series > which supports dynptr reads/writes), the verifier enforces that the > dynptr has been initialized by checking that their corresponding stack > slots have been marked as STACK_DYNPTR. Dynptr release functions > (eg bpf_dynptr_put) will clear the stack slots. The verifier enforces at > program exit that there are no acquired dynptr stack slots that need > to be released. > > There are other constraints that are enforced by the verifier as > well, such as that the dynptr cannot be written to directly by the bpf > program or by non-dynptr helper functions. The last patch in this series > contains tests that trigger different cases that the verifier needs to > successfully reject. > > For now, local dynptrs cannot point to referenced memory since the > memory can be freed anytime. Support for this will be added as part > of a separate patchset. > > Signed-off-by: Joanne Koong <joannelkoong@xxxxxxxxx> > --- > include/linux/bpf.h | 68 +++++- > include/linux/bpf_verifier.h | 28 +++ > include/uapi/linux/bpf.h | 44 ++++ > kernel/bpf/helpers.c | 110 ++++++++++ > kernel/bpf/verifier.c | 372 +++++++++++++++++++++++++++++++-- > scripts/bpf_doc.py | 2 + > tools/include/uapi/linux/bpf.h | 44 ++++ > 7 files changed, 654 insertions(+), 14 deletions(-) > > [...] > +/* Called at BPF_EXIT to detect if there are any reference-tracked dynptrs that have > + * not been released. Dynptrs to local memory do not need to be released. > + */ > +static int check_dynptr_unreleased(struct bpf_verifier_env *env) > +{ > + struct bpf_func_state *state = cur_func(env); > + int allocated_slots, i; > + > + allocated_slots = state->allocated_stack / BPF_REG_SIZE; > + > + for (i = 0; i < allocated_slots; i++) { > + if (state->stack[i].slot_type[0] == STACK_DYNPTR) { > + if (dynptr_type_refcounted(state->stack[i].spilled_ptr.dynptr.type)) { > + verbose(env, "spi=%d is an unreleased dynptr\n", i); > + return -EINVAL; > + } > + } > + } > + > + return 0; > +} We need to call this function in check_ld_abs as well. > [...] -- Kartikeya