Skip to content

Commit 2f2a5be

Browse files
[llvm-objdump] Error with relevant message when adding invalid notes
Also add a --no-verify-note-sections flag to make it possible to add invalid sections if needs be.
1 parent c2f92a3 commit 2f2a5be

File tree

5 files changed

+105
-6
lines changed

5 files changed

+105
-6
lines changed

llvm/include/llvm/ObjCopy/CommonConfig.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ struct CommonConfig {
258258
bool StripNonAlloc = false;
259259
bool StripSections = false;
260260
bool StripUnneeded = false;
261+
bool VerifyNoteSections = true;
261262
bool Weaken = false;
262263
bool DecompressDebugSections = false;
263264

llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp

Lines changed: 65 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, endianness Endianness,
627+
ArrayRef<uint8_t> Data) {
628+
// An ELF note has the following structure:
629+
// Name Size: 4 bytes (integer)
630+
// Desc Size: 4 bytes (integer)
631+
// Type : 4 bytes
632+
// Name : variable size, padded to a 4 byte boundary
633+
// Desc : variable size, padded to a 4 byte boundary
634+
635+
if (Data.empty())
636+
return Error::success();
637+
638+
if (Data.size() < 12) {
639+
std::string msg;
640+
raw_string_ostream(msg)
641+
<< Name << " data must be either empty or at least 12 bytes long";
642+
return createStringError(errc::invalid_argument, msg);
643+
}
644+
if (Data.size() % 4 != 0) {
645+
std::string msg;
646+
raw_string_ostream(msg)
647+
<< Name << " data size must be a multiple of 4 bytes";
648+
return createStringError(errc::invalid_argument, msg);
649+
}
650+
ArrayRef<uint8_t> NameSize = Data.slice(0, 4);
651+
ArrayRef<uint8_t> DescSize = Data.slice(4, 4);
652+
653+
uint32_t NameSizeValue = *reinterpret_cast<const uint32_t *>(NameSize.data());
654+
uint32_t DescSizeValue = *reinterpret_cast<const uint32_t *>(DescSize.data());
655+
656+
if (Endianness != llvm::endianness::native) {
657+
NameSizeValue = byteswap(NameSizeValue);
658+
DescSizeValue = byteswap(DescSizeValue);
659+
}
660+
uint64_t ExpectedDataSize =
661+
/*NameSize=*/4 + /*DescSize=*/4 + /*Type=*/4 +
662+
/*Name=*/(NameSizeValue + 3) / 4 * 4 +
663+
/*Desc=*/(DescSizeValue + 3) / 4 * 4;
664+
uint64_t ActualDataSize = Data.size();
665+
if (ActualDataSize != ExpectedDataSize) {
666+
std::string msg;
667+
raw_string_ostream(msg)
668+
<< Name
669+
<< " data size is incompatible with the content of "
670+
"the name and description size fields:"
671+
<< " expecting " << ExpectedDataSize << ", found " << 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,19 @@ 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+
if (Config.VerifyNoteSections)
741+
return verifyNoteSection(Name, E, Data);
742+
}
684743
return Error::success();
685744
};
686745
if (Error E = handleUserSection(AddedSection, AddSection))
@@ -813,7 +872,7 @@ Error objcopy::elf::executeObjcopyOnIHex(const CommonConfig &Config,
813872

814873
const ElfType OutputElfType =
815874
getOutputElfType(Config.OutputArch.value_or(MachineInfo()));
816-
if (Error E = handleArgs(Config, ELFConfig, **Obj))
875+
if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))
817876
return E;
818877
return writeOutput(Config, **Obj, Out, OutputElfType);
819878
}
@@ -831,7 +890,7 @@ Error objcopy::elf::executeObjcopyOnRawBinary(const CommonConfig &Config,
831890
// (-B<arch>).
832891
const ElfType OutputElfType =
833892
getOutputElfType(Config.OutputArch.value_or(MachineInfo()));
834-
if (Error E = handleArgs(Config, ELFConfig, **Obj))
893+
if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj))
835894
return E;
836895
return writeOutput(Config, **Obj, Out, OutputElfType);
837896
}
@@ -850,7 +909,7 @@ Error objcopy::elf::executeObjcopyOnBinary(const CommonConfig &Config,
850909
? getOutputElfType(*Config.OutputArch)
851910
: getOutputElfType(In);
852911

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

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

llvm/tools/llvm-objcopy/ObjcopyOptions.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -943,6 +943,8 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
943943
? DiscardType::All
944944
: DiscardType::Locals;
945945
}
946+
Config.VerifyNoteSections =
947+
!InputArgs.hasArg(OBJCOPY_no_verify_note_sections);
946948
Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
947949
ELFConfig.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
948950
MachOConfig.KeepUndefined = InputArgs.hasArg(OBJCOPY_keep_undefined);

llvm/tools/llvm-objcopy/ObjcopyOpts.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,9 @@ def G : JoinedOrSeparate<["-"], "G">,
176176
Alias<keep_global_symbol>,
177177
HelpText<"Alias for --keep-global-symbol">;
178178

179+
def no_verify_note_sections : Flag<["--"], "no-verify-note-sections">,
180+
HelpText<"Disable note section validation">;
181+
179182
defm keep_global_symbols
180183
: Eq<"keep-global-symbols",
181184
"Read a list of symbols from <filename> and run as if "

0 commit comments

Comments
 (0)