This is an automated email from the ASF dual-hosted git repository.

chamikaramj pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/beam.git


The following commit(s) were added to refs/heads/master by this push:
     new 7d93ef8e76a Filter classes accepted by TransformUpgrader 
deserialization (#40438)
7d93ef8e76a is described below

commit 7d93ef8e76aa3fd7874e760010f6479fba40721a
Author: Chamikara Jayalath <[email protected]>
AuthorDate: Fri Oct 9 13:51:08 2026 -0700

    Filter classes accepted by TransformUpgrader deserialization (#40438)
---
 .../beam_PostCommit_TransformService_Direct.json   |  2 +-
 .../sdk/util/construction/TransformUpgrader.java   | 33 ++++++++++++++++++
 .../util/construction/TransformUpgraderTest.java   | 39 ++++++++++++++++++++++
 3 files changed, 73 insertions(+), 1 deletion(-)

diff --git a/.github/trigger_files/beam_PostCommit_TransformService_Direct.json 
b/.github/trigger_files/beam_PostCommit_TransformService_Direct.json
index 540e8267eaf..198f7347563 100644
--- a/.github/trigger_files/beam_PostCommit_TransformService_Direct.json
+++ b/.github/trigger_files/beam_PostCommit_TransformService_Direct.json
@@ -1,5 +1,5 @@
 {
   "comment": "Modify this file in a trivial way to cause this test suite to 
run",
-  "revision": 5,
+  "revision": 2,
   "https://github.com/apache/beam/pull/39990": "removing dead code from 
FnApiDoFnRunner"
 }
diff --git 
a/sdks/java/core/src/main/java/org/apache/beam/sdk/util/construction/TransformUpgrader.java
 
b/sdks/java/core/src/main/java/org/apache/beam/sdk/util/construction/TransformUpgrader.java
index d3f9d9f9194..80f05677535 100644
--- 
a/sdks/java/core/src/main/java/org/apache/beam/sdk/util/construction/TransformUpgrader.java
+++ 
b/sdks/java/core/src/main/java/org/apache/beam/sdk/util/construction/TransformUpgrader.java
@@ -24,6 +24,7 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InvalidClassException;
+import java.io.ObjectInputFilter;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.net.ServerSocket;
@@ -69,6 +70,29 @@ public class TransformUpgrader implements AutoCloseable {
   private static final Logger LOG = 
LoggerFactory.getLogger(TransformUpgrader.class);
   private static final String UPGRADE_NAMESPACE = "transform:upgrade:";
 
+  public static final String DESERIALIZATION_FILTER_PROPERTY =
+      "beam.transformUpgrader.deserializationFilter";
+
+  private static final String DEFAULT_DESERIALIZATION_FILTER_PATTERN =
+      "maxdepth=100;maxrefs=10000;maxbytes=10485760;maxarray=10000;"
+          + "org.apache.beam.**;"
+          + "com.google.**;"
+          + "org.apache.kafka.**;"
+          + "org.apache.avro.**;"
+          + "org.joda.time.**;"
+          + "!java.lang.ProcessBuilder;"
+          + "!java.lang.Runtime;"
+          + "!java.lang.Thread;"
+          + "java.lang.**;"
+          + "java.util.**;"
+          + "java.io.**;"
+          + "java.math.**;"
+          + "java.time.**;"
+          + "!*";
+
+  private static final ObjectInputFilter DEFAULT_DESERIALIZATION_FILTER =
+      
ObjectInputFilter.Config.createFilter(DEFAULT_DESERIALIZATION_FILTER_PATTERN);
+
   @VisibleForTesting static final String UPGRADE_KEY = "upgraded_to_version";
 
   private ExpansionServiceClientFactory clientFactory;
@@ -463,12 +487,21 @@ public class TransformUpgrader implements AutoCloseable {
    * A utility method that converts a byte array obtained by invoking {@link 
#toByteArray(Object)}
    * back to a Java object.
    *
+   * <p>Applies a deserialization filter with resource limits and a package 
allowlist. The filter
+   * pattern can be overridden via the {@link 
#DESERIALIZATION_FILTER_PROPERTY} system property.
+   *
    * @param bytes an array of bytes generated by invoking the {@link 
#toByteArray(Object)} method.
    * @return re-generated object.
    */
   public static Object fromByteArray(byte[] bytes) throws 
InvalidClassException {
     try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
         ObjectInputStream in = new ObjectInputStream(bis)) {
+      String customPattern = 
System.getProperty(DESERIALIZATION_FILTER_PROPERTY);
+      ObjectInputFilter filter =
+          (customPattern != null && !customPattern.isEmpty())
+              ? ObjectInputFilter.Config.createFilter(customPattern)
+              : DEFAULT_DESERIALIZATION_FILTER;
+      in.setObjectInputFilter(filter);
       return in.readObject();
     } catch (InvalidClassException e) {
       LOG.info(
diff --git 
a/sdks/java/core/src/test/java/org/apache/beam/sdk/util/construction/TransformUpgraderTest.java
 
b/sdks/java/core/src/test/java/org/apache/beam/sdk/util/construction/TransformUpgraderTest.java
index 674540fa984..ea44d99d1a1 100644
--- 
a/sdks/java/core/src/test/java/org/apache/beam/sdk/util/construction/TransformUpgraderTest.java
+++ 
b/sdks/java/core/src/test/java/org/apache/beam/sdk/util/construction/TransformUpgraderTest.java
@@ -18,13 +18,16 @@
 package org.apache.beam.sdk.util.construction;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 
 import com.google.auto.service.AutoService;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.io.InvalidClassException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
+import java.net.URI;
 import java.nio.charset.Charset;
 import java.util.Collections;
 import java.util.List;
@@ -487,4 +490,40 @@ public class TransformUpgraderTest {
     assertTrue(TransformUpgrader.compareVersions("2.55.0-SNAPSHOT", "2.53.0") 
> 0);
     assertTrue(TransformUpgrader.compareVersions("2.55.0.dev", "2.53.0") > 0);
   }
+
+  @Test
+  public void testFromByteArrayAllowedAndBlockedClasses() throws Exception {
+    byte[] stringBytes = TransformUpgrader.toByteArray("hello");
+    assertEquals("hello", TransformUpgrader.fromByteArray(stringBytes));
+
+    byte[] beamObjectBytes = TransformUpgrader.toByteArray(new 
TestTransform(5));
+    TestTransform deserializedTransform =
+        (TestTransform) TransformUpgrader.fromByteArray(beamObjectBytes);
+    assertEquals(Integer.valueOf(5), deserializedTransform.getTestParam());
+
+    byte[] disallowedPackageBytes = 
TransformUpgrader.toByteArray(URI.create("http://example.com";));
+    assertThrows(
+        InvalidClassException.class, () -> 
TransformUpgrader.fromByteArray(disallowedPackageBytes));
+
+    byte[] disallowedClassBytes = 
TransformUpgrader.toByteArray(ProcessBuilder.class);
+    assertThrows(
+        InvalidClassException.class, () -> 
TransformUpgrader.fromByteArray(disallowedClassBytes));
+  }
+
+  @Test
+  public void testFromByteArrayCustomFilterProperty() throws Exception {
+    URI uri = URI.create("http://example.com";);
+    byte[] uriBytes = TransformUpgrader.toByteArray(uri);
+    byte[] largeArrayBytes = TransformUpgrader.toByteArray(new byte[100]);
+
+    try {
+      System.setProperty(
+          TransformUpgrader.DESERIALIZATION_FILTER_PROPERTY, 
"maxarray=10;java.net.**;!*");
+      assertEquals(uri, TransformUpgrader.fromByteArray(uriBytes));
+      assertThrows(
+          InvalidClassException.class, () -> 
TransformUpgrader.fromByteArray(largeArrayBytes));
+    } finally {
+      System.clearProperty(TransformUpgrader.DESERIALIZATION_FILTER_PROPERTY);
+    }
+  }
 }

Reply via email to