Skip to content

Conversation

@cabbaken
Copy link
Contributor

Add overflow check to ELF note iterator to handle large p_filesz or sh_size, avoid accessing invalid memory.

Signed-off-by: Ruoyu Qiu <cabbaken@outlook.com>
@llvmbot
Copy link
Member

llvmbot commented Sep 24, 2025

@llvm/pr-subscribers-llvm-binary-utilities

Author: Ruoyu Qiu (cabbaken)

Changes

Add overflow check to ELF note iterator to handle large p_filesz or sh_size, avoid accessing invalid memory.


Full diff: https://github.com/llvm/llvm-project/pull/160451.diff

1 Files Affected:

  • (modified) llvm/include/llvm/Object/ELF.h (+4-2)
diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h
index 0b362d389c177..59f63eb6b5bb6 100644
--- a/llvm/include/llvm/Object/ELF.h
+++ b/llvm/include/llvm/Object/ELF.h
@@ -407,7 +407,8 @@ class ELFFile {
   Elf_Note_Iterator notes_begin(const Elf_Phdr &Phdr, Error &Err) const {
     assert(Phdr.p_type == ELF::PT_NOTE && "Phdr is not of type PT_NOTE");
     ErrorAsOutParameter ErrAsOutParam(Err);
-    if (Phdr.p_offset + Phdr.p_filesz > getBufSize()) {
+    if (Phdr.p_offset + Phdr.p_filesz > getBufSize() ||
+        Phdr.p_offset + Phdr.p_filesz < Phdr.p_offset) {
       Err =
           createError("invalid offset (0x" + Twine::utohexstr(Phdr.p_offset) +
                       ") or size (0x" + Twine::utohexstr(Phdr.p_filesz) + ")");
@@ -435,7 +436,8 @@ class ELFFile {
   Elf_Note_Iterator notes_begin(const Elf_Shdr &Shdr, Error &Err) const {
     assert(Shdr.sh_type == ELF::SHT_NOTE && "Shdr is not of type SHT_NOTE");
     ErrorAsOutParameter ErrAsOutParam(Err);
-    if (Shdr.sh_offset + Shdr.sh_size > getBufSize()) {
+    if (Shdr.sh_offset + Shdr.sh_size > getBufSize() ||
+        Shdr.sh_offset + Shdr.sh_size < Shdr.sh_offset) {
       Err =
           createError("invalid offset (0x" + Twine::utohexstr(Shdr.sh_offset) +
                       ") or size (0x" + Twine::utohexstr(Shdr.sh_size) + ")");

Copy link
Collaborator

@jh7370 jh7370 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test case? You should be able to craft an input using yaml2obj either in a lit or unit test that exercises these two code paths.

The PR description should mention both the size and offset fields, not just the size fields.

@cabbaken
Copy link
Contributor Author

cabbaken commented Sep 24, 2025

Will it be good to add a unit test in llvm/unittests/Object/ELFObjectFileTest.cpp?

@jh7370
Copy link
Collaborator

jh7370 commented Sep 24, 2025

Will it be good to add a unit test in llvm/unittests/Object/ELFObjectFileTest.cpp?

ELFObjectFileTest.cpp is for testing the ELFObjectFile.cpp file. There's ELFTest.cpp for testing ELF.h/ELF.cpp, so you should add it to that one.

Signed-off-by: Ruoyu Qiu <cabbaken@outlook.com>
Signed-off-by: Ruoyu Qiu <cabbaken@outlook.com>
Signed-off-by: Ruoyu Qiu <cabbaken@outlook.com>
@cabbaken
Copy link
Contributor Author

ELFObjectFileTest.cpp is for testing the ELFObjectFile.cpp file. There's ELFTest.cpp for testing ELF.h/ELF.cpp, so you should add it to that one.

I've added the unit test in ELFTest.cpp.

Copy link
Collaborator

@jh7370 jh7370 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One nit, otherwise looks fine.

.str());
};

auto PhdrsOrErr = Obj.program_headers();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd avoid auto in these tests to make it clearer what the type is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type of PhdrsOrErr is Expected<ELFFile<ELF64LE>::Elf_Phdr_Range>, which is a bit verbose here. Since the getBuildID code uses auto, I followed the same style.
I can adjust this if needed.

auto PhdrsOrErr = Obj.program_headers();
Expected<ELFFile<ELF64LE>::Elf_Phdr_Range> PhdrsOrErr = Obj.program_headers();
EXPECT_FALSE(!PhdrsOrErr);
for (auto P : *PhdrsOrErr)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still using auto here and in the similar loop below. You could probably add a couple of using declarations to avoid repeating the full ELFFile<ELF64LE>::Elf_Phdr_Range and Shdr equivalent.

Signed-off-by: Ruoyu Qiu <cabbaken@outlook.com>
Copy link
Collaborator

@jh7370 jh7370 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One remaining nit, otherwise LGTM.

FileSize: 0xffffffffffffff88
FirstSec: .note.gnu.build-id
LastSec: .note.gnu.build-id
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: delete this blank line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Signed-off-by: Ruoyu Qiu <cabbaken@outlook.com>
@jh7370
Copy link
Collaborator

jh7370 commented Oct 2, 2025

@cabbaken, do you need me to merge this?

@cabbaken
Copy link
Contributor Author

cabbaken commented Oct 2, 2025

That would be great, thanks. I don’t have merge rights here.

@jh7370 jh7370 merged commit 3c39187 into llvm:main Oct 2, 2025
9 checks passed
mahesh-attarde pushed a commit to mahesh-attarde/llvm-project that referenced this pull request Oct 3, 2025
Add overflow check to ELF note iterator to handle large `p_filesz` or
`sh_size`, avoid accessing invalid memory.

---------

Signed-off-by: Ruoyu Qiu <cabbaken@outlook.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants