GP-6712 fix some ext4 bounds checking

This commit is contained in:
dev747368
2026-04-17 17:48:45 +00:00
parent 5a209ba931
commit 76ebd0fb77
3 changed files with 49 additions and 22 deletions
@@ -40,6 +40,8 @@ public class Ext4FileSystem extends AbstractFileSystem<Ext4File> {
public static final Charset EXT4_DEFAULT_CHARSET = StandardCharsets.UTF_8;
private static final int MAX_SANE_INODE_COUNT = 30_000_000; // should handle 500gb disk images
private int blockSize;
private ByteProvider provider;
private String volumeName;
@@ -58,24 +60,17 @@ public class Ext4FileSystem extends AbstractFileSystem<Ext4File> {
this.volumeName = superBlock.getVolumeName();
this.uuid = NumericUtilities.convertBytesToString(superBlock.getS_uuid());
long blockCount = superBlock.getS_blocks_count();
int s_log_block_size = superBlock.getS_log_block_size();
this.blockSize = (int) Math.pow(2, (10 + s_log_block_size));
int groupSize = blockSize * superBlock.getS_blocks_per_group();
if (groupSize <= 0) {
throw new IOException("Invalid groupSize: " + groupSize);
}
int numGroups = (int) (blockCount / superBlock.getS_blocks_per_group());
if (blockCount % superBlock.getS_blocks_per_group() != 0) {
numGroups++;
this.blockSize = superBlock.getBlockSize();
long numGroups = superBlock.getNumGroups();
if (numGroups > Integer.MAX_VALUE - 1000 /*ensure we can alloc jvm array */) {
throw new IOException("Bad numgroups: " + numGroups);
}
int groupDescriptorOffset = blockSize + (superBlock.getS_first_data_block() * blockSize);
reader.setPointerIndex(groupDescriptorOffset);
monitor.initialize(numGroups);
monitor.setMessage("Reading inode tables");
Ext4GroupDescriptor[] groupDescriptors = new Ext4GroupDescriptor[numGroups];
Ext4GroupDescriptor[] groupDescriptors = new Ext4GroupDescriptor[(int) numGroups];
for (int i = 0; i < numGroups; i++) {
groupDescriptors[i] = new Ext4GroupDescriptor(reader, superBlock.is64Bit());
monitor.increment();
@@ -297,6 +292,10 @@ public class Ext4FileSystem extends AbstractFileSystem<Ext4File> {
private Ext4Inode[] getInodes(BinaryReader reader, Ext4GroupDescriptor[] groupDescriptors,
TaskMonitor monitor) throws IOException, CancelledException {
if (superBlock.getS_inodes_count() > MAX_SANE_INODE_COUNT) {
throw new IOException("Inode number too big: " + superBlock.getS_inodes_count());
}
int inodeCount = superBlock.getS_inodes_count();
int inodesPerGroup = superBlock.getS_inodes_per_group();
Ext4Inode[] inodes = new Ext4Inode[inodeCount + 1];
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -19,8 +19,7 @@ import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.ByteProvider;
import ghidra.formats.gfilesystem.FSRLRoot;
import ghidra.formats.gfilesystem.FileSystemService;
import ghidra.formats.gfilesystem.*;
import ghidra.formats.gfilesystem.factory.GFileSystemFactoryByteProvider;
import ghidra.formats.gfilesystem.factory.GFileSystemProbeByteProvider;
import ghidra.util.exception.CancelledException;
@@ -34,10 +33,16 @@ public class Ext4FileSystemFactory
FileSystemService fsService, TaskMonitor monitor)
throws IOException, CancelledException {
Ext4FileSystem fs = new Ext4FileSystem(targetFSRL, byteProvider);
fs.mountFS(monitor);
try {
Ext4FileSystem fs = new Ext4FileSystem(targetFSRL, byteProvider);
fs.mountFS(monitor);
return fs;
return fs;
}
catch (IOException e) {
FSUtilities.uncheckedClose(byteProvider, null);
throw e;
}
}
@Override
@@ -125,15 +125,15 @@ public class Ext4SuperBlock implements StructConverter {
}
public Ext4SuperBlock( BinaryReader reader ) throws IOException {
s_inodes_count = reader.readNextInt();
s_inodes_count = reader.readNextUnsignedIntExact(); // error if more than 2.1billion
s_blocks_count_lo = reader.readNextInt();
s_r_blocks_count_lo = reader.readNextInt();
s_free_blocks_count_lo = reader.readNextInt();
s_free_inodes_count = reader.readNextInt();
s_first_data_block = reader.readNextInt();
s_log_block_size = reader.readNextInt();
s_log_block_size = reader.readNextUnsignedIntExact();
s_log_cluster_size = reader.readNextInt();
s_blocks_per_group = reader.readNextInt();
s_blocks_per_group = reader.readNextUnsignedIntExact();
s_clusters_per_group = reader.readNextInt();
s_inodes_per_group = reader.readNextInt();
s_mtime = reader.readNextInt();
@@ -254,6 +254,14 @@ public class Ext4SuperBlock implements StructConverter {
return s_log_block_size;
}
public int getBlockSize() throws IOException {
if (s_log_block_size > 6) {
throw new IOException("Blocksize out of range: " + s_log_block_size);
}
int result = 1 << (10 + s_log_block_size);
return result;
}
public int getS_log_cluster_size() {
return s_log_cluster_size;
}
@@ -262,6 +270,21 @@ public class Ext4SuperBlock implements StructConverter {
return s_blocks_per_group;
}
private static final int MAX_BLOCKS_PER_GROUP = 1 << 19;
public long getNumGroups() throws IOException {
int bs = getBlockSize();
if (s_blocks_per_group < bs || s_blocks_per_group > MAX_BLOCKS_PER_GROUP) {
throw new IOException("Bad blocks per group: " + s_blocks_per_group);
}
long blockCount = getS_blocks_count();
long numGroups = blockCount / s_blocks_per_group;
if (blockCount % s_blocks_per_group != 0) {
numGroups++;
}
return numGroups;
}
public int getS_clusters_per_group() {
return s_clusters_per_group;
}