From patchwork Sat Mar 1 03:02:03 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: 13997278 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 EFC7F1CA84 for ; Sat, 1 Mar 2025 03:02:13 +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=1740798135; cv=none; b=WJkvbY9e71kshYFnZlutJMjp7R53QUEl0Pmb6PIX2TSG3TnT93kISwh5tSNk3ssJx5zPyUNtXkjaMFsmm17eDftOV8ts1IKSB0bU6jxemPmGaWACVh1ITGBW7nf5Fq0Laohc938tFO3m08xc5d7yQeUyrrLfg9e0Fiu1gHVJk5k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740798135; c=relaxed/simple; bh=SJCowbVKLs1OnsqlOi39v/+vLx+o2dOZ+aMHiQT9mw0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dYsqscoAIAbrpdP4Sv34aEiAaknxTV8GbaacRwBsG+4/hYFkJeKXXtCo8Be+XWn3B4Rs38B7M5Q493NYO3DXUiLntamkshUIO45I/BjCSKOanaXqRNq7SGo+xQ3NMOT+nGdC7kRNyjCnThc301r4e9O1x7vgXhzmtGnUg8R+3Cw= 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=kQNxqjRV; 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="kQNxqjRV" Received: by mail-wm1-f66.google.com with SMTP id 5b1f17b1804b1-4398c8c8b2cso28602225e9.2 for ; Fri, 28 Feb 2025 19:02:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1740798132; x=1741402932; 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=kQNxqjRVSNrdD+7RA0H+Mj3wXJB6kMmhG0tVSzheDrMqxxk3ouPWE3TP+VYCApXm99 pB4tBBExE44uSK2fiCgODxdbnuMNQOWi2u6SkOYOadruKIqucxyTAlReUOTMbgL0Qt8H kiVKMl+H5yFbwTSlDR9qLRMsvh/sRiZ6o6IlZGFeBNMYU3JrBBfO3Bw1bMjR8tDIEXHH Z1EDcwmfU2bn8C2R9rNqfY9Nyy3INv/YuCgLSqvfZG74tTrb8tfjQvslDgV1mHt2UWsa YgE8ERdWOeQl9mk6fnh/FLBfyQaXGxjFNAk8jw+d7+wN8VktDkdtiWaRucUMruF1gDve gZjA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1740798132; x=1741402932; 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=LZ1LJTuo77nwG2mklHn/q5nzect2cHE0nrLLABtruxMospyr9XCvSNcOY3EdwQm8S7 mXfunNPA0cbldoqdSAz0VwCWmH0PRZS3bKfQY5/Zf1zf6EsnUN2GMlrqndoA6KJHO0sa WE5iQXGqIjyfOTpun3UyH5lpf25dt75eLI5qrG49DiF2lCDu3QDZ2m4cPvf/BYrrwdot rItwUD0oTbMuB8DfhjH+Q8h6zKvkn16QonoXRdmYFL5N3nh3r8TPYbFxFHkS9dRYiwBj 8Mnl/szFIuNvY5Tq1UhwJ2XhovcN6bBBU/W1cRaybOiripCakpnpLCW/rHXTd4gk+wLD LjZA== X-Gm-Message-State: AOJu0Yx/8eyZqlDtbJOfka9Qg4h+njyfF0WqhTiP2Lu/IwsAMy99bqkp +5n8NBmFLtFxvcPOFdPe4NHOzrHwpzE92w2WcGkLmGCv1V4zPV0KOL8XsJbh644= X-Gm-Gg: ASbGncubUG8cn1KLGxod5idgUeX6B5oPfEGsmnsi+oEmizxROtLNVcnM3uSuZZlX79P qUiL2b2ExoNFq5J0YymjcGzZHfTJDLL3NhsejBuwUSzuf6Q3tDN1VrBTCPjB6K9aU7Fo3amYhIO T+3G8sr7RaHuYe6durBzjoL7SBT46gBxoY3yc+F+gFJN4W51MLVu7uLn0/12WNc/Xk6ibYKeODi NajYyXH/kPtIUHAIilF18ogXNzQqtgMMevLoFZmQxgQpkjvw4RZetEWHVgUK2GRTW6ZHvsnfwRC YVyKiaaZ0VNiPc72Yc6diuyl5EXY+5ueQf4= X-Google-Smtp-Source: AGHT+IGA0QioO1nfruzEz8FW6UWZsjhuWLX8sXvpcum0t5CQBPCky5RIAD0IlDUtg0tgPN/HychQhw== X-Received: by 2002:a05:600c:4fd3:b0:439:a255:b2ed with SMTP id 5b1f17b1804b1-43ba66e5f09mr56694695e9.9.1740798131553; Fri, 28 Feb 2025 19:02:11 -0800 (PST) Received: from localhost ([2a03:2880:31ff:72::]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-43aba539450sm105814685e9.21.2025.02.28.19.02.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Feb 2025 19:02:10 -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 v2 1/3] bpf: Summarize sleepable global subprogs Date: Fri, 28 Feb 2025 19:02:03 -0800 Message-ID: <20250301030205.1221223-2-memxor@gmail.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20250301030205.1221223-1-memxor@gmail.com> References: <20250301030205.1221223-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/ZANAwAIAUzgyIZIvxHKAcsmYgBnwnU/Xj7wIa5MOt6EPLiW9JLHc4Ki2UMcZTAk5wdn 5RoiEICJAjMEAAEIAB0WIQRLvip+Buz51YI8YRFM4MiGSL8RygUCZ8J1PwAKCRBM4MiGSL8RyvPqEA Chdosn3uGh1ehpyrAeRJlsfK8w6dhxWcrIeuHXHRd53PewZnlSNFAQ3wNiMCZyxdl4uaIKkr/KP+En kMjrQYXZcf37bMOxcQUeoVXWCeQhbZypTihcJ8OsKSVYQnB5YlY0zRQR2wlslQ0p4YzeejHqoFto+E zd7Z61KJxDzq89l5brVME2Pt0nZLl60OWgNQEjYQ+FUxigm41XkXV2aVZ2aZq6bUvwv+kRC7i6ou6L OVLwkyYJHYV5JTuqO55VvqPcPucuLFmuf0Z3li13l/C4SgGh7a9d4GiX75zkABb7B/1HEV5uCayU2w wihwCSq6UG1u68JNYPmMooMm4Z/fNPnClyhp3QoJVBRrMolPMHyg5Pg99vEp/9Zr191TekVdzFJuz9 zhdCxMSkuc8bkAkQT5VFcd3HAG//NRGi12It0gh6SZLx/IcZPIIgfcvNweTN3HJuWEMDVW42hxWpG1 hpiZpDOKrr3mTQ7i5VCGMe0yzTm8uJ80T86xJ4u5eYTjUc7H1wHpVAjxR+Fnzpo63EYq6+VNqQlVMt 60VQvbkGumbW8qelAu50B05E62HTzOXI4ChGtaOLm4/KemtQ0DEf18kr1Q5WYP4zuIBCmoDhs3lpwz kat7M674N9Ju4gpAQ6qDl4S723TtSmSBEXXp0iNtO3yUOr591H2XmM7CsrHQ== 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 03:02:04 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: 13997279 X-Patchwork-Delegate: bpf@iogearbox.net Received: from mail-wr1-f67.google.com (mail-wr1-f67.google.com [209.85.221.67]) (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 3527715ECD7 for ; Sat, 1 Mar 2025 03:02:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.67 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740798138; cv=none; b=fhTTVW7Bs9ouokZzQgDqKRAjXEaNYq/k8sVI3tiopYFb4KuIRPCm5ZWsYdEErAlcjL/M+A0sTYYq1L1H7VZEj90/KltBufaGqauTrokfDFCVhkUnM0ywY+TlVT6QqAaq38UYQamBBYp/kDwJms6iVlst0+ZVYuKqJxayy0kAhUw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740798138; c=relaxed/simple; bh=y+sHsLEqdew+DfOuBOU9KArsJMmccspgbdU2aqyaCd4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nLnhXIAdjDPASMR2kjBEmMoLc9eMMDbJHMyktHgQ70GNI5cogQoFwIQYVa18uFgck83uK1Zm7gLDAQ0aVaNosvl1ozXW2ZkccLJsGxNtGqqN2G4gabKY5R9QdQiuoUJbDKVbvf3O4QiX3ksbTxGILYYwQ/UfHigFeXPfREdKSy4= 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=ZD+S94OY; arc=none smtp.client-ip=209.85.221.67 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="ZD+S94OY" Received: by mail-wr1-f67.google.com with SMTP id ffacd0b85a97d-38f6475f747so1363824f8f.3 for ; Fri, 28 Feb 2025 19:02:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1740798133; x=1741402933; 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=ZD+S94OYaYLGWr3itRIAM3L18fZ5RwXoqOU+q8ytXxdtp1xisvEcydsYinhnla5fMw CCIKnIu19fCLiuZB7LcmqDYMaTR/VB2n5NWpJCQEBNQuN89rF404emusdh1t0V9ZJ5xo UpX7qyAkgtd9qG8JwqWZ+nUEvPs5HNUGmksMkGoJeHr7yexfzviWG2Y5FUrKhP7S5wVu TLcs9boHCALuaEydXsm8HRqnxR1cNq/QfbbhcBFqmdFaKSgy0I+8qi/jwIg/qfVfl5Ij Rze4RcQl0V43uPS0yMbPjKuiw4n07OpAr5VF6smR595+wKuNcJAZqP/+8rKZ+tAyAxuz JaJA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1740798133; x=1741402933; 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=FeMfjaRVErrYhvwUIRPIq5Z3cF+NR+eYwKx5Um0tWvbsOQjtA0fqVzcwaj+BOq8Ete +wLcl4jvDV5UYJ29bAyRreJ36V2LINCcfza5LDjbhkjicZLqPISp39AqexfYPYmZVpJu VZLgQN2VBcWyJED1p11kCaLYKRUB+wOwez3eV1RD1Sv3X40dxKyc4TxqCUeheIirVk6x JXGdbDJFg5XTjQ42VyMqA/gXXWFS+RMoyotqJlXHRLRpLwt23IFvMonIizd7MCP2Dghr T3yeMJbJz2DWJWJltqqVff2LZVG3EcggSMbg+buumwjgdE++FMv8BZvBVl07JeRDovLe KT5A== X-Gm-Message-State: AOJu0Yw88UUDiQuomoPq4OL/jacbMTKUDGUQkfFrTlqF/YOWQlOpfXeP HWQJh/pixsgqCQeNQ5y0Ew0fOZMWft6LJMgYMBYIgKzq5czVnzprezQR1b2GkHg= X-Gm-Gg: ASbGncug6Z0i7bfkhj3kW++B2k1rBXOmZ+NTAKq3xEyI8VR/GNOkfQ3BZuRThyRqIBr lpIqc7ZkGE6fUYCu9YnrWsdtlDp5uJyX5/+DbW2jYTuKd8zd2wjqWNsjgmO4X7M+LJjT5prj8rS kaIGpZIn9uJYFzmppFCTrTXHJT0OJcM0Ko2IJLlFBMiYdE9rv0wuqfcR+Z/yZJe2NbpfrK+LZVu iRl9+zCBa52RC1V9CCaCwkWW0dkJqEcW1HUob0GIxYF7vhMeChIVCbEMrdLzA7VqgC2nguLLGGz JXB39JaWkNN3okF5tkhQ9daryWioxI4= X-Google-Smtp-Source: AGHT+IFXvNegqS9lVKQHqGTXpAf0nm/MCxfEWfzVEpacmC0LjbydWuC9oS7eNxe/V5/NwrLkUepcnw== X-Received: by 2002:a05:6000:2ce:b0:390:f9d0:5e3 with SMTP id ffacd0b85a97d-390f9d0075cmr340248f8f.1.1740798132978; Fri, 28 Feb 2025 19:02:12 -0800 (PST) Received: from localhost ([2a03:2880:31ff::]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-390e4796600sm6852616f8f.20.2025.02.28.19.02.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Feb 2025 19:02:12 -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 v2 2/3] selftests/bpf: Test sleepable global subprogs in atomic contexts Date: Fri, 28 Feb 2025 19:02:04 -0800 Message-ID: <20250301030205.1221223-3-memxor@gmail.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20250301030205.1221223-1-memxor@gmail.com> References: <20250301030205.1221223-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/ZANAwAIAUzgyIZIvxHKAcsmYgBnwnVALKOHjfLJChnSeMHFb6wygHu2qIeh/03QGtK5 /KZs9+SJAjMEAAEIAB0WIQRLvip+Buz51YI8YRFM4MiGSL8RygUCZ8J1QAAKCRBM4MiGSL8Ryi5GD/ 9oUPRj7MVngil40eTjNQQHO28/bQT2R0poyjvDOnVx5oipqDM461im1uWcalz0A/PT7AmPRVTeKpgN O2tHlwEhA65BO2oKkbblTwrO4AQSluEQGs3xY/OvYb7MCCWe+IWODZToNb7RMmV+5hiir3i2CifhV0 fBpCNnPm/8+O2SFHSFW9/fRRpiEvtdMnW7CoLN0/GpZE79vE9R0c1N+Qk5bvT3tw3bOGDUG+/LeSSj eqiNc0aKHEO/9FNw8F3PU87864Zl3Ae3Lw/khfaRtHlk0qqCESjhKXMHfzX44NSYtR5UD2KtEAt1Bc XKqbBMPw50TyznlK4ER9iWjkZYh8O2LYZzT0mIhFy5y1woHjOFW8gYKOgJ7vzrIr6f3XzsvSM+B7vW 16dQgFyq5jH7pzO9rW8I+oDx0QDNcgewajXPYPuz6SwqB5l7SamF4r/11bfK0Kg0SVrlUyILOaHhIv 8iNy8cQJBDKIOT8X6AEo4DqE6+mmDI3CdktAWhpMCf4kvNJOXjxCznRP4M9Bo3GZJ19sozayiR8M+i 90g6LTlR/QJfhDc30BmZ/mpTHZr1jnCox2juL5wFzIQpLc8KD7iQ+r8H1x/9YuU1EdUgetw4YOK9ej 9aK15AVosyEYVN8bENaR46tMV1qh+ofCFOTQo9OLsLldJ9siIPFFgZHVDQSw== 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 03:02:05 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: 13997280 X-Patchwork-Delegate: bpf@iogearbox.net Received: from mail-wm1-f65.google.com (mail-wm1-f65.google.com [209.85.128.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 A4FE11CA84 for ; Sat, 1 Mar 2025 03:02:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.65 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740798139; cv=none; b=c5ybrmYHaOte7yFSSob40EXa06KRom7AEH8/0K3cRUDQiJ4Z/Rom9sAHlFm2WPGDopVfz1GVcBPuna6Apf5GBPI1K+WrIGS5e/Y5NcHRl1Czl9nhnqmWNrE58xLV8MK2+GQhIFtKS2eJfOs1qCW5ohHwuZ6uutXbcgrwPr1o4qE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740798139; c=relaxed/simple; bh=xtnwzGz8N+rP2QXagom8tXWjNGA2I4BEXiqL+8BnRFo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ileXDe7Ig9bBiP3IZHPm0f4jEDD3obtpEkWNZjv5KaN/+O82DWvja83DxW19N03M7PHeMqMhyCtn+7b50/kAl65GpVu0zW8MUyOXiYV2c+hClt0+W0UDxJnsNiSS+irV5kSZddtyOIwG2FhJGmTuYNA/+E0CScSBr6sTadLt5xM= 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=FgwgqRr8; arc=none smtp.client-ip=209.85.128.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="FgwgqRr8" Received: by mail-wm1-f65.google.com with SMTP id 5b1f17b1804b1-43aac0390e8so17717725e9.2 for ; Fri, 28 Feb 2025 19:02:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1740798134; x=1741402934; 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=GYBIgSDdjCsi6kW+edufKKreTkO/TuPvwk2aqVo4MjQ=; b=FgwgqRr8s+rTSnSjMborEHGTV8lPU4knORv9vfU1Y0TzWZ4TvbO2pvBSoQ2IMuA7sT Ec1xifsyyR0C9KNFmwoHnwgdbdzAnfrYka6Tjo6aLyW4W3BI7xdwM2Kmrw9ttxymCTWk QuTZSWBChuwEhCs8BGgbPruXPTqufT2a5URtM96F7NqgWJCmQS75ao5g3UQM+a8r4aBE WtbrKo5TkISpOGGOTI+9UXukEqM5YhqJfxGXNY6roDZcXbIqqKeqMrBo5vKJzuVqNCE9 KTA/QxVW178szvLuREoorlrIskfpFAKubnLntW9n2TWVsLXQjLyJko6VDqjgwrBzirI6 42eA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1740798134; x=1741402934; 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=GYBIgSDdjCsi6kW+edufKKreTkO/TuPvwk2aqVo4MjQ=; b=VbCH6qZAc6EQNeGRfzBmoMOC3CpS3avlFTszqTI+KvfxV874ta6zojAhx1vk/Z6dTs 5NEZ/hlpAB7RAoS59drnN0JrIFpEluOUSVU+wGFlOx5heIDzjTG8Qp6WFABSQC1DBEYg 43Nu17MGNYWGDwHNiRkocF3JxTC98fLtkCOGEGn3fMlepEfTRgPSWRAGvLx0nZEtx7DF m235qoLOFmaYXk8tm/iCC85GPUswos6dl+fbqtrNLq/nODmF7ZQV1M/a2V2Q0rr8ZN+/ D/c+yEEuog2Dst6Nl2IodfmPELXvpKd4vezGDJsM4vPx44eaE5NBPb4XYIWbMqlsd0b5 133g== X-Gm-Message-State: AOJu0Ywbhrc9+QyRWQxWbF/BRqEvvHXK1fnZ7aF/EITCSdlspWpZAuXU /dpXm89Xw+tdZThrzZybIUoulOrugRd4SSS02hzorj66xx1gAO7i3avM4Vdq9MI= X-Gm-Gg: ASbGnctzgb+QCp1veDJmrFFMqKRHBOunYVaoVrU45/nzyqU5qiy4N+QH+l5DrXNvEHF 2HxZkRvevxmyZS8V1M1VpxFM8crMJamk0ZNVsGBZJIQWpD86NxWQeucfgfTaeWXzupk5d1GqfpP AaEJ+0IySkfRm/AhIEse4xgFByiYVzSBOMayWPE5dlb5MNDq3KyDoPZoWq9F6UtHZN0ve0qEHKV ZmVwefXAOIhIE51Crcl580/IQdFRTdGBVMTUxOyW3oxeF9hp4oswax/9EivMV5/uetsCaNeu6VG Q+4gK/KmnQbTa+blWjo/tkk+7eGYf00lDKI= X-Google-Smtp-Source: AGHT+IG5tIhlmlslQzYMLDIc/YD/Qmpsyy2XZDtsQl3bPGCXGdJLQ7LFB//gM50MxByK5wv1ap9Hng== X-Received: by 2002:a05:6000:1447:b0:38f:2350:7f70 with SMTP id ffacd0b85a97d-390ec7d25ddmr4858726f8f.24.1740798134401; Fri, 28 Feb 2025 19:02:14 -0800 (PST) Received: from localhost ([2a03:2880:31ff:71::]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-390e47a72d5sm7065918f8f.31.2025.02.28.19.02.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Feb 2025 19:02:13 -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 v2 3/3] selftests/bpf: Add tests for extending sleepable global subprogs Date: Fri, 28 Feb 2025 19:02:05 -0800 Message-ID: <20250301030205.1221223-4-memxor@gmail.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20250301030205.1221223-1-memxor@gmail.com> References: <20250301030205.1221223-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=12699; h=from:subject; bh=xtnwzGz8N+rP2QXagom8tXWjNGA2I4BEXiqL+8BnRFo=; b=owEBbQKS/ZANAwAIAUzgyIZIvxHKAcsmYgBnwnVAuehVdKdpJEWaFWhD6N7FL970EGk/Zj3QbKyF l76FmliJAjMEAAEIAB0WIQRLvip+Buz51YI8YRFM4MiGSL8RygUCZ8J1QAAKCRBM4MiGSL8RyoUfD/ 4unS4dt4IC8AD5CrhI+3lRAKVywZRL2Rl396JgypEz0oJVXFhG31z3OX4Qc8ZEjkI61fUUjfO1Qvxt X+kcHGaqwfwsXbQMAG/0RsGQKY0wosghffVDEFRdLp+EiQVo/m5rhMOERjItKJlAtLzyeUD3nMaoNd /UzUSDVh9Uw2uEwqBkB2TzVp1V/+CxZ5pOhosCWmxWmh62lZAU7Gs7G3IMi0pk8bjgfOjLDV6R1k4a hzzCwcwWguL9M+GZPZxOlmP7EyCiz3H+s3u5NXAiTqoRBOg84lY00G5XqlFB8gjtGQOGT3yFNL+AgR 6EPP0VMZxbSib5FahcD1TbGkijWvtBeHOIg7PrzsQUQxCxtjCIN+WePYrPCMNzjHVmgbwGpqUKDFwf gGsuBV1AL0Ldj5ziJ4Jvq3iGwdJw4oS0H7ZeJ2vjE4lRC+DAaT79Niz86arM2acapob9H7GBmIJ8l4 +atm7XHjX80vJJJZeLEXsp/yofDrP04tMLVjt67+TndZ3FqZKhYYpOPopeiU7H72dSwZm3PTGRBTjC FbZlFonQG7ZqLRCc247cpSN0abK+JaBoyYF4rNvcaKQh+mvfebXIxB9jF9mNQnclp0iOVAIA+046Dg Lnhh1uDQe4NKtSy0EfXzXVSWo1yKGOZpH/omYDlB6iqJ/QuM0J5vEg6xOd0w== 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. Sleepable extensions don't work yet, so add support but disable it for now, allow support to be tested once it's enabled (and ensure we will complain then). Signed-off-by: Kumar Kartikeya Dwivedi --- .../bpf/prog_tests/changes_pkt_data.c | 107 ------------- .../selftests/bpf/prog_tests/summarization.c | 143 ++++++++++++++++++ .../{changes_pkt_data.c => summarization.c} | 38 ++++- ...ta_freplace.c => summarization_freplace.c} | 13 ++ 4 files changed, 193 insertions(+), 108 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 rename tools/testing/selftests/bpf/progs/{changes_pkt_data.c => summarization.c} (52%) rename tools/testing/selftests/bpf/progs/{changes_pkt_data_freplace.c => summarization_freplace.c} (66%) 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..ee7517b2a606 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/summarization.c @@ -0,0 +1,143 @@ +// 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); + + /* Sleepable extension prog doesn't work yet, but make sure we catch + * this condition and activate the error below in case it becomes + * supported, as we would need to test this condition then. + */ + if (!strcmp("might_sleep", replacement)) { + ASSERT_EQ(err, -EINVAL, "might_sleep load must fail"); + 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", "might_sleep", true }, + { "main_does_not_sleep", "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/summarization.c similarity index 52% rename from tools/testing/selftests/bpf/progs/changes_pkt_data.c rename to tools/testing/selftests/bpf/progs/summarization.c index 43cada48b28a..730342f7b37c 100644 --- a/tools/testing/selftests/bpf/progs/changes_pkt_data.c +++ b/tools/testing/selftests/bpf/progs/summarization.c @@ -16,7 +16,7 @@ long does_not_change_pkt_data(struct __sk_buff *sk) } SEC("?tc") -int main_with_subprogs(struct __sk_buff *sk) +int main_changes_with_subprogs(struct __sk_buff *sk) { changes_pkt_data(sk); does_not_change_pkt_data(sk); @@ -36,4 +36,40 @@ int main_does_not_change(struct __sk_buff *sk) return 0; } +__noinline +long might_sleep(int i) +{ + bpf_copy_from_user(&i, sizeof(i), NULL); + return i; +} + +__noinline __weak +long does_not_sleep(int i) +{ + return 0; +} + +SEC("?syscall") +int main_might_sleep_with_subprogs(void *ctx) +{ + might_sleep(0); + does_not_sleep(0); + return 0; +} + +SEC("?syscall") +int main_might_sleep(void *ctx) +{ + int i; + + bpf_copy_from_user(&i, sizeof(i), NULL); + return i; +} + +SEC("?syscall") +int main_does_not_sleep(void *sk) +{ + 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 66% rename from tools/testing/selftests/bpf/progs/changes_pkt_data_freplace.c rename to tools/testing/selftests/bpf/progs/summarization_freplace.c index f9a622705f1b..c813b1278138 100644 --- a/tools/testing/selftests/bpf/progs/changes_pkt_data_freplace.c +++ b/tools/testing/selftests/bpf/progs/summarization_freplace.c @@ -15,4 +15,17 @@ long does_not_change_pkt_data(struct __sk_buff *sk) return 0; } +SEC("?freplace") +long might_sleep(int i) +{ + bpf_copy_from_user(&i, sizeof(i), NULL); + return i; +} + +SEC("?freplace") +long does_not_sleep(int i) +{ + return 0; +} + char _license[] SEC("license") = "GPL";