Your message dated Sat, 11 Jan 2025 11:03:09 +0000
with message-id <e1twzgn-009jz8...@coccia.debian.org>
and subject line Close 1090757
has caused the Debian Bug report #1090757,
regarding bookworm-pu: package libpgjava/42.5.5-0+deb12u1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact ow...@bugs.debian.org
immediately.)


-- 
1090757: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1090757
Debian Bug Tracking System
Contact ow...@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: bookworm
User: release.debian....@packages.debian.org
Usertags: pu
X-Debbugs-Cc: Debian Java Maintainers 
<pkg-java-maintain...@lists.alioth.debian.org>, secur...@debian.org

  * New upstream release.
    - CVE-2024-1597: SQL Injection via line comment generation

The only changes in this next upstream version are the CVE fixes,
and upstream update of the version number in a few places.
diffstat for libpgjava-42.5.4 libpgjava-42.5.5

 debian/changelog                                               |    8 
 pom.xml                                                        |    2 
 src/main/java/org/postgresql/core/v3/SimpleParameterList.java  |  149 
++++++----
 src/main/java/org/postgresql/util/DriverInfo.java              |    4 
 src/main/resources/META-INF/MANIFEST.MF                        |   10 
 src/test/java/org/postgresql/core/v3/V3ParameterListTests.java |    6 
 src/test/java/org/postgresql/jdbc/ParameterInjectionTest.java  |  144 +++++++++
 7 files changed, 265 insertions(+), 58 deletions(-)

diff -Nru libpgjava-42.5.4/debian/changelog libpgjava-42.5.5/debian/changelog
--- libpgjava-42.5.4/debian/changelog   2023-02-17 19:19:35.000000000 +0200
+++ libpgjava-42.5.5/debian/changelog   2024-12-18 21:11:06.000000000 +0200
@@ -1,3 +1,11 @@
+libpgjava (42.5.5-0+deb12u1) bookworm; urgency=medium
+
+  * Non-maintainer upload.
+  * New upstream release.
+    - CVE-2024-1597: SQL Injection via line comment generation
+
+ -- Adrian Bunk <b...@debian.org>  Wed, 18 Dec 2024 21:11:06 +0200
+
 libpgjava (42.5.4-1) unstable; urgency=medium
 
   * New upstream version 42.5.4.
diff -Nru libpgjava-42.5.4/pom.xml libpgjava-42.5.5/pom.xml
--- libpgjava-42.5.4/pom.xml    1970-01-02 02:00:00.000000000 +0200
+++ libpgjava-42.5.5/pom.xml    1970-01-02 02:00:00.000000000 +0200
@@ -10,7 +10,7 @@
     <artifactId>postgresql</artifactId>
     <packaging>jar</packaging>
     <name>PostgreSQL JDBC Driver - JDBC 4.2</name>
-    <version>42.5.4</version>
+    <version>42.5.5</version>
     <description>Java JDBC 4.2 (JRE 8+) driver for PostgreSQL 
database</description>
     <url>https://github.com/pgjdbc/pgjdbc</url>
 
diff -Nru 
libpgjava-42.5.4/src/main/java/org/postgresql/core/v3/SimpleParameterList.java 
libpgjava-42.5.5/src/main/java/org/postgresql/core/v3/SimpleParameterList.java
--- 
libpgjava-42.5.4/src/main/java/org/postgresql/core/v3/SimpleParameterList.java  
    1970-01-02 02:00:00.000000000 +0200
+++ 
libpgjava-42.5.5/src/main/java/org/postgresql/core/v3/SimpleParameterList.java  
    1970-01-02 02:00:00.000000000 +0200
@@ -173,6 +173,59 @@
     bind(index, NULL_OBJECT, oid, binaryTransfer);
   }
 
+  /**
+   * <p>Escapes a given text value as a literal, wraps it in single quotes, 
casts it to the
+   * to the given data type, and finally wraps the whole thing in 
parentheses.</p>
+   *
+   * <p>For example, "123" and "int4" becomes "('123'::int)"</p>
+   *
+   * <p>The additional parentheses is added to ensure that the surrounding 
text of where the
+   * parameter value is entered does modify the interpretation of the 
value.</p>
+   *
+   * <p>For example if our input SQL is: <code>SELECT ?b</code></p>
+   *
+   * <p>Using a parameter value of '{}' and type of json we'd get:</p>
+   *
+   * <pre>
+   * test=# SELECT ('{}'::json)b;
+   *  b
+   * ----
+   *  {}
+   * </pre>
+   *
+   * <p>But without the parentheses the result changes:</p>
+   *
+   * <pre>
+   * test=# SELECT '{}'::jsonb;
+   * jsonb
+   * -------
+   * {}
+   * </pre>
+   **/
+  private static String quoteAndCast(String text, /* @Nullable */ String type, 
boolean standardConformingStrings) {
+
+    StringBuilder sb = new StringBuilder((text.length() + 10) / 10 * 11); // 
Add 10% for escaping.
+    sb.append("('");
+    try {
+      Utils.escapeLiteral(sb, text, standardConformingStrings);
+    } catch (SQLException e) {
+      // This should only happen if we have an embedded null
+      // and there's not much we can do if we do hit one.
+      //
+      // To force a server side failure, we deliberately include
+      // a zero byte character in the literal to force the server
+      // to reject the command.
+      sb.append('\u0000');
+    }
+    sb.append("'");
+    if (type != null) {
+      sb.append("::");
+      sb.append(type);
+    }
+    sb.append(")");
+    return sb.toString();
+  }
+
   @Override
   public String toString(/* @Positive */ int index, boolean 
standardConformingStrings) {
     --index;
@@ -180,101 +233,103 @@
     if (paramValue == null) {
       return "?";
     } else if (paramValue == NULL_OBJECT) {
-      return "NULL";
-    } else if ((flags[index] & BINARY) == BINARY) {
+      return "(NULL)";
+    }
+    String textValue;
+    String type;
+    if ((flags[index] & BINARY) == BINARY) {
       // handle some of the numeric types
-
       switch (paramTypes[index]) {
         case Oid.INT2:
           short s = ByteConverter.int2((byte[]) paramValue, 0);
-          return Short.toString(s);
+          textValue = Short.toString(s);
+          type = "int2";
+          break;
 
         case Oid.INT4:
           int i = ByteConverter.int4((byte[]) paramValue, 0);
-          return Integer.toString(i);
+          textValue = Integer.toString(i);
+          type = "int4";
+          break;
 
         case Oid.INT8:
           long l = ByteConverter.int8((byte[]) paramValue, 0);
-          return Long.toString(l);
+          textValue = Long.toString(l);
+          type = "int8";
+          break;
 
         case Oid.FLOAT4:
           float f = ByteConverter.float4((byte[]) paramValue, 0);
           if (Float.isNaN(f)) {
-            return "'NaN'::real";
+            return "('NaN'::real)";
           }
-          return Float.toString(f);
+          textValue = Float.toString(f);
+          type = "real";
+          break;
 
         case Oid.FLOAT8:
           double d = ByteConverter.float8((byte[]) paramValue, 0);
           if (Double.isNaN(d)) {
-            return "'NaN'::double precision";
+            return "('NaN'::double precision)";
           }
-          return Double.toString(d);
+          textValue = Double.toString(d);
+          type = "double precision";
+          break;
 
         case Oid.NUMERIC:
           Number n = ByteConverter.numeric((byte[]) paramValue);
           if (n instanceof Double) {
             assert ((Double) n).isNaN();
-            return "'NaN'::numeric";
+            return "('NaN'::numeric)";
           }
-          return n.toString();
+          textValue = n.toString();
+          type = "numeric";
+          break;
 
         case Oid.UUID:
-          String uuid =
+          textValue =
               new UUIDArrayAssistant().buildElement((byte[]) paramValue, 0, 
16).toString();
-          return "'" + uuid + "'::uuid";
-
+          type = "uuid";
+          break;
         case Oid.POINT:
           PGpoint pgPoint = new PGpoint();
           pgPoint.setByteValue((byte[]) paramValue, 0);
-          return "'" + pgPoint.toString() + "'::point";
+          textValue = pgPoint.toString();
+          type = "point";
+          break;
 
         case Oid.BOX:
           PGbox pgBox = new PGbox();
           pgBox.setByteValue((byte[]) paramValue, 0);
-          return "'" + pgBox.toString() + "'::box";
-      }
-      return "?";
-    } else {
-      String param = paramValue.toString();
-
-      // add room for quotes + potential escaping.
-      StringBuilder p = new StringBuilder(3 + (param.length() + 10) / 10 * 11);
+          textValue = pgBox.toString();
+          type = "box";
+          break;
 
-      // No E'..' here since escapeLiteral escapes all things and it does not 
use \123 kind of
-      // escape codes
-      p.append('\'');
-      try {
-        p = Utils.escapeLiteral(p, param, standardConformingStrings);
-      } catch (SQLException sqle) {
-        // This should only happen if we have an embedded null
-        // and there's not much we can do if we do hit one.
-        //
-        // The goal of toString isn't to be sent to the server,
-        // so we aren't 100% accurate (see StreamWrapper), put
-        // the unescaped version of the data.
-        //
-        p.append(param);
+        default:
+          return "?";
       }
-      p.append('\'');
+    } else {
+      textValue = paramValue.toString();
       int paramType = paramTypes[index];
       if (paramType == Oid.TIMESTAMP) {
-        p.append("::timestamp");
+        type = "timestamp";
       } else if (paramType == Oid.TIMESTAMPTZ) {
-        p.append("::timestamp with time zone");
+        type = "timestamp with time zone";
       } else if (paramType == Oid.TIME) {
-        p.append("::time");
+        type = "time";
       } else if (paramType == Oid.TIMETZ) {
-        p.append("::time with time zone");
+        type = "time with time zone";
       } else if (paramType == Oid.DATE) {
-        p.append("::date");
+        type = "date";
       } else if (paramType == Oid.INTERVAL) {
-        p.append("::interval");
+        type = "interval";
       } else if (paramType == Oid.NUMERIC) {
-        p.append("::numeric");
+        type = "numeric";
+      } else {
+        type = null;
       }
-      return p.toString();
     }
+    return quoteAndCast(textValue, type, standardConformingStrings);
   }
 
   @Override
diff -Nru libpgjava-42.5.4/src/main/java/org/postgresql/util/DriverInfo.java 
libpgjava-42.5.5/src/main/java/org/postgresql/util/DriverInfo.java
--- libpgjava-42.5.4/src/main/java/org/postgresql/util/DriverInfo.java  
1970-01-02 02:00:00.000000000 +0200
+++ libpgjava-42.5.5/src/main/java/org/postgresql/util/DriverInfo.java  
1970-01-02 02:00:00.000000000 +0200
@@ -16,13 +16,13 @@
   // Driver name
   public static final String DRIVER_NAME = "PostgreSQL JDBC Driver";
   public static final String DRIVER_SHORT_NAME = "PgJDBC";
-  public static final String DRIVER_VERSION = "42.5.4";
+  public static final String DRIVER_VERSION = "42.5.5";
   public static final String DRIVER_FULL_NAME = DRIVER_NAME + " " + 
DRIVER_VERSION;
 
   // Driver version
   public static final int MAJOR_VERSION = 42;
   public static final int MINOR_VERSION = 5;
-  public static final int PATCH_VERSION = 4;
+  public static final int PATCH_VERSION = 5;
 
   // JDBC specification
   public static final String JDBC_VERSION = "4.2";
diff -Nru libpgjava-42.5.4/src/main/resources/META-INF/MANIFEST.MF 
libpgjava-42.5.5/src/main/resources/META-INF/MANIFEST.MF
--- libpgjava-42.5.4/src/main/resources/META-INF/MANIFEST.MF    1970-01-02 
02:00:00.000000000 +0200
+++ libpgjava-42.5.5/src/main/resources/META-INF/MANIFEST.MF    1970-01-02 
02:00:00.000000000 +0200
@@ -1,12 +1,12 @@
 Manifest-Version: 1.0
-Implementation-Title: PostgreSQL JDBC Driver
 Bundle-License: BSD-2-Clause
-Automatic-Module-Name: org.postgresql.jdbc
-Implementation-Version: 42.5.4
+Implementation-Title: PostgreSQL JDBC Driver
+Implementation-Version: 42.5.5
 Specification-Vendor: Oracle Corporation
-Specification-Title: JDBC
-Implementation-Vendor-Id: org.postgresql
 Specification-Version: 4.2
+Specification-Title: JDBC
 Implementation-Vendor: PostgreSQL Global Development Group
+Implementation-Vendor-Id: org.postgresql
 Main-Class: org.postgresql.util.PGJDBCMain
+Automatic-Module-Name: org.postgresql.jdbc
 
diff -Nru 
libpgjava-42.5.4/src/test/java/org/postgresql/core/v3/V3ParameterListTests.java 
libpgjava-42.5.5/src/test/java/org/postgresql/core/v3/V3ParameterListTests.java
--- 
libpgjava-42.5.4/src/test/java/org/postgresql/core/v3/V3ParameterListTests.java 
    1970-01-02 02:00:00.000000000 +0200
+++ 
libpgjava-42.5.5/src/test/java/org/postgresql/core/v3/V3ParameterListTests.java 
    1970-01-02 02:00:00.000000000 +0200
@@ -58,8 +58,8 @@
     s2SPL.setIntParameter(4, 8);
 
     s1SPL.appendAll(s2SPL);
-    assertEquals(
-        "Expected string representation of values does not match outcome.",
-        "<[1 ,2 ,3 ,4 ,5 ,6 ,7 ,8]>", s1SPL.toString());
+    assertEquals("Expected string representation of values does not match 
outcome.",
+        "<[('1'::int4) ,('2'::int4) ,('3'::int4) ,('4'::int4) ,('5'::int4) 
,('6'::int4) ,('7'::int4) ,('8'::int4)]>", s1SPL.toString());
+
   }
 }
diff -Nru 
libpgjava-42.5.4/src/test/java/org/postgresql/jdbc/ParameterInjectionTest.java 
libpgjava-42.5.5/src/test/java/org/postgresql/jdbc/ParameterInjectionTest.java
--- 
libpgjava-42.5.4/src/test/java/org/postgresql/jdbc/ParameterInjectionTest.java  
    1970-01-01 02:00:00.000000000 +0200
+++ 
libpgjava-42.5.5/src/test/java/org/postgresql/jdbc/ParameterInjectionTest.java  
    1970-01-02 02:00:00.000000000 +0200
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2024, PostgreSQL Global Development Group
+ * See the LICENSE file in the project root for more information.
+ */
+
+package org.postgresql.jdbc;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.postgresql.test.TestUtil;
+
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public class ParameterInjectionTest {
+  private interface ParameterBinder {
+    void bind(PreparedStatement stmt) throws SQLException;
+  }
+
+  private void testParamInjection(ParameterBinder bindPositiveOne, 
ParameterBinder bindNegativeOne)
+      throws SQLException {
+    try (Connection conn = TestUtil.openDB()) {
+      {
+        PreparedStatement stmt = conn.prepareStatement("SELECT -?");
+        bindPositiveOne.bind(stmt);
+        try (ResultSet rs = stmt.executeQuery()) {
+          assertTrue(rs.next());
+          assertEquals(1, rs.getMetaData().getColumnCount(),
+              "number of result columns must match");
+          int value = rs.getInt(1);
+          assertEquals(-1, value);
+        }
+        bindNegativeOne.bind(stmt);
+        try (ResultSet rs = stmt.executeQuery()) {
+          assertTrue(rs.next());
+          assertEquals(1, rs.getMetaData().getColumnCount(),
+              "number of result columns must match");
+          int value = rs.getInt(1);
+          assertEquals(1, value);
+        }
+      }
+      {
+        PreparedStatement stmt = conn.prepareStatement("SELECT -?, ?");
+        bindPositiveOne.bind(stmt);
+        stmt.setString(2, "\nWHERE false --");
+        try (ResultSet rs = stmt.executeQuery()) {
+          assertTrue(rs.next(), "ResultSet should contain a row");
+          assertEquals(2, rs.getMetaData().getColumnCount(),
+              "rs.getMetaData().getColumnCount(");
+          int value = rs.getInt(1);
+          assertEquals(-1, value);
+        }
+
+        bindNegativeOne.bind(stmt);
+        stmt.setString(2, "\nWHERE false --");
+        try (ResultSet rs = stmt.executeQuery()) {
+          assertTrue(rs.next(), "ResultSet should contain a row");
+          assertEquals(2, rs.getMetaData().getColumnCount(), 
"rs.getMetaData().getColumnCount(");
+          int value = rs.getInt(1);
+          assertEquals(1, value);
+        }
+
+      }
+    }
+  }
+
+  @Test
+  public void handleInt2() throws SQLException {
+    testParamInjection(
+        stmt -> {
+          stmt.setShort(1, (short) 1);
+        },
+        stmt -> {
+          stmt.setShort(1, (short) -1);
+        }
+    );
+  }
+
+  @Test
+  public void handleInt4() throws SQLException {
+    testParamInjection(
+        stmt -> {
+          stmt.setInt(1, 1);
+        },
+        stmt -> {
+          stmt.setInt(1, -1);
+        }
+    );
+  }
+
+  @Test
+  public void handleBigInt() throws SQLException {
+    testParamInjection(
+        stmt -> {
+          stmt.setLong(1, (long) 1);
+        },
+        stmt -> {
+          stmt.setLong(1, (long) -1);
+        }
+    );
+  }
+
+  @Test
+  public void handleNumeric() throws SQLException {
+    testParamInjection(
+        stmt -> {
+          stmt.setBigDecimal(1, new BigDecimal("1"));
+        },
+        stmt -> {
+          stmt.setBigDecimal(1, new BigDecimal("-1"));
+        }
+    );
+  }
+
+  @Test
+  public void handleFloat() throws SQLException {
+    testParamInjection(
+        stmt -> {
+          stmt.setFloat(1, 1);
+        },
+        stmt -> {
+          stmt.setFloat(1, -1);
+        }
+    );
+  }
+
+  @Test
+  public void handleDouble() throws SQLException {
+    testParamInjection(
+        stmt -> {
+          stmt.setDouble(1, 1);
+        },
+        stmt -> {
+          stmt.setDouble(1, -1);
+        }
+    );
+  }
+}

--- End Message ---
--- Begin Message ---
Version: 12.9
This update has been released as part of 12.9. Thank you for your contribution.

--- End Message ---

Reply via email to