[llvm-branch-commits] [llvm] release/23.x: [llvm-objcopy][MachO] Fix use-after-free when stripping (#228607) (PR #228733)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sat Oct 3 09:06:46 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

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

Author: llvmbot

<details>
<summary>Changes</summary>

Backport feb8b100771af6b617efd3ef5b6ebcf51d858b9b

Requested by: @<!-- -->mstorsjo

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


4 Files Affected:

- (modified) llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp (+12-3) 
- (modified) llvm/lib/ObjCopy/MachO/MachOObject.h (+1-1) 
- (added) llvm/test/tools/llvm-objcopy/MachO/discard-all-relocations.test (+186) 
- (modified) llvm/test/tools/llvm-objcopy/MachO/indirect-symbol-table-copy.s (+21) 


``````````diff
diff --git a/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp b/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp
index 7f862595449b53..1bca325198e0d8 100644
--- a/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp
+++ b/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp
@@ -83,11 +83,21 @@ static Error removeSections(const CommonConfig &Config, Object &Obj) {
   return Obj.removeSections(RemovePred);
 }
 
-static void markSymbols(const CommonConfig &, Object &Obj) {
+static void markSymbols(const CommonConfig &Config, Object &Obj) {
   // Symbols referenced from the indirect symbol table must not be removed.
   for (IndirectSymbolEntry &ISE : Obj.IndirectSymTable.Symbols)
     if (ISE.Symbol)
       (*ISE.Symbol)->Referenced = true;
+
+  // --strip-all removes relocations, so their symbols need not be preserved.
+  if (Config.StripAll)
+    return;
+
+  for (const LoadCommand &LC : Obj.LoadCommands)
+    for (const std::unique_ptr<Section> &Sec : LC.Sections)
+      for (const RelocationInfo &R : Sec->Relocations)
+        if (R.Symbol && *R.Symbol)
+          (*R.Symbol)->Referenced = true;
 }
 
 static void updateAndRemoveSymbols(const CommonConfig &Config,
@@ -454,8 +464,7 @@ static Error handleArgs(const CommonConfig &Config,
     return createFileError(Config.InputFilename, std::move(E));
 
   // Mark symbols to determine which symbols are still needed.
-  if (Config.StripAll)
-    markSymbols(Config, Obj);
+  markSymbols(Config, Obj);
 
   updateAndRemoveSymbols(Config, MachOConfig, Obj);
 
diff --git a/llvm/lib/ObjCopy/MachO/MachOObject.h b/llvm/lib/ObjCopy/MachO/MachOObject.h
index 86c6b120fa6c3e..9895585fcab143 100644
--- a/llvm/lib/ObjCopy/MachO/MachOObject.h
+++ b/llvm/lib/ObjCopy/MachO/MachOObject.h
@@ -172,7 +172,7 @@ struct StringTable {
 
 struct RelocationInfo {
   // The referenced symbol entry. Set if !Scattered && Extern.
-  std::optional<const SymbolEntry *> Symbol;
+  std::optional<SymbolEntry *> Symbol;
   // The referenced section. Set if !Scattered && !Extern.
   std::optional<const Section *> Sec;
   // True if Info is a scattered_relocation_info.
diff --git a/llvm/test/tools/llvm-objcopy/MachO/discard-all-relocations.test b/llvm/test/tools/llvm-objcopy/MachO/discard-all-relocations.test
new file mode 100644
index 00000000000000..7d947af42c62c2
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/MachO/discard-all-relocations.test
@@ -0,0 +1,186 @@
+## Local symbols referenced by relocations must survive --discard-all. Removing
+## an unreferenced symbol must also update the remaining relocation indices.
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-objcopy --discard-all %t %t.copy
+# RUN: llvm-readobj --relocations --expand-relocs --symbols %t.copy | FileCheck %s
+# RUN: llvm-strip -x %t -o %t.strip
+# RUN: cmp %t.copy %t.strip
+
+## --strip-all removes relocations, so their symbols can be removed too.
+# RUN: llvm-objcopy --strip-all %t %t.all
+# RUN: llvm-readobj --relocations --symbols %t.all | FileCheck %s --check-prefix=ALL
+
+## Symbols referenced only by relocations in removed sections can be discarded.
+# RUN: llvm-objcopy -x --remove-section=__TEXT,__text %t %t.remove
+# RUN: llvm-readobj --relocations --symbols %t.remove | FileCheck %s --check-prefix=REMOVE
+
+# CHECK:       Relocations [
+# CHECK-NEXT:    Section __text {
+# CHECK-NEXT:      Relocation {
+# CHECK-NEXT:        Offset: 0x10
+# CHECK-NEXT:        PCRel: 0
+# CHECK-NEXT:        Length: 3
+# CHECK-NEXT:        Type: X86_64_RELOC_UNSIGNED (0)
+# CHECK-NEXT:        Symbol: _undefined (1)
+# CHECK-NEXT:      }
+# CHECK-NEXT:      Relocation {
+# CHECK-NEXT:        Offset: 0x8
+# CHECK-NEXT:        PCRel: 0
+# CHECK-NEXT:        Length: 3
+# CHECK-NEXT:        Type: X86_64_RELOC_UNSIGNED (0)
+# CHECK-NEXT:        Section: __data (2)
+# CHECK-NEXT:      }
+# CHECK-NEXT:      Relocation {
+# CHECK-NEXT:        Offset: 0x0
+# CHECK-NEXT:        PCRel: 0
+# CHECK-NEXT:        Length: 3
+# CHECK-NEXT:        Type: X86_64_RELOC_UNSIGNED (0)
+# CHECK-NEXT:        Symbol: _referenced (0)
+# CHECK-NEXT:      }
+# CHECK-NEXT:    }
+# CHECK-NEXT:  ]
+# CHECK-NEXT:  Symbols [
+# CHECK-NEXT:    Symbol {
+# CHECK-NEXT:      Name: _referenced
+# CHECK-NEXT:      Type: Section (0xE)
+# CHECK-NEXT:      Section: __data (0x2)
+# CHECK-NEXT:      RefType: UndefinedNonLazy (0x0)
+# CHECK-NEXT:      Flags [ (0x0)
+# CHECK-NEXT:      ]
+# CHECK-NEXT:      Value: 0x1C
+# CHECK-NEXT:    }
+# CHECK-NEXT:    Symbol {
+# CHECK-NEXT:      Name: _undefined
+# CHECK-NEXT:      Extern
+# CHECK-NEXT:      Type: Undef (0x0)
+# CHECK-NEXT:      Section:  (0x0)
+# CHECK-NEXT:      RefType: UndefinedNonLazy (0x0)
+# CHECK-NEXT:      Flags [ (0x0)
+# CHECK-NEXT:      ]
+# CHECK-NEXT:      Value: 0x0
+# CHECK-NEXT:    }
+# CHECK-NEXT:  ]
+
+# ALL:       Relocations [
+# ALL-NEXT:  ]
+# ALL-NEXT:  Symbols [
+# ALL-NEXT:  ]
+
+# REMOVE:       Relocations [
+# REMOVE-NEXT:  ]
+# REMOVE-NEXT:  Symbols [
+# REMOVE-NEXT:    Symbol {
+# REMOVE-NEXT:      Name: _undefined
+# REMOVE-NEXT:      Extern
+# REMOVE-NEXT:      Type: Undef (0x0)
+# REMOVE-NEXT:      Section:  (0x0)
+# REMOVE-NEXT:      RefType: UndefinedNonLazy (0x0)
+# REMOVE-NEXT:      Flags [ (0x0)
+# REMOVE-NEXT:      ]
+# REMOVE-NEXT:      Value: 0x0
+# REMOVE-NEXT:    }
+# REMOVE-NEXT:  ]
+
+--- !mach-o
+FileHeader:
+  magic:      0xFEEDFACF
+  cputype:    0x01000007
+  cpusubtype: 3
+  filetype:   1
+  ncmds:      2
+  sizeofcmds: 256
+  flags:      0
+  reserved:   0
+LoadCommands:
+  - cmd:      LC_SEGMENT_64
+    cmdsize:  232
+    segname:  ''
+    vmaddr:   0
+    vmsize:   32
+    fileoff:  288
+    filesize: 32
+    maxprot:  7
+    initprot: 7
+    nsects:   2
+    flags:    0
+    Sections:
+      - sectname: __text
+        segname:  __TEXT
+        addr:     0
+        size:     24
+        offset:   288
+        align:    3
+        reloff:   320
+        nreloc:   3
+        flags:    0
+        reserved1: 0
+        reserved2: 0
+        reserved3: 0
+        content:  '000000000000000018000000000000000000000000000000'
+        relocations:
+          - address:   16
+            symbolnum: 2
+            pcrel:     false
+            length:    3
+            extern:    true
+            type:      0
+            scattered: false
+            value:     0
+          - address:   8
+            symbolnum: 2
+            pcrel:     false
+            length:    3
+            extern:    false
+            type:      0
+            scattered: false
+            value:     0
+          - address:   0
+            symbolnum: 1
+            pcrel:     false
+            length:    3
+            extern:    true
+            type:      0
+            scattered: false
+            value:     0
+      - sectname: __data
+        segname:  __DATA
+        addr:     24
+        size:     8
+        offset:   312
+        align:    2
+        reloff:   0
+        nreloc:   0
+        flags:    0
+        reserved1: 0
+        reserved2: 0
+        reserved3: 0
+        content:  '0000000000000000'
+  - cmd:     LC_SYMTAB
+    cmdsize: 24
+    symoff:  344
+    nsyms:   3
+    stroff:  392
+    strsize: 39
+LinkEditData:
+  NameList:
+    - n_strx:  1
+      n_type:  0x0E
+      n_sect:  2
+      n_desc:  0
+      n_value: 24
+    - n_strx:  15
+      n_type:  0x0E
+      n_sect:  2
+      n_desc:  0
+      n_value: 28
+    - n_strx:  27
+      n_type:  0x01
+      n_sect:  0
+      n_desc:  0
+      n_value: 0
+  StringTable:
+    - ''
+    - _unreferenced
+    - _referenced
+    - _undefined
+    - ''
diff --git a/llvm/test/tools/llvm-objcopy/MachO/indirect-symbol-table-copy.s b/llvm/test/tools/llvm-objcopy/MachO/indirect-symbol-table-copy.s
index 6b03f2e31471d1..e95136dd97d23f 100644
--- a/llvm/test/tools/llvm-objcopy/MachO/indirect-symbol-table-copy.s
+++ b/llvm/test/tools/llvm-objcopy/MachO/indirect-symbol-table-copy.s
@@ -6,6 +6,13 @@
 # RUN: llvm-readobj --symbols --macho-indirect-symbols %t.copy \
 # RUN:   | FileCheck %s
 
+## Local symbols referenced by the indirect symbol table must be preserved.
+# RUN: llvm-objcopy -x %t %t.discard
+# RUN: llvm-readobj --symbols --macho-indirect-symbols %t.discard \
+# RUN:   | FileCheck %s --check-prefix=DISCARD
+# RUN: llvm-strip -x %t -o %t.strip
+# RUN: cmp %t.discard %t.strip
+
 # __DATA,__nl_symbol_ptr
 .non_lazy_symbol_pointer
 bar:
@@ -64,3 +71,17 @@ foo:
 # CHECK-NEXT:     }
 # CHECK-NEXT:   ]
 # CHECK-NEXT: }
+
+# DISCARD:      Symbols [
+# DISCARD-NEXT:   Symbol {
+# DISCARD-NEXT:     Name: foo
+# DISCARD-NEXT:     Type: Section (0xE)
+# DISCARD-NEXT:     Section: __la_symbol_ptr (0x3)
+# DISCARD-NEXT:     RefType: UndefinedNonLazy (0x0)
+# DISCARD-NEXT:     Flags [ (0x0)
+# DISCARD-NEXT:     ]
+# DISCARD-NEXT:     Value: 0x8
+# DISCARD-NEXT:   }
+# DISCARD-NEXT: ]
+# DISCARD:        Symbol Index: 0x80000000
+# DISCARD:        Symbol Index: 0x0

``````````

</details>


https://github.com/llvm/llvm-project/pull/228733


More information about the llvm-branch-commits mailing list