undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,147 @@
/*
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8306461
* @summary ObjectInputStream::readObject() should handle negative array sizes without throwing NegativeArraySizeExceptions
* @run main/othervm NegativeArraySizeTest
*/
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InvalidClassException;
import java.io.IOException;
import java.io.ObjectInputFilter;
import java.io.ObjectInputFilter.Status;
import java.util.PriorityQueue;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
public class NegativeArraySizeTest {
private static byte[] buildArrayPayload() throws IOException {
// Serialize to bytes
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(new String[1]);
oos.close();
byte[] serializedData = baos.toByteArray();
// Find the right location to modify, looking for the first instance of TC_ENDBLOCKDATA
int firstPos = 0;
for (int i = 0; i < serializedData.length - 1; i++) {
// 0x78 = TC_ENDBLOCKDATA
if (serializedData[i] == 0x78) {
// Replace array length with -2
serializedData[i + 2] = (byte) 0xff;
serializedData[i + 3] = (byte) 0xff;
serializedData[i + 4] = (byte) 0xff;
serializedData[i + 5] = (byte) 0xfe;
return serializedData;
}
}
throw new RuntimeException("Can't find TC_ENDBLOCKDATA in object output stream");
}
private static byte[] buildPriorityQueuePayload() throws IOException {
// Serialize to bytes
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(new PriorityQueue<>());
oos.close();
byte[] serializedData = baos.toByteArray();
// Find the right location to modify, looking for the first instance of TC_BLOCKDATA
int firstPos = 0;
for (int i = 0; i < serializedData.length - 1; i++) {
// 0x77 = TC_BLOCKDATA
if (serializedData[i] == 0x77) {
// Replace array length with -3
serializedData[i - 5] = (byte) 0xff;
serializedData[i - 4] = (byte) 0xff;
serializedData[i - 3] = (byte) 0xff;
serializedData[i - 2] = (byte) 0xfd;
return serializedData;
}
}
throw new RuntimeException("Can't find TC_BLOCKDATA in object output stream");
}
private static class CustomFilter implements ObjectInputFilter {
@Override
public Status checkInput(FilterInfo filterInfo) {
Class<?> cl = filterInfo.serialClass();
if (cl != null && cl.isArray() && filterInfo.arrayLength() < -1) {
throw new RuntimeException("FilterInfo.arrayLength() must be >= -1 for arrays (was " + filterInfo.arrayLength() + ")");
}
return Status.ALLOWED;
}
}
public static void main(String[] args) throws Exception {
// Test object input stream with negative sized array
try (ByteArrayInputStream bais = new ByteArrayInputStream(buildArrayPayload());
ObjectInputStream ois = new ObjectInputStream(bais)) {
ois.readObject();
} catch (NegativeArraySizeException nase) {
throw new Exception("ObjectInputStream::readObject() shouldn't throw a NegativeArraySizeException", nase);
} catch (ObjectStreamException ose) {
// OK, because a NegativeArraySizeException should be converted into an ObjectStreamException
if (!"Array length is negative".equals(ose.getMessage())) {
throw new Exception("Expected \"Array length is negative\" as exception message", ose);
}
}
// Test object input stream with negative sized array and custom object input filter
try (ByteArrayInputStream bais = new ByteArrayInputStream(buildArrayPayload());
ObjectInputStream ois = new ObjectInputStream(bais)) {
ois.setObjectInputFilter(new CustomFilter());
ois.readObject();
} catch (NegativeArraySizeException nase) {
throw new Exception("ObjectInputStream::readObject() shouldn't throw a NegativeArraySizeException", nase);
} catch (ObjectStreamException ose) {
if (ose instanceof InvalidClassException ice && ice.getMessage().contains("filter status: REJECTED")) {
throw new Exception("ObjectInputStream::readObject() should catch NegativeArraySizeExceptions before filtering", ice);
}
// OK, because a NegativeArraySizeException should be converted into an ObjectStreamException *before* filtering
if (!"Array length is negative".equals(ose.getMessage())) {
throw new Exception("Expected \"Array length is negative\" as exception message", ose);
}
}
// Test object input stream with negative sized PriorityQueue
try (ByteArrayInputStream bais = new ByteArrayInputStream(buildPriorityQueuePayload());
ObjectInputStream ois = new ObjectInputStream(bais)) {
ois.readObject();
} catch (NegativeArraySizeException nase) {
throw new Exception("ObjectInputStream::readObject() shouldn't throw a NegativeArraySizeException", nase);
} catch (ObjectStreamException ose) {
// OK, because a NegativeArraySizeException should be converted into an ObjectStreamException
if (!"Array length is negative".equals(ose.getMessage())) {
throw new Exception("Expected \"Array length is negative\" as exception message", ose);
}
}
}
}

View file

@ -0,0 +1,92 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/*
* @test
* @bug 8067870
* @modules java.base/java.io:open
* @summary verifies java.io.ObjectInputStream.PeekInputStream.skip works
* as intended
*/
public class PeekInputStreamTest {
public static void main(String[] args) throws ReflectiveOperationException,
IOException {
InputStream pin = createPeekInputStream(
new ByteArrayInputStream(new byte[]{1, 2, 3, 4}));
peek(pin);
if (pin.skip(1) != 1 || pin.read() != 2)
throw new AssertionError();
InputStream pin1 = createPeekInputStream(
new ByteArrayInputStream(new byte[]{1, 2, 3, 4}));
if (pin1.skip(1) != 1 || pin1.read() != 2)
throw new AssertionError();
InputStream pin2 = createPeekInputStream(
new ByteArrayInputStream(new byte[]{1, 2, 3, 4}));
if (pin2.skip(0) != 0 || pin2.read() != 1)
throw new AssertionError();
InputStream pin3 = createPeekInputStream(
new ByteArrayInputStream(new byte[]{1, 2, 3, 4}));
if (pin3.skip(2) != 2 || pin3.read() != 3)
throw new AssertionError();
InputStream pin4 = createPeekInputStream(
new ByteArrayInputStream(new byte[]{1, 2, 3, 4}));
if (pin4.skip(3) != 3 || pin4.read() != 4)
throw new AssertionError();
InputStream pin5 = createPeekInputStream(
new ByteArrayInputStream(new byte[]{1, 2, 3, 4}));
if (pin5.skip(16) != 4 || pin5.read() != -1)
throw new AssertionError();
}
private static InputStream createPeekInputStream(InputStream underlying)
throws ReflectiveOperationException {
Class<? extends InputStream> clazz =
Class.forName("java.io.ObjectInputStream$PeekInputStream")
.asSubclass(InputStream.class);
Constructor<? extends InputStream> ctr =
clazz.getDeclaredConstructor(InputStream.class);
ctr.setAccessible(true);
return ctr.newInstance(underlying);
}
private static void peek(InputStream pin)
throws ReflectiveOperationException {
Method p = pin.getClass().getDeclaredMethod("peek");
p.setAccessible(true);
p.invoke(pin);
}
}

View file

@ -0,0 +1,103 @@
/*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 4258644
* @summary ObjectInputStream's default implementation of its protected
* resolveProxyClass method is specified to pass the first non-null class
* loader up the execution stack to the Proxy.getProxyClass method when
* it creates the specified proxy class; this test makes sure that it does
* that in situations where it hadn't in the past, such as if the defining
* loaders of the interfaces were all strict ancestors of the first
* non-null loader up the stack.
* @author Peter Jones
*
* @build ResolveProxyClass
* @run main ResolveProxyClass
*/
import java.io.*;
public class ResolveProxyClass {
/*
* This class is a dummy ObjectInputStream subclass that allows the
* test code to access ObjectInputStream's protected resolveProxyClass
* method directly.
*/
private static class TestObjectInputStream extends ObjectInputStream {
TestObjectInputStream() throws IOException {
super();
}
protected Class<?> resolveProxyClass(String[] interfaces)
throws IOException, ClassNotFoundException
{
return super.resolveProxyClass(interfaces);
}
}
public static void main(String[] args) {
System.err.println("\nRegression test for bug 4258644\n");
try {
/*
* Set this thread's context class loader to null, so that the
* resolveProxyClass implementation cannot cheat by guessing that
* the context class loader is the appropriate loader to pass to
* the Proxy.getProxyClass method.
*/
Thread.currentThread().setContextClassLoader(null);
/*
* Expect the proxy class to be defined in the system class
* loader, because that is the defining loader of this test
* code, and it should be the first loader on the stack when
* ObjectInputStream.resolveProxyClass gets executed.
*/
ClassLoader expectedLoader = ResolveProxyClass.class.getClassLoader();
TestObjectInputStream in = new TestObjectInputStream();
Class<?> proxyClass = in.resolveProxyClass(
new String[] { Runnable.class.getName() });
ClassLoader proxyLoader = proxyClass.getClassLoader();
System.err.println("proxy class \"" + proxyClass +
"\" defined in loader: " + proxyLoader);
if (proxyLoader != expectedLoader) {
throw new RuntimeException(
"proxy class defined in loader: " + proxyLoader);
}
System.err.println("\nTEST PASSED");
} catch (Throwable e) {
System.err.println("\nTEST FAILED:");
e.printStackTrace();
throw new RuntimeException("TEST FAILED: " + e.toString());
}
}
}

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 8135043
* @summary ObjectStreamClass.getField(String) too restrictive
*/
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.Serializable;
public class TestObjectStreamClass {
public static void main(String[] args) throws Exception {
ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
ObjectOutputStream output = new ObjectOutputStream(byteOutput);
output.writeObject(new TestClass());
ByteArrayInputStream bais = new ByteArrayInputStream(byteOutput.toByteArray());
TestObjectInputStream input = new TestObjectInputStream(bais);
input.readObject();
ObjectStreamClass osc = input.getDescriptor();
// All OSC public API methods should complete without throwing.
osc.getName();
osc.forClass();
osc.getField("str");
osc.getFields();
osc.getSerialVersionUID();
osc.toString();
}
static class TestClass implements Serializable {
private static final long serialVersionUID = 1L;
String str = "hello world";
}
static class TestObjectInputStream extends ObjectInputStream {
private ObjectStreamClass objectStreamClass;
public TestObjectInputStream(InputStream in) throws IOException {
super(in);
}
public ObjectStreamClass getDescriptor()
throws IOException, ClassNotFoundException
{
return objectStreamClass;
}
public ObjectStreamClass readClassDescriptor()
throws IOException, ClassNotFoundException
{
objectStreamClass = super.readClassDescriptor();
return objectStreamClass;
}
}
}