From patchwork Thu Jan 19 02:14:32 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kumar Kartikeya Dwivedi X-Patchwork-Id: 13107294 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 634ABC38159 for ; Thu, 19 Jan 2023 02:14:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229463AbjASCOw (ORCPT ); Wed, 18 Jan 2023 21:14:52 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37316 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229876AbjASCOv (ORCPT ); Wed, 18 Jan 2023 21:14:51 -0500 Received: from mail-pl1-x643.google.com (mail-pl1-x643.google.com [IPv6:2607:f8b0:4864:20::643]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B93D5222F1 for ; Wed, 18 Jan 2023 18:14:49 -0800 (PST) Received: by mail-pl1-x643.google.com with SMTP id 20so982375plo.3 for ; Wed, 18 Jan 2023 18:14:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Dg/IsF541yZad4CsNwSCeHTnte62ogz8+MGacLdAV7U=; b=Zp/OyAsnlPYveELPmO70ftawtiqJge5hYs/A0Iocd47L+XFJBavkafLyf4QgSVjD2m VMEZCIx9kmA8t/DnGYGN2dOCfENA/TSYGxDK1n2wF44w8EMBHU/Sbj6kGc3Is1RHNtg8 tx24O1xDk2uXbuqznM13cmE+Uf2jOJxmXyH71F3xFcvthuAgVd14mmZGQVMhbIYprnDZ zVvo0wrKnS34pCx8QOg+V321NjbVtL1OpA9dV76DRLPYQRMDikBXvTfHjJ/Z0MxVROL5 qJ3c2zy6gc5yr8OQNQY3hfv5drwdXYcSYW0VdiuuuFgDIKPpvVjaLEbnkx/hHycFKvEM TqLw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Dg/IsF541yZad4CsNwSCeHTnte62ogz8+MGacLdAV7U=; b=nyvxG0AmV1LyeQytdVnI76QCGiEQcDUHjtgW7ycPCOvbiXaEPVLWeqgDmF4hyTzy7u KWFZkcOLUF+qXB+PXTdNVByA4rTkQhczn+Nbi1Pi5Uwd1o6Tc6HfJTz1CD+9VZA/onol R4cM5vNqFKTNh5p44b5cPx/lXVQo2gUFIHBZqbYnjACm3tthZmDJZZfEp6gzslwXkPfB v8Dk96Eun0wDawgILtTRCCdNWxMFGO+6dul9Vm58o6jYIqoszXWQXwqfyASi8lRec1L9 IbKG+K2mPfLoNy/xJSi1o0auEt2/ztlGVLzQmEKFpvF0VMEIUOVC2EQ0fROVPN721+Zt 4JlQ== X-Gm-Message-State: AFqh2kpBbZkgo8cMkci8kD33YexufyHnTcakzpMxp6TrQrJg0or5pQMo dASJ0uERCbq9TkIsfaiV2VT/cBuQk/4= X-Google-Smtp-Source: AMrXdXsplgJGUdcaUfC3AWufT44hK6S4gFmvqMOAgqHTlOlLE/6KW69iImlAVlcViTFv/R6wsoCOXA== X-Received: by 2002:a05:6a20:1399:b0:b0:a35:b763 with SMTP id w25-20020a056a20139900b000b00a35b763mr11790472pzh.5.1674094488807; Wed, 18 Jan 2023 18:14:48 -0800 (PST) Received: from localhost ([2405:201:6014:dae3:7dbb:8857:7c39:bb2a]) by smtp.gmail.com with ESMTPSA id z2-20020a626502000000b0058bcb7b437bsm8384275pfb.215.2023.01.18.18.14.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 18 Jan 2023 18:14:48 -0800 (PST) From: Kumar Kartikeya Dwivedi To: bpf@vger.kernel.org Cc: Eduard Zingerman , Alexei Starovoitov , Andrii Nakryiko , Daniel Borkmann , Martin KaFai Lau , Joanne Koong , David Vernet Subject: [PATCH bpf-next v2 01/11] bpf: Fix state pruning for STACK_DYNPTR stack slots Date: Thu, 19 Jan 2023 07:44:32 +0530 Message-Id: <20230119021442.1465269-2-memxor@gmail.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230119021442.1465269-1-memxor@gmail.com> References: <20230119021442.1465269-1-memxor@gmail.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=10135; i=memxor@gmail.com; h=from:subject; bh=mwjmr0Y6+WJB7gOBG1vvDB64xGwmYogyGXkqVWtxWH8=; b=owEBbQKS/ZANAwAIAUzgyIZIvxHKAcsmYgBjyKc/+H8Qa6zfCRHCSO9wiyIjlmoMe19vzjvaYvVV Ni0FePuJAjMEAAEIAB0WIQRLvip+Buz51YI8YRFM4MiGSL8RygUCY8inPwAKCRBM4MiGSL8RyrsGD/ 4oPma20AogOOZoIRWdKYGAef9fa7YLJWIkuDmuE8lIBBove2WEHI/Z8rEHCAyFzy1gchBK66Hqmdl+ lMgKTlj6UJtjGivfEoKPN0siwNtZmVcrAAUoipyR/elmINLOk6FgVZfmV5uS2CsNOIzQzvaqzKS2jb MXJJcRvT9BAaAk6WfJ2MBuCyW2vkDF9h4uKWIMfHhCg5USJwEhD/3E0JPTNgorD54ztJveLJHL9cHW c8IkMSVynz4AY4c+agGM/HyvNDBh+X9lrLWv6R/CthxoEyZUT3NSXvyhngFI6rxpPON3BtGE7qwaak /F2kiAtvAh+LmcCKnB2kPV/hfs6BQibWB+2rlLwbc/p1N0Ld+KQKDnoh5eQlJPx32yced4lOU//Rtd MnyySqBvNFXrBRPMM65CLtBZTihDd58nP7Xgame9J1rT8hnEN3uf8RqDcM/nICN6aWcpgwx1d6TWQL pboOH0UFrU6NeKHenY1en0MNkYi0gJeIWU7YR867qDiHAHizrBLRZldSV3houjeJb0ifC67rza2wEa H79pt4OCcEXAFtLcwr+EzubVX91lyqWh3qm38dVOyfndMIXcxOp+U6dU1YbG9jD1nv7X4snbXDimVN X7evUStGOpsjTTstCJznMx2QqjN2nu0y8Wq8B5sBtZZB/YUdN+eMAUS/u3pQ== X-Developer-Key: i=memxor@gmail.com; a=openpgp; fpr=4BBE2A7E06ECF9D5823C61114CE0C88648BF11CA Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net The root of the problem is missing liveness marking for STACK_DYNPTR slots. This leads to all kinds of problems inside stacksafe. The verifier by default inside stacksafe ignores spilled_ptr in stack slots which do not have REG_LIVE_READ marks. Since this is being checked in the 'old' explored state, it must have already done clean_live_states for this old bpf_func_state. Hence, it won't be receiving any more liveness marks from to be explored insns (it has received REG_LIVE_DONE marking from liveness point of view). What this means is that verifier considers that it's safe to not compare the stack slot if was never read by children states. While liveness marks are usually propagated correctly following the parentage chain for spilled registers (SCALAR_VALUE and PTR_* types), the same is not the case for STACK_DYNPTR. clean_live_states hence simply rewrites these stack slots to the type STACK_INVALID since it sees no REG_LIVE_READ marks. The end result is that we will never see STACK_DYNPTR slots in explored state. Even if verifier was conservatively matching !REG_LIVE_READ slots, very next check continuing the stacksafe loop on seeing STACK_INVALID would again prevent further checks. Now as long as verifier stores an explored state which we can compare to when reaching a pruning point, we can abuse this bug to make verifier prune search for obviously unsafe paths using STACK_DYNPTR slots thinking they are never used hence safe. Doing this in unprivileged mode is a bit challenging. add_new_state is only set when seeing BPF_F_TEST_STATE_FREQ (which requires privileges) or when jmps_processed difference is >= 2 and insn_processed difference is >= 8. So coming up with the unprivileged case requires a little more work, but it is still totally possible. The test case being discussed below triggers the heuristic even in unprivileged mode. However, it no longer works since commit 8addbfc7b308 ("bpf: Gate dynptr API behind CAP_BPF"). Let's try to study the test step by step. Consider the following program (C style BPF ASM): 0 r0 = 0; 1 r6 = &ringbuf_map; 3 r1 = r6; 4 r2 = 8; 5 r3 = 0; 6 r4 = r10; 7 r4 -= -16; 8 call bpf_ringbuf_reserve_dynptr; 9 if r0 == 0 goto pc+1; 10 goto pc+1; 11 *(r10 - 16) = 0xeB9F; 12 r1 = r10; 13 r1 -= -16; 14 r2 = 0; 15 call bpf_ringbuf_discard_dynptr; 16 r0 = 0; 17 exit; We know that insn 12 will be a pruning point, hence if we force add_new_state for it, it will first verify the following path as safe in straight line exploration: 0 1 3 4 5 6 7 8 9 -> 10 -> (12) 13 14 15 16 17 Then, when we arrive at insn 12 from the following path: 0 1 3 4 5 6 7 8 9 -> 11 (12) We will find a state that has been verified as safe already at insn 12. Since register state is same at this point, regsafe will pass. Next, in stacksafe, for spi = 0 and spi = 1 (location of our dynptr) is skipped seeing !REG_LIVE_READ. The rest matches, so stacksafe returns true. Next, refsafe is also true as reference state is unchanged in both states. The states are considered equivalent and search is pruned. Hence, we are able to construct a dynptr with arbitrary contents and use the dynptr API to operate on this arbitrary pointer and arbitrary size + offset. To fix this, first define a mark_dynptr_read function that propagates liveness marks whenever a valid initialized dynptr is accessed by dynptr helpers. REG_LIVE_WRITTEN is marked whenever we initialize an uninitialized dynptr. This is done in mark_stack_slots_dynptr. It allows screening off mark_reg_read and not propagating marks upwards from that point. This ensures that we either set REG_LIVE_READ64 on both dynptr slots, or none, so clean_live_states either sets both slots to STACK_INVALID or none of them. This is the invariant the checks inside stacksafe rely on. Next, do a complete comparison of both stack slots whenever they have STACK_DYNPTR. Compare the dynptr type stored in the spilled_ptr, and also whether both form the same first_slot. Only then is the later path safe. Fixes: 97e03f521050 ("bpf: Add verifier support for dynptrs") Acked-by: Eduard Zingerman Signed-off-by: Kumar Kartikeya Dwivedi --- kernel/bpf/verifier.c | 83 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 79 insertions(+), 4 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index ca7db2ce70b9..89de5bc46f27 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -781,6 +781,9 @@ static int mark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_reg_ state->stack[spi - 1].spilled_ptr.ref_obj_id = id; } + state->stack[spi].spilled_ptr.live |= REG_LIVE_WRITTEN; + state->stack[spi - 1].spilled_ptr.live |= REG_LIVE_WRITTEN; + return 0; } @@ -805,6 +808,31 @@ static int unmark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_re __mark_reg_not_init(env, &state->stack[spi].spilled_ptr); __mark_reg_not_init(env, &state->stack[spi - 1].spilled_ptr); + + /* Why do we need to set REG_LIVE_WRITTEN for STACK_INVALID slot? + * + * While we don't allow reading STACK_INVALID, it is still possible to + * do <8 byte writes marking some but not all slots as STACK_MISC. Then, + * helpers or insns can do partial read of that part without failing, + * but check_stack_range_initialized, check_stack_read_var_off, and + * check_stack_read_fixed_off will do mark_reg_read for all 8-bytes of + * the slot conservatively. Hence we need to prevent those liveness + * marking walks. + * + * This was not a problem before because STACK_INVALID is only set by + * default (where the default reg state has its reg->parent as NULL), or + * in clean_live_states after REG_LIVE_DONE (at which point + * mark_reg_read won't walk reg->parent chain), but not randomly during + * verifier state exploration (like we did above). Hence, for our case + * parentage chain will still be live (i.e. reg->parent may be + * non-NULL), while earlier reg->parent was NULL, so we need + * REG_LIVE_WRITTEN to screen off read marker propagation when it is + * done later on reads or by mark_dynptr_read as well to unnecessary + * mark registers in verifier state. + */ + state->stack[spi].spilled_ptr.live |= REG_LIVE_WRITTEN; + state->stack[spi - 1].spilled_ptr.live |= REG_LIVE_WRITTEN; + return 0; } @@ -2390,6 +2418,30 @@ static int mark_reg_read(struct bpf_verifier_env *env, return 0; } +static int mark_dynptr_read(struct bpf_verifier_env *env, struct bpf_reg_state *reg) +{ + struct bpf_func_state *state = func(env, reg); + int spi, ret; + + /* For CONST_PTR_TO_DYNPTR, it must have already been done by + * check_reg_arg in check_helper_call and mark_btf_func_reg_size in + * check_kfunc_call. + */ + if (reg->type == CONST_PTR_TO_DYNPTR) + return 0; + spi = get_spi(reg->off); + /* Caller ensures dynptr is valid and initialized, which means spi is in + * bounds and spi is the first dynptr slot. Simply mark stack slot as + * read. + */ + ret = mark_reg_read(env, &state->stack[spi].spilled_ptr, + state->stack[spi].spilled_ptr.parent, REG_LIVE_READ64); + if (ret) + return ret; + return mark_reg_read(env, &state->stack[spi - 1].spilled_ptr, + state->stack[spi - 1].spilled_ptr.parent, REG_LIVE_READ64); +} + /* This function is supposed to be used by the following 32-bit optimization * code only. It returns TRUE if the source or destination register operates * on 64-bit, otherwise return FALSE. @@ -5930,6 +5982,7 @@ int process_dynptr_func(struct bpf_verifier_env *env, int regno, enum bpf_arg_type arg_type, struct bpf_call_arg_meta *meta) { struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[regno]; + int err; /* MEM_UNINIT and MEM_RDONLY are exclusive, when applied to an * ARG_PTR_TO_DYNPTR (or ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_*): @@ -6010,6 +6063,10 @@ int process_dynptr_func(struct bpf_verifier_env *env, int regno, err_extra, regno); return -EINVAL; } + + err = mark_dynptr_read(env, reg); + if (err) + return err; } return 0; } @@ -13174,6 +13231,7 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold, static bool stacksafe(struct bpf_verifier_env *env, struct bpf_func_state *old, struct bpf_func_state *cur, struct bpf_id_pair *idmap) { + const struct bpf_reg_state *old_reg, *cur_reg; int i, spi; /* walk slots of the explored stack and ignore any additional @@ -13215,10 +13273,9 @@ static bool stacksafe(struct bpf_verifier_env *env, struct bpf_func_state *old, return false; if (i % BPF_REG_SIZE != BPF_REG_SIZE - 1) continue; - if (!is_spilled_reg(&old->stack[spi])) - continue; - if (!regsafe(env, &old->stack[spi].spilled_ptr, - &cur->stack[spi].spilled_ptr, idmap)) + /* Both old and cur are having same slot_type */ + switch (old->stack[spi].slot_type[BPF_REG_SIZE - 1]) { + case STACK_SPILL: /* when explored and current stack slot are both storing * spilled registers, check that stored pointers types * are the same as well. @@ -13229,7 +13286,25 @@ static bool stacksafe(struct bpf_verifier_env *env, struct bpf_func_state *old, * such verifier states are not equivalent. * return false to continue verification of this path */ + if (!regsafe(env, &old->stack[spi].spilled_ptr, + &cur->stack[spi].spilled_ptr, idmap)) + return false; + break; + case STACK_DYNPTR: + old_reg = &old->stack[spi].spilled_ptr; + cur_reg = &cur->stack[spi].spilled_ptr; + if (old_reg->dynptr.type != cur_reg->dynptr.type || + old_reg->dynptr.first_slot != cur_reg->dynptr.first_slot || + !check_ids(old_reg->ref_obj_id, cur_reg->ref_obj_id, idmap)) + return false; + break; + case STACK_MISC: + case STACK_ZERO: + case STACK_INVALID: + continue; + default: return false; + } } return true; } From patchwork Thu Jan 19 02:14:33 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kumar Kartikeya Dwivedi X-Patchwork-Id: 13107295 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 3C3C6C38159 for ; Thu, 19 Jan 2023 02:14:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229719AbjASCO5 (ORCPT ); Wed, 18 Jan 2023 21:14:57 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37356 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229850AbjASCOz (ORCPT ); Wed, 18 Jan 2023 21:14:55 -0500 Received: from mail-pl1-x643.google.com (mail-pl1-x643.google.com [IPv6:2607:f8b0:4864:20::643]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 21B1B4ABC7 for ; Wed, 18 Jan 2023 18:14:53 -0800 (PST) Received: by mail-pl1-x643.google.com with SMTP id d9so948566pll.9 for ; Wed, 18 Jan 2023 18:14:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=pF+zT5uY51i3QCWhl5Ub8dzTFXa/KM+z58fj2lg7VUg=; b=cCV4deTpksyqKTEsmVPMKIwYX09CPR57GhhZWgxwQrEF/K5vv3N2Ee10qfmLNKy8jT kr0mlhLLNtEm71TMAI3veUWbfOHydg+9UJu2IijjGU2XBCyaoVhSd0i77COn9zbxyvlE DAkJzO/S2EjeoziqCq+796kwrKdHpYr2VVJmpyc9Qo/hNTYSyDHm0V9hExfgpneK2uI9 NIcwbSgqlraN156bixJizQJ6oCgcKzFBjrMbfZQ67V1MLoZMZZ5WKWQJqD1sJ5LcYgZn 1s3SMbBb5J8+MxV8WkLH3EXOO0792ECKLB4F5eH0PR4z2bDTpKgTVZeSiKWXCeYhHq8N xSrA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=pF+zT5uY51i3QCWhl5Ub8dzTFXa/KM+z58fj2lg7VUg=; b=1ItCq3H1kFvs0V4vihfDiI147CFKErlaL4/YUPk2AqCBTk2saD6vyIVqJGvCprDZOX xSrjKX2H9WGQVbyKqpE2b/onS/65R0c+XXETRFWxiXPIIOaRc/dvexaq/bLpwMmGRhFO wRkvN1ifWx5xcVLTAZqLxB3sQA29ctbW9XTvNMDEy7O8eTyARAX1+P1foOlvqTG9onMm 5WJPJlbng8xtKb0pf7HVc3UGElN2vVqxj4v/ArnAwCuZEEMePIOhs4pzqJOWriGRJOIh fHU+bSZgBukjudKtRMKutw3kd8tL+QQtAHgZkvzOy5wr3vB3u/Mqb7r2wHe9XZXsgIih Wwsg== X-Gm-Message-State: AFqh2kon5ip1rWu/KzWcOW0pDUTPatydTzG1OYEhkw7oxjxfGpCIrHpX Vt92cbkMHW3C/WaTql8ehNXTdiV8sPk= X-Google-Smtp-Source: AMrXdXucUom35iybPLtOYcvhKVOyQN1v0/3jZhd1YNHAe4LmdWphkOtxzOdxaDK49kD5Dbin9oAtew== X-Received: by 2002:a05:6a20:c198:b0:b8:ca86:d1e8 with SMTP id bg24-20020a056a20c19800b000b8ca86d1e8mr9345034pzb.14.1674094492246; Wed, 18 Jan 2023 18:14:52 -0800 (PST) Received: from localhost ([2405:201:6014:dae3:7dbb:8857:7c39:bb2a]) by smtp.gmail.com with ESMTPSA id x21-20020aa79ad5000000b00580c8a15d13sm14309562pfp.11.2023.01.18.18.14.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 18 Jan 2023 18:14:51 -0800 (PST) From: Kumar Kartikeya Dwivedi To: bpf@vger.kernel.org Cc: Alexei Starovoitov , Andrii Nakryiko , Daniel Borkmann , Martin KaFai Lau , Joanne Koong , David Vernet , Eduard Zingerman Subject: [PATCH bpf-next v2 02/11] bpf: Fix missing var_off check for ARG_PTR_TO_DYNPTR Date: Thu, 19 Jan 2023 07:44:33 +0530 Message-Id: <20230119021442.1465269-3-memxor@gmail.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230119021442.1465269-1-memxor@gmail.com> References: <20230119021442.1465269-1-memxor@gmail.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=9485; i=memxor@gmail.com; h=from:subject; bh=JO6ysJpkKMlF5l7uuTFCTNOtXsfbqEGzZzVmRu4NCPU=; b=owEBbQKS/ZANAwAIAUzgyIZIvxHKAcsmYgBjyKc/b1K0wODWB/GR4RRWxE3XEPcFSEnjFITbZMxO pPqs4JiJAjMEAAEIAB0WIQRLvip+Buz51YI8YRFM4MiGSL8RygUCY8inPwAKCRBM4MiGSL8Ryn03D/ 901/BCRv3zRzQjhFmGLrslYXOM3pt5Msl7de5GUQFtZAWSqouTiEiWXffXlz8BqAlqvhIcJK3Z+8RO dlv81rQ/JuLQciFT8kkmx62qAv6Mvr9XQMu0HCx1/ul86qZhUJdMt2C/4i1TdP2qJXpCDF/xa4jTui mHRrllE6BuGXLPxEAAwlxI6nDf22vxBokwRyzyiGdw+ogGj030D62TJ1rW7fNoWNB5i9IobjfucEyE XbOQhPNbx6444Jj4+cdujiEO5OOv0X55h6u5X+xvNqW+C/NwcBD5DkvF6DLD7uonYoDj2PgrcWmPo6 7ygSzuf0Ncsunwk1bmaNcQT61IyNWHnKHxZCVeQ/s1ljK4+SKJv0My75+03hsSu0u1DwRPM0mcPoaA WThSLdGD9Fxeojq74Cf3Mlp4LBskgOxN3hxXG99/NqWg+H412rLU3SlNU68ZAdJGWOGDGsWbGYv8hn q4xmYQlW+4mglsyogGo/lrZ1KDcNU9mbzsXVwb3TsPfkcyboem4BSDdGl1VgJoNex0ezQO5hN/KmKV A4/Vswh/HsEUaWFscXu8/fwGtwVfmdslGgXkPO0w4wBRYSoB6X8KUWW8BzXeoN5VgjxgWfdMt+Nb9m KDWjSV6fbqoW7M9ahnsKKFZhkdPRymtDGzRXK8LedpQOMhBIVPTp33UG4ZcA== X-Developer-Key: i=memxor@gmail.com; a=openpgp; fpr=4BBE2A7E06ECF9D5823C61114CE0C88648BF11CA Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net Currently, the dynptr function is not checking the variable offset part of PTR_TO_STACK that it needs to check. The fixed offset is considered when computing the stack pointer index, but if the variable offset was not a constant (such that it could not be accumulated in reg->off), we will end up a discrepency where runtime pointer does not point to the actual stack slot we mark as STACK_DYNPTR. It is impossible to precisely track dynptr state when variable offset is not constant, hence, just like bpf_timer, kptr, bpf_spin_lock, etc. simply reject the case where reg->var_off is not constant. Then, consider both reg->off and reg->var_off.value when computing the stack pointer index. A new helper dynptr_get_spi is introduced to hide over these details since the dynptr needs to be located in multiple places outside the process_dynptr_func checks, hence once we know it's a PTR_TO_STACK, we need to enforce these checks in all places. Note that it is disallowed for unprivileged users to have a non-constant var_off, so this problem should only be possible to trigger from programs having CAP_PERFMON. However, its effects can vary. Without the fix, it is possible to replace the contents of the dynptr arbitrarily by making verifier mark different stack slots than actual location and then doing writes to the actual stack address of dynptr at runtime. Fixes: 97e03f521050 ("bpf: Add verifier support for dynptrs") Signed-off-by: Kumar Kartikeya Dwivedi Acked-by: Joanne Koong --- kernel/bpf/verifier.c | 83 +++++++++++++++---- .../bpf/prog_tests/kfunc_dynptr_param.c | 2 +- .../testing/selftests/bpf/progs/dynptr_fail.c | 4 +- 3 files changed, 68 insertions(+), 21 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 89de5bc46f27..eeb6f1b2bd60 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -638,11 +638,34 @@ static void print_liveness(struct bpf_verifier_env *env, verbose(env, "D"); } -static int get_spi(s32 off) +static int __get_spi(s32 off) { return (-off - 1) / BPF_REG_SIZE; } +static int dynptr_get_spi(struct bpf_verifier_env *env, struct bpf_reg_state *reg) +{ + int off, spi; + + if (!tnum_is_const(reg->var_off)) { + verbose(env, "dynptr has to be at the constant offset\n"); + return -EINVAL; + } + + off = reg->off + reg->var_off.value; + if (off % BPF_REG_SIZE) { + verbose(env, "cannot pass in dynptr at an offset=%d\n", off); + return -EINVAL; + } + + spi = __get_spi(off); + if (spi < 1) { + verbose(env, "cannot pass in dynptr at an offset=%d\n", off); + return -EINVAL; + } + return spi; +} + static bool is_spi_bounds_valid(struct bpf_func_state *state, int spi, int nr_slots) { int allocated_slots = state->allocated_stack / BPF_REG_SIZE; @@ -754,7 +777,9 @@ static int mark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_reg_ enum bpf_dynptr_type type; int spi, i, id; - spi = get_spi(reg->off); + spi = dynptr_get_spi(env, reg); + if (spi < 0) + return spi; if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS)) return -EINVAL; @@ -792,7 +817,9 @@ static int unmark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_re struct bpf_func_state *state = func(env, reg); int spi, i; - spi = get_spi(reg->off); + spi = dynptr_get_spi(env, reg); + if (spi < 0) + return spi; if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS)) return -EINVAL; @@ -844,7 +871,11 @@ static bool is_dynptr_reg_valid_uninit(struct bpf_verifier_env *env, struct bpf_ if (reg->type == CONST_PTR_TO_DYNPTR) return false; - spi = get_spi(reg->off); + spi = dynptr_get_spi(env, reg); + if (spi < 0) + return false; + + /* We will do check_mem_access to check and update stack bounds later */ if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS)) return true; @@ -860,14 +891,15 @@ static bool is_dynptr_reg_valid_uninit(struct bpf_verifier_env *env, struct bpf_ static bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, struct bpf_reg_state *reg) { struct bpf_func_state *state = func(env, reg); - int spi; - int i; + int spi, i; /* This already represents first slot of initialized bpf_dynptr */ if (reg->type == CONST_PTR_TO_DYNPTR) return true; - spi = get_spi(reg->off); + spi = dynptr_get_spi(env, reg); + if (spi < 0) + return false; if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS) || !state->stack[spi].spilled_ptr.dynptr.first_slot) return false; @@ -896,7 +928,9 @@ static bool is_dynptr_type_expected(struct bpf_verifier_env *env, struct bpf_reg if (reg->type == CONST_PTR_TO_DYNPTR) { return reg->dynptr.type == dynptr_type; } else { - spi = get_spi(reg->off); + spi = dynptr_get_spi(env, reg); + if (spi < 0) + return false; return state->stack[spi].spilled_ptr.dynptr.type == dynptr_type; } } @@ -2429,7 +2463,9 @@ static int mark_dynptr_read(struct bpf_verifier_env *env, struct bpf_reg_state * */ if (reg->type == CONST_PTR_TO_DYNPTR) return 0; - spi = get_spi(reg->off); + spi = dynptr_get_spi(env, reg); + if (spi < 0) + return spi; /* Caller ensures dynptr is valid and initialized, which means spi is in * bounds and spi is the first dynptr slot. Simply mark stack slot as * read. @@ -5993,12 +6029,14 @@ int process_dynptr_func(struct bpf_verifier_env *env, int regno, } /* CONST_PTR_TO_DYNPTR already has fixed and var_off as 0 due to * check_func_arg_reg_off's logic. We only need to check offset - * alignment for PTR_TO_STACK. + * and its alignment for PTR_TO_STACK. */ - if (reg->type == PTR_TO_STACK && (reg->off % BPF_REG_SIZE)) { - verbose(env, "cannot pass in dynptr at an offset=%d\n", reg->off); - return -EINVAL; + if (reg->type == PTR_TO_STACK) { + err = dynptr_get_spi(env, reg); + if (err < 0) + return err; } + /* MEM_UNINIT - Points to memory that is an appropriate candidate for * constructing a mutable bpf_dynptr object. * @@ -6404,15 +6442,16 @@ int check_func_arg_reg_off(struct bpf_verifier_env *env, } } -static u32 dynptr_ref_obj_id(struct bpf_verifier_env *env, struct bpf_reg_state *reg) +static int dynptr_ref_obj_id(struct bpf_verifier_env *env, struct bpf_reg_state *reg) { struct bpf_func_state *state = func(env, reg); int spi; if (reg->type == CONST_PTR_TO_DYNPTR) return reg->ref_obj_id; - - spi = get_spi(reg->off); + spi = dynptr_get_spi(env, reg); + if (spi < 0) + return spi; return state->stack[spi].spilled_ptr.ref_obj_id; } @@ -6486,7 +6525,9 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, * PTR_TO_STACK. */ if (reg->type == PTR_TO_STACK) { - spi = get_spi(reg->off); + spi = dynptr_get_spi(env, reg); + if (spi < 0) + return spi; if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS) || !state->stack[spi].spilled_ptr.ref_obj_id) { verbose(env, "arg %d is an unacquired reference\n", regno); @@ -7976,13 +8017,19 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn for (i = 0; i < MAX_BPF_FUNC_REG_ARGS; i++) { if (arg_type_is_dynptr(fn->arg_type[i])) { struct bpf_reg_state *reg = ®s[BPF_REG_1 + i]; + int ref_obj_id; if (meta.ref_obj_id) { verbose(env, "verifier internal error: meta.ref_obj_id already set\n"); return -EFAULT; } - meta.ref_obj_id = dynptr_ref_obj_id(env, reg); + ref_obj_id = dynptr_ref_obj_id(env, reg); + if (err < 0) { + verbose(env, "verifier internal error: failed to obtain dynptr ref_obj_id\n"); + return err; + } + meta.ref_obj_id = ref_obj_id; break; } } diff --git a/tools/testing/selftests/bpf/prog_tests/kfunc_dynptr_param.c b/tools/testing/selftests/bpf/prog_tests/kfunc_dynptr_param.c index a9229260a6ce..72800b1e8395 100644 --- a/tools/testing/selftests/bpf/prog_tests/kfunc_dynptr_param.c +++ b/tools/testing/selftests/bpf/prog_tests/kfunc_dynptr_param.c @@ -18,7 +18,7 @@ static struct { const char *expected_verifier_err_msg; int expected_runtime_err; } kfunc_dynptr_tests[] = { - {"not_valid_dynptr", "Expected an initialized dynptr as arg #1", 0}, + {"not_valid_dynptr", "cannot pass in dynptr at an offset=-8", 0}, {"not_ptr_to_stack", "arg#0 expected pointer to stack or dynptr_ptr", 0}, {"dynptr_data_null", NULL, -EBADMSG}, }; diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c index 78debc1b3820..02d57b95cf6e 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_fail.c +++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c @@ -382,7 +382,7 @@ int invalid_helper1(void *ctx) /* A dynptr can't be passed into a helper function at a non-zero offset */ SEC("?raw_tp") -__failure __msg("Expected an initialized dynptr as arg #3") +__failure __msg("cannot pass in dynptr at an offset=-8") int invalid_helper2(void *ctx) { struct bpf_dynptr ptr; @@ -584,7 +584,7 @@ int invalid_read4(void *ctx) /* Initializing a dynptr on an offset should fail */ SEC("?raw_tp") -__failure __msg("invalid write to stack") +__failure __msg("cannot pass in dynptr at an offset=0") int invalid_offset(void *ctx) { struct bpf_dynptr ptr; From patchwork Thu Jan 19 02:14:34 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kumar Kartikeya Dwivedi X-Patchwork-Id: 13107296 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 51B8FC678D4 for ; Thu, 19 Jan 2023 02:15:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229780AbjASCO7 (ORCPT ); Wed, 18 Jan 2023 21:14:59 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37394 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229744AbjASCO6 (ORCPT ); Wed, 18 Jan 2023 21:14:58 -0500 Received: from mail-pl1-x643.google.com (mail-pl1-x643.google.com [IPv6:2607:f8b0:4864:20::643]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A424E45BE4 for ; Wed, 18 Jan 2023 18:14:56 -0800 (PST) Received: by mail-pl1-x643.google.com with SMTP id v23so992221plo.1 for ; Wed, 18 Jan 2023 18:14:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=FJ6M0fYb+kKSjua9KImxru1Mcnu2oPYISTytAcNabI8=; b=Q2vXGr7mIO7Agys0E9m7pRqTYLsZQ1WpzVY5X8BvptxrdtxIn0gCRDt2ZMYeq0PjcU DPcU9FCb6B4ZqykkPlq3e+JoO/XQ0PdwCyq2yC0RL67fUwd6icaV8mwd9rwPuJiLes0f nM9JuZdIPHTZGFmWl+4e7CahGFEYVEKG/Ik0og2XlYRqawYRG03AgaUGE2Y8SOgDAqI0 eBRsNAJ4HeBwKEMxZzilEhMEXtczkFA54P2XCe/5YKHpzEs1ZtVhs8mvGPVvp0R3plhl EemiHNJuWL7ooVUSWEW0QLoQyrxaPndm3alIkprtUacHOVJOZO4QqCaEVDjXorQIAsh5 2mfw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=FJ6M0fYb+kKSjua9KImxru1Mcnu2oPYISTytAcNabI8=; b=hkA02JqE6iSxYvLcZ8q5taT73O1KqUZ/8b4AcBLeIm8Zif1WkR8pLtghgeXJZntmU4 Y62K0HTZiTXHivmLMMXRiCaWZ52tHONFlB5gT7akHV7Uu9w9boyu+clbBk5+7wwoCulM 8+D02N3YfrLlPzouIgVgMQnNwkp/L+WIQj01OnqIr+9mh3B15TyABQcUn1IbVMvz91PJ Lp2AIyxuwetSK21Tbkwh12lsz0fJ8QswckeySs9qEbh0l4beXBml6EbdiVux7QBu8AdV kwp1KpYxlcF9nDyjDKxaWcE4KiMhZ6joDgbaIg7rginN32PEYlqsBn8l6j9XXEyqYsYj eTSw== X-Gm-Message-State: AFqh2kqACZTxrJDBBNR3O3uRz0yc6puNWkhMRJi7k2HeUgTwJ44H9N/r g2UxScMvHw3Zxz1iy0/RB9LVQWoXpbE= X-Google-Smtp-Source: AMrXdXuN0MYrxl10rxkSEHHIa6J3pOB7KV/CtOtmjNX+LPzMbpvhj9WLiPU9NXcmmt/SbNAgWNf5ug== X-Received: by 2002:a17:902:f304:b0:194:6e8d:89af with SMTP id c4-20020a170902f30400b001946e8d89afmr8445839ple.27.1674094495822; Wed, 18 Jan 2023 18:14:55 -0800 (PST) Received: from localhost ([2405:201:6014:dae3:7dbb:8857:7c39:bb2a]) by smtp.gmail.com with ESMTPSA id y13-20020a170902b48d00b00192f7f8db8esm10611676plr.297.2023.01.18.18.14.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 18 Jan 2023 18:14:55 -0800 (PST) From: Kumar Kartikeya Dwivedi To: bpf@vger.kernel.org Cc: Alexei Starovoitov , Andrii Nakryiko , Daniel Borkmann , Martin KaFai Lau , Joanne Koong , David Vernet , Eduard Zingerman Subject: [PATCH bpf-next v2 03/11] bpf: Fix partial dynptr stack slot reads/writes Date: Thu, 19 Jan 2023 07:44:34 +0530 Message-Id: <20230119021442.1465269-4-memxor@gmail.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230119021442.1465269-1-memxor@gmail.com> References: <20230119021442.1465269-1-memxor@gmail.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=9385; i=memxor@gmail.com; h=from:subject; bh=Cepeq0DQIm/49c5PYR07xlZ5eiGiFAAUzkDv0sGQ9oM=; b=owEBbQKS/ZANAwAIAUzgyIZIvxHKAcsmYgBjyKc/NZG7jF+/PcTgBNnX5rOifEQuhXLO4xkXapxO s7PW0SuJAjMEAAEIAB0WIQRLvip+Buz51YI8YRFM4MiGSL8RygUCY8inPwAKCRBM4MiGSL8Ryr0zD/ 9Ji9DlyHOW06DyOovxJ7ESTGhVDgPkG24oucwFFmcrU4xEkq1Rn5AvdjvJUcWEl4rJ666tLTgcXN5u +1Yw3Fkz7qrRH+XUjoBWlvI7Hb3IovxX1/dYEdAnh6bBYb6YDdF+NHDzSWugBZ/A9+xMRNLmRHfTMl g+KcE9PE1VaqEAv9MTRz6ZxHswT40/yskbNa4dZsrlqY98smoKL98UIZDj7Mzha0BL7oNoB08/aJ10 b6bO0mlrBhWfJd1at20uffdW6L1rRJlnkh4CVZnOoUeu85Aun2gd18y3a9upKdUmGapMnnbv4FjglD MJPvc5lgii7+LfQX6nygbZF5QDVUX1B7/gEm8D4ehaTsoDBVX/Zq7GmwmF6PGBUTljFQXl+VhZlpsZ 4UouUk1aEsMg8OtvSCDQArCVJ+bP4q3Cvbb4u92GsIV8xJnbV2grEUiTLY40f/VfAWP4AxVU/u7ouY EVLTNxpfScyjtE0elC6lx0kQJm2u5hb1UOD0C1n6/AcBgQ/QQD7Cj7qHb3DBvFJ0ADkVyLTVp+zSuO Xyz6IVFjZzuel8frXcp2EyiymGWXjQDAvRZnRC5b1oLzOsPXBu/wg9Io3XiBENtgMaX7TFZsZzMSFP LTrm2Y23jESyZLaLALxDfOkhLXQlHcUaeRQKELIJO34OKokOnDXXALP7YwDQ== X-Developer-Key: i=memxor@gmail.com; a=openpgp; fpr=4BBE2A7E06ECF9D5823C61114CE0C88648BF11CA Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net Currently, while reads are disallowed for dynptr stack slots, writes are not. Reads don't work from both direct access and helpers, while writes do work in both cases, but have the effect of overwriting the slot_type. While this is fine, handling for a few edge cases is missing. Firstly, a user can overwrite the stack slots of dynptr partially. Consider the following layout: spi: [d][d][?] 2 1 0 First slot is at spi 2, second at spi 1. Now, do a write of 1 to 8 bytes for spi 1. This will essentially either write STACK_MISC for all slot_types or STACK_MISC and STACK_ZERO (in case of size < BPF_REG_SIZE partial write of zeroes). The end result is that slot is scrubbed. Now, the layout is: spi: [d][m][?] 2 1 0 Suppose if user initializes spi = 1 as dynptr. We get: spi: [d][d][d] 2 1 0 But this time, both spi 2 and spi 1 have first_slot = true. Now, when passing spi 2 to dynptr helper, it will consider it as initialized as it does not check whether second slot has first_slot == false. And spi 1 should already work as normal. This effectively replaced size + offset of first dynptr, hence allowing invalid OOB reads and writes. Make a few changes to protect against this: When writing to PTR_TO_STACK using BPF insns, when we touch spi of a STACK_DYNPTR type, mark both first and second slot (regardless of which slot we touch) as STACK_INVALID. Reads are already prevented. Second, prevent writing to stack memory from helpers if the range may contain any STACK_DYNPTR slots. Reads are already prevented. For helpers, we cannot allow it to destroy dynptrs from the writes as depending on arguments, helper may take uninit_mem and dynptr both at the same time. This would mean that helper may write to uninit_mem before it reads the dynptr, which would be bad. PTR_TO_MEM: [?????dd] Depending on the code inside the helper, it may end up overwriting the dynptr contents first and then read those as the dynptr argument. Verifier would only simulate destruction when it does byte by byte access simulation in check_helper_call for meta.access_size, and fail to catch this case, as it happens after argument checks. The same would need to be done for any other non-trivial objects created on the stack in the future, such as bpf_list_head on stack, or bpf_rb_root on stack. A common misunderstanding in the current code is that MEM_UNINIT means writes, but note that writes may also be performed even without MEM_UNINIT in case of helpers, in that case the code after handling meta && meta->raw_mode will complain when it sees STACK_DYNPTR. So that invalid read case also covers writes to potential STACK_DYNPTR slots. The only loophole was in case of meta->raw_mode which simulated writes through instructions which could overwrite them. A future series sequenced after this will focus on the clean up of helper access checks and bugs around that. Fixes: 97e03f521050 ("bpf: Add verifier support for dynptrs") Signed-off-by: Kumar Kartikeya Dwivedi --- kernel/bpf/verifier.c | 102 ++++++++++++++++++ .../testing/selftests/bpf/progs/dynptr_fail.c | 6 +- 2 files changed, 105 insertions(+), 3 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index eeb6f1b2bd60..09c09d9bfd89 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -769,6 +769,8 @@ static void mark_dynptr_cb_reg(struct bpf_reg_state *reg, __mark_dynptr_reg(reg, type, true); } +static int destroy_if_dynptr_stack_slot(struct bpf_verifier_env *env, + struct bpf_func_state *state, int spi); static int mark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_reg_state *reg, enum bpf_arg_type arg_type, int insn_idx) @@ -863,6 +865,69 @@ static int unmark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_re return 0; } +static void __mark_reg_unknown(const struct bpf_verifier_env *env, + struct bpf_reg_state *reg); + +static int destroy_if_dynptr_stack_slot(struct bpf_verifier_env *env, + struct bpf_func_state *state, int spi) +{ + int i; + + /* We always ensure that STACK_DYNPTR is never set partially, + * hence just checking for slot_type[0] is enough. This is + * different for STACK_SPILL, where it may be only set for + * 1 byte, so code has to use is_spilled_reg. + */ + if (state->stack[spi].slot_type[0] != STACK_DYNPTR) + return 0; + + /* Reposition spi to first slot */ + if (!state->stack[spi].spilled_ptr.dynptr.first_slot) + spi = spi + 1; + + if (dynptr_type_refcounted(state->stack[spi].spilled_ptr.dynptr.type)) { + verbose(env, "cannot overwrite referenced dynptr\n"); + return -EINVAL; + } + + mark_stack_slot_scratched(env, spi); + mark_stack_slot_scratched(env, spi - 1); + + /* Writing partially to one dynptr stack slot destroys both. */ + for (i = 0; i < BPF_REG_SIZE; i++) { + state->stack[spi].slot_type[i] = STACK_INVALID; + state->stack[spi - 1].slot_type[i] = STACK_INVALID; + } + + /* Invalidate any slices associated with this dynptr */ + if (dynptr_type_refcounted(state->stack[spi].spilled_ptr.dynptr.type)) { + int ref_obj_id = state->stack[spi].spilled_ptr.ref_obj_id; + struct bpf_func_state *fstate; + struct bpf_reg_state *reg; + + bpf_for_each_reg_in_vstate(env->cur_state, fstate, reg, ({ + if (reg->ref_obj_id == ref_obj_id) { + if (!env->allow_ptr_leaks) + __mark_reg_not_init(env, reg); + else + __mark_reg_unknown(env, reg); + } + })); + } + + /* Do not release reference state, we are destroying dynptr on stack, + * not using some helper to release it. Just reset register. + */ + __mark_reg_not_init(env, &state->stack[spi].spilled_ptr); + __mark_reg_not_init(env, &state->stack[spi - 1].spilled_ptr); + + /* Same reason as unmark_stack_slots_dynptr above */ + state->stack[spi].spilled_ptr.live |= REG_LIVE_WRITTEN; + state->stack[spi - 1].spilled_ptr.live |= REG_LIVE_WRITTEN; + + return 0; +} + static bool is_dynptr_reg_valid_uninit(struct bpf_verifier_env *env, struct bpf_reg_state *reg) { struct bpf_func_state *state = func(env, reg); @@ -3391,6 +3456,10 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, env->insn_aux_data[insn_idx].sanitize_stack_spill = true; } + err = destroy_if_dynptr_stack_slot(env, state, spi); + if (err) + return err; + mark_stack_slot_scratched(env, spi); if (reg && !(off % BPF_REG_SIZE) && register_is_bounded(reg) && !register_is_null(reg) && env->bpf_capable) { @@ -3504,6 +3573,14 @@ static int check_stack_write_var_off(struct bpf_verifier_env *env, if (err) return err; + for (i = min_off; i < max_off; i++) { + int spi; + + spi = __get_spi(i); + err = destroy_if_dynptr_stack_slot(env, state, spi); + if (err) + return err; + } /* Variable offset writes destroy any spilled pointers in range. */ for (i = min_off; i < max_off; i++) { @@ -5531,6 +5608,31 @@ static int check_stack_range_initialized( } if (meta && meta->raw_mode) { + /* Ensure we won't be overwriting dynptrs when simulating byte + * by byte access in check_helper_call using meta.access_size. + * This would be a problem if we have a helper in the future + * which takes: + * + * helper(uninit_mem, len, dynptr) + * + * Now, uninint_mem may overlap with dynptr pointer. Hence, it + * may end up writing to dynptr itself when touching memory from + * arg 1. This can be relaxed on a case by case basis for known + * safe cases, but reject due to the possibilitiy of aliasing by + * default. + */ + for (i = min_off; i < max_off + access_size; i++) { + int stack_off = -i - 1; + + spi = __get_spi(i); + /* raw_mode may write past allocated_stack */ + if (state->allocated_stack <= stack_off) + continue; + if (state->stack[spi].slot_type[stack_off % BPF_REG_SIZE] == STACK_DYNPTR) { + verbose(env, "potential write to dynptr at off=%d disallowed\n", i); + return -EACCES; + } + } meta->access_size = access_size; meta->regno = regno; return 0; diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c index 02d57b95cf6e..9dc3f23a8270 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_fail.c +++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c @@ -420,7 +420,7 @@ int invalid_write1(void *ctx) * offset */ SEC("?raw_tp") -__failure __msg("Expected an initialized dynptr as arg #3") +__failure __msg("cannot overwrite referenced dynptr") int invalid_write2(void *ctx) { struct bpf_dynptr ptr; @@ -444,7 +444,7 @@ int invalid_write2(void *ctx) * non-const offset */ SEC("?raw_tp") -__failure __msg("Expected an initialized dynptr as arg #1") +__failure __msg("cannot overwrite referenced dynptr") int invalid_write3(void *ctx) { struct bpf_dynptr ptr; @@ -476,7 +476,7 @@ static int invalid_write4_callback(__u32 index, void *data) * be invalidated as a dynptr */ SEC("?raw_tp") -__failure __msg("arg 1 is an unacquired reference") +__failure __msg("cannot overwrite referenced dynptr") int invalid_write4(void *ctx) { struct bpf_dynptr ptr; From patchwork Thu Jan 19 02:14:35 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kumar Kartikeya Dwivedi X-Patchwork-Id: 13107297 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 9785EC38159 for ; Thu, 19 Jan 2023 02:15:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229861AbjASCPC (ORCPT ); Wed, 18 Jan 2023 21:15:02 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37444 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229840AbjASCPB (ORCPT ); Wed, 18 Jan 2023 21:15:01 -0500 Received: from mail-pf1-x441.google.com (mail-pf1-x441.google.com [IPv6:2607:f8b0:4864:20::441]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2A43C46089 for ; Wed, 18 Jan 2023 18:15:00 -0800 (PST) Received: by mail-pf1-x441.google.com with SMTP id a184so400733pfa.9 for ; Wed, 18 Jan 2023 18:15:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=id88U8b5DhWAUq+b2vG3/F9nyL2akCy+zDRYHvXeozM=; b=fjcExwTk/tcA3tlIZr8co6n6zrWssVcppOLsUErLczCGSfvK2U15AsvmqXWCveiSHH JhebhmaSBeDmSJvj0UY6JczKS4kCf9qu0cgjemn8vCdoJikn79eTyf9/CRPJ2/rgnQDT fVjby8+egBa92GaEVb+fxfxv3Hm6sw99TcFBHQRGlRf/D0Im3Ii8SmLXDce1OABaguaZ IGXF+IMd1ygyh4TEcMPozvavJ4kGydIJWg6QFEf6qO9FtzgeId1P76YczVWQXcbDu0W6 ndm+iIZScoHAHbY8UKa16ubnVNToI7+uxfUDrLz3CQkZKWQFNxB3guBPJLbaQXe4KNig mqdQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=id88U8b5DhWAUq+b2vG3/F9nyL2akCy+zDRYHvXeozM=; b=TpXcVaySJf/JhKd/HPDXMhGd98BIUtFaa3lgG7uVlvOiowmaNJdBoHD0Ff9lerYHDm iXU+UbwCpw75U5JpSSG85qFdjK8taCbXWYHSnplSgWFOCCHXhjz8S0nY+5Ffmm4ciSog gufW8L2q1jtjqpURLCy90CWG2QD6Hr3M7a+LrI9Hh3hQoqisoL6Nq1+d22Vxc6/whbCO C6J/Ar5fdLTZFqNIzX2p4bo35ClBd8eKs+QCRC17Caoqhliqm0Tj7yliX5dbLKp+Bwuu CQFwYV3b2tQIAuYxEBqV3Zkd/tHS6oj6KnA4oAGc7gtqQMOnVAAwv1CRbaRoxxz0ChAv sm5A== X-Gm-Message-State: AFqh2kpuesCrsorucue2uZbFR98Q/Tidtj1hB0BhLvVyXp9GilTfz1I3 WT0SOFndu9+2Q0dxBA1z6+fe7z96qQE= X-Google-Smtp-Source: AMrXdXsZvL+HfJAWx3uqVVv4fs4w3E7RUqY95nPJ4UjLDXa3y1HOtSqNeW3erHaM+75IijM4KesdgQ== X-Received: by 2002:aa7:854f:0:b0:58b:b9ce:cda1 with SMTP id y15-20020aa7854f000000b0058bb9cecda1mr9468684pfn.28.1674094499441; Wed, 18 Jan 2023 18:14:59 -0800 (PST) Received: from localhost ([2405:201:6014:dae3:7dbb:8857:7c39:bb2a]) by smtp.gmail.com with ESMTPSA id a20-20020aa79714000000b0058d9a5bac88sm7092575pfg.203.2023.01.18.18.14.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 18 Jan 2023 18:14:59 -0800 (PST) From: Kumar Kartikeya Dwivedi To: bpf@vger.kernel.org Cc: Alexei Starovoitov , Andrii Nakryiko , Daniel Borkmann , Martin KaFai Lau , Joanne Koong , David Vernet , Eduard Zingerman Subject: [PATCH bpf-next v2 04/11] bpf: Allow reinitializing unreferenced dynptr stack slots Date: Thu, 19 Jan 2023 07:44:35 +0530 Message-Id: <20230119021442.1465269-5-memxor@gmail.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230119021442.1465269-1-memxor@gmail.com> References: <20230119021442.1465269-1-memxor@gmail.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=3839; i=memxor@gmail.com; h=from:subject; bh=D4qFbTmmFP8S+m3Q6q6jtE75Nl7+PC5zEX3xx4xQgdY=; b=owEBbQKS/ZANAwAIAUzgyIZIvxHKAcsmYgBjyKc/WawmUYZLBHTmNaHoctqyIEhThCX9axVuJS4L DoKrY4+JAjMEAAEIAB0WIQRLvip+Buz51YI8YRFM4MiGSL8RygUCY8inPwAKCRBM4MiGSL8RyiRyD/ 9rjDdhYHOGsL/E3/h4z4XZ1Rz5XUMPLgwza8ybBYrLMJoDyPyZWuHqCZPY0mwV1NzQ8b8IvQeEogPk Taq0kR1cb/5SsKzK5KvarxCwAR9tTxTeMPgXkCYLCLKonzDjXP0BqHRug92eS64n9410Ax7aP90Hij B29x0qZzl0HKKYAsYzqJp9DnEc7cs47Ho1zlos5d82cWotuX5jAU2FNoROjjnldtYLTUIoCncq/+qR EthydY64B2hnvWTWfsPiWKvJVllq3v1CG7QuIvtUNfQCyt/a+6lnVx9ghccY4OgVxLHuET49iGzYRQ 5q2slgN803V2haf1LkVm3UtB9H+yqrLE8ey2YnBMLCIDOqRex8lSzRT9YyTYHfbkb5eMYlaqOgCFtb GwoGYQqlQQC4fHSQyIGGLcZ1sO6cUz6vpyHO0ea68TfU7YiZaYkRzgHtHKq5xJ6bL4saTQ/cOExTXt QEMh0RT8xZcW1wpgcMkVzDGRKCUyDRGdOtRJzvZKYkXM+Vw8+DYUNKlb8LWxWz8YRBVBo1JDpNHvt8 lOuFA7KrZNB+swLxD6DTovOLS6G78NoiObriehanRrivP1rTdnMacutjwHFYuJLEa5jIKtxAvHcQV0 DPKh5L2LHTFkT9J2a3ONziqFoIQM8Nj5Ng8x86W3lwpshlsYAozU42PX1Jbw== X-Developer-Key: i=memxor@gmail.com; a=openpgp; fpr=4BBE2A7E06ECF9D5823C61114CE0C88648BF11CA Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net Consider a program like below: void prog(void) { { struct bpf_dynptr ptr; bpf_dynptr_from_mem(...); } ... { struct bpf_dynptr ptr; bpf_dynptr_from_mem(...); } } Here, the C compiler based on lifetime rules in the C standard would be well within in its rights to share stack storage for dynptr 'ptr' as their lifetimes do not overlap in the two distinct scopes. Currently, such an example would be rejected by the verifier, but this is too strict. Instead, we should allow reinitializing over dynptr stack slots and forget information about the old dynptr object. The destroy_if_dynptr_stack_slot function already makes necessary checks to avoid overwriting referenced dynptr slots. This is done to present a better error message instead of forgetting dynptr information on stack and preserving reference state, leading to an inevitable but undecipherable error at the end about an unreleased reference which has to be associated back to its allocating call instruction to make any sense to the user. Signed-off-by: Kumar Kartikeya Dwivedi Acked-by: Joanne Koong --- kernel/bpf/verifier.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 09c09d9bfd89..4feaddd5d6dc 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -777,7 +777,7 @@ static int mark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_reg_ { struct bpf_func_state *state = func(env, reg); enum bpf_dynptr_type type; - int spi, i, id; + int spi, i, id, err; spi = dynptr_get_spi(env, reg); if (spi < 0) @@ -786,6 +786,22 @@ static int mark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_reg_ if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS)) return -EINVAL; + /* We cannot assume both spi and spi - 1 belong to the same dynptr, + * hence we need to call destroy_if_dynptr_stack_slot twice for both, + * to ensure that for the following example: + * [d1][d1][d2][d2] + * spi 3 2 1 0 + * So marking spi = 2 should lead to destruction of both d1 and d2. In + * case they do belong to same dynptr, second call won't see slot_type + * as STACK_DYNPTR and will simply skip destruction. + */ + err = destroy_if_dynptr_stack_slot(env, state, spi); + if (err) + return err; + err = destroy_if_dynptr_stack_slot(env, state, spi - 1); + if (err) + return err; + for (i = 0; i < BPF_REG_SIZE; i++) { state->stack[spi].slot_type[i] = STACK_DYNPTR; state->stack[spi - 1].slot_type[i] = STACK_DYNPTR; @@ -931,7 +947,7 @@ static int destroy_if_dynptr_stack_slot(struct bpf_verifier_env *env, static bool is_dynptr_reg_valid_uninit(struct bpf_verifier_env *env, struct bpf_reg_state *reg) { struct bpf_func_state *state = func(env, reg); - int spi, i; + int spi; if (reg->type == CONST_PTR_TO_DYNPTR) return false; @@ -944,12 +960,14 @@ static bool is_dynptr_reg_valid_uninit(struct bpf_verifier_env *env, struct bpf_ if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS)) return true; - for (i = 0; i < BPF_REG_SIZE; i++) { - if (state->stack[spi].slot_type[i] == STACK_DYNPTR || - state->stack[spi - 1].slot_type[i] == STACK_DYNPTR) - return false; - } - + /* We allow overwriting existing unreferenced STACK_DYNPTR slots, see + * mark_stack_slots_dynptr which calls destroy_if_dynptr_stack_slot to + * ensure dynptr objects at the slots we are touching are completely + * destructed before we reinitialize them for a new one. For referenced + * ones, destroy_if_dynptr_stack_slot returns an error early instead of + * delaying it until the end where the user will get "Unreleased + * reference" error. + */ return true; } From patchwork Thu Jan 19 02:14:36 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kumar Kartikeya Dwivedi X-Patchwork-Id: 13107298 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 38A8FC38159 for ; Thu, 19 Jan 2023 02:15:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229840AbjASCPG (ORCPT ); Wed, 18 Jan 2023 21:15:06 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37520 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229850AbjASCPF (ORCPT ); Wed, 18 Jan 2023 21:15:05 -0500 Received: from mail-pl1-x643.google.com (mail-pl1-x643.google.com [IPv6:2607:f8b0:4864:20::643]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 78F026794B for ; Wed, 18 Jan 2023 18:15:03 -0800 (PST) Received: by mail-pl1-x643.google.com with SMTP id d9so948884pll.9 for ; Wed, 18 Jan 2023 18:15:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=zhSzY4zEwsqSV94SAMxDpdZWRwNBnCTmanJZGUNqQVo=; b=oAwVuP8sM01cciNQDmNQMD942BkcTYLnMS3CdeB/O6HgoyOSCNyTopIH14HVXBToZJ KLAWwEf3jgkbzIcqyfskxiLH/QkmyHHSM96PEU4frGlwJS0QSK4OWwrcjzvqoZFcc141 mbNPztPWI+Jjg7nenz5wapFKsKcEAx5j94FgnRPr5n+GH9UfZ7W2OF4E5oFRIrv2lR5f h074R4/CY3lUewV+ap3xWZdNKEVsueFbTeaZVm8E0nApWdyTw0OSCDqZOE0Tp0fkeh5C L+4amUGa08SULGKgVeSnVYyUociGJpQMtBNdMF9pTNWWGwRrWH4I4ZD/mHkEbJJ6JjrX wPyA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=zhSzY4zEwsqSV94SAMxDpdZWRwNBnCTmanJZGUNqQVo=; b=NxcywzSDiu2B/1DZ3QB9JLihG8WfUZX/8XK4eFK2AOyud9o/xUBGcmwTSIlT3qFCAE sHuJSI4COP0ndu6Im7FlR3LKj7/RVHqOlcYoHBuv5X4yily09MXMe8hlRKy5k4VRD046 5P70OBWsyn/DlJorG/dDadzVlCqBZvfadyT1NLi7SKy/cPThY1hszeRGe4O9zjqexHLn 7d4/se8MBQf0RwPQb6gYSCRICBZLHVU1I8ZlKWbuM2LqToeqSQly+9c2rxZL4bAWd56i 2kTP/f1iDCtLWzOr+nW0e6/xy6obusWQCrCbkzX8fUoiZh/YR7sOj516UGcAj1plSz8s CtDA== X-Gm-Message-State: AFqh2koOwr05cUMAE5POJUylEy0hS6pmq1l1fS78xk3IP12fjtLyUjmu 5/nDLym5inpd7XPAiHXSdD6DKzBrA9k= X-Google-Smtp-Source: AMrXdXtd3SY5zWUCSJYmEtekAumvHdt3znutCxQFyvEL8PcloE/8JS0oCH3rcJTyCJaNWMJqqkBMqg== X-Received: by 2002:a17:90b:2349:b0:226:7fcb:c215 with SMTP id ms9-20020a17090b234900b002267fcbc215mr9833946pjb.17.1674094502902; Wed, 18 Jan 2023 18:15:02 -0800 (PST) Received: from localhost ([2405:201:6014:dae3:7dbb:8857:7c39:bb2a]) by smtp.gmail.com with ESMTPSA id q35-20020a17090a752600b002265ddfc13esm1946944pjk.29.2023.01.18.18.15.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 18 Jan 2023 18:15:02 -0800 (PST) From: Kumar Kartikeya Dwivedi To: bpf@vger.kernel.org Cc: Joanne Koong , Alexei Starovoitov , Andrii Nakryiko , Daniel Borkmann , Martin KaFai Lau , David Vernet , Eduard Zingerman Subject: [PATCH bpf-next v2 05/11] bpf: Combine dynptr_get_spi and is_spi_bounds_valid Date: Thu, 19 Jan 2023 07:44:36 +0530 Message-Id: <20230119021442.1465269-6-memxor@gmail.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230119021442.1465269-1-memxor@gmail.com> References: <20230119021442.1465269-1-memxor@gmail.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=6131; i=memxor@gmail.com; h=from:subject; bh=/IAcZvEjbJcxQ0MZfs6LyNWglKcKtdSuhtUfQm35tho=; b=owEBbQKS/ZANAwAIAUzgyIZIvxHKAcsmYgBjyKc/ljXnvijVzt4AOizrjml63Zq5zYwqsvbeH/lF jrvvbMuJAjMEAAEIAB0WIQRLvip+Buz51YI8YRFM4MiGSL8RygUCY8inPwAKCRBM4MiGSL8RynH3D/ 9kuz4VGzfZQxlXTsiUtX3fcEnYMn/qkf/ZSgdf/c8Xg4BNKByaH7/RfVeFlGG9wB801wRLCtHK8lHs a+i0UEKf/gM7aiDvOkiIV4eWi2aqjECSXUzXgM8/FQDO09JAcjNOH0BxO9TwNSc4BlTnkMMdbHfpSD SRBvkzR9pSYB6kRikLUcN8UGcccBGVMyZTc1JfJ9nD1LUwXTvrYVFpknOJDQ6MRSQGLSKEYOfb9oA7 /S52YbQVdIrTsSiFo7EuYQM6NPxVlIVE1B7iOHtppE7VVe75miHlX4Z6Dc5ihQiCjeYhgi1EQTheFh 2V+QvJ8r9IvxDPp8XCfeJilxTocdahC5F/UKwmVD/9d6Whi1anYQERyv05SLVMaSjk/dn1AGwwWMPA iEM5eqMhC/wal8Be0bJemKCis7zx4bshU5c5DexT60yDZKr/MwQmA/jWZavjVzQVKGw05zUU+On06N n28G261wmtY4/SdQghHPDGkYw74KFIsLVrTgDjDtBaroGs64CXNcI8fN3lA6X658zsOwLN7PcBx/zb xm7VA78t2in5WrQE6awfl4xJlCOweIwmVdQg5skXZqZrIolm7YG/Rqn3i6bQ54pb4Y0W4NrnicefmC 0EO3LyeFEogmc5l6KoNi7/t7mjkBSoWThxRp0irnZHIzWqGOgpNabbsuGhdQ== X-Developer-Key: i=memxor@gmail.com; a=openpgp; fpr=4BBE2A7E06ECF9D5823C61114CE0C88648BF11CA Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net Currently, a check on spi resides in dynptr_get_spi, while others checking its validity for being within the allocated stack slots happens in is_spi_bounds_valid. Almost always barring a couple of cases (where being beyond allocated stack slots is not an error as stack slots need to be populated), both are used together to make checks. Hence, subsume the is_spi_bounds_valid check in dynptr_get_spi, and return -ERANGE to specially distinguish the case where spi is valid but not within allocated slots in the stack state. The is_spi_bounds_valid function is still kept around as it is a generic helper that will be useful for other objects on stack similar to dynptr in the future. Suggested-by: Joanne Koong Signed-off-by: Kumar Kartikeya Dwivedi Acked-by: Joanne Koong --- kernel/bpf/verifier.c | 75 +++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 42 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 4feaddd5d6dc..18b54b219fac 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -643,6 +643,28 @@ static int __get_spi(s32 off) return (-off - 1) / BPF_REG_SIZE; } +static struct bpf_func_state *func(struct bpf_verifier_env *env, + const struct bpf_reg_state *reg) +{ + struct bpf_verifier_state *cur = env->cur_state; + + return cur->frame[reg->frameno]; +} + +static bool is_spi_bounds_valid(struct bpf_func_state *state, int spi, int nr_slots) +{ + int allocated_slots = state->allocated_stack / BPF_REG_SIZE; + + /* We need to check that slots between [spi - nr_slots + 1, spi] are + * within [0, allocated_stack). + * + * Please note that the spi grows downwards. For example, a dynptr + * takes the size of two stack slots; the first slot will be at + * spi and the second slot will be at spi - 1. + */ + return spi - nr_slots + 1 >= 0 && spi < allocated_slots; +} + static int dynptr_get_spi(struct bpf_verifier_env *env, struct bpf_reg_state *reg) { int off, spi; @@ -663,29 +685,10 @@ static int dynptr_get_spi(struct bpf_verifier_env *env, struct bpf_reg_state *re verbose(env, "cannot pass in dynptr at an offset=%d\n", off); return -EINVAL; } - return spi; -} - -static bool is_spi_bounds_valid(struct bpf_func_state *state, int spi, int nr_slots) -{ - int allocated_slots = state->allocated_stack / BPF_REG_SIZE; - /* We need to check that slots between [spi - nr_slots + 1, spi] are - * within [0, allocated_stack). - * - * Please note that the spi grows downwards. For example, a dynptr - * takes the size of two stack slots; the first slot will be at - * spi and the second slot will be at spi - 1. - */ - return spi - nr_slots + 1 >= 0 && spi < allocated_slots; -} - -static struct bpf_func_state *func(struct bpf_verifier_env *env, - const struct bpf_reg_state *reg) -{ - struct bpf_verifier_state *cur = env->cur_state; - - return cur->frame[reg->frameno]; + if (!is_spi_bounds_valid(func(env, reg), spi, BPF_DYNPTR_NR_SLOTS)) + return -ERANGE; + return spi; } static const char *kernel_type_name(const struct btf* btf, u32 id) @@ -783,9 +786,6 @@ static int mark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_reg_ if (spi < 0) return spi; - if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS)) - return -EINVAL; - /* We cannot assume both spi and spi - 1 belong to the same dynptr, * hence we need to call destroy_if_dynptr_stack_slot twice for both, * to ensure that for the following example: @@ -839,9 +839,6 @@ static int unmark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_re if (spi < 0) return spi; - if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS)) - return -EINVAL; - for (i = 0; i < BPF_REG_SIZE; i++) { state->stack[spi].slot_type[i] = STACK_INVALID; state->stack[spi - 1].slot_type[i] = STACK_INVALID; @@ -946,20 +943,18 @@ static int destroy_if_dynptr_stack_slot(struct bpf_verifier_env *env, static bool is_dynptr_reg_valid_uninit(struct bpf_verifier_env *env, struct bpf_reg_state *reg) { - struct bpf_func_state *state = func(env, reg); int spi; if (reg->type == CONST_PTR_TO_DYNPTR) return false; spi = dynptr_get_spi(env, reg); + /* For -ERANGE (i.e. spi not falling into allocated stack slots), we + * will do check_mem_access to check and update stack bounds later, so + * return true for that case. + */ if (spi < 0) - return false; - - /* We will do check_mem_access to check and update stack bounds later */ - if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS)) - return true; - + return spi == -ERANGE; /* We allow overwriting existing unreferenced STACK_DYNPTR slots, see * mark_stack_slots_dynptr which calls destroy_if_dynptr_stack_slot to * ensure dynptr objects at the slots we are touching are completely @@ -983,8 +978,7 @@ static bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, struct bpf_re spi = dynptr_get_spi(env, reg); if (spi < 0) return false; - if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS) || - !state->stack[spi].spilled_ptr.dynptr.first_slot) + if (!state->stack[spi].spilled_ptr.dynptr.first_slot) return false; for (i = 0; i < BPF_REG_SIZE; i++) { @@ -6153,7 +6147,7 @@ int process_dynptr_func(struct bpf_verifier_env *env, int regno, */ if (reg->type == PTR_TO_STACK) { err = dynptr_get_spi(env, reg); - if (err < 0) + if (err < 0 && err != -ERANGE) return err; } @@ -6646,10 +6640,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, */ if (reg->type == PTR_TO_STACK) { spi = dynptr_get_spi(env, reg); - if (spi < 0) - return spi; - if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS) || - !state->stack[spi].spilled_ptr.ref_obj_id) { + if (spi < 0 || !state->stack[spi].spilled_ptr.ref_obj_id) { verbose(env, "arg %d is an unacquired reference\n", regno); return -EINVAL; } From patchwork Thu Jan 19 02:14:37 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kumar Kartikeya Dwivedi X-Patchwork-Id: 13107299 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 C0B8BC677F1 for ; Thu, 19 Jan 2023 02:15:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229744AbjASCPL (ORCPT ); Wed, 18 Jan 2023 21:15:11 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37612 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229863AbjASCPK (ORCPT ); Wed, 18 Jan 2023 21:15:10 -0500 Received: from mail-pj1-x1043.google.com (mail-pj1-x1043.google.com [IPv6:2607:f8b0:4864:20::1043]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E15C645BE4 for ; Wed, 18 Jan 2023 18:15:07 -0800 (PST) Received: by mail-pj1-x1043.google.com with SMTP id gz9-20020a17090b0ec900b002290bda1b07so3038968pjb.1 for ; Wed, 18 Jan 2023 18:15:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=bka/VtbZP54o8yxkzulZT0tqVF3UHzVaYFebUxjS0aM=; b=gFrXNp6btbveyZFu022ovIVtsHdGR+evsN6iUlWCPojSWakTfPrjld3xglrechEFk1 UpTeusm9qnbTb08u/Qhyh1YJXgGSwaUFpHU5Gv0JhP6b/RP9Z27Po0AX/SSG4cnNcH1E lFJeEqlNSpKRbsFVcuVhxIh8+cPIDXku8VGJ5dmF+pbjn/uHoTj2YQ7/rvPsvk0m1IfH 1nenQ3s2dqDvzEI5tsY0TD7r3s6ES5khNXOdfvEk8C/by+Znx1NlHqKPgtCnF8dlYFbg 8uABgRD+67N+AXhWP60XcwlF8UwGmIZwMHYTfd/neechddAQMHZxkZkn2QSZt5nsJgqU PSTA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=bka/VtbZP54o8yxkzulZT0tqVF3UHzVaYFebUxjS0aM=; b=nfIk1habqOTIwmU97R7Bnb1iZGyahOkmA3/I9Qyl0m83/yddQXfd18O+fYZGzCmcgy oPZiYNePtbHo6px9e3v9acBduVEk2j9rbMGMSRRVWPsmKjOTe88QQQkKiQ690PW/FcYm ubErfNIe4xhlzkjaecRqsW9hhx5mzZw7AK+GI65YJ7bfJdOQN+Qy8B5BXWwb5rD0qYu7 lIRjZDaZGbjGFBetQqAg6Y/iMp3UB9NaWecQUWm4X2ey0wdD1Z+C5s8NjNcSfkrt/PNy Pwe8Kmfzu9foIIiBmke000wfZ+sBBo63mBz58bZPaGyZ77ENPotKp4mXvKx3vtnUcNU6 FPVA== X-Gm-Message-State: AFqh2kporl7EIvh/UgZsrH0ClqVccnDTmSol2Bs/2wKDTsQ5BwampsUL BVCROx3EjdUkfor6Y4pFNPUeKHpCdps= X-Google-Smtp-Source: AMrXdXtciVXSdu4u/MN2TvcC127mekQUzbSRS2G5ECMuwr9KOh3+ta4KGlpbf13QDzg8JK/YsemKUQ== X-Received: by 2002:a17:90a:8c02:b0:228:d460:9f13 with SMTP id a2-20020a17090a8c0200b00228d4609f13mr8955400pjo.29.1674094506839; Wed, 18 Jan 2023 18:15:06 -0800 (PST) Received: from localhost ([2405:201:6014:dae3:7dbb:8857:7c39:bb2a]) by smtp.gmail.com with ESMTPSA id y1-20020a17090a474100b002262dd8a39bsm1922687pjg.49.2023.01.18.18.15.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 18 Jan 2023 18:15:06 -0800 (PST) From: Kumar Kartikeya Dwivedi To: bpf@vger.kernel.org Cc: Joanne Koong , Alexei Starovoitov , Andrii Nakryiko , Daniel Borkmann , Martin KaFai Lau , David Vernet , Eduard Zingerman Subject: [PATCH bpf-next v2 06/11] bpf: Avoid recomputing spi in process_dynptr_func Date: Thu, 19 Jan 2023 07:44:37 +0530 Message-Id: <20230119021442.1465269-7-memxor@gmail.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230119021442.1465269-1-memxor@gmail.com> References: <20230119021442.1465269-1-memxor@gmail.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=3658; i=memxor@gmail.com; h=from:subject; bh=b2/Djii2vJEiM6TboetEFiyTUch5FJ7vRID6r/EpgDc=; b=owEBbQKS/ZANAwAIAUzgyIZIvxHKAcsmYgBjyKc/8UWIRMQe37XOKFCP6+V8s4pKXSh4aTY/dyiw /a5oLTqJAjMEAAEIAB0WIQRLvip+Buz51YI8YRFM4MiGSL8RygUCY8inPwAKCRBM4MiGSL8RyprvEA C1sCJpjllkkmhETNxaAOYFGV7MikHHthiv0/gT197G6GnBdWFPUbqRUoViEYNK+jn6c/PPsRoh+nXH fD0T9Qj7ZbEOXvGY+d2xhKtPqNiOU6OBJk2Lds8xffM9OlptlLJMSpj11pq9C23mhYAOQHfD4vsNoy Zx/CnIHd3saihm2r9TVnklqitxhyvwGZXB2kqD963dq597FhmkmPUEfUlZrMBDdrhaXnZ5Om/JJaPx 8og04VWaS+iNi0sY2Xkch/YpQy2ypAPDT2m1L5rrm3H1UBxebkh9oryMjOjvbPv+6S5XkbzUnP3zGB vuryqcyQL+FE4QF7MzUaAcVxgAieuCL3xgmC5Ocm399Xvm+0IQhy0uHBrLRNmErhEogGeKuBKtNAIM EPjeFUs7KRLGPQsXDc/Z8a+2BWVRjIWQv4dSFahwHOt+Bv3gv5P4lWYQKl9Z2/6NUocl1wAo8O0pUG CFtMUcLKWaUyy3atNO/rAC0CRqGYRb6Iq+Ohkub02u+/3lJuTQFLljoynmzoftRWPrZU6RJBdK7DVJ 9QlDRn8CX9GmGaaCn6lfb0ejMxdP/GuC0PVIN3eHZVujAy8xjsfnGF60ciqN2xXn+b5CXRi8vjSz+k cNJn2CxP4N3CMJpDnQA85QXr+gDqLcV5fvzOnEcLHYu70zErw/MI5ZuxExsg== X-Developer-Key: i=memxor@gmail.com; a=openpgp; fpr=4BBE2A7E06ECF9D5823C61114CE0C88648BF11CA Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net Currently, process_dynptr_func first calls dynptr_get_spi and then is_dynptr_reg_valid_init and is_dynptr_reg_valid_uninit have to call it again to obtain the spi value. Instead of doing this twice, reuse the already obtained value (which is by default 0, and is only set for PTR_TO_STACK, and only used in that case in aforementioned functions). The input value for these two functions will either be -ERANGE or >= 1, and can either be permitted or rejected based on the respective check. Suggested-by: Joanne Koong Signed-off-by: Kumar Kartikeya Dwivedi Acked-by: Joanne Koong --- kernel/bpf/verifier.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 18b54b219fac..7b8de84568a3 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -941,14 +941,12 @@ static int destroy_if_dynptr_stack_slot(struct bpf_verifier_env *env, return 0; } -static bool is_dynptr_reg_valid_uninit(struct bpf_verifier_env *env, struct bpf_reg_state *reg) +static bool is_dynptr_reg_valid_uninit(struct bpf_verifier_env *env, struct bpf_reg_state *reg, + int spi) { - int spi; - if (reg->type == CONST_PTR_TO_DYNPTR) return false; - spi = dynptr_get_spi(env, reg); /* For -ERANGE (i.e. spi not falling into allocated stack slots), we * will do check_mem_access to check and update stack bounds later, so * return true for that case. @@ -966,16 +964,16 @@ static bool is_dynptr_reg_valid_uninit(struct bpf_verifier_env *env, struct bpf_ return true; } -static bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, struct bpf_reg_state *reg) +static bool is_dynptr_reg_valid_init(struct bpf_verifier_env *env, struct bpf_reg_state *reg, + int spi) { struct bpf_func_state *state = func(env, reg); - int spi, i; + int i; /* This already represents first slot of initialized bpf_dynptr */ if (reg->type == CONST_PTR_TO_DYNPTR) return true; - spi = dynptr_get_spi(env, reg); if (spi < 0) return false; if (!state->stack[spi].spilled_ptr.dynptr.first_slot) @@ -6132,7 +6130,7 @@ int process_dynptr_func(struct bpf_verifier_env *env, int regno, enum bpf_arg_type arg_type, struct bpf_call_arg_meta *meta) { struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[regno]; - int err; + int err, spi = 0; /* MEM_UNINIT and MEM_RDONLY are exclusive, when applied to an * ARG_PTR_TO_DYNPTR (or ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_*): @@ -6146,9 +6144,9 @@ int process_dynptr_func(struct bpf_verifier_env *env, int regno, * and its alignment for PTR_TO_STACK. */ if (reg->type == PTR_TO_STACK) { - err = dynptr_get_spi(env, reg); - if (err < 0 && err != -ERANGE) - return err; + spi = dynptr_get_spi(env, reg); + if (spi < 0 && spi != -ERANGE) + return spi; } /* MEM_UNINIT - Points to memory that is an appropriate candidate for @@ -6167,7 +6165,7 @@ int process_dynptr_func(struct bpf_verifier_env *env, int regno, * to. */ if (arg_type & MEM_UNINIT) { - if (!is_dynptr_reg_valid_uninit(env, reg)) { + if (!is_dynptr_reg_valid_uninit(env, reg, spi)) { verbose(env, "Dynptr has to be an uninitialized dynptr\n"); return -EINVAL; } @@ -6188,7 +6186,7 @@ int process_dynptr_func(struct bpf_verifier_env *env, int regno, return -EINVAL; } - if (!is_dynptr_reg_valid_init(env, reg)) { + if (!is_dynptr_reg_valid_init(env, reg, spi)) { verbose(env, "Expected an initialized dynptr as arg #%d\n", regno); From patchwork Thu Jan 19 02:14:38 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kumar Kartikeya Dwivedi X-Patchwork-Id: 13107300 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 4FBC0C678D4 for ; Thu, 19 Jan 2023 02:15:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229584AbjASCPN (ORCPT ); Wed, 18 Jan 2023 21:15:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37628 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229863AbjASCPM (ORCPT ); Wed, 18 Jan 2023 21:15:12 -0500 Received: from mail-pf1-x443.google.com (mail-pf1-x443.google.com [IPv6:2607:f8b0:4864:20::443]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BF41D67957 for ; Wed, 18 Jan 2023 18:15:10 -0800 (PST) Received: by mail-pf1-x443.google.com with SMTP id 207so416901pfv.5 for ; Wed, 18 Jan 2023 18:15:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Zs5n2Q1YRbL+FZCik99wIL5O/1FCJ2BZ9GlI4NG+zGU=; b=mjMSvwhR2ScbCZYXnXAUjZGK1qJlIyEDnj7lqwj7v3B+QOnmXIN+zayMremFOUtwaC GZIZGNUNT6Aqx6kbIKxb+Q+iSlmVPVxgYMjYa2ee9rqyxMnLQ2ryBaV+UJ7FZ9xYl6+X FyuOCwOl4Ri3kqslfjpGEZBbjI3Pp/i27/UNvWZH9LS+bkrnOzG2mru6CIV7E4y5ksNW 2BOdZf28mW8t4J+uQRLY/ge9EZMzrTnwy5oJ/22FL84xSrTlPsXTqE4pTiMO7sTsw8bN 9Xc2n6LoAO3M7RlWaZ3KzI8PH1TAV/a3x3wyWyhgGE/eNV2d0uVwC9i8NRhQ3h0eDQTj I0YA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Zs5n2Q1YRbL+FZCik99wIL5O/1FCJ2BZ9GlI4NG+zGU=; b=r++eINsdy9d8WEpmhaRPsa/QZzm6PFfPWtCJ3Gx5ZNc0YoOEvmGIsA1VwoKzVLxpPT WNCEW5lhGHioLx51p5W2QtGDPcTXeOZtBpF3shgewx81NxHy/qsOhb6T/1/3sfDGAsmx JsCwmDwSjR1nl0ndEp9UXLGd2d1s/r9WUWlpoKBFx7n81P0Cto/YVtgbEnpDV/RjdAfI Tvef0HOBt86ECf+gVzvafmmzX5fhbhfJe8nazLMy2ds4hCk9Z3u4XsNd9p0lV+gmI3EG taOq7wTdDIrWSMgusCz3mxDU8d8BN6M3B6xOZz5hiK9lXGYctuL5ORRxfVDq2y9cvM8o Tb1g== X-Gm-Message-State: AFqh2kqSDBNiY860HE5pCIml8X+HMz1rwvN7VGRwBNNipbmXpXJTc+WS ae5ePVQqgquPGYOQuD4PSDw/GCDBnq8= X-Google-Smtp-Source: AMrXdXvsPWWQB2vMzyvrsaNPJY2kkrM8kjMIYAJ989piEdEZqYa83vu8kvaM+d4zQamiCeEzpbEp7A== X-Received: by 2002:a05:6a00:1887:b0:589:d831:ad2a with SMTP id x7-20020a056a00188700b00589d831ad2amr13961885pfh.6.1674094510045; Wed, 18 Jan 2023 18:15:10 -0800 (PST) Received: from localhost ([2405:201:6014:dae3:7dbb:8857:7c39:bb2a]) by smtp.gmail.com with ESMTPSA id g1-20020a625201000000b0057a9b146592sm10236604pfb.186.2023.01.18.18.15.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 18 Jan 2023 18:15:09 -0800 (PST) From: Kumar Kartikeya Dwivedi To: bpf@vger.kernel.org Cc: Andrii Nakryiko , Yonghong Song , Eduard Zingerman , Alexei Starovoitov , Daniel Borkmann , Martin KaFai Lau , Joanne Koong , David Vernet Subject: [PATCH bpf-next v2 07/11] selftests/bpf: convenience macro for use with 'asm volatile' blocks Date: Thu, 19 Jan 2023 07:44:38 +0530 Message-Id: <20230119021442.1465269-8-memxor@gmail.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230119021442.1465269-1-memxor@gmail.com> References: <20230119021442.1465269-1-memxor@gmail.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=1699; i=memxor@gmail.com; h=from:subject; bh=SNRMXDcMW1zluX6a3W/WYa1RbpYDzrfdzhpCt6yThTA=; b=owEBbQKS/ZANAwAIAUzgyIZIvxHKAcsmYgBjyKc/s5JRMTd9QT6uBQgwWA2rgY8rE3jweRYNnMEY kA+RJ3KJAjMEAAEIAB0WIQRLvip+Buz51YI8YRFM4MiGSL8RygUCY8inPwAKCRBM4MiGSL8Rys6gEA C8W8ec6FwZEt8GZk52E1sKpbKU0pKwotJDquwVvOcVPa4+47OxVQLPtAkhOi9C7AbMBDkFp7WTJHw0 Zf8JUBRUzkLdpqo1BjVGd1Pl4GkZUOPfxSiE4JpgIoTo15STFaTCLXdCp6jpnI+RuMTq+NoAFHE7cQ 4yK+OGL8J+3TraPxLtk+aGEpXYG9/mevn/9nfLHUQjVSuh6R2PsRU9pFHCJMf8WzLohaxZpOnfKSj5 u5+BlYEIyA1PH8qRLi3xfrL43beOQTRTlVzAjoUMglgrsQoVbA9AJTCcozCSVgyCQj064DyukIU+RV ag/FDbLR3QkX+tn+QwdaVdmwn7MGS+wXReTlHKOQkvJZ2NwPPhN3CI8WfMzjbwjFryhiewQyhd66uT fa9ArhVf8C80YNVOXFbYmspkzt/p3xqXGglPZWtW0w4thuwSFC2m5W211RCfrsbPB/U3bTe/qm0r+x XmFPR7dQw8jS7x13GN1o+uZoWt4f8Xvkgj2CTfb+dDbJLLrZyKj9wbe5w62sdbIfOk5KQCxoFnhdjg D+OL1JRrHItkGFsELPPPHN/smO93nBZ+OGrAb1oaaWzTwiMv1YSW7Mmu2aC1zv7yI/rrOvYem9IzGj hq2kqkV9FIb+iWvspQfp1BVlI2Vfln7Go3yaqbBTI2JWoheHmSof4noLi0xw== X-Developer-Key: i=memxor@gmail.com; a=openpgp; fpr=4BBE2A7E06ECF9D5823C61114CE0C88648BF11CA Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net From: Eduard Zingerman A set of macros useful for writing naked BPF functions using inline assembly. E.g. as follows: struct map_struct { ... } map SEC(".maps"); SEC(...) __naked int foo_test(void) { asm volatile( "r0 = 0;" "*(u64*)(r10 - 8) = r0;" "r1 = %[map] ll;" "r2 = r10;" "r2 += -8;" "call %[bpf_map_lookup_elem];" "r0 = 0;" "exit;" : : __imm(bpf_map_lookup_elem), __imm_addr(map) : __clobber_all); } Acked-by: Andrii Nakryiko Acked-by: Yonghong Song Signed-off-by: Eduard Zingerman [ Kartikeya: Add acks, include __clobber_common from Andrii ] Signed-off-by: Kumar Kartikeya Dwivedi --- tools/testing/selftests/bpf/progs/bpf_misc.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h b/tools/testing/selftests/bpf/progs/bpf_misc.h index 4a01ea9113bf..2d7b89b447b2 100644 --- a/tools/testing/selftests/bpf/progs/bpf_misc.h +++ b/tools/testing/selftests/bpf/progs/bpf_misc.h @@ -7,6 +7,13 @@ #define __success __attribute__((btf_decl_tag("comment:test_expect_success"))) #define __log_level(lvl) __attribute__((btf_decl_tag("comment:test_log_level="#lvl))) +/* Convenience macro for use with 'asm volatile' blocks */ +#define __naked __attribute__((naked)) +#define __clobber_all "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "memory" +#define __clobber_common "r0", "r1", "r2", "r3", "r4", "r5", "memory" +#define __imm(name) [name]"i"(name) +#define __imm_addr(name) [name]"i"(&name) + #if defined(__TARGET_ARCH_x86) #define SYSCALL_WRAPPER 1 #define SYS_PREFIX "__x64_" From patchwork Thu Jan 19 02:14:39 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kumar Kartikeya Dwivedi X-Patchwork-Id: 13107301 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 0659EC677F1 for ; Thu, 19 Jan 2023 02:15:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229524AbjASCPQ (ORCPT ); Wed, 18 Jan 2023 21:15:16 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37698 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229851AbjASCPP (ORCPT ); Wed, 18 Jan 2023 21:15:15 -0500 Received: from mail-pl1-x644.google.com (mail-pl1-x644.google.com [IPv6:2607:f8b0:4864:20::644]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3B6CE67963 for ; Wed, 18 Jan 2023 18:15:14 -0800 (PST) Received: by mail-pl1-x644.google.com with SMTP id k13so1024849plg.0 for ; Wed, 18 Jan 2023 18:15:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=xdqLo4rY5bkeLnW4X1l29ghb6NgQBmCacIQ+rxEheYc=; b=dok/BadNTNm9fXrnw7SNFA9Dv4ejY0vObUYih3iASI2bW51VULuAMEeYy9wFyAKhOI EBgMb7zU/zycrccAy4Q8EINq5XklZHRu5y68NgjS30H1HKnphbA2Im+sD86eB3w5SlLR 1YNwjCZqjIhChtsB02ukZeAfWjk2jFkCqnkfpyV8oVoQ560dWD9xL2cHOjwyIXbHRw4b 96J3dwubeSzoamg5J1nHjShWaS//DIj2X6ZdoQ9PSB9DSzyMfcS3gi+fKV3j14zJ+fQP 6mcaKmQ4QA3Pg/aTIy2QG5QP9MO+MM5VEWC3+pojFuvi4X7xAdfogpviI4bpfIlZgKlQ 0jnQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=xdqLo4rY5bkeLnW4X1l29ghb6NgQBmCacIQ+rxEheYc=; b=Wgw8CHN38p3NCs3gBvZBozcIjIJUTR0gOzKfb19OHptPVkLw4Y74JWGXlJzcsiQD9f YWLP7X6FeRDTJSuyCpp9rWbPCD1x65xV73Pa2SpHem8eN259a9+CpeWI6MCzc/9KvyPK jzM8tLMntFxCk6UyV0LkDhzF+aPjDq8gGT0wQN5ror/F9tax8hE7yzNFAXylLP4b4q6q W76SCUDjz0rMxZR7VpO9mqGKbIVPzhIZzJ5Vs2BDyOeAvTqEiVix5ETJbR4WaJrGpaXK v3wnjcjfas0ttSvT2QjP95OwWyK48a4eChRp+g961sUoS/ZVMWfUq46j/bFI376Lu7uk gQ3Q== X-Gm-Message-State: AFqh2koIN/8r3N8ptL3gH8uVIi0zsZXAe5Y96eKN83tTd4Mii5J5kFA8 5NdVpsknbfpGeoTGBWpG+VeDoTxx07w= X-Google-Smtp-Source: AMrXdXuTMnY0vK+tvyRnVj2P1u1LWbK3kliz5ijJ042Q3giY93vZ6tzxYt1R4RrP6UzbzVQ68ABYKA== X-Received: by 2002:a17:902:cf10:b0:194:5fc9:f55a with SMTP id i16-20020a170902cf1000b001945fc9f55amr11119133plg.35.1674094513465; Wed, 18 Jan 2023 18:15:13 -0800 (PST) Received: from localhost ([2405:201:6014:dae3:7dbb:8857:7c39:bb2a]) by smtp.gmail.com with ESMTPSA id 21-20020a170902c21500b00189c4b8ca21sm11374816pll.18.2023.01.18.18.15.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 18 Jan 2023 18:15:13 -0800 (PST) From: Kumar Kartikeya Dwivedi To: bpf@vger.kernel.org Cc: Alexei Starovoitov , Andrii Nakryiko , Daniel Borkmann , Martin KaFai Lau , Joanne Koong , David Vernet , Eduard Zingerman Subject: [PATCH bpf-next v2 08/11] selftests/bpf: Add dynptr pruning tests Date: Thu, 19 Jan 2023 07:44:39 +0530 Message-Id: <20230119021442.1465269-9-memxor@gmail.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230119021442.1465269-1-memxor@gmail.com> References: <20230119021442.1465269-1-memxor@gmail.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=3977; i=memxor@gmail.com; h=from:subject; bh=Zf15ND1/1Wx5PKaPTNXdGmm4XAJT04+4c//QsnYsQfQ=; b=owEBbQKS/ZANAwAIAUzgyIZIvxHKAcsmYgBjyKdAM9vh8THvr/BQXXOpoAmNXvgBLZ77BnM0NPs6 NlisX9mJAjMEAAEIAB0WIQRLvip+Buz51YI8YRFM4MiGSL8RygUCY8inQAAKCRBM4MiGSL8RynSHEA Ci9/6dnXo2rzhqpq6ughP+X7VIZIkwYleL0CWVoxgYYyEsT0rlUztmAOx/2g6VVCeUbVNeyryj5UI3 g/G3NT/ra1U9AQ4Gaiq3SWuQEnfaZYtXQe1Vt0OsEb3YRolDxsIRjlHygM8nFfEcTkVFkw4KGzvVRJ DYFlbwG/tDWG19SYSJhR2Dc/2hODk+zoXieTIOiNiz4CjA+qoCt6AnACpMZ+s+q+PrCXDcTjGGwJzf eLh+6DPFkP/3ko670VkBNJTjhoABi5wOk1PzQjTChym8Jg6gUWqdE1rsBmz7pABz8ellJwCM/UfnjS wr3ORR1llShie6AcX/CkmUujx2eGyfCz+2uSqShTtWSb1RCW5URYVCOqwCIwrwd4+YhiWQzCy8U/Yw IKdvZY9jOcuaDidFarMA4kZkm1jUbqOPf7F8vjOqUXjTScobe17h0SOHWkKKtSgWNRGs9CnSBj4Roh RWtEDSBsXSvYnlCuT5X1RalnLN9fGa/yekTnyKaJdlGZLMUYW2jBiDKFgC3ghZwEk0WJYmkxoZeOK3 hC3UvnlG3Y8Y3zjkjZzxg2Cq3EDJLNNspb4EY6s8r206HvjL82SV1ZwE2NP9khEe6QUg2JthctUu9+ dN9cl0OF0DdnIpS8LAnBxjLmEAFyml1LELqVbMLQBjaubwubeZE4f1Rf1vKg== X-Developer-Key: i=memxor@gmail.com; a=openpgp; fpr=4BBE2A7E06ECF9D5823C61114CE0C88648BF11CA Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net Add verifier tests that verify the new pruning behavior for STACK_DYNPTR slots, and ensure that state equivalence takes into account changes to the old and current verifier state correctly. Also ensure that the stacksafe changes are actually enabling pruning in case states are equivalent from pruning PoV. Signed-off-by: Kumar Kartikeya Dwivedi --- .../testing/selftests/bpf/progs/dynptr_fail.c | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c index 9dc3f23a8270..023b3c36bc78 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_fail.c +++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c @@ -35,6 +35,13 @@ struct { __type(value, __u32); } array_map3 SEC(".maps"); +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 1); + __type(key, __u32); + __type(value, __u64); +} array_map4 SEC(".maps"); + struct sample { int pid; long value; @@ -653,3 +660,137 @@ int dynptr_from_mem_invalid_api(void *ctx) return 0; } + +SEC("?tc") +__failure __msg("cannot overwrite referenced dynptr") __log_level(2) +int dynptr_pruning_overwrite(struct __sk_buff *ctx) +{ + asm volatile ( + "r9 = 0xeB9F;" + "r6 = %[ringbuf] ll;" + "r1 = r6;" + "r2 = 8;" + "r3 = 0;" + "r4 = r10;" + "r4 += -16;" + "call %[bpf_ringbuf_reserve_dynptr];" + "if r0 == 0 goto pjmp1;" + "goto pjmp2;" + "pjmp1:" + "*(u64 *)(r10 - 16) = r9;" + "pjmp2:" + "r1 = r10;" + "r1 += -16;" + "r2 = 0;" + "call %[bpf_ringbuf_discard_dynptr];" + : + : __imm(bpf_ringbuf_reserve_dynptr), + __imm(bpf_ringbuf_discard_dynptr), + __imm_addr(ringbuf) + : __clobber_all + ); + return 0; +} + +SEC("?tc") +__success __msg("12: safe") __log_level(2) +int dynptr_pruning_stacksafe(struct __sk_buff *ctx) +{ + asm volatile ( + "r9 = 0xeB9F;" + "r6 = %[ringbuf] ll;" + "r1 = r6;" + "r2 = 8;" + "r3 = 0;" + "r4 = r10;" + "r4 += -16;" + "call %[bpf_ringbuf_reserve_dynptr];" + "if r0 == 0 goto stjmp1;" + "goto stjmp2;" + "stjmp1:" + "r9 = r9;" + "stjmp2:" + "r1 = r10;" + "r1 += -16;" + "r2 = 0;" + "call %[bpf_ringbuf_discard_dynptr];" + : + : __imm(bpf_ringbuf_reserve_dynptr), + __imm(bpf_ringbuf_discard_dynptr), + __imm_addr(ringbuf) + : __clobber_all + ); + return 0; +} + +SEC("?tc") +__failure __msg("cannot overwrite referenced dynptr") __log_level(2) +int dynptr_pruning_type_confusion(struct __sk_buff *ctx) +{ + asm volatile ( + "r6 = %[array_map4] ll;" + "r7 = %[ringbuf] ll;" + "r1 = r6;" + "r2 = r10;" + "r2 += -8;" + "r9 = 0;" + "*(u64 *)(r2 + 0) = r9;" + "r3 = r10;" + "r3 += -24;" + "r9 = 0xeB9FeB9F;" + "*(u64 *)(r10 - 16) = r9;" + "*(u64 *)(r10 - 24) = r9;" + "r9 = 0;" + "r4 = 0;" + "r8 = r2;" + "call %[bpf_map_update_elem];" + "r1 = r6;" + "r2 = r8;" + "call %[bpf_map_lookup_elem];" + "if r0 != 0 goto tjmp1;" + "exit;" + "tjmp1:" + "r8 = r0;" + "r1 = r7;" + "r2 = 8;" + "r3 = 0;" + "r4 = r10;" + "r4 += -16;" + "r0 = *(u64 *)(r0 + 0);" + "call %[bpf_ringbuf_reserve_dynptr];" + "if r0 == 0 goto tjmp2;" + "r8 = r8;" + "r8 = r8;" + "r8 = r8;" + "r8 = r8;" + "r8 = r8;" + "r8 = r8;" + "r8 = r8;" + "goto tjmp3;" + "tjmp2:" + "*(u64 *)(r10 - 8) = r9;" + "*(u64 *)(r10 - 16) = r9;" + "r1 = r8;" + "r1 += 8;" + "r2 = 0;" + "r3 = 0;" + "r4 = r10;" + "r4 += -16;" + "call %[bpf_dynptr_from_mem];" + "tjmp3:" + "r1 = r10;" + "r1 += -16;" + "r2 = 0;" + "call %[bpf_ringbuf_discard_dynptr];" + : + : __imm(bpf_map_update_elem), + __imm(bpf_map_lookup_elem), + __imm(bpf_ringbuf_reserve_dynptr), + __imm(bpf_dynptr_from_mem), + __imm(bpf_ringbuf_discard_dynptr), + __imm_addr(array_map4), + __imm_addr(ringbuf) + : __clobber_all + ); + return 0; +} From patchwork Thu Jan 19 02:14:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kumar Kartikeya Dwivedi X-Patchwork-Id: 13107302 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 7AAB9C677F1 for ; Thu, 19 Jan 2023 02:15:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229866AbjASCPU (ORCPT ); Wed, 18 Jan 2023 21:15:20 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37764 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229877AbjASCPT (ORCPT ); Wed, 18 Jan 2023 21:15:19 -0500 Received: from mail-pg1-x543.google.com (mail-pg1-x543.google.com [IPv6:2607:f8b0:4864:20::543]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3501567957 for ; Wed, 18 Jan 2023 18:15:17 -0800 (PST) Received: by mail-pg1-x543.google.com with SMTP id q9so407993pgq.5 for ; Wed, 18 Jan 2023 18:15:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=TyWwSNg9QzAeroGa/+/BxJKA6GqXjtdfjppelIMtWNc=; b=cekGRCsym0xj6j6V5fiM12CDlbG13NG8+GYHAxcT/oYo9NEQuncOezV+8i1JaE65t1 iV0Ck9PqZSD4Axkv9e7O5mebnIdTMrzxM3oLq5uRZQkE70YZX34tmfdNOKn4r/1q7+Dt oc5QbqE8eiYJJhpI6Bu05QSCCqWnWeDLbc2PsCJPE6FUU5NDNiBu03/d8ObegDBGs3ir GwAiMNb0tY/pamqbMLt2DalU4nl2q8IduLHgV/jfhmhDQltU/X0HluhpCrkYyODXrS9j 7uPEQI5zlwDBbh0ylq3zHJMMYftMb/Tv/UhNqHiACtrFnJdAwD72SyMD5l/eW/za5fro 5xyA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=TyWwSNg9QzAeroGa/+/BxJKA6GqXjtdfjppelIMtWNc=; b=no23dPuSGaBoXZjZlcgu3ypiulVs4mijuVcF/LsR4g8aS3KzhON9Op3ThazrfFIaH5 F/kyPq9N+48RuC384ONGpfrYwQ/cR+Ffi9UoIXCcQZ8FluplvdO5iosa7mszYVwi+a1C ER6FRbG/sQx8ZI5VpqKT4H9F/jI7N17qu70fXF5x+y7Tims73r5/+yq3jyVnwT2CgRRq 3+3ZGEh1y4UbiDxdivyK+0phzZcFxUNqvIfbskyAUIidz4Rr0tQyCvBPNALM4LdbJ+qG Akf9KNm9jKqzo+Zw+wv6W1K1Rlzdi8miRwL9zuneVqI/v1fxdo8C3mkZP+xxy1IKazZ3 Nxlg== X-Gm-Message-State: AFqh2krYbdzFMCjejW4e/iyur/wqbDvPFSiXT4lPNuqAj63m7AhqkwdH ijvFgqHZ5awU4jK78tSBm4Kn0I4SfEo= X-Google-Smtp-Source: AMrXdXswtMGv9+yFBMsXw5DkxMjr9AZSN5/5xyVODLevUbmhJwj2JDRLOWvjbfRtkDHJow/rq1QHcQ== X-Received: by 2002:a62:de44:0:b0:58d:a565:e2ea with SMTP id h65-20020a62de44000000b0058da565e2eamr10447105pfg.14.1674094516970; Wed, 18 Jan 2023 18:15:16 -0800 (PST) Received: from localhost ([2405:201:6014:dae3:7dbb:8857:7c39:bb2a]) by smtp.gmail.com with ESMTPSA id z13-20020aa7990d000000b0058a313f4e4esm17168181pff.149.2023.01.18.18.15.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 18 Jan 2023 18:15:16 -0800 (PST) From: Kumar Kartikeya Dwivedi To: bpf@vger.kernel.org Cc: Alexei Starovoitov , Andrii Nakryiko , Daniel Borkmann , Martin KaFai Lau , Joanne Koong , David Vernet , Eduard Zingerman Subject: [PATCH bpf-next v2 09/11] selftests/bpf: Add dynptr var_off tests Date: Thu, 19 Jan 2023 07:44:40 +0530 Message-Id: <20230119021442.1465269-10-memxor@gmail.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230119021442.1465269-1-memxor@gmail.com> References: <20230119021442.1465269-1-memxor@gmail.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=1572; i=memxor@gmail.com; h=from:subject; bh=aspe8EeCNDbrDriDvXyGcWu+p91GApIw3l2e0nxkZ9k=; b=owEBbQKS/ZANAwAIAUzgyIZIvxHKAcsmYgBjyKdAlEOmw0hPk8d0a6faIgyduUuCfRw5Be0GQOgn anmktwSJAjMEAAEIAB0WIQRLvip+Buz51YI8YRFM4MiGSL8RygUCY8inQAAKCRBM4MiGSL8RyuXqD/ 4gVsZEp2a+K/L5hpj7Kpf7ZIECeZevfTufrj2whHE4uJqm2VyHW29pT4jci2bHUSPgOwfW/wxmKC4j FlIsd5yULNn6w/KE0PpzJGHftv4gLYgZyoUPZ2s4BTiXwUZXQccq5qnTSjt2FaUmQZnMef4VWxGOxk Z7DZdcY8GWE3S1jbMnC2m4UUAso73DHa7B/NzEeooMGcD4MHHwJBMroLRrP1JHtp5Eq/qbpu2URjEb XtitCc2gB1OARPuOUuLzauDbbHUGmVZufY/bJ8wVB1SZbvnugqMlKIGvA3hXqVexej9FO6FUSl/69v It7xT8dC+BynjZmfrvvdvlx9b+W8msRW1p1pAD+fZ0DusckWcauzjWQVLEmV408vu+hWCLZZcoL7eC FBgV48j1gx3io2FZojlZEwyg+mmjxK5M2Y1qYJbo9tU8s7TnbV31GOmd/ReFFEqxSQYzHfG1lqdREQ Qhh+T/A0GzmKGX1IJ3i3Cb56obRRLfF1IWvZ/+ObWsKjOgg21JuoAW6AtsLsNQ7vJoAYosEQUEb9q3 4wC6ks38qNqU1Di610RQ9TscSBxJ/d+8qRFw2sfiJsLHJ2VT+G3mXgBAk/3SGZxeuzHEojRdHv3HFp uq34aOjPJRFUv7B5HYAM69etDefjppyqO34ujAxScftAJFSLtgoEiY9S+q2A== X-Developer-Key: i=memxor@gmail.com; a=openpgp; fpr=4BBE2A7E06ECF9D5823C61114CE0C88648BF11CA Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net Ensure that variable offset is handled correctly, and verifier takes both fixed and variable part into account. Also ensures that only constant var_off is allowed. Signed-off-by: Kumar Kartikeya Dwivedi --- .../testing/selftests/bpf/progs/dynptr_fail.c | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c index 023b3c36bc78..063d351f327a 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_fail.c +++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c @@ -794,3 +794,43 @@ int dynptr_pruning_type_confusion(struct __sk_buff *ctx) ); return 0; } + +SEC("?tc") +__failure __msg("dynptr has to be at the constant offset") __log_level(2) +int dynptr_var_off_overwrite(struct __sk_buff *ctx) +{ + asm volatile ( + "r9 = 16;" + "*(u32 *)(r10 - 4) = r9;" + "r8 = *(u32 *)(r10 - 4);" + "if r8 >= 0 goto vjmp1;" + "r0 = 1;" + "exit;" + "vjmp1:" + "if r8 <= 16 goto vjmp2;" + "r0 = 1;" + "exit;" + "vjmp2:" + "r8 &= 16;" + "r1 = %[ringbuf] ll;" + "r2 = 8;" + "r3 = 0;" + "r4 = r10;" + "r4 += -32;" + "r4 += r8;" + "call %[bpf_ringbuf_reserve_dynptr];" + "r9 = 0xeB9F;" + "*(u64 *)(r10 - 16) = r9;" + "r1 = r10;" + "r1 += -32;" + "r1 += r8;" + "r2 = 0;" + "call %[bpf_ringbuf_discard_dynptr];" + : + : __imm(bpf_ringbuf_reserve_dynptr), + __imm(bpf_ringbuf_discard_dynptr), + __imm_addr(ringbuf) + : __clobber_all + ); + return 0; +} From patchwork Thu Jan 19 02:14:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kumar Kartikeya Dwivedi X-Patchwork-Id: 13107303 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 7C76AC38159 for ; Thu, 19 Jan 2023 02:15:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229850AbjASCPW (ORCPT ); Wed, 18 Jan 2023 21:15:22 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37816 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229631AbjASCPV (ORCPT ); Wed, 18 Jan 2023 21:15:21 -0500 Received: from mail-pj1-x1043.google.com (mail-pj1-x1043.google.com [IPv6:2607:f8b0:4864:20::1043]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3086D6794B for ; Wed, 18 Jan 2023 18:15:21 -0800 (PST) Received: by mail-pj1-x1043.google.com with SMTP id cx21-20020a17090afd9500b00228f2ecc6dbso3342042pjb.0 for ; Wed, 18 Jan 2023 18:15:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=4MT64Kw2s7noQGB8gnrRJgRvyqyO0dwBS+rUz2DHLxU=; b=g6KSAesa3PZMFfk4gjMBn/uNRkI6K3iU0jU3E0w6TsWPjLRib2Xb7yUCHLC6P30LZv ccYipD4G6BuXGxZJZnh1myb7S4P8ex8oVJxkVMGvy3BmMYesPqCGiEDAHzgkA6L80mPw coiRAbA9eX5DGHSsnI2HazrGHr3tVvaUm+ucCZM9iyJJAUmZyz6lhcX3lS5PFmTRutE7 ju1XxDAUtyXxSK6hER6WmOcH1k2EVEE0KyOWSG6GwN3j4ku/9eZc6g5hqq+grlJkXvch q4iBNiKXCeXtJbAKkcFERZpUfJw9eNWmoVaaKAJmXN0erp+79mzBcLR4EB6OIT+YvOyK k/HA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=4MT64Kw2s7noQGB8gnrRJgRvyqyO0dwBS+rUz2DHLxU=; b=wVTzQ9CQPxy20u5d/9b5RnjVBXFYE+qS4UedquSZczEv6oX3XzgQd0VhmBV2rH/BVQ q3F12oadxKukNb+LAIFIpmZKNk47zNUL7GuAJPSDHtea88oN510nmqZ4y0Sroh0/0ZZ5 ke3izYtoxn/l9hDm8kOXvmVEcwT/3VwMa3NrVbvKYkVr5xXuhaBoRVXT9dDS3OJnu4hI 4Ffi6cGThy56YJ2X4CDNKre8C7RNkNAqQNZalb3m+0eShvrsPp67U0v74z/v97WgubKE fSN30J149gcNUKJzcxu2H1sIpWn9Ggd3Df5/SEBDze9a2I8LDWpYKtLs2jQOcKNhRC3/ u3Ag== X-Gm-Message-State: AFqh2ko8ifx2I0De6ytTHw8At6Sb7Nym6ELhXv+gJ86xxNV86ngRsgqX b8mRVvw9BUU9kjFZR37Ossw8jMpwjX4= X-Google-Smtp-Source: AMrXdXtlKq9hGXTzHMv54Wp/PXddA3ahIFJZkDVsissk/8oZB69VuWNUYomhohGx48fxjNCgOv5jMQ== X-Received: by 2002:a17:902:da91:b0:188:760f:d831 with SMTP id j17-20020a170902da9100b00188760fd831mr13354531plx.7.1674094520491; Wed, 18 Jan 2023 18:15:20 -0800 (PST) Received: from localhost ([2405:201:6014:dae3:7dbb:8857:7c39:bb2a]) by smtp.gmail.com with ESMTPSA id q25-20020a631f59000000b004cffa8c0227sm2291825pgm.23.2023.01.18.18.15.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 18 Jan 2023 18:15:20 -0800 (PST) From: Kumar Kartikeya Dwivedi To: bpf@vger.kernel.org Cc: Alexei Starovoitov , Andrii Nakryiko , Daniel Borkmann , Martin KaFai Lau , Joanne Koong , David Vernet , Eduard Zingerman Subject: [PATCH bpf-next v2 10/11] selftests/bpf: Add dynptr partial slot overwrite tests Date: Thu, 19 Jan 2023 07:44:41 +0530 Message-Id: <20230119021442.1465269-11-memxor@gmail.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230119021442.1465269-1-memxor@gmail.com> References: <20230119021442.1465269-1-memxor@gmail.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=2293; i=memxor@gmail.com; h=from:subject; bh=nJCImzp66liN96YM+JOp3WcmgJw4KR+gjbLZP/XY0WY=; b=owEBbQKS/ZANAwAIAUzgyIZIvxHKAcsmYgBjyKdASix/tPD73byymQVITMH4aifeVIIKI7fBSfUY jqHzv1SJAjMEAAEIAB0WIQRLvip+Buz51YI8YRFM4MiGSL8RygUCY8inQAAKCRBM4MiGSL8Ryr9mD/ 96PedKgVkEKl8oYZ1iXzgy18AJ2FBiz4S5e7mNwA1h2HjWOt3VbSX7Uj/LjPe/S/PeMjjWWbdXDtSs Uy3nwqSJbTfvYK4vB2SaMUHEivv9TO7xj4xMD2hjCJnjpKFC/EKiJZa/VfA8SmaqVZFtU9yvPBKYDE QRfvkG6RXTjIVNX1htvvAVkQNk+aoD+JxDs/rvZOaFv4opsbhoobm8MiKQZ4vwHDofUmwEVeH/fcjM jizdD3ksHSnT21l+P9q9dr2Y2ZyIgMbAj+2mWTLwaZ2BBc8GMAcyrVPouMLU4RTMhZZWHYBO1rMiNU bAIMSPGaxeqFVw3ttp/OE5yBYhc6gfC5Kb1MjyYndUNAT0Bl3LSLhC6Spa1Edz2SRP1N4itAaappGQ +ZOA27bXG7gc2ssP7IJs8PtYQZubvnt2vnsyDr5Gl5zTc0zw2zlOmHAFydd9SKeG0q1ub2KGFEdRJj XuIWe74tKDGZs3g8TpS858KRwKYyBkXDY8GdX5lyUkuBHuVOMQvkShJfQd+kEWcHeB/HXzDd4FTkdo it/12CzCKVhtS7xKfLDESpxA6G3TmuXErPmwBZnkD4QPVkVQ5wtC7Uw4R/oxpg/a44mJhmRJR5dZP1 DCg0/HGotC+5mHFf3WRG59AzPxfbeuEeYzD8y2G4UwgdfEDDOX7WuTwo8aMQ== X-Developer-Key: i=memxor@gmail.com; a=openpgp; fpr=4BBE2A7E06ECF9D5823C61114CE0C88648BF11CA Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net Try creating a dynptr, then overwriting second slot with first slot of another dynptr. Then, the first slot of first dynptr should also be invalidated, but without our fix that does not happen. As a consequence, the unfixed case allows passing first dynptr (as the kernel check only checks for slot_type and then first_slot == true). Signed-off-by: Kumar Kartikeya Dwivedi --- .../testing/selftests/bpf/progs/dynptr_fail.c | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c index 063d351f327a..e63d25d82b05 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_fail.c +++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c @@ -834,3 +834,69 @@ int dynptr_var_off_overwrite(struct __sk_buff *ctx) ); return 0; } + +SEC("?tc") +__failure __msg("cannot overwrite referenced dynptr") __log_level(2) +int dynptr_partial_slot_invalidate(struct __sk_buff *ctx) +{ + asm volatile ( + "r6 = %[ringbuf] ll;" + "r7 = %[array_map4] ll;" + "r1 = r7;" + "r2 = r10;" + "r2 += -8;" + "r9 = 0;" + "*(u64 *)(r2 + 0) = r9;" + "r3 = r2;" + "r4 = 0;" + "r8 = r2;" + "call %[bpf_map_update_elem];" + "r1 = r7;" + "r2 = r8;" + "call %[bpf_map_lookup_elem];" + "if r0 != 0 goto sjmp1;" + "exit;" + "sjmp1:" + "r7 = r0;" + "r1 = r6;" + "r2 = 8;" + "r3 = 0;" + "r4 = r10;" + "r4 += -24;" + "call %[bpf_ringbuf_reserve_dynptr];" + "*(u64 *)(r10 - 16) = r9;" + "r1 = r7;" + "r2 = 8;" + "r3 = 0;" + "r4 = r10;" + "r4 += -16;" + "call %[bpf_dynptr_from_mem];" + "r1 = r10;" + "r1 += -512;" + "r2 = 488;" + "r3 = r10;" + "r3 += -24;" + "r4 = 0;" + "r5 = 0;" + "call %[bpf_dynptr_read];" + "r8 = 1;" + "if r0 != 0 goto sjmp2;" + "r8 = 0;" + "sjmp2:" + "r1 = r10;" + "r1 += -24;" + "r2 = 0;" + "call %[bpf_ringbuf_reserve_dynptr];" + : + : __imm(bpf_map_update_elem), + __imm(bpf_map_lookup_elem), + __imm(bpf_ringbuf_reserve_dynptr), + __imm(bpf_ringbuf_discard_dynptr), + __imm(bpf_dynptr_from_mem), + __imm(bpf_dynptr_read), + __imm_addr(ringbuf), + __imm_addr(array_map4) + : __clobber_all + ); + return 0; +} From patchwork Thu Jan 19 02:14:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kumar Kartikeya Dwivedi X-Patchwork-Id: 13107304 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 BB923C38159 for ; Thu, 19 Jan 2023 02:15:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229631AbjASCP1 (ORCPT ); Wed, 18 Jan 2023 21:15:27 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37904 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229871AbjASCPZ (ORCPT ); Wed, 18 Jan 2023 21:15:25 -0500 Received: from mail-pj1-x1043.google.com (mail-pj1-x1043.google.com [IPv6:2607:f8b0:4864:20::1043]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8304467965 for ; Wed, 18 Jan 2023 18:15:24 -0800 (PST) Received: by mail-pj1-x1043.google.com with SMTP id 7-20020a17090a098700b002298931e366so447219pjo.2 for ; Wed, 18 Jan 2023 18:15:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=+yrpR/SCix5EZ4emtkeSeJwHi4dQd0xwh5o1jZ30hQs=; b=OuwF3ZJNMpbXT7ece4iWPjjF9m8EdIfffvxt35K22IfPNDbeBHiU80XFwV7mjbmtMx y3M/EiU4XJScCqFR31H0sZfRnBt/CqSjshEv+iVRD0OUB4105yM8nDsK0q8M3ifYSTrS cmjGG6fzDvsOo/UU6uIDCAt/+N/XqWDpjrM2wdifh3O0MTD+srFu0n+q8CQlunlDWO2g ieq+J5ei9LT/S790tGYNYoAfoKM7R2zm5kDRW14DzqQ1tuwkgVYCr2q33xkCUOuPYiwZ GYc4tuoHT6nYqh06P7QBsLpc41Ll8LtejVxFg1D6Xmwa1/tuXjOcyeMc6mMM1WahMMiG Cw0g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=+yrpR/SCix5EZ4emtkeSeJwHi4dQd0xwh5o1jZ30hQs=; b=y2mUi+RnKi8Ws7WpEZstsh8Ir98qxkeZS/s3tZH03b4ojyQaT7IwXF1cKe/2P8DEks rmcXfjU0Jd3x8qYiN39FEClfUvzzDUIizaKcf14r/dU/qRi1RTn+dD3OzSZXuNRm37Gx aOL/lTKVvBzEwksXx3nWoX6vFhYJfJNtUmMoLZsD1R5vQou2n6KlBPnhdpO6thb5sVos Af56Zl6LNWebyyCaYgjv0fIJkusMjGRO53nTHwvpvddse/kBP4Cj+TXeUS9IsrpQRcDr WC4iKB5uia95DW0GSm4PVAJ4vGd1z2R6RclyPk5RCUA2kRNqU8uFoAzgkt6F9xZm88Sk wBgw== X-Gm-Message-State: AFqh2krWXhZSc1PKODsGxfAueFoBhfefwheAzXpuOKcXFFmBHBE0FE9u f41vwKbcWmotm1DeD7dtlMk4gwr5eWQ= X-Google-Smtp-Source: AMrXdXur9ht9BpctGeuk1F7MFRVOoNDG0hlqezH1RdC9xZozOjhBrOEZKYS4FLSedbQcGU//MofBrg== X-Received: by 2002:a17:902:bd07:b0:194:9331:3d79 with SMTP id p7-20020a170902bd0700b0019493313d79mr9745657pls.32.1674094523984; Wed, 18 Jan 2023 18:15:23 -0800 (PST) Received: from localhost ([2405:201:6014:dae3:7dbb:8857:7c39:bb2a]) by smtp.gmail.com with ESMTPSA id a10-20020a170902ecca00b001891a17bd93sm23925943plh.43.2023.01.18.18.15.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 18 Jan 2023 18:15:23 -0800 (PST) From: Kumar Kartikeya Dwivedi To: bpf@vger.kernel.org Cc: Alexei Starovoitov , Andrii Nakryiko , Daniel Borkmann , Martin KaFai Lau , Joanne Koong , David Vernet , Eduard Zingerman Subject: [PATCH bpf-next v2 11/11] selftests/bpf: Add dynptr helper tests Date: Thu, 19 Jan 2023 07:44:42 +0530 Message-Id: <20230119021442.1465269-12-memxor@gmail.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230119021442.1465269-1-memxor@gmail.com> References: <20230119021442.1465269-1-memxor@gmail.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=2122; i=memxor@gmail.com; h=from:subject; bh=hZd0AYASHtGwY/BLZDwFFAlra8GAsKg+4NXfOeE+i5E=; b=owEBbQKS/ZANAwAIAUzgyIZIvxHKAcsmYgBjyKdAi3sdmPrFCEWEHf1V1ngxI4OE95eXlq2lC+0P mXb6Kg+JAjMEAAEIAB0WIQRLvip+Buz51YI8YRFM4MiGSL8RygUCY8inQAAKCRBM4MiGSL8RyrK8D/ 40VPVTFn0URC2Av6MDWfjwHPks03aAJEQF/tYGji6YWWuc3DrfoswTRS5m6u0ZUgt9qWY6o58NUzbJ 6BMKylNeSqYb/QPxwwq6Vj1uPBYMlHqqd7pXS49Xz8yQ6nhCpI+D0dlMWJV/KhAmAeT9qCP56UFYlK aPVvywJ1wxlrRHlHsnWhVLJD5qrhPH3bQyX5RoWDNhF8NnWsz5Rl3aMWECzuf//g7dluYT/3O2tvL5 BmD2C+mxi5epfOYsP/CUUhWAS4ArooabDlyXZvv/xesqxNFcTQLypq7B0xtj5Q3BugDL7pJagXEFTk RfSGL4VLH3I/L+yW0ouP/Mj9J7FNGKZ67Vq+taVjTSCaLJ3PPDRgsIO6N2aQjS9bfjopqD9p9NoT4e hCVXDzO/8DhaB1D6szGLDAZt8ApLNytIv0pqqgf7yLMhYhtoT/FFJXTPpx9srQuaQUDZGEt50Rm4eG z5fhkECdy2ZbX6DLw0NY998HF4B7SBkqpjQDAaFOmgby6jykwoCg3ZB28TryALzhI9vjRBZptS2xON TqZOUawzb7w+AtGWyXX2pEpslKIeQ3xhBEUZVxo/auIRPqppmtLZwVGiLKXOePDwB5uH4yVy4pNCrp 6CgEFvgzXCI15TpGFgUV2zAuDKNN2HV+xq3sEeDbNmYrRlrXXBiHTDiPKbmA== X-Developer-Key: i=memxor@gmail.com; a=openpgp; fpr=4BBE2A7E06ECF9D5823C61114CE0C88648BF11CA Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net First test that we allow overwriting dynptr slots and reinitializing them in unreferenced case, and disallow overwriting for referenced case. Next, test that MEM_UNINIT doesn't allow writing dynptr stack slots. Signed-off-by: Kumar Kartikeya Dwivedi --- .../testing/selftests/bpf/progs/dynptr_fail.c | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c index e63d25d82b05..94686366dcde 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_fail.c +++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c @@ -900,3 +900,65 @@ int dynptr_partial_slot_invalidate(struct __sk_buff *ctx) ); return 0; } + +SEC("?raw_tp") +__success +int dynptr_overwrite_unref(void *ctx) +{ + struct bpf_dynptr ptr; + + get_map_val_dynptr(&ptr); + get_map_val_dynptr(&ptr); + get_map_val_dynptr(&ptr); + + return 0; +} + +SEC("?raw_tp") +__failure __msg("cannot overwrite referenced dynptr") +int dynptr_overwrite_ref(void *ctx) +{ + struct bpf_dynptr ptr; + + bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr); + if (get_map_val_dynptr(&ptr)) + bpf_ringbuf_discard_dynptr(&ptr, 0); + return 0; +} + +/* Reject writes to dynptr slot from bpf_dynptr_read */ +SEC("?raw_tp") +__failure __msg("potential write to dynptr at off=-16") +int dynptr_read_into_slot(void *ctx) +{ + union { + struct { + char _pad[48]; + struct bpf_dynptr ptr; + }; + char buf[64]; + } data; + + bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &data.ptr); + /* this should fail */ + bpf_dynptr_read(data.buf, sizeof(data.buf), &data.ptr, 0, 0); + + return 0; +} + +/* Reject writes to dynptr slot for uninit arg */ +SEC("?raw_tp") +__failure __msg("potential write to dynptr at off=-16") +int uninit_write_into_slot(void *ctx) +{ + struct { + char buf[64]; + struct bpf_dynptr ptr; + } data; + + bpf_ringbuf_reserve_dynptr(&ringbuf, 80, 0, &data.ptr); + /* this should fail */ + bpf_get_current_comm(data.buf, 80); + + return 0; +}