mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-22 16:50:36 -09:00
GP-6875: Check Mach-O headear for invalid number of load commands
This commit is contained in:
@@ -51,6 +51,8 @@ public class MachHeader implements StructConverter {
|
||||
private long _machHeaderStartIndex = 0;
|
||||
private boolean _parsed = false;
|
||||
|
||||
private static final int MAX_LOAD_COMMANDS = 32_768;
|
||||
|
||||
/**
|
||||
* Returns true if the specified ByteProvider starts with a Mach header magic signature.
|
||||
*
|
||||
@@ -74,7 +76,7 @@ public class MachHeader implements StructConverter {
|
||||
*
|
||||
* @param provider the ByteProvider
|
||||
* @throws IOException if an I/O error occurs while reading from the ByteProvider
|
||||
* @throws MachException if an invalid MachHeader is detected
|
||||
* @throws MachException if an invalid header is detected
|
||||
*/
|
||||
public MachHeader(ByteProvider provider) throws IOException, MachException {
|
||||
this(provider, 0);
|
||||
@@ -88,7 +90,7 @@ public class MachHeader implements StructConverter {
|
||||
* @param machHeaderStartIndexInProvider the index into the ByteProvider where the MachHeader
|
||||
* begins
|
||||
* @throws IOException if an I/O error occurs while reading from the ByteProvider
|
||||
* @throws MachException if an invalid MachHeader is detected
|
||||
* @throws MachException if an invalid header is detected
|
||||
*/
|
||||
public MachHeader(ByteProvider provider, long machHeaderStartIndexInProvider)
|
||||
throws IOException, MachException {
|
||||
@@ -96,17 +98,17 @@ public class MachHeader implements StructConverter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creatse a new {@link MachHeader}. Assumes the MachHeader starts at index
|
||||
* Creates a new {@link MachHeader}. Assumes the MachHeader starts at index
|
||||
* <i>machHeaderStartIndexInProvider</i> in the ByteProvider.
|
||||
*
|
||||
* @param provider the ByteProvider
|
||||
* @param machHeaderStartIndexInProvider the index into the ByteProvider where the MachHeader
|
||||
* begins.
|
||||
* @param isRemainingMachoRelativeToStartIndex true if the rest of the macho uses relative
|
||||
* indexin (this is common in UBI and kernel cache files); otherwise, false if the rest of the
|
||||
* @param isRemainingMachoRelativeToStartIndex true if the rest of the Mach-O uses relative
|
||||
* indexes (this is common in UBI and kernel cache files); otherwise, false if the rest of the
|
||||
* file uses absolute indexing from 0 (this is common in DYLD cache files)
|
||||
* @throws IOException if an I/O error occurs while reading from the ByteProvider
|
||||
* @throws MachException if an invalid MachHeader is detected
|
||||
* @throws MachException if an invalid header is detected
|
||||
*/
|
||||
public MachHeader(ByteProvider provider, long machHeaderStartIndexInProvider,
|
||||
boolean isRemainingMachoRelativeToStartIndex) throws IOException, MachException {
|
||||
@@ -144,7 +146,7 @@ public class MachHeader implements StructConverter {
|
||||
*
|
||||
* @return This {@link MachHeader}, for convenience
|
||||
* @throws IOException If there was an IO-related error
|
||||
* @throws MachException if the load command is invalid
|
||||
* @throws MachException if a problem was detected with the load commands
|
||||
*/
|
||||
public MachHeader parse() throws IOException, MachException {
|
||||
return parse(null);
|
||||
@@ -157,13 +159,15 @@ public class MachHeader implements StructConverter {
|
||||
* if a split DYLD cache is not being used.
|
||||
* @return This {@link MachHeader}, for convenience
|
||||
* @throws IOException If there was an IO-related error
|
||||
* @throws MachException if the load command is invalid
|
||||
* @throws MachException if a problem was detected with the load commands
|
||||
*/
|
||||
public MachHeader parse(SplitDyldCache splitDyldCache) throws IOException, MachException {
|
||||
if (_parsed) {
|
||||
return this;
|
||||
}
|
||||
|
||||
validateNumLoadCommands();
|
||||
|
||||
// We must parse segment load commands first, so find and store their indexes separately
|
||||
long currentIndex = _commandIndex;
|
||||
List<Long> segmentIndexes = new ArrayList<>();
|
||||
@@ -198,8 +202,11 @@ public class MachHeader implements StructConverter {
|
||||
*
|
||||
* @return A {@link List} of this {@link MachHeader}'s {@link SegmentCommand segments}
|
||||
* @throws IOException If there was an IO-related error
|
||||
* @throws MachException if a problem was detected with the load commands
|
||||
*/
|
||||
public List<SegmentCommand> parseSegments() throws IOException {
|
||||
public List<SegmentCommand> parseSegments() throws IOException, MachException {
|
||||
validateNumLoadCommands();
|
||||
|
||||
List<SegmentCommand> segments = new ArrayList<>();
|
||||
_reader.setPointerIndex(_commandIndex);
|
||||
for (int i = 0; i < nCmds; ++i) {
|
||||
@@ -223,8 +230,11 @@ public class MachHeader implements StructConverter {
|
||||
* @return A {@link List} of this {@link MachHeader}'s
|
||||
* {@link DynamicLibraryCommand reexport load commands}
|
||||
* @throws IOException If there was an IO-related error
|
||||
* @throws MachException if a problem was detected with the load commands
|
||||
*/
|
||||
public List<DynamicLibraryCommand> parseReexports() throws IOException {
|
||||
public List<DynamicLibraryCommand> parseReexports() throws IOException, MachException {
|
||||
validateNumLoadCommands();
|
||||
|
||||
List<DynamicLibraryCommand> cmds = new ArrayList<>();
|
||||
_reader.setPointerIndex(_commandIndex);
|
||||
for (int i = 0; i < nCmds; ++i) {
|
||||
@@ -248,9 +258,12 @@ public class MachHeader implements StructConverter {
|
||||
* @param loadCommandType The type of {@link LoadCommand} to check for
|
||||
* @return True if this {@link MachHeader} contains the given {@link LoadCommand} type
|
||||
* @throws IOException If there was an IO-related error
|
||||
* @throws MachException if a problem was detected with the load commands
|
||||
* @see LoadCommandTypes
|
||||
*/
|
||||
public boolean parseAndCheck(int loadCommandType) throws IOException {
|
||||
public boolean parseAndCheck(int loadCommandType) throws IOException, MachException {
|
||||
validateNumLoadCommands();
|
||||
|
||||
_reader.setPointerIndex(_commandIndex);
|
||||
for (int i = 0; i < nCmds; ++i) {
|
||||
int type = _reader.peekNextInt();
|
||||
@@ -434,6 +447,17 @@ public class MachHeader implements StructConverter {
|
||||
return getDescription();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the specified number of load commands
|
||||
*
|
||||
* @throws MachException if this {@link MachHeader} has an invalid number of load commands
|
||||
*/
|
||||
private void validateNumLoadCommands() throws MachException {
|
||||
if (nCmds > MAX_LOAD_COMMANDS || nCmds < 0) {
|
||||
throw new MachException("Invalid number of load commands (%d)".formatted(nCmds));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes invalid segment/section names so they can be used as memory blocks and program tree
|
||||
* modules.
|
||||
|
||||
@@ -535,16 +535,21 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
|
||||
* @throws IOException if an IO-related error occurred
|
||||
*/
|
||||
private String detectCompilerName(MachHeader machHeader) throws IOException {
|
||||
List<String> sectionNames = machHeader.parseSegments()
|
||||
.stream()
|
||||
.flatMap(seg -> seg.getSections().stream())
|
||||
.map(section -> section.getSectionName())
|
||||
.toList();
|
||||
if (SwiftUtils.isSwift(sectionNames)) {
|
||||
return SwiftUtils.SWIFT_COMPILER;
|
||||
try {
|
||||
List<String> sectionNames = machHeader.parseSegments()
|
||||
.stream()
|
||||
.flatMap(seg -> seg.getSections().stream())
|
||||
.map(section -> section.getSectionName())
|
||||
.toList();
|
||||
if (SwiftUtils.isSwift(sectionNames)) {
|
||||
return SwiftUtils.SWIFT_COMPILER;
|
||||
}
|
||||
if (GoRttiMapper.hasGolangSections(sectionNames)) {
|
||||
return GoConstants.GOLANG_CSPEC_NAME;
|
||||
}
|
||||
}
|
||||
if (GoRttiMapper.hasGolangSections(sectionNames)) {
|
||||
return GoConstants.GOLANG_CSPEC_NAME;
|
||||
catch (MachException e) {
|
||||
// fall thru
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user