From patchwork Sat Mar 1 15:18:44 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kumar Kartikeya Dwivedi X-Patchwork-Id: 13997599 X-Patchwork-Delegate: bpf@iogearbox.net Received: from mail-wm1-f68.google.com (mail-wm1-f68.google.com [209.85.128.68]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9B4EF22F19 for ; Sat, 1 Mar 2025 15:18:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.68 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740842333; cv=none; b=FGEp2G8ErbLgXw+xqt8jxGPpryxi5SpG6PIroDRTFO3Teq4JlR8XyqUaZjQodrqE66BM6FkKzS/8Fy+lw/ia/Bj6dRVTVoDRaXjXuERceh/Skrj2S/8zIzYW85UFO3tFGI7ohPyZZwNo5mIRUo6ydJaUiIQccmg1rP5Y+ap0gEM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740842333; c=relaxed/simple; bh=SJCowbVKLs1OnsqlOi39v/+vLx+o2dOZ+aMHiQT9mw0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Hql2+ttMbDXd48zdhL84uztxBXGPk6n+Rr21MNCBwFxtfBbpkfLM+ktnqpyuqJubJ5Xnu0P0NXbMM3470RDc2dHtOCZ2lSNk/H6aDwyUPhC8GJKj1V1F4GKVZno3NSN7GPs1iDvFCnC87Xdr84H1gwf+M3oBz9jbxf9P4FJbqnU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=PJmQfeGC; arc=none smtp.client-ip=209.85.128.68 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="PJmQfeGC" Received: by mail-wm1-f68.google.com with SMTP id 5b1f17b1804b1-439ac3216dcso21168425e9.1 for ; Sat, 01 Mar 2025 07:18:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1740842329; x=1741447129; darn=vger.kernel.org; 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=vsuz84cgr5551RFT5Sw/c4oPp2dS8p6JRsRwMJHcwXU=; b=PJmQfeGCtnrFS/DvtLpD/LwvQua5bTq2wUYsfREdAFhS1abJL1UaLrT+qlHXVnoPWk HGgmpJZ/OJkL7RJzQu8LaRxoL1BOES2F3KNZwFFI6iZ7nKUAAFXD9thC8KytxTwGMF3q T4B1ASrPQo3ej715iXQpwuKYVVL6TlWlew7bSOdBuHG6krrQwOx0ITQUwT+ruDqqp6FB q7jIdnezdOWb3yqnz7Ixwnge7C3f1Kd2cCmf6GaBv5I122ewDgP2kYhKdjuUiMlNVWDH T/McXg8bnq6CYWKce6l12Az4jDo5z5eV/7NAzKzmlAuNHNtyYTupX/a6MGfgQytDzcMk 9Yqw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1740842329; x=1741447129; 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=vsuz84cgr5551RFT5Sw/c4oPp2dS8p6JRsRwMJHcwXU=; b=IqunKbhmLOrSwNPWzTcgCQaYNw3kCcZUib3lKdZcsticAwhz07UR79pAyp2V9gGhcd 7ae5BVKF0+3mW4ZRh23vpVpW0hZsoFnK5T1HQXS4zi6dbpBr484cABBoRh0sKscKrUZD +dKCCwj1srIO556OBGRYawTfb1uRCPvRfLpaNT4CJl5F5pl8MTo1wrfq94pV3WhBRizg U4sNU21QMQxCKDh6boDLcdbnLbFRFcIphcB2hRQRh00Y/jrNTAWI7Ax7CaR7NJIUgl94 qsdgonK6JlAbPE6PYHV7XDtE1hQWFbygi7E/afC3Yupmr5wViMK32BlJnNH+Cw/s05q0 tf9A== X-Gm-Message-State: AOJu0YwD9UGnv53L0qPreFDfgG6wwHk8ndgzyK5FnQ/MkUCeQiTrMdl7 aJ0oBwCycP0so42+ogeYaa11mZPfC2yzetsU2AjQ9UjXwmF5h6HOFs+e/1a0ZK4= X-Gm-Gg: ASbGncuqWIti83ApUZp4OhZsfgyIuah5M0tHeVV7uJzu/+cjYL+Rwya3nLKDp2JUdL7 0s31cPgFVMbbarLGUKQozmUopx23DXqTIfujc8tm/5E0bNKW1h4pMXf+8c8lv0afZK83qLJE7Zp 3E8F9FTlHTUz7CLMtilw8vpmAMr5wiGzNvckRqAGg/0f6PDETO78P2Oob8L3usGpB9JxryQrEw0 hObIJNZOs/mKYL2yfcoJP7FzuagAsQ72A9+yCI2QtSQtJFF9q3fcK77AHqJP4Vx5snjAqoJprkG oSB6oVR4fqUdP65irROEHHKjWUGbywXqbK8= X-Google-Smtp-Source: AGHT+IE99PC109IuQZJWU+pcHZHcQOhEPdxUEaVBoVC4HBUAsTHiIHCSV//ibhWuncRqWbkuuSqJSw== X-Received: by 2002:a05:6000:20c4:b0:385:f249:c336 with SMTP id ffacd0b85a97d-390eca26356mr4959972f8f.45.1740842329063; Sat, 01 Mar 2025 07:18:49 -0800 (PST) Received: from localhost ([2a03:2880:31ff:46::]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-390e4844a16sm8617545f8f.79.2025.03.01.07.18.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 01 Mar 2025 07:18:48 -0800 (PST) From: Kumar Kartikeya Dwivedi To: bpf@vger.kernel.org Cc: Alexei Starovoitov , Andrii Nakryiko , Daniel Borkmann , Martin KaFai Lau , Eduard Zingerman , kkd@meta.com, kernel-team@meta.com Subject: [PATCH bpf-next v3 1/3] bpf: Summarize sleepable global subprogs Date: Sat, 1 Mar 2025 07:18:44 -0800 Message-ID: <20250301151846.1552362-2-memxor@gmail.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20250301151846.1552362-1-memxor@gmail.com> References: <20250301151846.1552362-1-memxor@gmail.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=8141; h=from:subject; bh=SJCowbVKLs1OnsqlOi39v/+vLx+o2dOZ+aMHiQT9mw0=; b=owEBbQKS/ZANAwAIAUzgyIZIvxHKAcsmYgBnwyScXj7wIa5MOt6EPLiW9JLHc4Ki2UMcZTAk5wdn 5RoiEICJAjMEAAEIAB0WIQRLvip+Buz51YI8YRFM4MiGSL8RygUCZ8MknAAKCRBM4MiGSL8RypydD/ 9d/0B8wEeRNbdCmxEc6CqbMIbryju2Wb1Qm1eTfkmd9JhJkU8Y3PcelHF+R4DMkpR6xvc3fSgGRCS1 mM0f+cYvOtkaSxhhUUC8DWTfjMrV2yRufHCFqXrG7OPvBmX9TWUJo28ajc3PKWDXf32vGkasZ4mWDO o3VGXIbYOh6yITgXgAi4IGaN4wPGNR+oBov6dftiJrKEM4QMiUVWxZUrmoGhIeayE9gf85tQQUEqa7 OThIBTwqxfuld4ijv1ddKjwuct1OuJWmpnlHHtUcePm3v55+1xk4t9bHsgDBMaltUSYdumDiH7tMeh opQMQC1VJLnxDbRbF2ad+YCOlb6guMFIZ9hTYCRvtcczjBO9MTF8jr9EXdiAmC7CuVp7MXoCxu4pXs 0dfScqNYUESIyXzX7PcjFxG5HoRmw/LuSgC7sz8M1EuhxZH7M3v1qI1XWBM1wwX0M83AeeucHL7cqf NGwiZEe7SMLl5AXDBIreLJubYJVTR5zOK++bPKrqXs3nq70qi8FJlkdvHDBce6AK/uCYJlzUZzU9ty 6XPfNbozY/8cV3ylZviAho6ylSPHvAebNfHOk93WYFBFtx9PeuhzFuHGtIr8PtErIQ/wceEmEJZcdk xF9OmWxzAlf9rk0eDXjd5IHhYdPsz2Vypy9anXYJJA1WhYw6UO/S9qUj/lIw== X-Developer-Key: i=memxor@gmail.com; a=openpgp; fpr=4BBE2A7E06ECF9D5823C61114CE0C88648BF11CA X-Patchwork-Delegate: bpf@iogearbox.net The verifier currently does not permit global subprog calls when a lock is held, preemption is disabled, or when IRQs are disabled. This is because we don't know whether the global subprog calls sleepable functions or not. In case of locks, there's an additional reason: functions called by the global subprog may hold additional locks etc. The verifier won't know while verifying the global subprog whether it was called in context where a spin lock is already held by the program. Perform summarization of the sleepable nature of a global subprog just like changes_pkt_data and then allow calls to global subprogs for non-sleepable ones from atomic context. While making this change, I noticed that RCU read sections had no protection against sleepable global subprog calls, include it in the checks and fix this while we're at it. Care needs to be taken to not allow global subprog calls when regular bpf_spin_lock is held. When resilient spin locks is held, we want to potentially have this check relaxed, but not for now. Also make sure extensions freplacing global functions cannot do so in case the target is non-sleepable, but the extension is. The other combination is ok. Tests are included in the next patch to handle all special conditions. Fixes: 9bb00b2895cb ("bpf: Add kfunc bpf_rcu_read_lock/unlock()") Signed-off-by: Kumar Kartikeya Dwivedi --- include/linux/bpf.h | 1 + include/linux/bpf_verifier.h | 1 + kernel/bpf/verifier.c | 62 ++++++++++++++++++++++++++++-------- 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index aec102868b93..4c4028d865ee 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1531,6 +1531,7 @@ struct bpf_prog_aux { bool jits_use_priv_stack; bool priv_stack_requested; bool changes_pkt_data; + bool might_sleep; u64 prog_array_member_cnt; /* counts how many times as member of prog_array */ struct mutex ext_mutex; /* mutex for is_extended and prog_array_member_cnt */ struct bpf_arena *arena; diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index bbd013c38ff9..d338f2a96bba 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -667,6 +667,7 @@ struct bpf_subprog_info { /* true if bpf_fastcall stack region is used by functions that can't be inlined */ bool keep_fastcall_stack: 1; bool changes_pkt_data: 1; + bool might_sleep: 1; enum priv_stack_mode priv_stack_mode; u8 arg_cnt; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index dcd0da4e62fc..eb1624f6e743 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -10317,23 +10317,18 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn, if (subprog_is_global(env, subprog)) { const char *sub_name = subprog_name(env, subprog); - /* Only global subprogs cannot be called with a lock held. */ if (env->cur_state->active_locks) { verbose(env, "global function calls are not allowed while holding a lock,\n" "use static function instead\n"); return -EINVAL; } - /* Only global subprogs cannot be called with preemption disabled. */ - if (env->cur_state->active_preempt_locks) { - verbose(env, "global function calls are not allowed with preemption disabled,\n" - "use static function instead\n"); - return -EINVAL; - } - - if (env->cur_state->active_irq_id) { - verbose(env, "global function calls are not allowed with IRQs disabled,\n" - "use static function instead\n"); + if (env->subprog_info[subprog].might_sleep && + (env->cur_state->active_rcu_lock || env->cur_state->active_preempt_locks || + env->cur_state->active_irq_id || !in_sleepable(env))) { + verbose(env, "global functions that may sleep are not allowed in non-sleepable context,\n" + "i.e., in a RCU/IRQ/preempt-disabled section, or in\n" + "a non-sleepable BPF program context\n"); return -EINVAL; } @@ -16703,6 +16698,14 @@ static void mark_subprog_changes_pkt_data(struct bpf_verifier_env *env, int off) subprog->changes_pkt_data = true; } +static void mark_subprog_might_sleep(struct bpf_verifier_env *env, int off) +{ + struct bpf_subprog_info *subprog; + + subprog = find_containing_subprog(env, off); + subprog->might_sleep = true; +} + /* 't' is an index of a call-site. * 'w' is a callee entry point. * Eventually this function would be called when env->cfg.insn_state[w] == EXPLORED. @@ -16716,6 +16719,7 @@ static void merge_callee_effects(struct bpf_verifier_env *env, int t, int w) caller = find_containing_subprog(env, t); callee = find_containing_subprog(env, w); caller->changes_pkt_data |= callee->changes_pkt_data; + caller->might_sleep |= callee->might_sleep; } /* non-recursive DFS pseudo code @@ -17183,9 +17187,20 @@ static int visit_insn(int t, struct bpf_verifier_env *env) mark_prune_point(env, t); mark_jmp_point(env, t); } - if (bpf_helper_call(insn) && bpf_helper_changes_pkt_data(insn->imm)) - mark_subprog_changes_pkt_data(env, t); - if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) { + if (bpf_helper_call(insn)) { + const struct bpf_func_proto *fp; + + ret = get_helper_proto(env, insn->imm, &fp); + /* If called in a non-sleepable context program will be + * rejected anyway, so we should end up with precise + * sleepable marks on subprogs, except for dead code + * elimination. + */ + if (ret == 0 && fp->might_sleep) + mark_subprog_might_sleep(env, t); + if (bpf_helper_changes_pkt_data(insn->imm)) + mark_subprog_changes_pkt_data(env, t); + } else if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) { struct bpf_kfunc_call_arg_meta meta; ret = fetch_kfunc_meta(env, insn, &meta, NULL); @@ -17204,6 +17219,13 @@ static int visit_insn(int t, struct bpf_verifier_env *env) */ mark_force_checkpoint(env, t); } + /* Same as helpers, if called in a non-sleepable context + * program will be rejected anyway, so we should end up + * with precise sleepable marks on subprogs, except for + * dead code elimination. + */ + if (ret == 0 && is_kfunc_sleepable(&meta)) + mark_subprog_might_sleep(env, t); } return visit_func_call_insn(t, insns, env, insn->src_reg == BPF_PSEUDO_CALL); @@ -17320,6 +17342,7 @@ static int check_cfg(struct bpf_verifier_env *env) } ret = 0; /* cfg looks good */ env->prog->aux->changes_pkt_data = env->subprog_info[0].changes_pkt_data; + env->prog->aux->might_sleep = env->subprog_info[0].might_sleep; err_free: kvfree(insn_state); @@ -20845,6 +20868,7 @@ static int jit_subprogs(struct bpf_verifier_env *env) func[i]->aux->tail_call_reachable = env->subprog_info[i].tail_call_reachable; func[i]->aux->exception_cb = env->subprog_info[i].is_exception_cb; func[i]->aux->changes_pkt_data = env->subprog_info[i].changes_pkt_data; + func[i]->aux->might_sleep = env->subprog_info[i].might_sleep; if (!i) func[i]->aux->exception_boundary = env->seen_exception; func[i] = bpf_int_jit_compile(func[i]); @@ -22723,6 +22747,7 @@ int bpf_check_attach_target(struct bpf_verifier_log *log, if (tgt_prog) { struct bpf_prog_aux *aux = tgt_prog->aux; bool tgt_changes_pkt_data; + bool tgt_might_sleep; if (bpf_prog_is_dev_bound(prog->aux) && !bpf_prog_dev_bound_match(prog, tgt_prog)) { @@ -22765,6 +22790,15 @@ int bpf_check_attach_target(struct bpf_verifier_log *log, "Extension program changes packet data, while original does not\n"); return -EINVAL; } + + tgt_might_sleep = aux->func + ? aux->func[subprog]->aux->might_sleep + : aux->might_sleep; + if (prog->aux->might_sleep && !tgt_might_sleep) { + bpf_log(log, + "Extension program may sleep, while original does not\n"); + return -EINVAL; + } } if (!tgt_prog->jited) { bpf_log(log, "Can attach to only JITed progs\n"); From patchwork Sat Mar 1 15:18:45 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kumar Kartikeya Dwivedi X-Patchwork-Id: 13997600 X-Patchwork-Delegate: bpf@iogearbox.net Received: from mail-wr1-f65.google.com (mail-wr1-f65.google.com [209.85.221.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0F5A323F386 for ; Sat, 1 Mar 2025 15:18:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.65 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740842335; cv=none; b=eXXvKrU/vrzONLopwL+KYFHP8zZAB5iblZxt4K6nX6yO3D5B3lTh6ax9N0V87WLSLe6QQ2eBLBoSMW67jYhqje1P1SvVu4QUrWQQk7bM7utN678109jDDzvgK/buFkYwwulIJigKc3ae9kdmlkkJOONf2pcq5s/dCnPolDDW2tI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740842335; c=relaxed/simple; bh=y+sHsLEqdew+DfOuBOU9KArsJMmccspgbdU2aqyaCd4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=OGg68KJhgL7MulC4KzIO+QZpfWSUPlqDrmg+7LFoiA4HNm/7hUw9DilkHxneZdq1U4iRuays9Q1EtQQagJ/+o7zBGjhC9Ld3y/3L9+/mAHUW8JdMKP0q4QX2R2nFibGFKX8A0TqfviAH/y55bk1n0uo7ZAh+13kF2L7aMQcFYng= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=ltYC1aGx; arc=none smtp.client-ip=209.85.221.65 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ltYC1aGx" Received: by mail-wr1-f65.google.com with SMTP id ffacd0b85a97d-390e6ac844fso2672286f8f.3 for ; Sat, 01 Mar 2025 07:18:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1740842330; x=1741447130; darn=vger.kernel.org; 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=5ErwRhf6FvDxB2tk+JTbXqp+BUu3Yb98sxSMDVeInZk=; b=ltYC1aGxt50E64/fOrVzfAEMZHJQ3+AlNvcXZ8zjgm/3y+dhRMxu5wBiK0Sj6aQtYB rCffG61/0tVq+XFj3lGbDBmLWoAMIUIN0JckjfggHsz3oma9ZuIS094YU1BBWNkCRtgh +mvToal/A22OM7U6dbqDeCPzb59SaN0Xd7MvrMTKJhCUED6TeNSEGrNDw4zUibVPok9+ K/rxHnWWzvxSqOpE2OE/p0gkwVWkC0LJU5dexXyGNUKUhVUcpPpHtlrCXnf/vRfoeRzp 8zyNmIgeif5+NVyU4HDdL10BDYmjw8VsJ298Qc0zYkxeeV3OoEIrOghfdmRcKnHlv/4l aUxA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1740842330; x=1741447130; 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=5ErwRhf6FvDxB2tk+JTbXqp+BUu3Yb98sxSMDVeInZk=; b=UpTFBMrAMdJvWpG+OTvxNuW7FDbN/NhgA+CSiGd/k0ERqz7Pl/uzWOIPiUrHPgkjTe Hharj9I7E+zu3IFm1rDuJlYnYTaY4U6LDDuSqprphQ235E7BOQsLUbbYKAIr/j5DF84w kuvw/giDtaduMuR9EWmL3+1wb+NHbMMSW9oz+c/pv5LpFPZwvP47jK685DSrcMfFkvvV Q5pTlSIE8Qd8B9Qe/nMgB51gFEsUvXI2g/F5jQBJ0Rq3/AhZ7hhA3/XAxvIP7p/rx9WN 7OptbfZjfjobTcXfM/bV/3Q/YUG5fyOFe4bnT9n2FnqRz9SJvirRx5r/nOietw0gSyZz DA/A== X-Gm-Message-State: AOJu0YzyZKzdO9OtneYQcMVX5oTmr21ppVokPpnY8d/4cP0gDaimApIq lkaKcl6u6R05TbtLDv292fnIiJlhvYYZ139Y8B/lQCq5TZphnoEvD7FhSEIvcmw= X-Gm-Gg: ASbGncsvwzdiI7tBTHUw1HjVim0DMNXLLDMLMjMGinYEfnDNREWmxiY15dM9CZDrNMz GJ3QMIX22hQU/EJDDgsxY9HFOdKhe6tmgO7ihbyFWe/P8uABrMVD3n4iHR2J4C6+sENAV96ByBl Y/EuxcgXF34rGnufJzR951q6lOcSlLcN5zF/lMzWFtiYbqmhjiTJnJF19f1l7V4qIY8yzv1ZfmG PMLlq3V+XsKTdDzRmvACw5KmjbBHpEizKK8jBOwUxvdkv0A8A1/GB2WG5uVptPiMRyj803OVqGv Nf2+/b318ARpUkxhwRzwSDe98W0vsO+ECw== X-Google-Smtp-Source: AGHT+IFdnxnHGbOMWpo9J2tQHABa0tFCSAwClKjYKbCb2fe0KY0TOA7OTXMkQUIP9+bwON7/UaCecg== X-Received: by 2002:a5d:64e2:0:b0:38d:dfdc:52b6 with SMTP id ffacd0b85a97d-390eca27b9bmr5202760f8f.37.1740842330544; Sat, 01 Mar 2025 07:18:50 -0800 (PST) Received: from localhost ([2a03:2880:31ff:8::]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-390e485db77sm8452694f8f.86.2025.03.01.07.18.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 01 Mar 2025 07:18:49 -0800 (PST) From: Kumar Kartikeya Dwivedi To: bpf@vger.kernel.org Cc: Alexei Starovoitov , Andrii Nakryiko , Daniel Borkmann , Martin KaFai Lau , Eduard Zingerman , kkd@meta.com, kernel-team@meta.com Subject: [PATCH bpf-next v3 2/3] selftests/bpf: Test sleepable global subprogs in atomic contexts Date: Sat, 1 Mar 2025 07:18:45 -0800 Message-ID: <20250301151846.1552362-3-memxor@gmail.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20250301151846.1552362-1-memxor@gmail.com> References: <20250301151846.1552362-1-memxor@gmail.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=10038; h=from:subject; bh=y+sHsLEqdew+DfOuBOU9KArsJMmccspgbdU2aqyaCd4=; b=owEBbQKS/ZANAwAIAUzgyIZIvxHKAcsmYgBnwyScLKOHjfLJChnSeMHFb6wygHu2qIeh/03QGtK5 /KZs9+SJAjMEAAEIAB0WIQRLvip+Buz51YI8YRFM4MiGSL8RygUCZ8MknAAKCRBM4MiGSL8Ryg6dD/ 99sFBXejDwjAU3J2dB3+wOGmLPUSnnn7jnQt1mepdnXKJBnL2i8E71zbdN1YxKyfMr7LBTRC3KHEHy MHgN2orjstIZ4zF579HIjkLem4kjicwhAkqOuTrjoXvHx1zOoKle/vSgkKb2HyPh0TbkhWqSdX8Kl3 f3lGQw802x7qhTMb5T0hEqTBrr7xpcfe54FW9mMfU5pHWikzNILt/xb4LMzVTqSwFhCyhkPa19A8fb grI8NeS3kuoZACXeSReJgxFwPu3HDuyVG8M6HUlatH4xXxjrfV8CZ4wEZ0lwUNKbhYtv5oH3eBLXZG AHmmy0lTrkP1LSWiXweE/EGW3mLk/TLEjAl1mU+BKwtoyAO349gH/mCCDfA/jxHpyqU3//0Pn+wfv5 lDsGNqOknVrxvZnXpS1tkbJia7XhXGTEeQeIQQSStn4hxjkvOgOq/t7Uaz4AiEF9zZG00wED0zaNbF 1pvDPbehV9zgZ2nKqjwzrK+Koi517rCOKDx5TCZxclyMosc73Ir8YEgZ038KLri8UVUjcZntDjbY7V g99CO46BEfWumVlhX+tOPZhh4VRnWntr/JKzuyTtzbWJgu53KnWcocEZCU3NHUmjXY6QII2TA37W9J JfWJX+FA24eVS4e946pTjBP56b9zIxLGr/BAppScao82ABDu730aY6BN4A3g== X-Developer-Key: i=memxor@gmail.com; a=openpgp; fpr=4BBE2A7E06ECF9D5823C61114CE0C88648BF11CA X-Patchwork-Delegate: bpf@iogearbox.net Add tests for rejecting sleepable and accepting non-sleepable global function calls in atomic contexts. For spin locks, we still reject all global function calls. Once resilient spin locks land, we will carefully lift in cases where we deem it safe. Signed-off-by: Kumar Kartikeya Dwivedi --- .../selftests/bpf/prog_tests/rcu_read_lock.c | 3 + .../selftests/bpf/prog_tests/spin_lock.c | 3 + tools/testing/selftests/bpf/progs/irq.c | 71 ++++++++++++++++++- .../selftests/bpf/progs/preempt_lock.c | 68 +++++++++++++++++- .../selftests/bpf/progs/rcu_read_lock.c | 58 +++++++++++++++ .../selftests/bpf/progs/test_spin_lock_fail.c | 69 ++++++++++++++++++ 6 files changed, 270 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c b/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c index ebe0c12b5536..c9f855e5da24 100644 --- a/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c +++ b/tools/testing/selftests/bpf/prog_tests/rcu_read_lock.c @@ -81,6 +81,9 @@ static const char * const inproper_region_tests[] = { "nested_rcu_region", "rcu_read_lock_global_subprog_lock", "rcu_read_lock_global_subprog_unlock", + "rcu_read_lock_sleepable_helper_global_subprog", + "rcu_read_lock_sleepable_kfunc_global_subprog", + "rcu_read_lock_sleepable_global_subprog_indirect", }; static void test_inproper_region(void) diff --git a/tools/testing/selftests/bpf/prog_tests/spin_lock.c b/tools/testing/selftests/bpf/prog_tests/spin_lock.c index 2b0068742ef9..e3ea5dc2f697 100644 --- a/tools/testing/selftests/bpf/prog_tests/spin_lock.c +++ b/tools/testing/selftests/bpf/prog_tests/spin_lock.c @@ -50,6 +50,9 @@ static struct { { "lock_id_mismatch_innermapval_mapval", "bpf_spin_unlock of different lock" }, { "lock_global_subprog_call1", "global function calls are not allowed while holding a lock" }, { "lock_global_subprog_call2", "global function calls are not allowed while holding a lock" }, + { "lock_global_sleepable_helper_subprog", "global function calls are not allowed while holding a lock" }, + { "lock_global_sleepable_kfunc_subprog", "global function calls are not allowed while holding a lock" }, + { "lock_global_sleepable_subprog_indirect", "global function calls are not allowed while holding a lock" }, }; static int match_regex(const char *pattern, const char *string) diff --git a/tools/testing/selftests/bpf/progs/irq.c b/tools/testing/selftests/bpf/progs/irq.c index b0b53d980964..298d48d7886d 100644 --- a/tools/testing/selftests/bpf/progs/irq.c +++ b/tools/testing/selftests/bpf/progs/irq.c @@ -222,7 +222,7 @@ int __noinline global_local_irq_balance(void) } SEC("?tc") -__failure __msg("global function calls are not allowed with IRQs disabled") +__success int irq_global_subprog(struct __sk_buff *ctx) { unsigned long flags; @@ -441,4 +441,73 @@ int irq_ooo_refs_array(struct __sk_buff *ctx) return 0; } +int __noinline +global_subprog(int i) +{ + if (i) + bpf_printk("%p", &i); + return i; +} + +int __noinline +global_sleepable_helper_subprog(int i) +{ + if (i) + bpf_copy_from_user(&i, sizeof(i), NULL); + return i; +} + +int __noinline +global_sleepable_kfunc_subprog(int i) +{ + if (i) + bpf_copy_from_user_str(&i, sizeof(i), NULL, 0); + global_subprog(i); + return i; +} + +int __noinline +global_subprog_calling_sleepable_global(int i) +{ + if (!i) + global_sleepable_kfunc_subprog(i); + return i; +} + +SEC("?syscall") +__success +int irq_non_sleepable_global_subprog(void *ctx) +{ + unsigned long flags; + + bpf_local_irq_save(&flags); + global_subprog(0); + bpf_local_irq_restore(&flags); + return 0; +} + +SEC("?syscall") +__failure __msg("global functions that may sleep are not allowed in non-sleepable context") +int irq_sleepable_helper_global_subprog(void *ctx) +{ + unsigned long flags; + + bpf_local_irq_save(&flags); + global_sleepable_helper_subprog(0); + bpf_local_irq_restore(&flags); + return 0; +} + +SEC("?syscall") +__failure __msg("global functions that may sleep are not allowed in non-sleepable context") +int irq_sleepable_global_subprog_indirect(void *ctx) +{ + unsigned long flags; + + bpf_local_irq_save(&flags); + global_subprog_calling_sleepable_global(0); + bpf_local_irq_restore(&flags); + return 0; +} + char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/preempt_lock.c b/tools/testing/selftests/bpf/progs/preempt_lock.c index 6c5797bf0ead..7d04254e61f1 100644 --- a/tools/testing/selftests/bpf/progs/preempt_lock.c +++ b/tools/testing/selftests/bpf/progs/preempt_lock.c @@ -134,7 +134,7 @@ int __noinline preempt_global_subprog(void) } SEC("?tc") -__failure __msg("global function calls are not allowed with preemption disabled") +__success int preempt_global_subprog_test(struct __sk_buff *ctx) { preempt_disable(); @@ -143,4 +143,70 @@ int preempt_global_subprog_test(struct __sk_buff *ctx) return 0; } +int __noinline +global_subprog(int i) +{ + if (i) + bpf_printk("%p", &i); + return i; +} + +int __noinline +global_sleepable_helper_subprog(int i) +{ + if (i) + bpf_copy_from_user(&i, sizeof(i), NULL); + return i; +} + +int __noinline +global_sleepable_kfunc_subprog(int i) +{ + if (i) + bpf_copy_from_user_str(&i, sizeof(i), NULL, 0); + global_subprog(i); + return i; +} + +int __noinline +global_subprog_calling_sleepable_global(int i) +{ + if (!i) + global_sleepable_kfunc_subprog(i); + return i; +} + +SEC("?syscall") +__failure __msg("global functions that may sleep are not allowed in non-sleepable context") +int preempt_global_sleepable_helper_subprog(struct __sk_buff *ctx) +{ + preempt_disable(); + if (ctx->mark) + global_sleepable_helper_subprog(ctx->mark); + preempt_enable(); + return 0; +} + +SEC("?syscall") +__failure __msg("global functions that may sleep are not allowed in non-sleepable context") +int preempt_global_sleepable_kfunc_subprog(struct __sk_buff *ctx) +{ + preempt_disable(); + if (ctx->mark) + global_sleepable_kfunc_subprog(ctx->mark); + preempt_enable(); + return 0; +} + +SEC("?syscall") +__failure __msg("global functions that may sleep are not allowed in non-sleepable context") +int preempt_global_sleepable_subprog_indirect(struct __sk_buff *ctx) +{ + preempt_disable(); + if (ctx->mark) + global_subprog_calling_sleepable_global(ctx->mark); + preempt_enable(); + return 0; +} + char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/rcu_read_lock.c b/tools/testing/selftests/bpf/progs/rcu_read_lock.c index ab3a532b7dd6..5cf1ae637ec7 100644 --- a/tools/testing/selftests/bpf/progs/rcu_read_lock.c +++ b/tools/testing/selftests/bpf/progs/rcu_read_lock.c @@ -439,3 +439,61 @@ int rcu_read_lock_global_subprog_unlock(void *ctx) ret += global_subprog_unlock(ret); return 0; } + +int __noinline +global_sleepable_helper_subprog(int i) +{ + if (i) + bpf_copy_from_user(&i, sizeof(i), NULL); + return i; +} + +int __noinline +global_sleepable_kfunc_subprog(int i) +{ + if (i) + bpf_copy_from_user_str(&i, sizeof(i), NULL, 0); + global_subprog(i); + return i; +} + +int __noinline +global_subprog_calling_sleepable_global(int i) +{ + if (!i) + global_sleepable_kfunc_subprog(i); + return i; +} + +SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") +int rcu_read_lock_sleepable_helper_global_subprog(void *ctx) +{ + volatile int ret = 0; + + bpf_rcu_read_lock(); + ret += global_sleepable_helper_subprog(ret); + bpf_rcu_read_unlock(); + return 0; +} + +SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") +int rcu_read_lock_sleepable_kfunc_global_subprog(void *ctx) +{ + volatile int ret = 0; + + bpf_rcu_read_lock(); + ret += global_sleepable_kfunc_subprog(ret); + bpf_rcu_read_unlock(); + return 0; +} + +SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") +int rcu_read_lock_sleepable_global_subprog_indirect(void *ctx) +{ + volatile int ret = 0; + + bpf_rcu_read_lock(); + ret += global_subprog_calling_sleepable_global(ret); + bpf_rcu_read_unlock(); + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/test_spin_lock_fail.c b/tools/testing/selftests/bpf/progs/test_spin_lock_fail.c index 1c8b678e2e9a..f678ee6bd7ea 100644 --- a/tools/testing/selftests/bpf/progs/test_spin_lock_fail.c +++ b/tools/testing/selftests/bpf/progs/test_spin_lock_fail.c @@ -245,4 +245,73 @@ int lock_global_subprog_call2(struct __sk_buff *ctx) return ret; } +int __noinline +global_subprog_int(int i) +{ + if (i) + bpf_printk("%p", &i); + return i; +} + +int __noinline +global_sleepable_helper_subprog(int i) +{ + if (i) + bpf_copy_from_user(&i, sizeof(i), NULL); + return i; +} + +int __noinline +global_sleepable_kfunc_subprog(int i) +{ + if (i) + bpf_copy_from_user_str(&i, sizeof(i), NULL, 0); + global_subprog_int(i); + return i; +} + +int __noinline +global_subprog_calling_sleepable_global(int i) +{ + if (!i) + global_sleepable_kfunc_subprog(i); + return i; +} + +SEC("?syscall") +int lock_global_sleepable_helper_subprog(struct __sk_buff *ctx) +{ + int ret = 0; + + bpf_spin_lock(&lockA); + if (ctx->mark == 42) + ret = global_sleepable_helper_subprog(ctx->mark); + bpf_spin_unlock(&lockA); + return ret; +} + +SEC("?syscall") +int lock_global_sleepable_kfunc_subprog(struct __sk_buff *ctx) +{ + int ret = 0; + + bpf_spin_lock(&lockA); + if (ctx->mark == 42) + ret = global_sleepable_kfunc_subprog(ctx->mark); + bpf_spin_unlock(&lockA); + return ret; +} + +SEC("?syscall") +int lock_global_sleepable_subprog_indirect(struct __sk_buff *ctx) +{ + int ret = 0; + + bpf_spin_lock(&lockA); + if (ctx->mark == 42) + ret = global_subprog_calling_sleepable_global(ctx->mark); + bpf_spin_unlock(&lockA); + return ret; +} + char _license[] SEC("license") = "GPL"; From patchwork Sat Mar 1 15:18:46 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kumar Kartikeya Dwivedi X-Patchwork-Id: 13997601 X-Patchwork-Delegate: bpf@iogearbox.net Received: from mail-wm1-f66.google.com (mail-wm1-f66.google.com [209.85.128.66]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2040D1E2616 for ; Sat, 1 Mar 2025 15:18:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.66 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740842336; cv=none; b=nM6D5o3ubHgJN8h/YASIv9VfEk9KiCZI77gDnzfP3OiKVpfMzXX0AyPCIYa1SUZPWoKwgJ3aokdybeEl3DmKkHvwSoJfDfVQnfHZGfSLafenkAO9V0JMjqSffA4F0GdF/V4VGOeukHGF6RsF+qRkK90ssUw0IVSUgOLQD3Sx3g4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740842336; c=relaxed/simple; bh=qaoLNXP6CZG1utXmYVbNKhcwzeDlyzLGDt8XEsfefHc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=d9ZJfo5pgto+9YhB5fybwJZtNXB0FPgrHQYQ+BjBkLru7fstiIxLZmXyZ5BUqBuZjICuBxUiWEyXoyX9gjyhSB+lAkAyGwmeW5TNi2B3bUt/O/IDTaMbbnTK+s+hthJXWktNUIvR/QawY7P5KoHg7ZNu5SilDRjcVIS93aYu2CA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=IIL6keXk; arc=none smtp.client-ip=209.85.128.66 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="IIL6keXk" Received: by mail-wm1-f66.google.com with SMTP id 5b1f17b1804b1-43bb25a8666so3026735e9.1 for ; Sat, 01 Mar 2025 07:18:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1740842332; x=1741447132; darn=vger.kernel.org; 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=uBCwFsTus+NV0qABJix3eMvo+FnTv/NKxMV1SZkgWAw=; b=IIL6keXk+rZkFHsk9HYfLxd1t7EG/lC29xw0Kz418eq0Lm29c516GAsJp6sz7zmEmz qWDTxEp15hV3/HEv8zwPfXMjP3b3jSbL1+Hp+YLDk1oKusTWwWM6+NHkdjUve10MWNJW Ez7LFudMbv1qRcjhMuZPtxjqT2t9ghRipvHTdNxGalhae9F6X1xoWIPhj4WKozXcK+ua 65VyVCkuG/zgwZQjjMQHWeHnq9trDC7A1I1CLyIOCzGeUbJYcEAylK0Cbb6ix2KXw6AS Q9nw2f6LsYA4rZuQ14TrBj7MTGRKQLEnEpRpozjpHaTDFWqVqAWgIVLYnROej6MMlhWl FFbA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1740842332; x=1741447132; 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=uBCwFsTus+NV0qABJix3eMvo+FnTv/NKxMV1SZkgWAw=; b=OsUDO+ahEQxBsVrGYLEPSriR1wBmHHTlUSukXeEPYPxb6u3ZD850CtvjgVpgi3MlNl tXJulLmQ+y/uWx4otY/WPoKbkAlHyR1FRjUvBLPwtGBnc4uyrWsnfP01FlwqOLzU5lpF DnY7UJoKDaBmQalrY39L2NxsbG81Lfp/cGG0AEiO5UEF2XDwD+RtB4PGLPKiSSWyOSOm +lQjjlV9IrB727Mbkx4/Xyk1IHjU7hL9iO0AonLCH6xOJ61sJYxVfl2SCpon/D61aeZU HZgi+2wc2JuM/3s+TFLjrbgiAmosMjhZSTQmlEEj9frVaEXnSBhIWnP1c7VyeyoXTzjT MDWA== X-Gm-Message-State: AOJu0Yw6XqPNkj92GGN6+Wy3Ep4JwcEaLFtskEG+3ueICf8MgngITn/7 qu3f4bwjNk6inD71kEs7ZA4BtP9U5WZi5p1bHNXKwqe4kodsjvn1Q0H1zVTX/io= X-Gm-Gg: ASbGncvBpfLGCBcSOofmABm/RcDdgZKYLRDxoIbbNIG/XEAIXaWAfXTKFVvFeVWLxpH 6IcNYphqW0f9eIDIFhqjhkBzfmRMjTYhiSgzOi4d983ea+xqZssfEAx6Gk++MauTsdshHK5eCpF qIWkFUY4kmICV4v+Ate0mVDx6TZfYssavh6iwaYxM2rW91y4RK21KzqJ1WdZlj+GtRG8GTcxs2V uim/gDdoN6w3no59+avfwymJzZhSZJyeRT0iqFp8erhE7LVfyyxCB1oB8qMpEQUqDBF22rA4xxu 8L+cXKT4FDp+LdNnRx74SIw/UbKdOeYQzQ== X-Google-Smtp-Source: AGHT+IGn+Z43gzovofPRnbDsVUZDkTV9ziD8KJ/TUJ4K8+MooouTpDTvQ1iYYQu7+dT45omyk9kEcQ== X-Received: by 2002:a05:600c:1d14:b0:439:9ee2:5534 with SMTP id 5b1f17b1804b1-43ba66f9f05mr62707355e9.12.1740842331943; Sat, 01 Mar 2025 07:18:51 -0800 (PST) Received: from localhost ([2a03:2880:31ff:6::]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-43b7a27aa69sm91478185e9.29.2025.03.01.07.18.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 01 Mar 2025 07:18:51 -0800 (PST) From: Kumar Kartikeya Dwivedi To: bpf@vger.kernel.org Cc: Alexei Starovoitov , Andrii Nakryiko , Daniel Borkmann , Martin KaFai Lau , Eduard Zingerman , kkd@meta.com, kernel-team@meta.com Subject: [PATCH bpf-next v3 3/3] selftests/bpf: Add tests for extending sleepable global subprogs Date: Sat, 1 Mar 2025 07:18:46 -0800 Message-ID: <20250301151846.1552362-4-memxor@gmail.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20250301151846.1552362-1-memxor@gmail.com> References: <20250301151846.1552362-1-memxor@gmail.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=14160; h=from:subject; bh=qaoLNXP6CZG1utXmYVbNKhcwzeDlyzLGDt8XEsfefHc=; b=owEBbQKS/ZANAwAIAUzgyIZIvxHKAcsmYgBnwyScV8xFVVD30RaeUhGF9qf4uXKN4iqRsFIjIXxU HWQNACqJAjMEAAEIAB0WIQRLvip+Buz51YI8YRFM4MiGSL8RygUCZ8MknAAKCRBM4MiGSL8Ryu2KEA CYd3sG+/K9JKPbfrV+RdmOwqsJl3pJvW6eD5dkZ0NY/0PwX65hp5A5HjGqUCMAPuxRccHFBGBd12Oq Lw+sTUvNsIjsj5G0ZAfRZYC0tKve8XveCyO00OP8FvDJC2TCIW4HVCu7qNXFwWnDeadJOJaTzPgych 62t8aBcSJqM/LS+rA/8b6h0viR23WaJg0smzuVWwd4xmNdq+TIIelMXk73eG0QBu1b58ESHJFLRoVK nqAYUepWrwM3tQTOOBALFiwr0Fr2IStL4MI+1zTIUMOlVb0IWgrNrirNm6O8gj0HNg7WQ56wm/Gt4b csxgSb9PPt06aSPA41NUVxsLmRkQwlPBZnYmuax5RERbpbqJEP4rUqyJLGtv5P+buPQIfWg+bYxdt4 M/6G59zFZpTHjBM4sc31Le8/N41NTY+JCh899FkL0sVI1sQQEGwXnZ4B2CZbmAS7b00ZfAlaiVdAk5 QWg6VoWmNucGdi855dAZDIh3u/Odsu/ywKZH1bRut6PaOAu5VjQxCw1yCxJY2IuAd08XbHXD99Tt9e 3Pko1rPkIa930IINUkwMslruAJefuzhwQBPZMsRFC6XRQxc9nT9DiZCSGQ3A2HO85fubTKvnpDkG3L 7Bml4FBDAr9WjL6l0ocOYtiIUTthkVRttNyz2Yf5pMr9UK/jA9DQJFud9dEQ== X-Developer-Key: i=memxor@gmail.com; a=openpgp; fpr=4BBE2A7E06ECF9D5823C61114CE0C88648BF11CA X-Patchwork-Delegate: bpf@iogearbox.net Add tests for freplace behavior with the combination of sleepable and non-sleepable global subprogs. The changes_pkt_data selftest did all the hardwork, so simply rename it and include new support for more summarization tests for might_sleep bit. Signed-off-by: Kumar Kartikeya Dwivedi --- .../bpf/prog_tests/changes_pkt_data.c | 107 ------------- .../selftests/bpf/prog_tests/summarization.c | 144 ++++++++++++++++++ .../selftests/bpf/progs/changes_pkt_data.c | 39 ----- .../selftests/bpf/progs/summarization.c | 78 ++++++++++ ...ta_freplace.c => summarization_freplace.c} | 17 ++- 5 files changed, 238 insertions(+), 147 deletions(-) delete mode 100644 tools/testing/selftests/bpf/prog_tests/changes_pkt_data.c create mode 100644 tools/testing/selftests/bpf/prog_tests/summarization.c delete mode 100644 tools/testing/selftests/bpf/progs/changes_pkt_data.c create mode 100644 tools/testing/selftests/bpf/progs/summarization.c rename tools/testing/selftests/bpf/progs/{changes_pkt_data_freplace.c => summarization_freplace.c} (57%) diff --git a/tools/testing/selftests/bpf/prog_tests/changes_pkt_data.c b/tools/testing/selftests/bpf/prog_tests/changes_pkt_data.c deleted file mode 100644 index 7526de379081..000000000000 --- a/tools/testing/selftests/bpf/prog_tests/changes_pkt_data.c +++ /dev/null @@ -1,107 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include "bpf/libbpf.h" -#include "changes_pkt_data_freplace.skel.h" -#include "changes_pkt_data.skel.h" -#include - -static void print_verifier_log(const char *log) -{ - if (env.verbosity >= VERBOSE_VERY) - fprintf(stdout, "VERIFIER LOG:\n=============\n%s=============\n", log); -} - -static void test_aux(const char *main_prog_name, - const char *to_be_replaced, - const char *replacement, - bool expect_load) -{ - struct changes_pkt_data_freplace *freplace = NULL; - struct bpf_program *freplace_prog = NULL; - struct bpf_program *main_prog = NULL; - LIBBPF_OPTS(bpf_object_open_opts, opts); - struct changes_pkt_data *main = NULL; - char log[16*1024]; - int err; - - opts.kernel_log_buf = log; - opts.kernel_log_size = sizeof(log); - if (env.verbosity >= VERBOSE_SUPER) - opts.kernel_log_level = 1 | 2 | 4; - main = changes_pkt_data__open_opts(&opts); - if (!ASSERT_OK_PTR(main, "changes_pkt_data__open")) - goto out; - main_prog = bpf_object__find_program_by_name(main->obj, main_prog_name); - if (!ASSERT_OK_PTR(main_prog, "main_prog")) - goto out; - bpf_program__set_autoload(main_prog, true); - err = changes_pkt_data__load(main); - print_verifier_log(log); - if (!ASSERT_OK(err, "changes_pkt_data__load")) - goto out; - freplace = changes_pkt_data_freplace__open_opts(&opts); - if (!ASSERT_OK_PTR(freplace, "changes_pkt_data_freplace__open")) - goto out; - freplace_prog = bpf_object__find_program_by_name(freplace->obj, replacement); - if (!ASSERT_OK_PTR(freplace_prog, "freplace_prog")) - goto out; - bpf_program__set_autoload(freplace_prog, true); - bpf_program__set_autoattach(freplace_prog, true); - bpf_program__set_attach_target(freplace_prog, - bpf_program__fd(main_prog), - to_be_replaced); - err = changes_pkt_data_freplace__load(freplace); - print_verifier_log(log); - if (expect_load) { - ASSERT_OK(err, "changes_pkt_data_freplace__load"); - } else { - ASSERT_ERR(err, "changes_pkt_data_freplace__load"); - ASSERT_HAS_SUBSTR(log, "Extension program changes packet data", "error log"); - } - -out: - changes_pkt_data_freplace__destroy(freplace); - changes_pkt_data__destroy(main); -} - -/* There are two global subprograms in both changes_pkt_data.skel.h: - * - one changes packet data; - * - another does not. - * It is ok to freplace subprograms that change packet data with those - * that either do or do not. It is only ok to freplace subprograms - * that do not change packet data with those that do not as well. - * The below tests check outcomes for each combination of such freplace. - * Also test a case when main subprogram itself is replaced and is a single - * subprogram in a program. - */ -void test_changes_pkt_data_freplace(void) -{ - struct { - const char *main; - const char *to_be_replaced; - bool changes; - } mains[] = { - { "main_with_subprogs", "changes_pkt_data", true }, - { "main_with_subprogs", "does_not_change_pkt_data", false }, - { "main_changes", "main_changes", true }, - { "main_does_not_change", "main_does_not_change", false }, - }; - struct { - const char *func; - bool changes; - } replacements[] = { - { "changes_pkt_data", true }, - { "does_not_change_pkt_data", false } - }; - char buf[64]; - - for (int i = 0; i < ARRAY_SIZE(mains); ++i) { - for (int j = 0; j < ARRAY_SIZE(replacements); ++j) { - snprintf(buf, sizeof(buf), "%s_with_%s", - mains[i].to_be_replaced, replacements[j].func); - if (!test__start_subtest(buf)) - continue; - test_aux(mains[i].main, mains[i].to_be_replaced, replacements[j].func, - mains[i].changes || !replacements[j].changes); - } - } -} diff --git a/tools/testing/selftests/bpf/prog_tests/summarization.c b/tools/testing/selftests/bpf/prog_tests/summarization.c new file mode 100644 index 000000000000..5dd6c120a838 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/summarization.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "bpf/libbpf.h" +#include "summarization_freplace.skel.h" +#include "summarization.skel.h" +#include + +static void print_verifier_log(const char *log) +{ + if (env.verbosity >= VERBOSE_VERY) + fprintf(stdout, "VERIFIER LOG:\n=============\n%s=============\n", log); +} + +static void test_aux(const char *main_prog_name, + const char *to_be_replaced, + const char *replacement, + bool expect_load, + const char *err_msg) +{ + struct summarization_freplace *freplace = NULL; + struct bpf_program *freplace_prog = NULL; + struct bpf_program *main_prog = NULL; + LIBBPF_OPTS(bpf_object_open_opts, opts); + struct summarization *main = NULL; + char log[16*1024]; + int err; + + opts.kernel_log_buf = log; + opts.kernel_log_size = sizeof(log); + if (env.verbosity >= VERBOSE_SUPER) + opts.kernel_log_level = 1 | 2 | 4; + main = summarization__open_opts(&opts); + if (!ASSERT_OK_PTR(main, "summarization__open")) + goto out; + main_prog = bpf_object__find_program_by_name(main->obj, main_prog_name); + if (!ASSERT_OK_PTR(main_prog, "main_prog")) + goto out; + bpf_program__set_autoload(main_prog, true); + err = summarization__load(main); + print_verifier_log(log); + if (!ASSERT_OK(err, "summarization__load")) + goto out; + freplace = summarization_freplace__open_opts(&opts); + if (!ASSERT_OK_PTR(freplace, "summarization_freplace__open")) + goto out; + freplace_prog = bpf_object__find_program_by_name(freplace->obj, replacement); + if (!ASSERT_OK_PTR(freplace_prog, "freplace_prog")) + goto out; + bpf_program__set_autoload(freplace_prog, true); + bpf_program__set_autoattach(freplace_prog, true); + bpf_program__set_attach_target(freplace_prog, + bpf_program__fd(main_prog), + to_be_replaced); + err = summarization_freplace__load(freplace); + print_verifier_log(log); + + /* The might_sleep extension doesn't work yet as sleepable calls are not + * allowed, but preserve the check in case it's supported later and then + * this particular combination can be enabled. + */ + if (!strcmp("might_sleep", replacement) && err) { + ASSERT_HAS_SUBSTR(log, "helper call might sleep in a non-sleepable prog", "error log"); + ASSERT_EQ(err, -EINVAL, "err"); + test__skip(); + goto out; + } + + if (expect_load) { + ASSERT_OK(err, "summarization_freplace__load"); + } else { + ASSERT_ERR(err, "summarization_freplace__load"); + ASSERT_HAS_SUBSTR(log, err_msg, "error log"); + } + +out: + summarization_freplace__destroy(freplace); + summarization__destroy(main); +} + +/* There are two global subprograms in both summarization.skel.h: + * - one changes packet data; + * - another does not. + * It is ok to freplace subprograms that change packet data with those + * that either do or do not. It is only ok to freplace subprograms + * that do not change packet data with those that do not as well. + * The below tests check outcomes for each combination of such freplace. + * Also test a case when main subprogram itself is replaced and is a single + * subprogram in a program. + * + * This holds for might_sleep programs. It is ok to replace might_sleep with + * might_sleep and with does_not_sleep, but does_not_sleep cannot be replaced + * with might_sleep. + */ +void test_summarization_freplace(void) +{ + struct { + const char *main; + const char *to_be_replaced; + bool has_side_effect; + } mains[2][4] = { + { + { "main_changes_with_subprogs", "changes_pkt_data", true }, + { "main_changes_with_subprogs", "does_not_change_pkt_data", false }, + { "main_changes", "main_changes", true }, + { "main_does_not_change", "main_does_not_change", false }, + }, + { + { "main_might_sleep_with_subprogs", "might_sleep", true }, + { "main_might_sleep_with_subprogs", "does_not_sleep", false }, + { "main_might_sleep", "main_might_sleep", true }, + { "main_does_not_sleep", "main_does_not_sleep", false }, + }, + }; + const char *pkt_err = "Extension program changes packet data"; + const char *slp_err = "Extension program may sleep"; + struct { + const char *func; + bool has_side_effect; + const char *err_msg; + } replacements[2][2] = { + { + { "changes_pkt_data", true, pkt_err }, + { "does_not_change_pkt_data", false, pkt_err }, + }, + { + { "might_sleep", true, slp_err }, + { "does_not_sleep", false, slp_err }, + }, + }; + char buf[64]; + + for (int t = 0; t < 2; t++) { + for (int i = 0; i < ARRAY_SIZE(mains); ++i) { + for (int j = 0; j < ARRAY_SIZE(replacements); ++j) { + snprintf(buf, sizeof(buf), "%s_with_%s", + mains[t][i].to_be_replaced, replacements[t][j].func); + if (!test__start_subtest(buf)) + continue; + test_aux(mains[t][i].main, mains[t][i].to_be_replaced, replacements[t][j].func, + mains[t][i].has_side_effect || !replacements[t][j].has_side_effect, + replacements[t][j].err_msg); + } + } + } +} diff --git a/tools/testing/selftests/bpf/progs/changes_pkt_data.c b/tools/testing/selftests/bpf/progs/changes_pkt_data.c deleted file mode 100644 index 43cada48b28a..000000000000 --- a/tools/testing/selftests/bpf/progs/changes_pkt_data.c +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include - -__noinline -long changes_pkt_data(struct __sk_buff *sk) -{ - return bpf_skb_pull_data(sk, 0); -} - -__noinline __weak -long does_not_change_pkt_data(struct __sk_buff *sk) -{ - return 0; -} - -SEC("?tc") -int main_with_subprogs(struct __sk_buff *sk) -{ - changes_pkt_data(sk); - does_not_change_pkt_data(sk); - return 0; -} - -SEC("?tc") -int main_changes(struct __sk_buff *sk) -{ - bpf_skb_pull_data(sk, 0); - return 0; -} - -SEC("?tc") -int main_does_not_change(struct __sk_buff *sk) -{ - return 0; -} - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/summarization.c b/tools/testing/selftests/bpf/progs/summarization.c new file mode 100644 index 000000000000..f89effe82c9e --- /dev/null +++ b/tools/testing/selftests/bpf/progs/summarization.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include "bpf_misc.h" + +__noinline +long changes_pkt_data(struct __sk_buff *sk) +{ + return bpf_skb_pull_data(sk, 0); +} + +__noinline __weak +long does_not_change_pkt_data(struct __sk_buff *sk) +{ + return 0; +} + +SEC("?tc") +int main_changes_with_subprogs(struct __sk_buff *sk) +{ + changes_pkt_data(sk); + does_not_change_pkt_data(sk); + return 0; +} + +SEC("?tc") +int main_changes(struct __sk_buff *sk) +{ + bpf_skb_pull_data(sk, 0); + return 0; +} + +SEC("?tc") +int main_does_not_change(struct __sk_buff *sk) +{ + return 0; +} + +__noinline +long might_sleep(struct pt_regs *ctx __arg_ctx) +{ + int i; + + bpf_copy_from_user(&i, sizeof(i), NULL); + return i; +} + +__noinline __weak +long does_not_sleep(struct pt_regs *ctx __arg_ctx) +{ + return 0; +} + +SEC("?uprobe.s") +int main_might_sleep_with_subprogs(struct pt_regs *ctx) +{ + might_sleep(ctx); + does_not_sleep(ctx); + return 0; +} + +SEC("?uprobe.s") +int main_might_sleep(struct pt_regs *ctx) +{ + int i; + + bpf_copy_from_user(&i, sizeof(i), NULL); + return i; +} + +SEC("?uprobe.s") +int main_does_not_sleep(struct pt_regs *ctx) +{ + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/changes_pkt_data_freplace.c b/tools/testing/selftests/bpf/progs/summarization_freplace.c similarity index 57% rename from tools/testing/selftests/bpf/progs/changes_pkt_data_freplace.c rename to tools/testing/selftests/bpf/progs/summarization_freplace.c index f9a622705f1b..935f00e0e9ea 100644 --- a/tools/testing/selftests/bpf/progs/changes_pkt_data_freplace.c +++ b/tools/testing/selftests/bpf/progs/summarization_freplace.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 -#include +#include #include SEC("?freplace") @@ -15,4 +15,19 @@ long does_not_change_pkt_data(struct __sk_buff *sk) return 0; } +SEC("?freplace") +long might_sleep(struct pt_regs *ctx) +{ + int i; + + bpf_copy_from_user(&i, sizeof(i), NULL); + return i; +} + +SEC("?freplace") +long does_not_sleep(struct pt_regs *ctx) +{ + return 0; +} + char _license[] SEC("license") = "GPL";