From 061ec06a79f4147267f6fc690b0dcf944b2d4957 Mon Sep 17 00:00:00 2001 From: dev747368 <48332326+dev747368@users.noreply.github.com> Date: Mon, 21 Sep 2026 21:52:54 +0000 Subject: [PATCH] GP-7239 limit max number of files in a filesystem --- .../gfilesystem/FileSystemIndexHelper.java | 22 +++- .../FileSystemIndexHelperTest.java | 102 ++++++++++++++++++ .../file/formats/zip/ZipFileSystem.java | 2 +- .../java/skeleton/SkeletonFileSystem.java | 3 +- 4 files changed, 122 insertions(+), 7 deletions(-) create mode 100644 Ghidra/Features/Base/src/test.slow/java/ghidra/formats/gfilesystem/FileSystemIndexHelperTest.java diff --git a/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/FileSystemIndexHelper.java b/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/FileSystemIndexHelper.java index add4505674..a13dfba94b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/FileSystemIndexHelper.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/FileSystemIndexHelper.java @@ -35,6 +35,8 @@ import ghidra.util.Msg; public class FileSystemIndexHelper { private static final int MAX_SYMLINK_RECURSE_DEPTH = 10; + public static final int MAX_FILEENTRY_COUNT = 500_000; + private FileData rootDir; static class FileData { @@ -336,9 +338,10 @@ public class FileSystemIndexHelper { * @param metadata opaque blob that will be stored and associated with the new * GFile instance * @return new GFile instance + * @throws IOException if error adding files (too many files) */ public synchronized GFile storeFile(String path, long fileIndex, boolean isDirectory, - long length, METADATATYPE metadata) { + long length, METADATATYPE metadata) throws IOException { String[] nameparts = FSUtilities.splitPath(path); if (nameparts.length == 0) { @@ -370,9 +373,10 @@ public class FileSystemIndexHelper { * @param metadata opaque blob that will be stored and associated with the new * GFile instance * @return new GFile instance + * @throws IOException if error adding files (too many files) */ public synchronized GFile storeFileWithParent(String filename, GFile parent, long fileIndex, - boolean isDirectory, long length, METADATATYPE metadata) { + boolean isDirectory, long length, METADATATYPE metadata) throws IOException { FileData fileData = doStoreFile(filename, parent, fileIndex, isDirectory, length, null, metadata); return fileData.file; @@ -397,9 +401,10 @@ public class FileSystemIndexHelper { * @param metadata opaque blob that will be stored and associated with the new * GFile instance * @return new GFile instance + * @throws IOException if error adding files (too many files) */ public synchronized GFile storeSymlink(String path, long fileIndex, String symlinkPath, - long length, METADATATYPE metadata) { + long length, METADATATYPE metadata) throws IOException { String[] nameparts = FSUtilities.splitPath(path); if (nameparts.length == 0) { Msg.warn(this, @@ -434,9 +439,10 @@ public class FileSystemIndexHelper { * @param metadata opaque blob that will be stored and associated with the new * GFile instance * @return new GFile instance + * @throws IOException if error adding files (too many files) */ public synchronized GFile storeSymlinkWithParent(String filename, GFile parent, long fileIndex, - String symlinkPath, long length, METADATATYPE metadata) { + String symlinkPath, long length, METADATATYPE metadata) throws IOException { length = length != 0 ? length : symlinkPath.length(); FileData fileData = doStoreFile(filename, parent, fileIndex, false, length, symlinkPath, metadata); @@ -458,7 +464,13 @@ public class FileSystemIndexHelper { } private FileData doStoreFile(String filename, GFile parent, long fileIndex, - boolean isDirectory, long length, String symlinkPath, METADATATYPE metadata) { + boolean isDirectory, long length, String symlinkPath, METADATATYPE metadata) + throws IOException { + + if (fileToEntryMap.size() > MAX_FILEENTRY_COUNT) { + throw new IOException("Too many file entries: " + fileToEntryMap.size()); + } + parent = (parent == null) ? rootDir.file : parent; long fileNum = (fileIndex != -1) ? fileIndex : fileToEntryMap.size(); if (fileIndexToEntryMap.containsKey(fileNum)) { diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/formats/gfilesystem/FileSystemIndexHelperTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/formats/gfilesystem/FileSystemIndexHelperTest.java new file mode 100644 index 0000000000..ec8d8e0c02 --- /dev/null +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/formats/gfilesystem/FileSystemIndexHelperTest.java @@ -0,0 +1,102 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.formats.gfilesystem; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.util.List; + +import org.junit.Test; + +import ghidra.app.util.bin.ByteProvider; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; + +public class FileSystemIndexHelperTest { + + @Test + public void testMaxFiles() throws IOException { + FSRLRoot fsFSRL = FSRLRoot.makeRoot("dummy"); + FileSystemIndexHelper fsih = + new FileSystemIndexHelper(new DummyFileSystem(), fsFSRL); + + for (int i = 0; i < FileSystemIndexHelper.MAX_FILEENTRY_COUNT; i++) { + fsih.storeFile("file" + i, -1, false, 1, null); + } + + try { + fsih.storeFile("toomuch", -1, false, 1, null); + fail("Should not get here"); + } + catch (IOException e) { + // good + } + } + + private static class DummyFileSystem implements GFileSystem { + + @Override + public void close() throws IOException { + // empty dummy + + } + + @Override + public GFile lookup(String path) throws IOException { + // empty dummy + return null; + } + + @Override + public boolean isClosed() { + // empty dummy + return false; + } + + @Override + public FileSystemRefManager getRefManager() { + // empty dummy + return null; + } + + @Override + public String getName() { + // empty dummy + return null; + } + + @Override + public List getListing(GFile directory) throws IOException { + // empty dummy + return null; + } + + @Override + public FSRLRoot getFSRL() { + // empty dummy + return null; + } + + @Override + public ByteProvider getByteProvider(GFile file, TaskMonitor monitor) + throws IOException, CancelledException { + // empty dummy + return null; + } + } + +} diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/zip/ZipFileSystem.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/zip/ZipFileSystem.java index 01a510f194..35cda74f61 100644 --- a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/zip/ZipFileSystem.java +++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/zip/ZipFileSystem.java @@ -187,7 +187,7 @@ public class ZipFileSystem extends AbstractFileSystem { }, monitor); } - private void indexFiles(TaskMonitor monitor) throws CancelledException { + private void indexFiles(TaskMonitor monitor) throws CancelledException, IOException { int zipIndex = 0; for (ZipArchiveEntry zipEntry : entries) { monitor.checkCancelled(); diff --git a/GhidraBuild/Skeleton/src/main/java/skeleton/SkeletonFileSystem.java b/GhidraBuild/Skeleton/src/main/java/skeleton/SkeletonFileSystem.java index 2bca41437d..3848e201ee 100644 --- a/GhidraBuild/Skeleton/src/main/java/skeleton/SkeletonFileSystem.java +++ b/GhidraBuild/Skeleton/src/main/java/skeleton/SkeletonFileSystem.java @@ -59,8 +59,9 @@ public class SkeletonFileSystem implements GFileSystem { * Mounts (opens) the file system. * * @param monitor A cancellable task monitor. + * @throws IOException */ - public void mount(TaskMonitor monitor) { + public void mount(TaskMonitor monitor) throws IOException { monitor.setMessage("Opening " + SkeletonFileSystem.class.getSimpleName() + "..."); // Customize how things in the file system are stored. The following should be