From nobody Thu Apr 2 10:56:05 2026 Received: from out-185.mta0.migadu.com (out-185.mta0.migadu.com [91.218.175.185]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 490D8314D1D for ; Mon, 16 Feb 2026 15:07:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.185 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771254452; cv=none; b=RPWiUf4Hy8bMYnHIgtYJLyOQFHhS4naOyLs2p3EcSiyIXwZsXD3hEzuHADwPxqinRhK4DOlCJljgVLRPoTNZKEhNOaiTfIihFgYxb8fhTmPDvpnIDcmygZd1gJrfEJctW/U97eVrL9xhoj2XKp2xdpdvUKzk+sMFZqkKIB8THiU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771254452; c=relaxed/simple; bh=F4ZsX+GBg7j3Svrnb/i49UgWXFRWo9S1UwYJFXijWM0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lrGDzDzSXHFMy39W5gmLd5QCMAGwlS/s4/1Hj6Ik1ybVBpXur7FgNLy/Mm0ZYKayeRLoPalOLk/epEvdFkFI5+hcyK1rhrUoPtbTTckfvC/czWjL3Kn305KtIv3TAFdfkb5Kid2Cgh4XtYMDI6n4KK5Bsu4SitTOckopYFLXaNs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=pbXaEZxA; arc=none smtp.client-ip=91.218.175.185 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="pbXaEZxA" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1771254448; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=SFGJ50n9+bv2f9D9DqaYiurpxwP/FhFm6n1QOwE8JOk=; b=pbXaEZxATZcpgwgRYW4SRhxr1Mzax45Gr4RpKnagXm1u9Iv6ww4EeD1GEfEDK/ujR3CYYn fDWled8rRW4PYvlXWGT/GayC0VUs1TgKAsGdh2Pma92m19fktf8Fd/U8XNxzmijuiWxIiE gQ1LnJ5nZy1fmD3AQC3Lle5XVKyQCjQ= From: Leon Hwang To: bpf@vger.kernel.org Cc: Alexei Starovoitov , Daniel Borkmann , John Fastabend , Andrii Nakryiko , Martin KaFai Lau , Eduard Zingerman , Song Liu , Yonghong Song , KP Singh , Stanislav Fomichev , Hao Luo , Jiri Olsa , Shuah Khan , Christian Brauner , Seth Forshee , Yuichiro Tsuji , Andrey Albershteyn , Leon Hwang , Willem de Bruijn , Jason Xing , Tao Chen , Mykyta Yatsenko , Kumar Kartikeya Dwivedi , Anton Protopopov , Amery Hung , Rong Tao , linux-kernel@vger.kernel.org, linux-api@vger.kernel.org, linux-kselftest@vger.kernel.org, kernel-patches-bot@fb.com Subject: [PATCH bpf-next v11 6/8] bpf: Add syscall common attributes support for map_create Date: Mon, 16 Feb 2026 23:04:43 +0800 Message-ID: <20260216150445.68278-7-leon.hwang@linux.dev> In-Reply-To: <20260216150445.68278-1-leon.hwang@linux.dev> References: <20260216150445.68278-1-leon.hwang@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" Many BPF_MAP_CREATE validation failures currently return -EINVAL without any explanation to userspace. Plumb common syscall log attributes into map_create(), create a verifier log from bpf_common_attr::log_buf/log_size/log_level, and report map-creation failure reasons through that buffer. This improves debuggability by allowing userspace to inspect why map creation failed and read back log_true_size from common attributes. Signed-off-by: Leon Hwang --- include/linux/bpf_verifier.h | 3 ++ kernel/bpf/log.c | 30 +++++++++++++++++ kernel/bpf/syscall.c | 65 ++++++++++++++++++++++++++++++------ 3 files changed, 88 insertions(+), 10 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index de1d42a48af5..6e02081fa24b 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -644,6 +644,9 @@ struct bpf_log_attr { int bpf_log_attr_init(struct bpf_log_attr *log, u64 log_buf, u32 log_size,= u32 log_level, u32 __user *log_true_size, struct bpf_common_attr *common, bpfptr_= t uattr, u32 size); +struct bpf_verifier_log *bpf_log_attr_create_vlog(struct bpf_log_attr *att= r_log, + struct bpf_common_attr *common, bpfptr_t uattr, + u32 size); int bpf_log_attr_finalize(struct bpf_log_attr *attr, struct bpf_verifier_l= og *log); =20 #define BPF_MAX_SUBPROGS 256 diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c index a1c0c42b0b8c..c31d4cf17517 100644 --- a/kernel/bpf/log.c +++ b/kernel/bpf/log.c @@ -899,6 +899,36 @@ int bpf_log_attr_init(struct bpf_log_attr *log, u64 lo= g_buf, u32 log_size, u32 l return 0; } =20 + +struct bpf_verifier_log *bpf_log_attr_create_vlog(struct bpf_log_attr *att= r_log, + struct bpf_common_attr *common, bpfptr_t uattr, + u32 size) +{ + struct bpf_verifier_log *log; + int err; + + memset(attr_log, 0, sizeof(*attr_log)); + if (size >=3D offsetofend(struct bpf_common_attr, log_true_size)) + attr_log->log_true_size =3D uattr.user + offsetof(struct bpf_common_attr, + log_true_size); + + if (!common->log_buf) + return NULL; + + log =3D kzalloc_obj(*log, GFP_KERNEL); + if (!log) + return ERR_PTR(-ENOMEM); + + err =3D bpf_vlog_init(log, common->log_level, u64_to_user_ptr(common->log= _buf), + common->log_size); + if (err) { + kfree(log); + return ERR_PTR(err); + } + + return log; +} + int bpf_log_attr_finalize(struct bpf_log_attr *attr, struct bpf_verifier_l= og *log) { u32 log_true_size; diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index be66b824e4cf..6f89dbbceb64 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1366,7 +1366,7 @@ static int map_check_btf(struct bpf_map *map, struct = bpf_token *token, =20 #define BPF_MAP_CREATE_LAST_FIELD excl_prog_hash_size /* called via syscall */ -static int map_create(union bpf_attr *attr, bpfptr_t uattr) +static int __map_create(union bpf_attr *attr, bpfptr_t uattr, struct bpf_v= erifier_log *log) { const struct bpf_map_ops *ops; struct bpf_token *token =3D NULL; @@ -1378,8 +1378,10 @@ static int map_create(union bpf_attr *attr, bpfptr_t= uattr) int err; =20 err =3D CHECK_ATTR(BPF_MAP_CREATE); - if (err) + if (err) { + bpf_log(log, "Invalid attr.\n"); return -EINVAL; + } =20 /* check BPF_F_TOKEN_FD flag, remember if it's set, and then clear it * to avoid per-map type checks tripping on unknown flag @@ -1388,17 +1390,25 @@ static int map_create(union bpf_attr *attr, bpfptr_= t uattr) attr->map_flags &=3D ~BPF_F_TOKEN_FD; =20 if (attr->btf_vmlinux_value_type_id) { - if (attr->map_type !=3D BPF_MAP_TYPE_STRUCT_OPS || - attr->btf_key_type_id || attr->btf_value_type_id) + if (attr->map_type !=3D BPF_MAP_TYPE_STRUCT_OPS) { + bpf_log(log, "btf_vmlinux_value_type_id can only be used with struct_op= s maps.\n"); return -EINVAL; + } + if (attr->btf_key_type_id || attr->btf_value_type_id) { + bpf_log(log, "btf_vmlinux_value_type_id is mutually exclusive with btf_= key_type_id and btf_value_type_id.\n"); + return -EINVAL; + } } else if (attr->btf_key_type_id && !attr->btf_value_type_id) { + bpf_log(log, "Invalid btf_value_type_id.\n"); return -EINVAL; } =20 if (attr->map_type !=3D BPF_MAP_TYPE_BLOOM_FILTER && attr->map_type !=3D BPF_MAP_TYPE_ARENA && - attr->map_extra !=3D 0) + attr->map_extra !=3D 0) { + bpf_log(log, "Invalid map_extra.\n"); return -EINVAL; + } =20 f_flags =3D bpf_get_file_flag(attr->map_flags); if (f_flags < 0) @@ -1406,13 +1416,17 @@ static int map_create(union bpf_attr *attr, bpfptr_= t uattr) =20 if (numa_node !=3D NUMA_NO_NODE && ((unsigned int)numa_node >=3D nr_node_ids || - !node_online(numa_node))) + !node_online(numa_node))) { + bpf_log(log, "Invalid numa_node.\n"); return -EINVAL; + } =20 /* find map type and init map: hashtable vs rbtree vs bloom vs ... */ map_type =3D attr->map_type; - if (map_type >=3D ARRAY_SIZE(bpf_map_types)) + if (map_type >=3D ARRAY_SIZE(bpf_map_types)) { + bpf_log(log, "Invalid map_type.\n"); return -EINVAL; + } map_type =3D array_index_nospec(map_type, ARRAY_SIZE(bpf_map_types)); ops =3D bpf_map_types[map_type]; if (!ops) @@ -1430,8 +1444,10 @@ static int map_create(union bpf_attr *attr, bpfptr_t= uattr) =20 if (token_flag) { token =3D bpf_token_get_from_fd(attr->map_token_fd); - if (IS_ERR(token)) + if (IS_ERR(token)) { + bpf_log(log, "Invalid map_token_fd.\n"); return PTR_ERR(token); + } =20 /* if current token doesn't grant map creation permissions, * then we can't use this token, so ignore it and rely on @@ -1514,8 +1530,10 @@ static int map_create(union bpf_attr *attr, bpfptr_t= uattr) =20 err =3D bpf_obj_name_cpy(map->name, attr->map_name, sizeof(attr->map_name)); - if (err < 0) + if (err < 0) { + bpf_log(log, "Invalid map_name.\n"); goto free_map; + } =20 preempt_disable(); map->cookie =3D gen_cookie_next(&bpf_map_cookie); @@ -1538,6 +1556,7 @@ static int map_create(union bpf_attr *attr, bpfptr_t = uattr) =20 btf =3D btf_get_by_fd(attr->btf_fd); if (IS_ERR(btf)) { + bpf_log(log, "Invalid btf_fd.\n"); err =3D PTR_ERR(btf); goto free_map; } @@ -1565,6 +1584,7 @@ static int map_create(union bpf_attr *attr, bpfptr_t = uattr) bpfptr_t uprog_hash =3D make_bpfptr(attr->excl_prog_hash, uattr.is_kerne= l); =20 if (attr->excl_prog_hash_size !=3D SHA256_DIGEST_SIZE) { + bpf_log(log, "Invalid excl_prog_hash_size.\n"); err =3D -EINVAL; goto free_map; } @@ -1580,6 +1600,7 @@ static int map_create(union bpf_attr *attr, bpfptr_t = uattr) goto free_map; } } else if (attr->excl_prog_hash_size) { + bpf_log(log, "Invalid excl_prog_hash_size.\n"); err =3D -EINVAL; goto free_map; } @@ -1618,6 +1639,30 @@ static int map_create(union bpf_attr *attr, bpfptr_t= uattr) return err; } =20 +static int map_create(union bpf_attr *attr, bpfptr_t uattr, struct bpf_com= mon_attr *attr_common, + bpfptr_t uattr_common, u32 size_common) +{ + struct bpf_verifier_log *log; + struct bpf_log_attr attr_log; + int err, ret; + + log =3D bpf_log_attr_create_vlog(&attr_log, attr_common, uattr_common, si= ze_common); + if (IS_ERR(log)) + return PTR_ERR(log); + + err =3D __map_create(attr, uattr, log); + if (err >=3D 0) + goto free; + + ret =3D bpf_log_attr_finalize(&attr_log, log); + if (ret) + err =3D ret; + +free: + kfree(log); + return err; +} + void bpf_map_inc(struct bpf_map *map) { atomic64_inc(&map->refcnt); @@ -6227,7 +6272,7 @@ static int __sys_bpf(enum bpf_cmd cmd, bpfptr_t uattr= , unsigned int size, =20 switch (cmd) { case BPF_MAP_CREATE: - err =3D map_create(&attr, uattr); + err =3D map_create(&attr, uattr, &attr_common, uattr_common, size_common= ); break; case BPF_MAP_LOOKUP_ELEM: err =3D map_lookup_elem(&attr); --=20 2.52.0