Skip to content

Commit 2aaf91d

Browse files
[llvm-objdump] Error with relevant message when adding invalid notes
1 parent 15f0272 commit 2aaf91d

File tree

2 files changed

+99
-6
lines changed

2 files changed

+99
-6
lines changed

llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,58 @@ handleUserSection(const NewSectionInfo &NewSection,
623623
return F(NewSection.SectionName, Data);
624624
}
625625

626+
static Error verifyNoteSection(StringRef Name, llvm::endianness E,
627+
ArrayRef<uint8_t> Data) {
628+
629+
// An ELF note have the following structure:
630+
// Name Size: 4 bytes (integer)
631+
// Desc Size: 4 bytes (integer)
632+
// Type : 4 bytes
633+
// Name : variable size, padded to a 4 byte boundary
634+
// Desc : variable size, padded to a 4 byte boundary
635+
636+
if (Data.empty())
637+
return Error::success();
638+
639+
if (Data.size() < 12) {
640+
std::string msg;
641+
raw_string_ostream(msg)
642+
<< Name << " data must be either empty or at least 12 bytes long.";
643+
return createStringError(errc::invalid_argument, msg);
644+
}
645+
if (Data.size() % 4 != 0) {
646+
std::string msg;
647+
raw_string_ostream(msg)
648+
<< Name << " data size must be a multiple of 4 bytes.";
649+
return createStringError(errc::invalid_argument, msg);
650+
}
651+
ArrayRef<uint8_t> NameSize = Data.slice(0, 4);
652+
ArrayRef<uint8_t> DescSize = Data.slice(4, 4);
653+
654+
uint32_t NameSizeValue, DescSizeValue;
655+
std::memcpy(&NameSizeValue, NameSize.data(), 4);
656+
std::memcpy(&DescSizeValue, DescSize.data(), 4);
657+
658+
if (llvm::endianness::native != E) {
659+
NameSizeValue = byteswap(NameSizeValue);
660+
DescSizeValue = byteswap(DescSizeValue);
661+
}
662+
uint64_t ExpectedDataSize =
663+
4 + 4 + 4 + (NameSizeValue + 3) / 4 * 4 + (DescSizeValue + 3) / 4 * 4;
664+
uint64_t ActualDataSize = Data.size();
665+
if (ActualDataSize != ExpectedDataSize) {
666+
std::string msg;
667+
raw_string_ostream(msg) << Name
668+
<< " data size is incompatible with the content of "
669+
"the name and description size fields:"
670+
<< " expecting " << ExpectedDataSize << ", found "
671+
<< ActualDataSize << ".";
672+
return createStringError(errc::invalid_argument, msg);
673+
}
674+
675+
return Error::success();
676+
}
677+
626678
// This function handles the high level operations of GNU objcopy including
627679
// handling command line options. It's important to outline certain properties
628680
// we expect to hold of the command line operations. Any operation that "keeps"
@@ -631,7 +683,7 @@ handleUserSection(const NewSectionInfo &NewSection,
631683
// depend a) on the order the options occur in or b) on some opaque priority
632684
// system. The only priority is that keeps/copies overrule removes.
633685
static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
634-
Object &Obj) {
686+
ElfType OutputElfType, Object &Obj) {
635687
if (Config.OutputArch) {
636688
Obj.Machine = Config.OutputArch->EMachine;
637689
Obj.OSABI = Config.OutputArch->OSABI;
@@ -675,12 +727,18 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
675727
if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE)
676728
Sec.Type = SHT_NOBITS;
677729

730+
endianness E = OutputElfType == ELFT_ELF32LE || OutputElfType == ELFT_ELF64LE
731+
? endianness::little
732+
: endianness::big;
733+
678734
for (const NewSectionInfo &AddedSection : Config.AddSection) {
679-
auto AddSection = [&](StringRef Name, ArrayRef<uint8_t> Data) {
735+
auto AddSection = [&](StringRef Name, ArrayRef<uint8_t> Data) -> Error {
680736
OwnedDataSection &NewSection =
681737
Obj.addSection<OwnedDataSection>(Name, Data);
682-
if (Name.starts_with(".note") && Name != ".note.GNU-stack")
738+
if (Name.starts_with(".note") && Name != ".note.GNU-stack") {
683739
NewSection.Type = SHT_NOTE;
740+
return verifyNoteSection(Name, E, Data);
741+
}
684742
return Error::success();
685743
};
686744
if (Error E = handleUserSection(AddedSection, AddSection))
@@ -813,7 +871,7 @@ Error objcopy::elf::executeObjcopyOnIHex(const CommonConfig &Config,
813871

814872
const ElfType OutputElfType =
815873
getOutputElfType(Config.OutputArch.value_or(MachineInfo()));
816-
if (Error E = handleArgs(Config, ELFConfig, **Obj))
874+
if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))
817875
return E;
818876
return writeOutput(Config, **Obj, Out, OutputElfType);
819877
}
@@ -831,7 +889,7 @@ Error objcopy::elf::executeObjcopyOnRawBinary(const CommonConfig &Config,
831889
// (-B<arch>).
832890
const ElfType OutputElfType =
833891
getOutputElfType(Config.OutputArch.value_or(MachineInfo()));
834-
if (Error E = handleArgs(Config, ELFConfig, **Obj))
892+
if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))
835893
return E;
836894
return writeOutput(Config, **Obj, Out, OutputElfType);
837895
}
@@ -850,7 +908,7 @@ Error objcopy::elf::executeObjcopyOnBinary(const CommonConfig &Config,
850908
? getOutputElfType(*Config.OutputArch)
851909
: getOutputElfType(In);
852910

853-
if (Error E = handleArgs(Config, ELFConfig, **Obj))
911+
if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))
854912
return createFileError(Config.InputFilename, std::move(E));
855913

856914
if (Error E = writeOutput(Config, **Obj, Out, OutputElfType))
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Verify that --add-section can be used to add a note section which is
2+
# successfully interpreted by tools that read notes.
3+
4+
# Add [namesz, descsz, type, name, desc] for a build id.
5+
#
6+
# RUN: echo -e -n "\x04\x00\x00\x00" > %t-miss-padding-note.bin
7+
# RUN: echo -e -n "\x07\x00\x00\x00" >> %t-miss-padding-note.bin
8+
# RUN: echo -e -n "\x03\x00\x00\x00" >> %t-miss-padding-note.bin
9+
# RUN: echo -e -n "GNU\x00" >> %t-miss-padding-note.bin
10+
# RUN: echo -e -n "\x0c\x0d\x0e" >> %t-miss-padding-note.bin
11+
#
12+
# RUN: echo -e -n "\x08\x00\x00\x00" > %t-invalid-size-note.bin
13+
# RUN: echo -e -n "\x07\x00\x00\x00" >> %t-invalid-size-note.bin
14+
# RUN: echo -e -n "\x03\x00\x00\x00" >> %t-invalid-size-note.bin
15+
# RUN: echo -e -n "GNU\x00" >> %t-invalid-size-note.bin
16+
# RUN: echo -e -n "\x0c\x0d\x0e\x00" >> %t-invalid-size-note.bin
17+
18+
# RUN: echo -e -n "\x08\x00\x00\x00" > %t-short-note.bin
19+
# RUN: echo -e -n "\x07\x00\x00\x00" >> %t-short-note.bin
20+
21+
# RUN: yaml2obj %s -o %t.o
22+
# RUN: not llvm-objcopy --add-section=.note.miss.padding=%t-miss-padding-note.bin %t.o %t-with-note.o 2>&1 | FileCheck --check-prefix=CHECK-MISS-PADDING %s
23+
# RUN: not llvm-objcopy --add-section=.note.invalid.size=%t-invalid-size-note.bin %t.o %t-with-note.o 2>&1 | FileCheck --check-prefix=CHECK-INVALID-SIZE %s
24+
# RUN: not llvm-objcopy --add-section=.note.short=%t-short-note.bin %t.o %t-with-note.o 2>&1 | FileCheck --check-prefix=CHECK-SHORT %s
25+
26+
!ELF
27+
FileHeader:
28+
Class: ELFCLASS64
29+
Data: ELFDATA2LSB
30+
Type: ET_REL
31+
Machine: EM_X86_64
32+
33+
# CHECK-MISS-PADDING: .note.miss.padding data size must be a multiple of 4 bytes.
34+
# CHECK-INVALID-SIZE: .note.invalid.size data size is incompatible with the content of the name and description size fields: expecting 28, found 20.
35+
# CHECK-SHORT: .note.short data must be either empty or at least 12 bytes long.

0 commit comments

Comments
 (0)