bpf/btf: Accept function names that contain dots
[ Upstream commit 9724160b3942b0a967b91a59f81da5593f28b8ba ]
When building a kernel with LLVM=1, LLVM_IAS=0 and CONFIG_KASAN=y, LLVM
leaves DWARF tags for the "asan.module_ctor" & co symbols. In turn,
pahole creates BTF_KIND_FUNC entries for these and this makes the BTF
metadata validation fail because they contain a dot.
In a dramatic turn of event, this BTF verification failure can cause
the netfilter_bpf initialization to fail, causing netfilter_core to
free the netfilter_helper hashmap and netfilter_ftp to trigger a
use-after-free. The risk of u-a-f in netfilter will be addressed
separately but the existence of "asan.module_ctor" debug info under some
build conditions sounds like a good enough reason to accept functions
that contain dots in BTF.
Although using only LLVM=1 is the recommended way to compile clang-based
kernels, users can certainly do LLVM=1, LLVM_IAS=0 as well and we still
try to support that combination according to Nick. To clarify:
- > v5.10 kernel, LLVM=1 (LLVM_IAS=0 is not the default) is recommended,
but user can still have LLVM=1, LLVM_IAS=0 to trigger the issue
- <= 5.10 kernel, LLVM=1 (LLVM_IAS=0 is the default) is recommended in
which case GNU as will be used
Fixes: 1dc9285184
("bpf: kernel side support for BTF Var and DataSec")
Signed-off-by: Florent Revest <revest@chromium.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Cc: Yonghong Song <yhs@meta.com>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Link: https://lore.kernel.org/bpf/20230615145607.3469985-1-revest@chromium.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
8b7454dd98
commit
29917a20be
@@ -604,31 +604,30 @@ static bool btf_name_offset_valid(const struct btf *btf, u32 offset)
|
|||||||
offset < btf->hdr.str_len;
|
offset < btf->hdr.str_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool __btf_name_char_ok(char c, bool first, bool dot_ok)
|
static bool __btf_name_char_ok(char c, bool first)
|
||||||
{
|
{
|
||||||
if ((first ? !isalpha(c) :
|
if ((first ? !isalpha(c) :
|
||||||
!isalnum(c)) &&
|
!isalnum(c)) &&
|
||||||
c != '_' &&
|
c != '_' &&
|
||||||
((c == '.' && !dot_ok) ||
|
c != '.')
|
||||||
c != '.'))
|
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool __btf_name_valid(const struct btf *btf, u32 offset, bool dot_ok)
|
static bool __btf_name_valid(const struct btf *btf, u32 offset)
|
||||||
{
|
{
|
||||||
/* offset must be valid */
|
/* offset must be valid */
|
||||||
const char *src = &btf->strings[offset];
|
const char *src = &btf->strings[offset];
|
||||||
const char *src_limit;
|
const char *src_limit;
|
||||||
|
|
||||||
if (!__btf_name_char_ok(*src, true, dot_ok))
|
if (!__btf_name_char_ok(*src, true))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* set a limit on identifier length */
|
/* set a limit on identifier length */
|
||||||
src_limit = src + KSYM_NAME_LEN;
|
src_limit = src + KSYM_NAME_LEN;
|
||||||
src++;
|
src++;
|
||||||
while (*src && src < src_limit) {
|
while (*src && src < src_limit) {
|
||||||
if (!__btf_name_char_ok(*src, false, dot_ok))
|
if (!__btf_name_char_ok(*src, false))
|
||||||
return false;
|
return false;
|
||||||
src++;
|
src++;
|
||||||
}
|
}
|
||||||
@@ -636,17 +635,14 @@ static bool __btf_name_valid(const struct btf *btf, u32 offset, bool dot_ok)
|
|||||||
return !*src;
|
return !*src;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only C-style identifier is permitted. This can be relaxed if
|
|
||||||
* necessary.
|
|
||||||
*/
|
|
||||||
static bool btf_name_valid_identifier(const struct btf *btf, u32 offset)
|
static bool btf_name_valid_identifier(const struct btf *btf, u32 offset)
|
||||||
{
|
{
|
||||||
return __btf_name_valid(btf, offset, false);
|
return __btf_name_valid(btf, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool btf_name_valid_section(const struct btf *btf, u32 offset)
|
static bool btf_name_valid_section(const struct btf *btf, u32 offset)
|
||||||
{
|
{
|
||||||
return __btf_name_valid(btf, offset, true);
|
return __btf_name_valid(btf, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *__btf_name_by_offset(const struct btf *btf, u32 offset)
|
static const char *__btf_name_by_offset(const struct btf *btf, u32 offset)
|
||||||
@@ -3417,7 +3413,7 @@ static s32 btf_var_check_meta(struct btf_verifier_env *env,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!t->name_off ||
|
if (!t->name_off ||
|
||||||
!__btf_name_valid(env->btf, t->name_off, true)) {
|
!__btf_name_valid(env->btf, t->name_off)) {
|
||||||
btf_verifier_log_type(env, t, "Invalid name");
|
btf_verifier_log_type(env, t, "Invalid name");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user