GP-6886: Fix OOM in ObjectStorageStreamAdapter

This commit is contained in:
Dan
2026-06-29 12:48:07 +00:00
parent 6fd250d041
commit 9767a16bde
2 changed files with 402 additions and 310 deletions

View File

@@ -28,6 +28,7 @@ import org.apache.logging.log4j.Logger;
import generic.jar.ResourceFile;
import ghidra.framework.Application;
import ghidra.util.Msg;
/**
* {@link GhidraObjectInputFilter} provides global serial input filter for use with Ghidra server
@@ -64,11 +65,24 @@ public class GhidraObjectInputFilter implements ObjectInputFilter {
private static final String MAXDEPTH = "maxdepth";
private static final String MAXBYTES = "maxbytes";
private static int getMaxArrayFromProperties() {
String limitStr = System.getProperty("ghidra.serial.array.limit", "200000");
try {
return Integer.parseInt(limitStr);
}
catch (Exception e) {
Msg.error(GhidraObjectInputFilter.class,
"Could not parse ghidra.serial.array.limit: %s. A decimal integer is required"
.formatted(limitStr));
}
return 200_000;
}
// NOTE: Be sure to update serialFilterREADME.md if values are updated.
private int MAXARRAY_DEFAULT = 200_000;
private int MAXREFS_DEFAULT = 10_000;
private int MAXDEPTH_DEFAULT = 50;
private int MAXBYTES_DEFAULT = 32 * 1024 * 1024; // 32MB
public static final int MAXARRAY_DEFAULT = getMaxArrayFromProperties();
public static final int MAXREFS_DEFAULT = 10_000;
public static final int MAXDEPTH_DEFAULT = 50;
public static final int MAXBYTES_DEFAULT = 32 * 1024 * 1024; // 32MB
private long maxArray;
private long maxRefs;

View File

@@ -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.
@@ -18,376 +18,454 @@ package ghidra.util;
import java.io.*;
/**
* Implementation for ObjectStorage to save and restore Strings and
* Java primitives using an ObjectOutputStream and ObjectInputStream,
* respectively.
* Implementation for ObjectStorage to save and restore Strings and Java primitives using an
* ObjectOutputStream and ObjectInputStream, respectively.
*
*
*/
public class ObjectStorageStreamAdapter implements ObjectStorage {
private static int getMaxArrayFromProperties() {
String limitStr = System.getProperty("ghidra.serial.array.limit", "200000");
try {
return Integer.parseInt(limitStr);
}
catch (Exception e) {
Msg.error(ObjectStorageStreamAdapter.class,
"Could not parse ghidra.serial.array.limit: %s. A decimal integer is required"
.formatted(limitStr));
}
return 200_000;
}
public static final int MAXARRAY = getMaxArrayFromProperties();
ObjectOutputStream out;
ObjectInputStream in;
/**
* Constructor for ObjectStorageStreamAdapter.
* @param out output stream to write to
*/
public ObjectStorageStreamAdapter(ObjectOutputStream out) {
this.out = out;
}
/**
* Constructor for new ObjectStorageStreamAdapter
* @param in input stream to read from
*/
public ObjectStorageStreamAdapter(ObjectInputStream in) {
this.in = in;
}
/**
* Constructor for ObjectStorageStreamAdapter.
*
* @param out output stream to write to
*/
public ObjectStorageStreamAdapter(ObjectOutputStream out) {
this.out = out;
}
/**
* Constructor for new ObjectStorageStreamAdapter
*
* @param in input stream to read from
*/
public ObjectStorageStreamAdapter(ObjectInputStream in) {
this.in = in;
}
@Override
public void putInt(int value) {
try {
out.writeInt(value);
} catch (IOException e) {}
}
public void putInt(int value) {
try {
out.writeInt(value);
}
catch (IOException e) {
}
}
@Override
public void putByte(byte value) {
try {
out.writeByte(value);
} catch (IOException e) {}
}
public void putByte(byte value) {
try {
out.writeByte(value);
}
catch (IOException e) {
}
}
@Override
public void putShort(short value) {
try {
out.writeShort(value);
} catch (IOException e) {}
}
public void putShort(short value) {
try {
out.writeShort(value);
}
catch (IOException e) {
}
}
@Override
public void putLong(long value) {
try {
out.writeLong(value);
} catch (IOException e) {}
}
public void putLong(long value) {
try {
out.writeLong(value);
}
catch (IOException e) {
}
}
@Override
public void putString(String value) {
try {
out.writeObject(value);
} catch (IOException e) {}
}
public void putString(String value) {
try {
out.writeObject(value);
}
catch (IOException e) {
}
}
@Override
public void putBoolean(boolean value) {
try {
out.writeBoolean(value);
} catch (IOException e) {}
}
public void putBoolean(boolean value) {
try {
out.writeBoolean(value);
}
catch (IOException e) {
}
}
@Override
public void putFloat(float value) {
try {
out.writeFloat(value);
} catch (IOException e) {}
}
public void putFloat(float value) {
try {
out.writeFloat(value);
}
catch (IOException e) {
}
}
@Override
public void putDouble(double value) {
try {
out.writeDouble(value);
} catch (IOException e) {}
}
public void putDouble(double value) {
try {
out.writeDouble(value);
}
catch (IOException e) {
}
}
@Override
public int getInt() {
try {
return in.readInt();
} catch (IOException e) {
return 0;
}
}
public int getInt() {
try {
return in.readInt();
}
catch (IOException e) {
return 0;
}
}
@Override
public byte getByte() {
try {
return in.readByte();
} catch (IOException e) {
return (byte)0;
}
}
public byte getByte() {
try {
return in.readByte();
}
catch (IOException e) {
return (byte) 0;
}
}
@Override
public short getShort() {
try {
return in.readShort();
} catch (IOException e) {
return (short)0;
}
}
public short getShort() {
try {
return in.readShort();
}
catch (IOException e) {
return (short) 0;
}
}
@Override
public long getLong() {
try {
return in.readLong();
} catch (IOException e) {
return 0;
}
}
public long getLong() {
try {
return in.readLong();
}
catch (IOException e) {
return 0;
}
}
@Override
public boolean getBoolean() {
try {
return in.readBoolean();
} catch (IOException e) {
return false;
}
}
public boolean getBoolean() {
try {
return in.readBoolean();
}
catch (IOException e) {
return false;
}
}
@Override
public String getString() {
try {
return (String)in.readObject();
}catch(Exception e) {
return null;
}
}
public String getString() {
try {
return (String) in.readObject();
}
catch (Exception e) {
return null;
}
}
@Override
public float getFloat() {
try {
return in.readFloat();
} catch (IOException e) {
return 0;
}
}
public float getFloat() {
try {
return in.readFloat();
}
catch (IOException e) {
return 0;
}
}
@Override
public double getDouble() {
try {
return in.readDouble();
} catch (IOException e) {
return 0.0;
}
}
public double getDouble() {
try {
return in.readDouble();
}
catch (IOException e) {
return 0.0;
}
}
protected void checkWriteArrayLength(int n) throws IOException {
if (n > MAXARRAY) {
throw new IOException("Array size %d exceeds max of %d".formatted(n, MAXARRAY));
}
out.writeInt(n);
}
@Override
public void putInts(int[] value) {
try {
if (value == null) {
out.writeInt(-1);
return;
}
out.writeInt(value.length);
for (int i = 0; i < value.length; i++) {
out.writeInt(value[i]);
}
} catch (IOException e) {}
}
public void putInts(int[] value) {
try {
if (value == null) {
out.writeInt(-1);
return;
}
checkWriteArrayLength(value.length);
for (int i = 0; i < value.length; i++) {
out.writeInt(value[i]);
}
}
catch (IOException e) {
}
}
@Override
public void putBytes(byte[] value) {
try {
if (value == null) {
out.writeInt(-1);
return;
}
out.writeInt(value.length);
for (int i = 0; i < value.length; i++) {
out.writeByte(value[i]);
}
} catch (IOException e) {}
}
public void putBytes(byte[] value) {
try {
if (value == null) {
out.writeInt(-1);
return;
}
checkWriteArrayLength(value.length);
for (int i = 0; i < value.length; i++) {
out.writeByte(value[i]);
}
}
catch (IOException e) {
}
}
@Override
public void putShorts(short[] value) {
try {
if (value == null) {
out.writeInt(-1);
return;
}
out.writeInt(value.length);
for (int i = 0; i < value.length; i++) {
out.writeShort(value[i]);
}
} catch (IOException e) {}
public void putShorts(short[] value) {
try {
if (value == null) {
out.writeInt(-1);
return;
}
checkWriteArrayLength(value.length);
for (int i = 0; i < value.length; i++) {
out.writeShort(value[i]);
}
}
catch (IOException e) {
}
}
}
@Override
public void putLongs(long[] value) {
try {
if (value == null) {
out.writeInt(-1);
return;
}
out.writeInt(value.length);
for (int i = 0; i < value.length; i++) {
out.writeLong(value[i]);
}
} catch (IOException e) {}
public void putLongs(long[] value) {
try {
if (value == null) {
out.writeInt(-1);
return;
}
checkWriteArrayLength(value.length);
for (int i = 0; i < value.length; i++) {
out.writeLong(value[i]);
}
}
catch (IOException e) {
}
}
}
@Override
public void putFloats(float[] value) {
try {
if (value == null) {
out.writeInt(-1);
return;
}
out.writeInt(value.length);
for (int i = 0; i < value.length; i++) {
out.writeFloat(value[i]);
}
} catch (IOException e) {}
}
public void putFloats(float[] value) {
try {
if (value == null) {
out.writeInt(-1);
return;
}
checkWriteArrayLength(value.length);
for (int i = 0; i < value.length; i++) {
out.writeFloat(value[i]);
}
}
catch (IOException e) {
}
}
@Override
public void putDoubles(double[] value) {
try {
if (value == null) {
out.writeInt(-1);
return;
}
out.writeInt(value.length);
for (int i = 0; i < value.length; i++) {
out.writeDouble(value[i]);
}
} catch (IOException e) {}
}
public void putDoubles(double[] value) {
try {
if (value == null) {
out.writeInt(-1);
return;
}
checkWriteArrayLength(value.length);
for (int i = 0; i < value.length; i++) {
out.writeDouble(value[i]);
}
}
catch (IOException e) {
}
}
@Override
public void putStrings(String[] value) {
try {
if (value == null) {
out.writeInt(-1);
return;
}
out.writeInt(value.length);
for (int i = 0; i < value.length; i++) {
out.writeObject(value[i]);
}
} catch (IOException e) {}
}
public void putStrings(String[] value) {
try {
if (value == null) {
out.writeInt(-1);
return;
}
checkWriteArrayLength(value.length);
for (int i = 0; i < value.length; i++) {
out.writeObject(value[i]);
}
}
catch (IOException e) {
}
}
protected int checkReadArrayLength() throws IOException {
int n = in.readInt();
if (n > MAXARRAY) {
throw new IOException("Array size %d exceeds max of %d".formatted(n, MAXARRAY));
}
return n;
}
@Override
public int[] getInts() {
try {
int n = in.readInt();
if (n < 0) {
return null;
}
int[] r = new int[n];
for(int i=0;i<n;i++) {
r[i] = in.readInt();
}
return r;
} catch (IOException e) {
return new int[0];
}
}
public int[] getInts() {
try {
int n = checkReadArrayLength();
if (n < 0) {
return null;
}
int[] r = new int[n];
for (int i = 0; i < n; i++) {
r[i] = in.readInt();
}
return r;
}
catch (IOException e) {
return new int[0];
}
}
@Override
public byte[] getBytes() {
try {
int n = in.readInt();
if (n < 0) {
return null;
}
byte[] r = new byte[n];
for(int i=0;i<n;i++) {
r[i] = in.readByte();
}
return r;
} catch (IOException e) {
return new byte[0];
}
}
public byte[] getBytes() {
try {
int n = checkReadArrayLength();
if (n < 0) {
return null;
}
byte[] r = new byte[n];
for (int i = 0; i < n; i++) {
r[i] = in.readByte();
}
return r;
}
catch (IOException e) {
return new byte[0];
}
}
@Override
public short[] getShorts() {
try {
int n = in.readInt();
if (n < 0) {
return null;
}
short[] r = new short[n];
for(int i=0;i<n;i++) {
r[i] = in.readShort();
}
return r;
} catch (IOException e) {
return new short[0];
}
}
public short[] getShorts() {
try {
int n = checkReadArrayLength();
if (n < 0) {
return null;
}
short[] r = new short[n];
for (int i = 0; i < n; i++) {
r[i] = in.readShort();
}
return r;
}
catch (IOException e) {
return new short[0];
}
}
@Override
public long[] getLongs() {
try {
int n = in.readInt();
if (n < 0) {
return null;
}
long[] r = new long[n];
for(int i=0;i<n;i++) {
r[i] = in.readLong();
}
return r;
} catch (IOException e) {
return new long[0];
}
}
public long[] getLongs() {
try {
int n = checkReadArrayLength();
if (n < 0) {
return null;
}
long[] r = new long[n];
for (int i = 0; i < n; i++) {
r[i] = in.readLong();
}
return r;
}
catch (IOException e) {
return new long[0];
}
}
@Override
public float[] getFloats() {
try {
int n = in.readInt();
if (n < 0) {
return null;
}
float[] r = new float[n];
for(int i=0;i<n;i++) {
r[i] = in.readFloat();
}
return r;
} catch (IOException e) {
return new float[0];
}
}
public float[] getFloats() {
try {
int n = checkReadArrayLength();
if (n < 0) {
return null;
}
float[] r = new float[n];
for (int i = 0; i < n; i++) {
r[i] = in.readFloat();
}
return r;
}
catch (IOException e) {
return new float[0];
}
}
@Override
public double[] getDoubles() {
try {
int n = in.readInt();
if (n < 0) {
return null;
}
double[] r = new double[n];
for(int i=0;i<n;i++) {
r[i] = in.readDouble();
}
return r;
} catch (IOException e) {
return new double[0];
}
}
public double[] getDoubles() {
try {
int n = checkReadArrayLength();
if (n < 0) {
return null;
}
double[] r = new double[n];
for (int i = 0; i < n; i++) {
r[i] = in.readDouble();
}
return r;
}
catch (IOException e) {
return new double[0];
}
}
@Override
public String[] getStrings() {
try {
int n = in.readInt();
if (n < 0) {
return null;
}
String[] r = new String[n];
for(int i=0;i<n;i++) {
r[i] = (String)in.readObject();
}
return r;
} catch (Exception e) {
return new String[0];
}
}
public String[] getStrings() {
try {
int n = checkReadArrayLength();
if (n < 0) {
return null;
}
String[] r = new String[n];
for (int i = 0; i < n; i++) {
r[i] = (String) in.readObject();
}
return r;
}
catch (Exception e) {
return new String[0];
}
}
}