Message ID | 20241217103629.2383809-1-alan.maguire@oracle.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | [dwarves] btf_encoder: verify 0 address DWARF variables are really in ELF section | expand |
Context | Check | Description |
---|---|---|
netdev/tree_selection | success | Not a local patch |
On Tue, Dec 17, 2024 at 10:36:29AM +0000, Alan Maguire wrote: > We use the DWARF location information to match a variable with its > associated ELF section. In the case of per-CPU variables their > ELF section address range starts at 0, so any 0 address variables will > appear to belong in that ELF section. However, for "discard" sections > DWARF encodes the associated variables with address location 0 so > we need to double-check that address 0 variables really are in the > associated section by checking the ELF symbol table. > > This resolves an issue exposed by CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y > kernel builds where __pcpu_* dummary variables in a .discard section > get misclassified as belonging in the per-CPU variable section since > they specify location address 0. > > Reported-by: Cong Wang <xiyou.wangcong@gmail.com> > Signed-off-by: Alan Maguire <alan.maguire@oracle.com> Tested/Acked-by: Jiri Olsa <jolsa@kernel.org> thanks, jirka > --- > btf_encoder.c | 27 +++++++++++++++++++++++++++ > 1 file changed, 27 insertions(+) > > diff --git a/btf_encoder.c b/btf_encoder.c > index 3754884..04f547c 100644 > --- a/btf_encoder.c > +++ b/btf_encoder.c > @@ -2189,6 +2189,26 @@ static bool filter_variable_name(const char *name) > return false; > } > > +bool variable_in_sec(struct btf_encoder *encoder, const char *name, size_t shndx) > +{ > + uint32_t sym_sec_idx; > + uint32_t core_id; > + GElf_Sym sym; > + > + elf_symtab__for_each_symbol_index(encoder->symtab, core_id, sym, sym_sec_idx) { > + const char *sym_name; > + > + if (sym_sec_idx != shndx || elf_sym__type(&sym) != STT_OBJECT) > + continue; > + sym_name = elf_sym__name(&sym, encoder->symtab); > + if (!sym_name) > + continue; > + if (strcmp(name, sym_name) == 0) > + return true; > + } > + return false; > +} > + > static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder) > { > struct cu *cu = encoder->cu; > @@ -2258,6 +2278,13 @@ static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder) > if (filter_variable_name(name)) > continue; > > + /* A 0 address may be in a "discard" section; DWARF provides > + * location information with address 0 for such variables. > + * Ensure the variable really is in this section by checking > + * the ELF symtab. > + */ > + if (addr == 0 && !variable_in_sec(encoder, name, shndx)) > + continue; > /* Check for invalid BTF names */ > if (!btf_name_valid(name)) { > dump_invalid_symbol("Found invalid variable name when encoding btf", > -- > 2.31.1 >
Alan Maguire <alan.maguire@oracle.com> writes: > We use the DWARF location information to match a variable with its > associated ELF section. In the case of per-CPU variables their > ELF section address range starts at 0, so any 0 address variables will > appear to belong in that ELF section. However, for "discard" sections > DWARF encodes the associated variables with address location 0 so > we need to double-check that address 0 variables really are in the > associated section by checking the ELF symbol table. > > This resolves an issue exposed by CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y > kernel builds where __pcpu_* dummary variables in a .discard section > get misclassified as belonging in the per-CPU variable section since > they specify location address 0. > > Reported-by: Cong Wang <xiyou.wangcong@gmail.com> > Signed-off-by: Alan Maguire <alan.maguire@oracle.com> Reviewed-by: Stephen Brennan <stephen.s.brennan@oracle.com> > --- > btf_encoder.c | 27 +++++++++++++++++++++++++++ > 1 file changed, 27 insertions(+) > > diff --git a/btf_encoder.c b/btf_encoder.c > index 3754884..04f547c 100644 > --- a/btf_encoder.c > +++ b/btf_encoder.c > @@ -2189,6 +2189,26 @@ static bool filter_variable_name(const char *name) > return false; > } > > +bool variable_in_sec(struct btf_encoder *encoder, const char *name, size_t shndx) > +{ > + uint32_t sym_sec_idx; > + uint32_t core_id; > + GElf_Sym sym; > + > + elf_symtab__for_each_symbol_index(encoder->symtab, core_id, sym, sym_sec_idx) { > + const char *sym_name; > + > + if (sym_sec_idx != shndx || elf_sym__type(&sym) != STT_OBJECT) > + continue; > + sym_name = elf_sym__name(&sym, encoder->symtab); > + if (!sym_name) > + continue; > + if (strcmp(name, sym_name) == 0) > + return true; > + } > + return false; > +} > + > static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder) > { > struct cu *cu = encoder->cu; > @@ -2258,6 +2278,13 @@ static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder) > if (filter_variable_name(name)) > continue; > > + /* A 0 address may be in a "discard" section; DWARF provides > + * location information with address 0 for such variables. > + * Ensure the variable really is in this section by checking > + * the ELF symtab. > + */ > + if (addr == 0 && !variable_in_sec(encoder, name, shndx)) > + continue; > /* Check for invalid BTF names */ > if (!btf_name_valid(name)) { > dump_invalid_symbol("Found invalid variable name when encoding btf", > -- > 2.31.1
diff --git a/btf_encoder.c b/btf_encoder.c index 3754884..04f547c 100644 --- a/btf_encoder.c +++ b/btf_encoder.c @@ -2189,6 +2189,26 @@ static bool filter_variable_name(const char *name) return false; } +bool variable_in_sec(struct btf_encoder *encoder, const char *name, size_t shndx) +{ + uint32_t sym_sec_idx; + uint32_t core_id; + GElf_Sym sym; + + elf_symtab__for_each_symbol_index(encoder->symtab, core_id, sym, sym_sec_idx) { + const char *sym_name; + + if (sym_sec_idx != shndx || elf_sym__type(&sym) != STT_OBJECT) + continue; + sym_name = elf_sym__name(&sym, encoder->symtab); + if (!sym_name) + continue; + if (strcmp(name, sym_name) == 0) + return true; + } + return false; +} + static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder) { struct cu *cu = encoder->cu; @@ -2258,6 +2278,13 @@ static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder) if (filter_variable_name(name)) continue; + /* A 0 address may be in a "discard" section; DWARF provides + * location information with address 0 for such variables. + * Ensure the variable really is in this section by checking + * the ELF symtab. + */ + if (addr == 0 && !variable_in_sec(encoder, name, shndx)) + continue; /* Check for invalid BTF names */ if (!btf_name_valid(name)) { dump_invalid_symbol("Found invalid variable name when encoding btf",
We use the DWARF location information to match a variable with its associated ELF section. In the case of per-CPU variables their ELF section address range starts at 0, so any 0 address variables will appear to belong in that ELF section. However, for "discard" sections DWARF encodes the associated variables with address location 0 so we need to double-check that address 0 variables really are in the associated section by checking the ELF symbol table. This resolves an issue exposed by CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y kernel builds where __pcpu_* dummary variables in a .discard section get misclassified as belonging in the per-CPU variable section since they specify location address 0. Reported-by: Cong Wang <xiyou.wangcong@gmail.com> Signed-off-by: Alan Maguire <alan.maguire@oracle.com> --- btf_encoder.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)