Message ID | 20240220035105.34626-2-dongmenglong.8@bytedance.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel+bounces-72290-ouuuleilei=gmail.com@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:693c:2685:b0:108:e6aa:91d0 with SMTP id mn5csp177320dyc; Mon, 19 Feb 2024 19:51:43 -0800 (PST) X-Forwarded-Encrypted: i=3; AJvYcCUR3Cv0UBz21J8PvgoYOh9Vr29DlV/maCzVVYYlbyAm6a18iM1j047xljbKjGwtWCRrrpA+XBU+kG5GGnOw9+orzV8ivw== X-Google-Smtp-Source: AGHT+IHHmnxCHcPsM86FaMHH+7W3W3H4esRzipvJvbHfBs/Ekh/gLuDTYpe+5bmTFk4GnCrs2bbe X-Received: by 2002:a17:906:2b88:b0:a3e:34b2:a2fc with SMTP id m8-20020a1709062b8800b00a3e34b2a2fcmr4243249ejg.1.1708401103636; Mon, 19 Feb 2024 19:51:43 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1708401103; cv=pass; d=google.com; s=arc-20160816; b=0OaYgyNAzdQ3qAMgcS7OO8G+t7MWVuGA0LKDpDEmx9BY+M2ztSS53/E0HVLu0qtfjs 5RGXpwZ+LNwGERif7Fa7SPX1SzBkLuYuh2wM4ITxKaVHOx7s5tcFR1m+GdlYEvVQyGQ7 TIvaOiyGSML/6A1DQh3rOtvd0KuwMSFiuiY6e8cXaskqiXWs1uysIIdpvZtTzBg/Hygx OI862+irclpF18+5wlFawM83QPU7uJ7+6+zI7GetePLSfDIsI03Vt3s1se7IM9mYJ1e+ f8GNCsVB+Dh4y3dmrYIykft1Opbik7+6Jav2NX3HKsvP+o9AWp5R+SCPEb8UkaRqsoLI FeMQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=WHXPVUB1nr0Sthgk6cohE38ljuRgW7sUP/a10lgKv7E=; fh=Jlvm654toBrDfUIfYPpC9jkJPI554TxpOZgOJ1561vY=; b=ghremUvnV7T3ozsbnX+Ku7iMkg2760KYUginXk2KiXiTX0GlTsR+AwwuvCtKPKZA7+ NwrgfmtrDqqJdcad/vKJyYc0u4yWMCs4bnoyB/bTM3yLmYMaw6mwdooli0TqBp7h41g7 CLggg9pTj9ztV4dNocK90z915AlWxIXCvYHpykzwXaWBRSXYGFDPaX/RN5PILA8xOvGS VHHWUjf1/lrAL9PHRvLh/dHmGx04AFPqWJrEpkjoeXlSr9rn0n533IAeD4iG5eSZ5Le9 46O9RhkbxF5IoQmYYIXvAbgMLWW/RAdyuCe2TsGxS9iUMXHlAoPG1/R1ELHMqu4Cf/xQ 3U+Q==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@bytedance.com header.s=google header.b=ACTkIr9x; arc=pass (i=1 spf=pass spfdomain=bytedance.com dkim=pass dkdomain=bytedance.com dmarc=pass fromdomain=bytedance.com); spf=pass (google.com: domain of linux-kernel+bounces-72290-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.80.249 as permitted sender) smtp.mailfrom="linux-kernel+bounces-72290-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=bytedance.com Received: from am.mirrors.kernel.org (am.mirrors.kernel.org. [147.75.80.249]) by mx.google.com with ESMTPS id jx8-20020a170906ca4800b00a3ebdea18e1si1061863ejb.240.2024.02.19.19.51.43 for <ouuuleilei@gmail.com> (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 19 Feb 2024 19:51:43 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-72290-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.80.249 as permitted sender) client-ip=147.75.80.249; Authentication-Results: mx.google.com; dkim=pass header.i=@bytedance.com header.s=google header.b=ACTkIr9x; arc=pass (i=1 spf=pass spfdomain=bytedance.com dkim=pass dkdomain=bytedance.com dmarc=pass fromdomain=bytedance.com); spf=pass (google.com: domain of linux-kernel+bounces-72290-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.80.249 as permitted sender) smtp.mailfrom="linux-kernel+bounces-72290-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=bytedance.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by am.mirrors.kernel.org (Postfix) with ESMTPS id 1FF901F22C09 for <ouuuleilei@gmail.com>; Tue, 20 Feb 2024 03:51:37 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id C73E256B81; Tue, 20 Feb 2024 03:51:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bytedance.com header.i=@bytedance.com header.b="ACTkIr9x" Received: from mail-pf1-f170.google.com (mail-pf1-f170.google.com [209.85.210.170]) (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 027BA47A4C for <linux-kernel@vger.kernel.org>; Tue, 20 Feb 2024 03:51:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708401073; cv=none; b=LECS/2jETIwTmpFiOEoZzeKZm05O6SvqW9zq7W5GZ/JxdZAJZandzzuQ5TXojshP4xqJKyuW32uT9mP842P0r8G9rn/SUZf/iIDTkCRhALsFfIRbvB8A+TUYmuAazAmu8ylkI6+76gm0zo4YEbZQpXKqaH8jExxxJAXEbPp1JFE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708401073; c=relaxed/simple; bh=WCeJYOWpFA4aAYG9AU6cqenBm2lq0LDB3RA405EROwc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=XcDdRvWcnTlrY1ExqdhlKOE9U1LHVEOXl5aY6UeRkOTHgCwp1AGoa/z7eaRECG1qWjrOfIh7l44rKMARJ4GSUoIa9QPlccsyGp89FK0EsiZVW+u0+n+DblLTg3X113c7EPqR/e2tGtaaun0a0x7qQAZK1oOq0Dqgp5y3QsP4brY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=bytedance.com; spf=pass smtp.mailfrom=bytedance.com; dkim=pass (2048-bit key) header.d=bytedance.com header.i=@bytedance.com header.b=ACTkIr9x; arc=none smtp.client-ip=209.85.210.170 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=bytedance.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bytedance.com Received: by mail-pf1-f170.google.com with SMTP id d2e1a72fcca58-6de3141f041so3398717b3a.0 for <linux-kernel@vger.kernel.org>; Mon, 19 Feb 2024 19:51:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bytedance.com; s=google; t=1708401071; x=1709005871; 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=WHXPVUB1nr0Sthgk6cohE38ljuRgW7sUP/a10lgKv7E=; b=ACTkIr9xj//tSv77Mh3wVhdbBIsjhVyRHdOYAhRDLQaNIkaUoaZ++O3l7nP/RoYehB bCt3cPHQ7uhFW7Zf4pr3apx0NDDg7Ii9s1rEJubMsoHoJglDLlQaCsBWmzgudb5XAZO6 Z2haZQwfuMyO7GjCFAUPXuqNao+C1Xbt9nkIr1UkGZPoK07q/drH8KIKk6wlepejINzh mLE1wZ03+PIxARAlDtLZcdLeHfUK7su6ce4DaGecIKpY37SmTSKZhwQjFQNOWZngsrcO xY2ptpByehN0AxSFUz3jKqEBHmRII7iDcNJm4RmzVKD5NUMf1iBioxM4piMoj4VZ6Qsr OzuQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1708401071; x=1709005871; 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=WHXPVUB1nr0Sthgk6cohE38ljuRgW7sUP/a10lgKv7E=; b=O+50rXBLdvo9UH3/OZlUu7Bo3LxUytgClmyOcW7qDSJkQ7XZzYdDx/C5eidmusJD4v ZFongaCEBLot3gTEMB8U5mLAdway6XzCJzOygSWVeVKLN0HdTjVBwbfE6tN+8TkRJqef MXz0qNJoKrbR7KrBpRdEbToeY3lw5EWOh63RnHEVO193yqoERmCucnq1zDOWOYmsWGEK kqU5HrGZdcPAAmGcxoju02jE0G9hPJxNgNNMmJ6NFsg6igYFW+Yylc9Iikf27KrnBTqy +egsBmhRx00D9arqKw396d5FMw023Yw1nKEocOtpJupYG1kzJOxDUBAEMR8qdLmiPXmb ptIQ== X-Forwarded-Encrypted: i=1; AJvYcCWGkiZpeOtXuTLOGpUL53VVH+b1mYW5FumpDEsAeeKPrYHJvyfHf6Ylr/qXFtIQetJVTWad0r551xBzoidF2v2fWAKQDS7G1uopDZ3y X-Gm-Message-State: AOJu0Yz0O/A8FIuMrklPDwtWRVIC9k6ATAgQaqrjB4m6SKSEzuonge7C QDwVHyREZ2MaG+d9Le4nq/O4Hj7np6vmy7U2i54KbI/IhQPArXBPvAPUNuWx42I= X-Received: by 2002:a05:6a20:6f88:b0:19a:47f2:5766 with SMTP id gv8-20020a056a206f8800b0019a47f25766mr13853615pzb.56.1708401071235; Mon, 19 Feb 2024 19:51:11 -0800 (PST) Received: from localhost.localdomain ([43.129.25.208]) by smtp.gmail.com with ESMTPSA id jz7-20020a170903430700b001d94678a76csm5131723plb.117.2024.02.19.19.51.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 19 Feb 2024 19:51:11 -0800 (PST) From: Menglong Dong <dongmenglong.8@bytedance.com> To: andrii@kernel.org Cc: ast@kernel.org, daniel@iogearbox.net, martin.lau@linux.dev, eddyz87@gmail.com, song@kernel.org, yonghong.song@linux.dev, john.fastabend@gmail.com, kpsingh@kernel.org, sdf@google.com, haoluo@google.com, jolsa@kernel.org, mykolal@fb.com, shuah@kernel.org, mcoquelin.stm32@gmail.com, alexandre.torgue@foss.st.com, thinker.li@gmail.com, dongmenglong.8@bytedance.com, zhoufeng.zf@bytedance.com, davemarchevsky@fb.com, dxu@dxuuu.xyz, linux-kernel@vger.kernel.org, bpf@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, linux-arm-kernel@lists.infradead.org Subject: [PATCH bpf-next 1/5] bpf: tracing: add support to record and check the accessed args Date: Tue, 20 Feb 2024 11:51:01 +0800 Message-Id: <20240220035105.34626-2-dongmenglong.8@bytedance.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240220035105.34626-1-dongmenglong.8@bytedance.com> References: <20240220035105.34626-1-dongmenglong.8@bytedance.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: <linux-kernel.vger.kernel.org> List-Subscribe: <mailto:linux-kernel+subscribe@vger.kernel.org> List-Unsubscribe: <mailto:linux-kernel+unsubscribe@vger.kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1791388395773116520 X-GMAIL-MSGID: 1791388395773116520 |
Series |
bpf: make tracing program support multi-attach
|
|
Commit Message
梦龙董
Feb. 20, 2024, 3:51 a.m. UTC
In this commit, we add the 'accessed_args' field to struct bpf_prog_aux,
which is used to record the accessed index of the function args in
btf_ctx_access().
Meanwhile, we add the function btf_check_func_part_match() to compare the
accessed function args of two function prototype. This function will be
used in the following commit.
Signed-off-by: Menglong Dong <dongmenglong.8@bytedance.com>
---
include/linux/bpf.h | 4 ++
kernel/bpf/btf.c | 121 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 125 insertions(+)
Comments
On Tue, Feb 20, 2024 at 11:51:01AM +0800, Menglong Dong wrote: SNIP > +static int get_ctx_arg_idx_aligned(struct btf *btf, const struct btf_type *t, > + int off) > +{ > + const struct btf_param *args; > + u32 offset = 0, nr_args; > + int i; > + > + nr_args = btf_type_vlen(t); > + args = (const struct btf_param *)(t + 1); > + for (i = 0; i < nr_args; i++) { > + if (offset == off) > + return i; > + > + t = btf_type_skip_modifiers(btf, args[i].type, NULL); > + offset += btf_type_is_ptr(t) ? 8 : roundup(t->size, 8); > + if (offset > off) > + return -1; > + } > + return -1; > +} > + > +/* This function is similar to btf_check_func_type_match(), except that it > + * only compare some function args of the function prototype t1 and t2. > + */ could we reuse btf_check_func_type_match instead? perhaps just adding extra argument with arguments bitmap to it? jirka > +int btf_check_func_part_match(struct btf *btf1, const struct btf_type *func1, > + struct btf *btf2, const struct btf_type *func2, > + u64 func_args) > +{ > + const struct btf_param *args1, *args2; > + u32 nargs1, i, offset = 0; > + const char *s1, *s2; > + > + if (!btf_type_is_func_proto(func1) || !btf_type_is_func_proto(func2)) > + return -EINVAL; > + > + args1 = (const struct btf_param *)(func1 + 1); > + args2 = (const struct btf_param *)(func2 + 1); > + nargs1 = btf_type_vlen(func1); > + > + for (i = 0; i <= nargs1; i++) { > + const struct btf_type *t1, *t2; > + > + if (!(func_args & (1 << i))) > + goto next; > + > + if (i < nargs1) { > + int t2_index; > + > + /* get the index of the arg corresponding to args1[i] > + * by the offset. > + */ > + t2_index = get_ctx_arg_idx_aligned(btf2, func2, > + offset); > + if (t2_index < 0) > + return -EINVAL; > + > + t1 = btf_type_skip_modifiers(btf1, args1[i].type, NULL); > + t2 = btf_type_skip_modifiers(btf2, args2[t2_index].type, > + NULL); > + } else { > + /* i == nargs1, this is the index of return value of t1 */ > + if (get_ctx_arg_total_size(btf1, func1) != > + get_ctx_arg_total_size(btf2, func2)) > + return -EINVAL; > + > + /* check the return type of t1 and t2 */ > + t1 = btf_type_skip_modifiers(btf1, func1->type, NULL); > + t2 = btf_type_skip_modifiers(btf2, func2->type, NULL); > + } > + > + if (t1->info != t2->info || > + (btf_type_has_size(t1) && t1->size != t2->size)) > + return -EINVAL; > + if (btf_type_is_int(t1) || btf_is_any_enum(t1)) > + goto next; > + > + if (btf_type_is_struct(t1)) > + goto on_struct; > + > + if (!btf_type_is_ptr(t1)) > + return -EINVAL; > + > + t1 = btf_type_skip_modifiers(btf1, t1->type, NULL); > + t2 = btf_type_skip_modifiers(btf2, t2->type, NULL); > + if (!btf_type_is_struct(t1) || !btf_type_is_struct(t2)) > + return -EINVAL; > + > +on_struct: > + s1 = btf_name_by_offset(btf1, t1->name_off); > + s2 = btf_name_by_offset(btf2, t2->name_off); > + if (strcmp(s1, s2)) > + return -EINVAL; > +next: > + if (i < nargs1) { > + t1 = btf_type_skip_modifiers(btf1, args1[i].type, NULL); > + offset += btf_type_is_ptr(t1) ? 8 : roundup(t1->size, 8); > + } > + } > + > + return 0; > +} > + > static bool btf_is_dynptr_ptr(const struct btf *btf, const struct btf_type *t) > { > const char *name; > -- > 2.39.2 >
On 2/19/24 19:51, Menglong Dong wrote: > In this commit, we add the 'accessed_args' field to struct bpf_prog_aux, > which is used to record the accessed index of the function args in > btf_ctx_access(). > > Meanwhile, we add the function btf_check_func_part_match() to compare the > accessed function args of two function prototype. This function will be > used in the following commit. > > Signed-off-by: Menglong Dong <dongmenglong.8@bytedance.com> > --- > include/linux/bpf.h | 4 ++ > kernel/bpf/btf.c | 121 ++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 125 insertions(+) > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > index c7aa99b44dbd..0225b8dbdd9d 100644 > --- a/include/linux/bpf.h > +++ b/include/linux/bpf.h > @@ -1464,6 +1464,7 @@ struct bpf_prog_aux { > const struct btf_type *attach_func_proto; > /* function name for valid attach_btf_id */ > const char *attach_func_name; > + u64 accessed_args; > struct bpf_prog **func; > void *jit_data; /* JIT specific data. arch dependent */ > struct bpf_jit_poke_descriptor *poke_tab; > @@ -2566,6 +2567,9 @@ struct bpf_reg_state; > int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog); > int btf_check_type_match(struct bpf_verifier_log *log, const struct bpf_prog *prog, > struct btf *btf, const struct btf_type *t); > +int btf_check_func_part_match(struct btf *btf1, const struct btf_type *t1, > + struct btf *btf2, const struct btf_type *t2, > + u64 func_args); > const char *btf_find_decl_tag_value(const struct btf *btf, const struct btf_type *pt, > int comp_idx, const char *tag_key); > int btf_find_next_decl_tag(const struct btf *btf, const struct btf_type *pt, > diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c > index 6ff0bd1a91d5..3a6931402fe4 100644 > --- a/kernel/bpf/btf.c > +++ b/kernel/bpf/btf.c > @@ -6203,6 +6203,9 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type, > /* skip first 'void *__data' argument in btf_trace_##name typedef */ > args++; > nr_args--; > + prog->aux->accessed_args |= (1 << (arg + 1)); > + } else { > + prog->aux->accessed_args |= (1 << arg); > } > > if (arg > nr_args) { > @@ -7010,6 +7013,124 @@ int btf_check_type_match(struct bpf_verifier_log *log, const struct bpf_prog *pr > return btf_check_func_type_match(log, btf1, t1, btf2, t2); > } > > +static u32 get_ctx_arg_total_size(struct btf *btf, const struct btf_type *t) > +{ > + const struct btf_param *args; > + u32 size = 0, nr_args; > + int i; > + > + nr_args = btf_type_vlen(t); > + args = (const struct btf_param *)(t + 1); > + for (i = 0; i < nr_args; i++) { > + t = btf_type_skip_modifiers(btf, args[i].type, NULL); > + size += btf_type_is_ptr(t) ? 8 : roundup(t->size, 8); > + } > + > + return size; > +} > + > +static int get_ctx_arg_idx_aligned(struct btf *btf, const struct btf_type *t, > + int off) > +{ > + const struct btf_param *args; > + u32 offset = 0, nr_args; > + int i; > + > + nr_args = btf_type_vlen(t); > + args = (const struct btf_param *)(t + 1); > + for (i = 0; i < nr_args; i++) { > + if (offset == off) > + return i; > + > + t = btf_type_skip_modifiers(btf, args[i].type, NULL); > + offset += btf_type_is_ptr(t) ? 8 : roundup(t->size, 8); > + if (offset > off) > + return -1; > + } > + return -1; > +} This one is very similar to get_ctx_arg_idx(). How about to refactor get_ctx_arg_idx() and share the code between get_ctx_arg_idx() and get_ctx_arg_idx_aligned(). For example, -static u32 get_ctx_arg_idx(struct btf *btf, const struct btf_type *func_proto, - int off) +static u32 _get_ctx_arg_idx(struct btf *btf, const struct btf_type *func_proto, + int off, u32 *arg_off) { const struct btf_param *args; const struct btf_type *t; u32 offset = 0, nr_args; int i; if (!func_proto) return off / 8; nr_args = btf_type_vlen(func_proto); args = (const struct btf_param *)(func_proto + 1); for (i = 0; i < nr_args; i++) { + if (arg_off) + *arg_off = offset; t = btf_type_skip_modifiers(btf, args[i].type, NULL); offset += btf_type_is_ptr(t) ? 8 : roundup(t->size, 8); if (off < offset) return i; } + if (arg_off) + *arg_off = offset; t = btf_type_skip_modifiers(btf, func_proto->type, NULL); offset += btf_type_is_ptr(t) ? 8 : roundup(t->size, 8); if (off < offset) return nr_args; return nr_args + 1; } +static u32 get_ctx_arg_idx(struct btf *btf, const struct btf_type *func_proto, + int off) +{ + return _get_ctx_arg_idx(btf, func_proto, off, NULL); +} + +static u32 get_ctx_arg_idx_aligned(struct btf *btf, + const struct btf_type *func_proto, + int off) +{ + u32 arg_off; + u32 arg_idx = _get_ctx_arg_idx(btf, func_proto, off, &arg_off); + return arg_off == off ? arg_idx : -1; +} + > + > +/* This function is similar to btf_check_func_type_match(), except that it > + * only compare some function args of the function prototype t1 and t2. > + */ > +int btf_check_func_part_match(struct btf *btf1, const struct btf_type *func1, > + struct btf *btf2, const struct btf_type *func2, > + u64 func_args) > +{ > + const struct btf_param *args1, *args2; > + u32 nargs1, i, offset = 0; > + const char *s1, *s2; > + > + if (!btf_type_is_func_proto(func1) || !btf_type_is_func_proto(func2)) > + return -EINVAL; > + > + args1 = (const struct btf_param *)(func1 + 1); > + args2 = (const struct btf_param *)(func2 + 1); > + nargs1 = btf_type_vlen(func1); > + > + for (i = 0; i <= nargs1; i++) { > + const struct btf_type *t1, *t2; > + > + if (!(func_args & (1 << i))) > + goto next; > + > + if (i < nargs1) { > + int t2_index; > + > + /* get the index of the arg corresponding to args1[i] > + * by the offset. > + */ > + t2_index = get_ctx_arg_idx_aligned(btf2, func2, > + offset); > + if (t2_index < 0) > + return -EINVAL; > + > + t1 = btf_type_skip_modifiers(btf1, args1[i].type, NULL); > + t2 = btf_type_skip_modifiers(btf2, args2[t2_index].type, > + NULL); > + } else { > + /* i == nargs1, this is the index of return value of t1 */ > + if (get_ctx_arg_total_size(btf1, func1) != > + get_ctx_arg_total_size(btf2, func2)) > + return -EINVAL; > + > + /* check the return type of t1 and t2 */ > + t1 = btf_type_skip_modifiers(btf1, func1->type, NULL); > + t2 = btf_type_skip_modifiers(btf2, func2->type, NULL); > + } > + > + if (t1->info != t2->info || > + (btf_type_has_size(t1) && t1->size != t2->size)) > + return -EINVAL; > + if (btf_type_is_int(t1) || btf_is_any_enum(t1)) > + goto next; > + > + if (btf_type_is_struct(t1)) > + goto on_struct; > + > + if (!btf_type_is_ptr(t1)) > + return -EINVAL; > + > + t1 = btf_type_skip_modifiers(btf1, t1->type, NULL); > + t2 = btf_type_skip_modifiers(btf2, t2->type, NULL); > + if (!btf_type_is_struct(t1) || !btf_type_is_struct(t2)) > + return -EINVAL; > + > +on_struct: > + s1 = btf_name_by_offset(btf1, t1->name_off); > + s2 = btf_name_by_offset(btf2, t2->name_off); > + if (strcmp(s1, s2)) > + return -EINVAL; > +next: > + if (i < nargs1) { > + t1 = btf_type_skip_modifiers(btf1, args1[i].type, NULL); > + offset += btf_type_is_ptr(t1) ? 8 : roundup(t1->size, 8); > + } > + } > + > + return 0; > +} > + > static bool btf_is_dynptr_ptr(const struct btf *btf, const struct btf_type *t) > { > const char *name;
On Wed, Feb 21, 2024 at 1:18 AM Jiri Olsa <olsajiri@gmail.com> wrote: > > On Tue, Feb 20, 2024 at 11:51:01AM +0800, Menglong Dong wrote: > > SNIP > > > +static int get_ctx_arg_idx_aligned(struct btf *btf, const struct btf_type *t, > > + int off) > > +{ > > + const struct btf_param *args; > > + u32 offset = 0, nr_args; > > + int i; > > + > > + nr_args = btf_type_vlen(t); > > + args = (const struct btf_param *)(t + 1); > > + for (i = 0; i < nr_args; i++) { > > + if (offset == off) > > + return i; > > + > > + t = btf_type_skip_modifiers(btf, args[i].type, NULL); > > + offset += btf_type_is_ptr(t) ? 8 : roundup(t->size, 8); > > + if (offset > off) > > + return -1; > > + } > > + return -1; > > +} > > + > > +/* This function is similar to btf_check_func_type_match(), except that it > > + * only compare some function args of the function prototype t1 and t2. > > + */ > > could we reuse btf_check_func_type_match instead? perhaps just > adding extra argument with arguments bitmap to it? > This is a little difficult, as the way we check the consistency of t1 and t2 is a little different. in btf_check_func_type_match(), we check the args of t1 and t2 by index. But in btf_check_func_part_match(), we check the args of t1 and t2 by offset. Reusing can make btf_check_func_type_match become complex and hard to understand. Anyway, let me have a try to see if it works to reuse btf_check_func_type_match(). Thanks! Menglong Dong > jirka > > > +int btf_check_func_part_match(struct btf *btf1, const struct btf_type *func1, > > + struct btf *btf2, const struct btf_type *func2, > > + u64 func_args) > > +{ > > + const struct btf_param *args1, *args2; > > + u32 nargs1, i, offset = 0; > > + const char *s1, *s2; > > + > > + if (!btf_type_is_func_proto(func1) || !btf_type_is_func_proto(func2)) > > + return -EINVAL; > > + > > + args1 = (const struct btf_param *)(func1 + 1); > > + args2 = (const struct btf_param *)(func2 + 1); > > + nargs1 = btf_type_vlen(func1); > > + > > + for (i = 0; i <= nargs1; i++) { > > + const struct btf_type *t1, *t2; > > + > > + if (!(func_args & (1 << i))) > > + goto next; > > + > > + if (i < nargs1) { > > + int t2_index; > > + > > + /* get the index of the arg corresponding to args1[i] > > + * by the offset. > > + */ > > + t2_index = get_ctx_arg_idx_aligned(btf2, func2, > > + offset); > > + if (t2_index < 0) > > + return -EINVAL; > > + > > + t1 = btf_type_skip_modifiers(btf1, args1[i].type, NULL); > > + t2 = btf_type_skip_modifiers(btf2, args2[t2_index].type, > > + NULL); > > + } else { > > + /* i == nargs1, this is the index of return value of t1 */ > > + if (get_ctx_arg_total_size(btf1, func1) != > > + get_ctx_arg_total_size(btf2, func2)) > > + return -EINVAL; > > + > > + /* check the return type of t1 and t2 */ > > + t1 = btf_type_skip_modifiers(btf1, func1->type, NULL); > > + t2 = btf_type_skip_modifiers(btf2, func2->type, NULL); > > + } > > + > > + if (t1->info != t2->info || > > + (btf_type_has_size(t1) && t1->size != t2->size)) > > + return -EINVAL; > > + if (btf_type_is_int(t1) || btf_is_any_enum(t1)) > > + goto next; > > + > > + if (btf_type_is_struct(t1)) > > + goto on_struct; > > + > > + if (!btf_type_is_ptr(t1)) > > + return -EINVAL; > > + > > + t1 = btf_type_skip_modifiers(btf1, t1->type, NULL); > > + t2 = btf_type_skip_modifiers(btf2, t2->type, NULL); > > + if (!btf_type_is_struct(t1) || !btf_type_is_struct(t2)) > > + return -EINVAL; > > + > > +on_struct: > > + s1 = btf_name_by_offset(btf1, t1->name_off); > > + s2 = btf_name_by_offset(btf2, t2->name_off); > > + if (strcmp(s1, s2)) > > + return -EINVAL; > > +next: > > + if (i < nargs1) { > > + t1 = btf_type_skip_modifiers(btf1, args1[i].type, NULL); > > + offset += btf_type_is_ptr(t1) ? 8 : roundup(t1->size, 8); > > + } > > + } > > + > > + return 0; > > +} > > + > > static bool btf_is_dynptr_ptr(const struct btf *btf, const struct btf_type *t) > > { > > const char *name; > > -- > > 2.39.2 > >
On Wed, Feb 21, 2024 at 2:22 AM Kui-Feng Lee <sinquersw@gmail.com> wrote: > > > > On 2/19/24 19:51, Menglong Dong wrote: > > In this commit, we add the 'accessed_args' field to struct bpf_prog_aux, > > which is used to record the accessed index of the function args in > > btf_ctx_access(). > > > > Meanwhile, we add the function btf_check_func_part_match() to compare the > > accessed function args of two function prototype. This function will be > > used in the following commit. > > > > Signed-off-by: Menglong Dong <dongmenglong.8@bytedance.com> > > --- > > include/linux/bpf.h | 4 ++ > > kernel/bpf/btf.c | 121 ++++++++++++++++++++++++++++++++++++++++++++ > > 2 files changed, 125 insertions(+) > > > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > > index c7aa99b44dbd..0225b8dbdd9d 100644 > > --- a/include/linux/bpf.h > > +++ b/include/linux/bpf.h > > @@ -1464,6 +1464,7 @@ struct bpf_prog_aux { > > const struct btf_type *attach_func_proto; > > /* function name for valid attach_btf_id */ > > const char *attach_func_name; > > + u64 accessed_args; > > struct bpf_prog **func; > > void *jit_data; /* JIT specific data. arch dependent */ > > struct bpf_jit_poke_descriptor *poke_tab; > > @@ -2566,6 +2567,9 @@ struct bpf_reg_state; > > int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog); > > int btf_check_type_match(struct bpf_verifier_log *log, const struct bpf_prog *prog, > > struct btf *btf, const struct btf_type *t); > > +int btf_check_func_part_match(struct btf *btf1, const struct btf_type *t1, > > + struct btf *btf2, const struct btf_type *t2, > > + u64 func_args); > > const char *btf_find_decl_tag_value(const struct btf *btf, const struct btf_type *pt, > > int comp_idx, const char *tag_key); > > int btf_find_next_decl_tag(const struct btf *btf, const struct btf_type *pt, > > diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c > > index 6ff0bd1a91d5..3a6931402fe4 100644 > > --- a/kernel/bpf/btf.c > > +++ b/kernel/bpf/btf.c > > @@ -6203,6 +6203,9 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type, > > /* skip first 'void *__data' argument in btf_trace_##name typedef */ > > args++; > > nr_args--; > > + prog->aux->accessed_args |= (1 << (arg + 1)); > > + } else { > > + prog->aux->accessed_args |= (1 << arg); > > } > > > > if (arg > nr_args) { > > @@ -7010,6 +7013,124 @@ int btf_check_type_match(struct bpf_verifier_log *log, const struct bpf_prog *pr > > return btf_check_func_type_match(log, btf1, t1, btf2, t2); > > } > > > > +static u32 get_ctx_arg_total_size(struct btf *btf, const struct btf_type *t) > > +{ > > + const struct btf_param *args; > > + u32 size = 0, nr_args; > > + int i; > > + > > + nr_args = btf_type_vlen(t); > > + args = (const struct btf_param *)(t + 1); > > + for (i = 0; i < nr_args; i++) { > > + t = btf_type_skip_modifiers(btf, args[i].type, NULL); > > + size += btf_type_is_ptr(t) ? 8 : roundup(t->size, 8); > > + } > > + > > + return size; > > +} > > + > > +static int get_ctx_arg_idx_aligned(struct btf *btf, const struct btf_type *t, > > + int off) > > +{ > > + const struct btf_param *args; > > + u32 offset = 0, nr_args; > > + int i; > > + > > + nr_args = btf_type_vlen(t); > > + args = (const struct btf_param *)(t + 1); > > + for (i = 0; i < nr_args; i++) { > > + if (offset == off) > > + return i; > > + > > + t = btf_type_skip_modifiers(btf, args[i].type, NULL); > > + offset += btf_type_is_ptr(t) ? 8 : roundup(t->size, 8); > > + if (offset > off) > > + return -1; > > + } > > + return -1; > > +} > > This one is very similar to get_ctx_arg_idx(). > How about to refactor get_ctx_arg_idx() and share the code > between get_ctx_arg_idx() and get_ctx_arg_idx_aligned(). > This seems to work, I'll combine them in the next version. Thanks for the example code! Menglong Dong > For example, > > -static u32 get_ctx_arg_idx(struct btf *btf, const struct btf_type > *func_proto, > - int off) > +static u32 _get_ctx_arg_idx(struct btf *btf, const struct btf_type > *func_proto, > + int off, u32 *arg_off) > { > const struct btf_param *args; > const struct btf_type *t; > u32 offset = 0, nr_args; > int i; > > if (!func_proto) > return off / 8; > > nr_args = btf_type_vlen(func_proto); > args = (const struct btf_param *)(func_proto + 1); > for (i = 0; i < nr_args; i++) { > + if (arg_off) > + *arg_off = offset; > t = btf_type_skip_modifiers(btf, args[i].type, NULL); > offset += btf_type_is_ptr(t) ? 8 : roundup(t->size, 8); > if (off < offset) > return i; > } > > + if (arg_off) > + *arg_off = offset; > t = btf_type_skip_modifiers(btf, func_proto->type, NULL); > offset += btf_type_is_ptr(t) ? 8 : roundup(t->size, 8); > if (off < offset) > return nr_args; > > return nr_args + 1; > } > > +static u32 get_ctx_arg_idx(struct btf *btf, const struct btf_type > *func_proto, > + int off) > +{ > + return _get_ctx_arg_idx(btf, func_proto, off, NULL); > +} > + > +static u32 get_ctx_arg_idx_aligned(struct btf *btf, > + const struct btf_type *func_proto, > + int off) > +{ > + u32 arg_off; > + u32 arg_idx = _get_ctx_arg_idx(btf, func_proto, off, &arg_off); > + return arg_off == off ? arg_idx : -1; > +} > + > > > + > > +/* This function is similar to btf_check_func_type_match(), except that it > > + * only compare some function args of the function prototype t1 and t2. > > + */ > > +int btf_check_func_part_match(struct btf *btf1, const struct btf_type *func1, > > + struct btf *btf2, const struct btf_type *func2, > > + u64 func_args) > > +{ > > + const struct btf_param *args1, *args2; > > + u32 nargs1, i, offset = 0; > > + const char *s1, *s2; > > + > > + if (!btf_type_is_func_proto(func1) || !btf_type_is_func_proto(func2)) > > + return -EINVAL; > > + > > + args1 = (const struct btf_param *)(func1 + 1); > > + args2 = (const struct btf_param *)(func2 + 1); > > + nargs1 = btf_type_vlen(func1); > > + > > + for (i = 0; i <= nargs1; i++) { > > + const struct btf_type *t1, *t2; > > + > > + if (!(func_args & (1 << i))) > > + goto next; > > + > > + if (i < nargs1) { > > + int t2_index; > > + > > + /* get the index of the arg corresponding to args1[i] > > + * by the offset. > > + */ > > + t2_index = get_ctx_arg_idx_aligned(btf2, func2, > > + offset); > > + if (t2_index < 0) > > + return -EINVAL; > > + > > + t1 = btf_type_skip_modifiers(btf1, args1[i].type, NULL); > > + t2 = btf_type_skip_modifiers(btf2, args2[t2_index].type, > > + NULL); > > + } else { > > + /* i == nargs1, this is the index of return value of t1 */ > > + if (get_ctx_arg_total_size(btf1, func1) != > > + get_ctx_arg_total_size(btf2, func2)) > > + return -EINVAL; > > + > > + /* check the return type of t1 and t2 */ > > + t1 = btf_type_skip_modifiers(btf1, func1->type, NULL); > > + t2 = btf_type_skip_modifiers(btf2, func2->type, NULL); > > + } > > + > > + if (t1->info != t2->info || > > + (btf_type_has_size(t1) && t1->size != t2->size)) > > + return -EINVAL; > > + if (btf_type_is_int(t1) || btf_is_any_enum(t1)) > > + goto next; > > + > > + if (btf_type_is_struct(t1)) > > + goto on_struct; > > + > > + if (!btf_type_is_ptr(t1)) > > + return -EINVAL; > > + > > + t1 = btf_type_skip_modifiers(btf1, t1->type, NULL); > > + t2 = btf_type_skip_modifiers(btf2, t2->type, NULL); > > + if (!btf_type_is_struct(t1) || !btf_type_is_struct(t2)) > > + return -EINVAL; > > + > > +on_struct: > > + s1 = btf_name_by_offset(btf1, t1->name_off); > > + s2 = btf_name_by_offset(btf2, t2->name_off); > > + if (strcmp(s1, s2)) > > + return -EINVAL; > > +next: > > + if (i < nargs1) { > > + t1 = btf_type_skip_modifiers(btf1, args1[i].type, NULL); > > + offset += btf_type_is_ptr(t1) ? 8 : roundup(t1->size, 8); > > + } > > + } > > + > > + return 0; > > +} > > + > > static bool btf_is_dynptr_ptr(const struct btf *btf, const struct btf_type *t) > > { > > const char *name;
diff --git a/include/linux/bpf.h b/include/linux/bpf.h index c7aa99b44dbd..0225b8dbdd9d 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1464,6 +1464,7 @@ struct bpf_prog_aux { const struct btf_type *attach_func_proto; /* function name for valid attach_btf_id */ const char *attach_func_name; + u64 accessed_args; struct bpf_prog **func; void *jit_data; /* JIT specific data. arch dependent */ struct bpf_jit_poke_descriptor *poke_tab; @@ -2566,6 +2567,9 @@ struct bpf_reg_state; int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog); int btf_check_type_match(struct bpf_verifier_log *log, const struct bpf_prog *prog, struct btf *btf, const struct btf_type *t); +int btf_check_func_part_match(struct btf *btf1, const struct btf_type *t1, + struct btf *btf2, const struct btf_type *t2, + u64 func_args); const char *btf_find_decl_tag_value(const struct btf *btf, const struct btf_type *pt, int comp_idx, const char *tag_key); int btf_find_next_decl_tag(const struct btf *btf, const struct btf_type *pt, diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 6ff0bd1a91d5..3a6931402fe4 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -6203,6 +6203,9 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type, /* skip first 'void *__data' argument in btf_trace_##name typedef */ args++; nr_args--; + prog->aux->accessed_args |= (1 << (arg + 1)); + } else { + prog->aux->accessed_args |= (1 << arg); } if (arg > nr_args) { @@ -7010,6 +7013,124 @@ int btf_check_type_match(struct bpf_verifier_log *log, const struct bpf_prog *pr return btf_check_func_type_match(log, btf1, t1, btf2, t2); } +static u32 get_ctx_arg_total_size(struct btf *btf, const struct btf_type *t) +{ + const struct btf_param *args; + u32 size = 0, nr_args; + int i; + + nr_args = btf_type_vlen(t); + args = (const struct btf_param *)(t + 1); + for (i = 0; i < nr_args; i++) { + t = btf_type_skip_modifiers(btf, args[i].type, NULL); + size += btf_type_is_ptr(t) ? 8 : roundup(t->size, 8); + } + + return size; +} + +static int get_ctx_arg_idx_aligned(struct btf *btf, const struct btf_type *t, + int off) +{ + const struct btf_param *args; + u32 offset = 0, nr_args; + int i; + + nr_args = btf_type_vlen(t); + args = (const struct btf_param *)(t + 1); + for (i = 0; i < nr_args; i++) { + if (offset == off) + return i; + + t = btf_type_skip_modifiers(btf, args[i].type, NULL); + offset += btf_type_is_ptr(t) ? 8 : roundup(t->size, 8); + if (offset > off) + return -1; + } + return -1; +} + +/* This function is similar to btf_check_func_type_match(), except that it + * only compare some function args of the function prototype t1 and t2. + */ +int btf_check_func_part_match(struct btf *btf1, const struct btf_type *func1, + struct btf *btf2, const struct btf_type *func2, + u64 func_args) +{ + const struct btf_param *args1, *args2; + u32 nargs1, i, offset = 0; + const char *s1, *s2; + + if (!btf_type_is_func_proto(func1) || !btf_type_is_func_proto(func2)) + return -EINVAL; + + args1 = (const struct btf_param *)(func1 + 1); + args2 = (const struct btf_param *)(func2 + 1); + nargs1 = btf_type_vlen(func1); + + for (i = 0; i <= nargs1; i++) { + const struct btf_type *t1, *t2; + + if (!(func_args & (1 << i))) + goto next; + + if (i < nargs1) { + int t2_index; + + /* get the index of the arg corresponding to args1[i] + * by the offset. + */ + t2_index = get_ctx_arg_idx_aligned(btf2, func2, + offset); + if (t2_index < 0) + return -EINVAL; + + t1 = btf_type_skip_modifiers(btf1, args1[i].type, NULL); + t2 = btf_type_skip_modifiers(btf2, args2[t2_index].type, + NULL); + } else { + /* i == nargs1, this is the index of return value of t1 */ + if (get_ctx_arg_total_size(btf1, func1) != + get_ctx_arg_total_size(btf2, func2)) + return -EINVAL; + + /* check the return type of t1 and t2 */ + t1 = btf_type_skip_modifiers(btf1, func1->type, NULL); + t2 = btf_type_skip_modifiers(btf2, func2->type, NULL); + } + + if (t1->info != t2->info || + (btf_type_has_size(t1) && t1->size != t2->size)) + return -EINVAL; + if (btf_type_is_int(t1) || btf_is_any_enum(t1)) + goto next; + + if (btf_type_is_struct(t1)) + goto on_struct; + + if (!btf_type_is_ptr(t1)) + return -EINVAL; + + t1 = btf_type_skip_modifiers(btf1, t1->type, NULL); + t2 = btf_type_skip_modifiers(btf2, t2->type, NULL); + if (!btf_type_is_struct(t1) || !btf_type_is_struct(t2)) + return -EINVAL; + +on_struct: + s1 = btf_name_by_offset(btf1, t1->name_off); + s2 = btf_name_by_offset(btf2, t2->name_off); + if (strcmp(s1, s2)) + return -EINVAL; +next: + if (i < nargs1) { + t1 = btf_type_skip_modifiers(btf1, args1[i].type, NULL); + offset += btf_type_is_ptr(t1) ? 8 : roundup(t1->size, 8); + } + } + + return 0; +} + static bool btf_is_dynptr_ptr(const struct btf *btf, const struct btf_type *t) { const char *name;