GP-7175: Checking count values in Mach-O BindingTable.java and

RebaseTable.java
This commit is contained in:
Ryan Kurtz
2026-08-31 06:19:29 -04:00
parent 5f2c181c3e
commit 2fce7f119d
3 changed files with 26 additions and 6 deletions

View File

@@ -18,8 +18,7 @@ package ghidra.app.util.bin.format.macho.commands;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.macho.MachConstants;
import ghidra.app.util.bin.format.macho.MachHeader;
import ghidra.app.util.bin.format.macho.*;
import ghidra.app.util.bin.format.macho.commands.dyld.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.program.flatapi.FlatProgramAPI;
@@ -61,9 +60,10 @@ public class DyldInfoCommand extends LoadCommand {
* references. Note that this might be in a different underlying provider.
* @param header The {@link MachHeader header} associated with this load command
* @throws IOException if an IO-related error occurs while parsing
* @throws MachException if the {@link DyldInfoCommand} is invalid
*/
DyldInfoCommand(BinaryReader loadCommandReader, BinaryReader dataReader, MachHeader header)
throws IOException {
throws IOException, MachException {
super(loadCommandReader);
rebaseOff = loadCommandReader.readNextUnsignedInt();

View File

@@ -22,6 +22,7 @@ import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.macho.MachException;
import ghidra.app.util.bin.format.macho.MachHeader;
import ghidra.app.util.bin.format.macho.commands.DyldInfoCommandConstants;
import ghidra.program.model.data.LEB128;
@@ -31,10 +32,11 @@ import ghidra.program.model.data.LEB128;
*/
public class BindingTable extends OpcodeTable {
private static final int COUNT_LIMIT = 100_000;
private List<Binding> bindings = new ArrayList<>();
private List<Binding> threadedBindings;
/**
* Creates an empty {@link BindingTable}
*/
@@ -50,9 +52,10 @@ public class BindingTable extends OpcodeTable {
* @param tableSize The size of the table, in bytes
* @param lazy True if this is a lazy binding table; otherwise, false
* @throws IOException if an IO-related error occurs while parsing
* @throws MachException if the {@link BindingTable} is invalid
*/
public BindingTable(BinaryReader reader, MachHeader header, long tableSize, boolean lazy)
throws IOException {
throws IOException, MachException {
this();
int pointerSize = header.getAddressSize();
@@ -143,6 +146,10 @@ public class BindingTable extends OpcodeTable {
case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: { // 0xC0
ulebOffsets.add(reader.getPointerIndex() - origIndex);
long count = reader.readNext(LEB128::unsigned);
if (count < 0 || count > COUNT_LIMIT) {
throw new MachException("BIND_OPCODE count exceeds limit (%s): %s"
.formatted(COUNT_LIMIT, count));
}
ulebOffsets.add(reader.getPointerIndex() - origIndex);
long skip = reader.readNext(LEB128::unsigned);
for ( int i = 0 ; i < count ; ++i ) {

View File

@@ -22,6 +22,7 @@ import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.macho.MachException;
import ghidra.app.util.bin.format.macho.MachHeader;
import ghidra.program.model.data.LEB128;
@@ -30,6 +31,8 @@ import ghidra.program.model.data.LEB128;
*/
public class RebaseTable extends OpcodeTable {
private static final int COUNT_LIMIT = 100_000;
private List<Rebase> rebases = new ArrayList<>();
/**
@@ -46,8 +49,10 @@ public class RebaseTable extends OpcodeTable {
* @param header The header
* @param tableSize The size of the table, in bytes
* @throws IOException if an IO-related error occurs while parsing
* @throws MachException if the {@link RebaseTable} is invalid
*/
public RebaseTable(BinaryReader reader, MachHeader header, long tableSize) throws IOException {
public RebaseTable(BinaryReader reader, MachHeader header, long tableSize)
throws IOException, MachException {
this();
int pointerSize = header.getAddressSize();
@@ -94,6 +99,10 @@ public class RebaseTable extends OpcodeTable {
case REBASE_OPCODE_DO_REBASE_ULEB_TIMES: { // 0x60
ulebOffsets.add(reader.getPointerIndex() - origIndex);
int count = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
if (count < 0 || count > COUNT_LIMIT) {
throw new MachException("REBASE_OPCODE count exceeds limit (%s): %s"
.formatted(COUNT_LIMIT, count));
}
for (int i = 0; i < count; ++i) {
rebases.add(new Rebase(rebase));
rebase.segmentOffset += pointerSize;
@@ -109,6 +118,10 @@ public class RebaseTable extends OpcodeTable {
case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: { // 0x80
ulebOffsets.add(reader.getPointerIndex() - origIndex);
int count = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
if (count < 0 || count > COUNT_LIMIT) {
throw new MachException("REBASE_OPCODE count exceeds limit (%s): %s"
.formatted(COUNT_LIMIT, count));
}
ulebOffsets.add(reader.getPointerIndex() - origIndex);
int skip = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
for (int i = 0; i < count; ++i) {