Bug#1090757: bookworm-pu: package libpgjava/42.5.5-0+deb12u1
Adrian Bunk
bunk at debian.org
Wed Dec 18 19:32:08 GMT 2024
Package: release.debian.org
Severity: normal
Tags: bookworm
User: release.debian.org at packages.debian.org
Usertags: pu
X-Debbugs-Cc: Debian Java Maintainers <pkg-java-maintainers at lists.alioth.debian.org>, security at 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.
-------------- next part --------------
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 <bunk at 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);
+ }
+ );
+ }
+}
More information about the pkg-java-maintainers
mailing list