-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[llvm-objcopy] Add verification of added .note section format #90458
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
7483002
f3c0f53
1a4aa18
2c82ed7
36daa11
a9e09b8
6861413
bb4ca67
8c4abe2
1f4dc6b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -623,6 +623,54 @@ handleUserSection(const NewSectionInfo &NewSection, | |
return F(NewSection.SectionName, Data); | ||
} | ||
|
||
static Error verifyNoteSection(StringRef Name, endianness Endianness, | ||
ArrayRef<uint8_t> Data) { | ||
// An ELF note has the following structure: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Random thought: I wonder if there's a way to leverage existing code in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems possible to hook in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note: one note section may contain multiple notes. There is some alignment complexity. See https://reviews.llvm.org/D150022 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I always get confused about .note and alignment behaviours. Are you suggesting @MaskRay that some action needs taking here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some note sections ( |
||
// Name Size: 4 bytes (integer) | ||
// Desc Size: 4 bytes (integer) | ||
// Type : 4 bytes | ||
// Name : variable size, padded to a 4 byte boundary | ||
// Desc : variable size, padded to a 4 byte boundary | ||
|
||
if (Data.empty()) | ||
return Error::success(); | ||
|
||
if (Data.size() < 12) { | ||
std::string msg; | ||
raw_string_ostream(msg) | ||
<< Name << " data must be either empty or at least 12 bytes long"; | ||
return createStringError(errc::invalid_argument, msg); | ||
} | ||
if (Data.size() % 4 != 0) { | ||
std::string msg; | ||
raw_string_ostream(msg) | ||
<< Name << " data size must be a multiple of 4 bytes"; | ||
return createStringError(errc::invalid_argument, msg); | ||
} | ||
ArrayRef<uint8_t> NameSize = Data.slice(0, 4); | ||
ArrayRef<uint8_t> DescSize = Data.slice(4, 4); | ||
|
||
uint32_t NameSizeValue = support::endian::read32(NameSize.data(), Endianness); | ||
uint32_t DescSizeValue = support::endian::read32(DescSize.data(), Endianness); | ||
|
||
uint64_t ExpectedDataSize = | ||
/*NameSize=*/4 + /*DescSize=*/4 + /*Type=*/4 + | ||
/*Name=*/alignTo(NameSizeValue, 4) + | ||
/*Desc=*/alignTo(DescSizeValue, 4); | ||
uint64_t ActualDataSize = Data.size(); | ||
if (ActualDataSize != ExpectedDataSize) { | ||
std::string msg; | ||
raw_string_ostream(msg) | ||
<< Name | ||
<< " data size is incompatible with the content of " | ||
"the name and description size fields:" | ||
<< " expecting " << ExpectedDataSize << ", found " << ActualDataSize; | ||
return createStringError(errc::invalid_argument, msg); | ||
} | ||
|
||
return Error::success(); | ||
} | ||
|
||
// This function handles the high level operations of GNU objcopy including | ||
// handling command line options. It's important to outline certain properties | ||
// we expect to hold of the command line operations. Any operation that "keeps" | ||
|
@@ -631,7 +679,7 @@ handleUserSection(const NewSectionInfo &NewSection, | |
// depend a) on the order the options occur in or b) on some opaque priority | ||
// system. The only priority is that keeps/copies overrule removes. | ||
static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig, | ||
Object &Obj) { | ||
ElfType OutputElfType, Object &Obj) { | ||
if (Config.OutputArch) { | ||
Obj.Machine = Config.OutputArch->EMachine; | ||
Obj.OSABI = Config.OutputArch->OSABI; | ||
|
@@ -702,12 +750,19 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig, | |
if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE) | ||
Sec.Type = SHT_NOBITS; | ||
|
||
endianness E = OutputElfType == ELFT_ELF32LE || OutputElfType == ELFT_ELF64LE | ||
? endianness::little | ||
: endianness::big; | ||
|
||
for (const NewSectionInfo &AddedSection : Config.AddSection) { | ||
auto AddSection = [&](StringRef Name, ArrayRef<uint8_t> Data) { | ||
auto AddSection = [&](StringRef Name, ArrayRef<uint8_t> Data) -> Error { | ||
OwnedDataSection &NewSection = | ||
Obj.addSection<OwnedDataSection>(Name, Data); | ||
if (Name.starts_with(".note") && Name != ".note.GNU-stack") | ||
if (Name.starts_with(".note") && Name != ".note.GNU-stack") { | ||
NewSection.Type = SHT_NOTE; | ||
if (ELFConfig.VerifyNoteSections) | ||
return verifyNoteSection(Name, E, Data); | ||
} | ||
return Error::success(); | ||
}; | ||
if (Error E = handleUserSection(AddedSection, AddSection)) | ||
|
@@ -840,7 +895,7 @@ Error objcopy::elf::executeObjcopyOnIHex(const CommonConfig &Config, | |
|
||
const ElfType OutputElfType = | ||
getOutputElfType(Config.OutputArch.value_or(MachineInfo())); | ||
if (Error E = handleArgs(Config, ELFConfig, **Obj)) | ||
if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj)) | ||
return E; | ||
return writeOutput(Config, **Obj, Out, OutputElfType); | ||
} | ||
|
@@ -858,7 +913,7 @@ Error objcopy::elf::executeObjcopyOnRawBinary(const CommonConfig &Config, | |
// (-B<arch>). | ||
const ElfType OutputElfType = | ||
getOutputElfType(Config.OutputArch.value_or(MachineInfo())); | ||
if (Error E = handleArgs(Config, ELFConfig, **Obj)) | ||
if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj)) | ||
return E; | ||
return writeOutput(Config, **Obj, Out, OutputElfType); | ||
} | ||
|
@@ -877,7 +932,7 @@ Error objcopy::elf::executeObjcopyOnBinary(const CommonConfig &Config, | |
? getOutputElfType(*Config.OutputArch) | ||
: getOutputElfType(In); | ||
|
||
if (Error E = handleArgs(Config, ELFConfig, **Obj)) | ||
if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj)) | ||
return createFileError(Config.InputFilename, std::move(E)); | ||
|
||
if (Error E = writeOutput(Config, **Obj, Out, OutputElfType)) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
## Verify that --add-section warns on invalid note sections. | ||
|
||
## Add [namesz, descsz, type, name, desc] for a build id. | ||
|
||
## Notes should be padded to 8 bytes. | ||
# RUN: printf "\x04\x00\x00\x00" > %t-miss-padding-note.bin | ||
# RUN: printf "\x07\x00\x00\x00" >> %t-miss-padding-note.bin | ||
# RUN: printf "\x03\x00\x00\x00" >> %t-miss-padding-note.bin | ||
# RUN: printf "GNU\x00" >> %t-miss-padding-note.bin | ||
# RUN: printf "\x0c\x0d\x0e" >> %t-miss-padding-note.bin | ||
|
||
## The namesz field bit is incorrect. | ||
# RUN: printf "\x08\x00\x00\x00" > %t-invalid-size-note.bin | ||
# RUN: printf "\x07\x00\x00\x00" >> %t-invalid-size-note.bin | ||
# RUN: printf "\x03\x00\x00\x00" >> %t-invalid-size-note.bin | ||
# RUN: printf "GNU\x00" >> %t-invalid-size-note.bin | ||
# RUN: printf "\x0c\x0d\x0e\x00" >> %t-invalid-size-note.bin | ||
|
||
## Missing type field. | ||
# RUN: printf "\x08\x00\x00\x00" > %t-short-note.bin | ||
# RUN: printf "\x07\x00\x00\x00" >> %t-short-note.bin | ||
|
||
# RUN: yaml2obj %s -o %t.o | ||
|
||
## Test each invalid note. | ||
# 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 | ||
serge-sans-paille marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# CHECK-MISS-PADDING: .note.miss.padding data size must be a multiple of 4 bytes | ||
|
||
# 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 | ||
# CHECK-INVALID-SIZE: .note.invalid.size data size is incompatible with the content of the name and description size fields: expecting 28, found 20 | ||
|
||
# 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 | ||
# CHECK-SHORT: .note.short data must be either empty or at least 12 bytes long | ||
|
||
## Test compatibility with .note.gnu.property, which has 8-byte alignment. | ||
# RUN: printf "\x04\x00\x00\x00\x40\x00\x00\x00\x05\x00\x00\x00\x47\x4e\x55\x00" > %t-note-gnu-property.bin | ||
# RUN: printf "\x02\x00\x00\xc0\x04\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00" >> %t-note-gnu-property.bin | ||
# RUN: printf "\x01\x80\x01\xc0\x04\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00" >> %t-note-gnu-property.bin | ||
# RUN: printf "\x01\x00\x01\xc0\x04\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00" >> %t-note-gnu-property.bin | ||
# RUN: printf "\x02\x00\x01\xc0\x04\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00" >> %t-note-gnu-property.bin | ||
# RUN: llvm-objcopy --add-section=.note.gnu.property=%t-note-gnu-property.bin %t.o %t-with-note-gnu-property.o | ||
|
||
## Test that verification can be disabled. | ||
# RUN: llvm-objcopy --add-section=.note.short=%t-short-note.bin --no-verify-note-sections %t.o %t-with-note.o | ||
|
||
## Test that last argument has precedence. | ||
# RUN: llvm-objcopy --add-section=.note.short=%t-short-note.bin --verify-note-sections --no-verify-note-sections %t.o %t-with-note.o | ||
jh7370 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# RUN: not llvm-objcopy --add-section=.note.short=%t-short-note.bin --no-verify-note-sections --verify-note-sections %t.o %t-with-note.o 2>&1 | FileCheck --check-prefix=CHECK-SHORT %s | ||
|
||
!ELF | ||
FileHeader: | ||
Class: ELFCLASS64 | ||
Data: ELFDATA2LSB | ||
Type: ET_REL |
Uh oh!
There was an error while loading. Please reload this page.