Projects
openEuler:Mainline
derby
_service:tar_scm:CVE-2018-1313.patch
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:CVE-2018-1313.patch of Package derby
From a2027c64e185a9ce46929f352e2db03371c1f95b Mon Sep 17 00:00:00 2001 From: Bryan Pendleton <bpendleton@apache.org> Date: Sun, 11 Mar 2018 21:50:26 +0000 Subject: [PATCH] Remove support for COMMAND_TESTCONNECTION connectToDatabase feature. It was never documented, and was never part of the regression tests. A new regression test demonstrates that attempting to use this feature now results in a "usage" response from the Network Server. Also, change the Network Server's default security policy file, as well as the template security policy file that we distribute with the release and in the documentation. The new policy files do not use the <<ALL FILES>> permission; instead they restrict the permission to certain directories only. Also, change the implementation of the Network Server's "sysinfo" sub-command. Prior to this change, that feature would open each jar file on the Network Server's class path, and would report on whatever information it could find about that jar file. Now, the only jar files that are opened and reported on are the known Derby jar files; a table of those jar file names is compiled into the sysinfo command. This causes sysinfo to return less information, but it also means that it only needs the permission to access the known Derby jar files on the classpath. git-svn-id: https://svn.apache.org/repos/asf/db/derby/code/branches/10.14@1826467 13f79535-47bb-0310-9956-ffa450edef68 --- .../derby/drda/NetworkServerControl.java | 24 +++- java/drda/org/apache/derby/drda/server.policy | 24 +--- .../org/apache/derby/drda/template.policy | 18 ++- .../impl/drda/NetworkServerControlImpl.java | 48 +------ .../apache/derby/iapi/reference/Property.java | 1 + .../derbynet/NetworkServerControlApiTest.java | 136 ++++++++++++++++++ .../NetworkServerControlApiTest.policy | 4 + .../apache/derby/impl/tools/sysinfo/Main.java | 41 ++++++ 8 files changed, 222 insertions(+), 74 deletions(-) diff --git a/java/drda/org/apache/derby/drda/NetworkServerControl.java b/java/drda/org/apache/derby/drda/NetworkServerControl.java index 73a925b1ef..103342ec87 100644 --- a/java/drda/org/apache/derby/drda/NetworkServerControl.java +++ b/java/drda/org/apache/derby/drda/NetworkServerControl.java @@ -21,6 +21,7 @@ Licensed to the Apache Software Foundation (ASF) under one or more package org.apache.derby.drda; +import java.io.File; import java.io.PrintWriter; import java.net.Inet6Address; import java.net.InetAddress; @@ -686,10 +687,14 @@ private static void installSecurityManager( NetworkServerControlImpl server ) // network codesources. Do not let the customer // override this // - String derbyInstallURL = getCodeSourcePrefix( server ); + URL derbyInstallURL = getCodeSourceURL( server ); + String derbyInstallStr = getCodeSourcePrefix( server, derbyInstallURL ); + String derbyInstallPth = new File(derbyInstallURL.getFile()) + .getParentFile().getAbsolutePath(); + + System.setProperty( Property.DERBY_INSTALL_URL, derbyInstallStr ); + System.setProperty( Property.DERBY_INSTALL_PATH, derbyInstallPth ); - System.setProperty( Property.DERBY_INSTALL_URL, derbyInstallURL ); - // // Now install a SecurityManager, using the Basic policy file. // @@ -790,7 +795,7 @@ private static boolean isIPV6Address( String hostname ) * same directory. * </p> */ - private static String getCodeSourcePrefix( NetworkServerControlImpl server ) + private static URL getCodeSourceURL( NetworkServerControlImpl server ) throws Exception { // Note: This method is expected to run only when no security manager @@ -801,9 +806,14 @@ private static String getCodeSourcePrefix( NetworkServerControlImpl server ) return null; } URL url = cs.getLocation(); - if (url == null) { - return null; - } + return url; + } + + private static String getCodeSourcePrefix( + NetworkServerControlImpl server, + URL url ) + throws Exception + { // Replace in "file://some", but not in "file:///some". String extForm = url.toExternalForm().replaceFirst( "^file://([^/].*)", "file:////$1"); diff --git a/java/drda/org/apache/derby/drda/server.policy b/java/drda/org/apache/derby/drda/server.policy index 30c321cb59..a91c079624 100644 --- a/java/drda/org/apache/derby/drda/server.policy +++ b/java/drda/org/apache/derby/drda/server.policy @@ -32,17 +32,7 @@ grant codeBase "${derby.install.url}derby.jar" permission java.io.FilePermission "${derby.system.home}${/}-", "read,write,delete"; - // This permission lets you backup and restore databases to and from - // arbitrary locations in your file system. - // - // This permission also lets you import/export data to and from arbitrary - // locations in your file system. - // - // You may want to restrict this access to specific directories. - // - permission java.io.FilePermission "<<ALL FILES>>", "read,write,delete"; - - // Needed by sysinfo. The file permission is needed to check the existence of + // Needed by sysinfo. A file permission is needed to check the existence of // jars on the classpath. You can limit this permission to just the locations // which hold your jar files. This block is reproduced for all codebases // which include the sysinfo classes--the policy file syntax does not let you @@ -54,9 +44,9 @@ grant codeBase "${derby.install.url}derby.jar" permission java.util.PropertyPermission "java.runtime.version", "read"; permission java.util.PropertyPermission "java.fullversion", "read"; permission java.lang.RuntimePermission "getProtectionDomain"; - permission java.io.FilePermission "<<ALL FILES>>", "read"; permission java.io.FilePermission "java.runtime.version", "read"; permission java.io.FilePermission "java.fullversion", "read"; + permission java.io.FilePermission "${derby.install.path}${/}-", "read"; // Permissions needed for JMX based management and monitoring. // @@ -143,7 +133,7 @@ grant codeBase "${derby.install.url}derbynet.jar" "control,monitor"; permission org.apache.derby.security.SystemPermission "engine", "usederbyinternals"; - // Needed by sysinfo. The file permission is needed to check the existence of + // Needed by sysinfo. A file permission is needed to check the existence of // jars on the classpath. You can limit this permission to just the locations // which hold your jar files. This block is reproduced for all codebases // which include the sysinfo classes--the policy file syntax does not let you @@ -155,15 +145,15 @@ grant codeBase "${derby.install.url}derbynet.jar" permission java.util.PropertyPermission "java.runtime.version", "read"; permission java.util.PropertyPermission "java.fullversion", "read"; permission java.lang.RuntimePermission "getProtectionDomain"; - permission java.io.FilePermission "<<ALL FILES>>", "read"; permission java.io.FilePermission "java.runtime.version", "read"; permission java.io.FilePermission "java.fullversion", "read"; + permission java.io.FilePermission "${derby.install.path}${/}-", "read"; }; grant codeBase "${derby.install.url}derbytools.jar" { - // Needed by sysinfo. The file permission is needed to check the existence of + // Needed by sysinfo. A file permission is needed to check the existence of // jars on the classpath. You can limit this permission to just the locations // which hold your jar files. This block is for all codebases which include // the sysinfo classes--the policy file syntax does not let you grant @@ -182,7 +172,7 @@ grant codeBase "${derby.install.url}derbytools.jar" grant codeBase "${derby.install.url}derbyclient.jar" { - // Needed by sysinfo. The file permission is needed to check the existence of + // Needed by sysinfo. A file permission is needed to check the existence of // jars on the classpath. You can limit this permission to just the locations // which hold your jar files. This block is reproduced for all codebases // which include the sysinfo classes--the policy file syntax does not let you @@ -194,7 +184,7 @@ grant codeBase "${derby.install.url}derbyclient.jar" permission java.util.PropertyPermission "java.runtime.version", "read"; permission java.util.PropertyPermission "java.fullversion", "read"; permission java.lang.RuntimePermission "getProtectionDomain"; - permission java.io.FilePermission "<<ALL FILES>>", "read"; + permission java.io.FilePermission "${derby.install.path}${/}-", "read"; // The following permission must be granted for Connection.abort(Executor) to // work. Note that this permission must also be granted to outer diff --git a/java/drda/org/apache/derby/drda/template.policy b/java/drda/org/apache/derby/drda/template.policy index 6331564216..60d811e730 100644 --- a/java/drda/org/apache/derby/drda/template.policy +++ b/java/drda/org/apache/derby/drda/template.policy @@ -52,9 +52,13 @@ grant codeBase "${derby.install.url}derby.jar" // This permission also lets you import/export data to and from arbitrary // locations in your file system. // - // You may want to restrict this access to specific directories. + // NOTE: this permission is commented out. You should NOT grant blanket + // permission to the entire filesystem! If you choose to use this + // permission to allow the server to access files outside of the + // server's home directory, you should name those specific directories + // in the permisson (that is, do NOT specify ALL FILES). // - permission java.io.FilePermission "<<ALL FILES>>", "read,write,delete"; + // permission java.io.FilePermission "<<ALL FILES>>", "read,write,delete"; // Permissions needed for JMX based management and monitoring. // @@ -139,9 +143,11 @@ grant codeBase "${derby.install.url}derbynet.jar" // // permission java.net.SocketPermission "*", "connect,resolve"; - // Needed by sysinfo. The file permission is needed to check the existence of - // jars on the classpath. You can limit this permission to just the locations - // which hold your jar files. + // Needed by sysinfo. A file permission is needed to check the existence of + // jars on the classpath. Note that this permission is commented out! + // You should limit this permission to just the locations which hold + // your jar files; do NOT grant blanket permission to read the entire + // filesystem. // // In this template file, this block of permissions is granted to // derbynet.jar under the assumption that derbynet.jar is the first jar file @@ -155,12 +161,12 @@ grant codeBase "${derby.install.url}derbynet.jar" // derbyclient.jar // derbytools.jar // + // permission java.io.FilePermission "${derby.install.directory}${/}-", "read"; permission java.util.PropertyPermission "user.*", "read"; permission java.util.PropertyPermission "java.home", "read"; permission java.util.PropertyPermission "java.class.path", "read"; permission java.util.PropertyPermission "java.runtime.version", "read"; permission java.util.PropertyPermission "java.fullversion", "read"; permission java.lang.RuntimePermission "getProtectionDomain"; - permission java.io.FilePermission "<<ALL FILES>>", "read"; }; diff --git a/java/drda/org/apache/derby/impl/drda/NetworkServerControlImpl.java b/java/drda/org/apache/derby/impl/drda/NetworkServerControlImpl.java index fc624276df..2f5e9ccde8 100644 --- a/java/drda/org/apache/derby/impl/drda/NetworkServerControlImpl.java +++ b/java/drda/org/apache/derby/impl/drda/NetworkServerControlImpl.java @@ -1820,11 +1820,11 @@ protected synchronized void processCommands(DDMReader reader, DDMWriter writer, consolePropertyMessage("DRDA_TraceDirectoryChange.I", traceDirectory); break; case COMMAND_TESTCONNECTION: - databaseArg = reader.readCmdString(); - userArg = reader.readCmdString(); - passwordArg = reader.readCmdString(); + databaseArg = reader.readCmdString(); // This is ... + userArg = reader.readCmdString(); // ... no longer ... + passwordArg = reader.readCmdString(); // ... supported. if (databaseArg != null) - connectToDatabase(writer, databaseArg, userArg, passwordArg); + sendMessage(writer, ERROR, "Usage: ping()"); else sendOK(writer); break; @@ -3931,46 +3931,6 @@ private void setTraceDirectory(String value) - /** - * Connect to a database to test whether a connection can be made - * - * @param writer connection to send message to - * @param database database directory to connect to - * @param user user to use - * @param password password to use - */ - private void connectToDatabase(DDMWriter writer, String database, String user, - String password) throws Exception - { - Properties p = new Properties(); - if (user != null) - p.put("user", user); - if (password != null) - p.put("password", password); - try { - Class.forName(CLOUDSCAPE_DRIVER); - } - catch (Exception e) { - sendMessage(writer, ERROR, e.getMessage()); - return; - } - try { - //Note, we add database to the url so that we can allow additional - //url attributes - Connection conn = getDriver().connect(Attribute.PROTOCOL+database, p); - // send warnings - SQLWarning warn = conn.getWarnings(); - if (warn != null) - sendSQLMessage(writer, warn, SQLWARNING); - else - sendOK(writer); - conn.close(); - return; - } catch (SQLException se) { - sendSQLMessage(writer, se, SQLERROR); - } - } - /** * Wrap SQL Error - display to console and raise exception * diff --git a/java/engine/org/apache/derby/iapi/reference/Property.java b/java/engine/org/apache/derby/iapi/reference/Property.java index bda045629a..ecf9bd9a5b 100644 --- a/java/engine/org/apache/derby/iapi/reference/Property.java +++ b/java/engine/org/apache/derby/iapi/reference/Property.java @@ -416,6 +416,7 @@ Default value for wait timeouts (60 seconds) * This property is the location of the derby jars. **/ public static final String DERBY_INSTALL_URL = "derby.install.url"; + public static final String DERBY_INSTALL_PATH = "derby.install.path"; /** * This property is private to Derby. diff --git a/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/NetworkServerControlApiTest.java b/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/NetworkServerControlApiTest.java index a10c41b595..e50cd5e581 100644 --- a/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/NetworkServerControlApiTest.java +++ b/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/NetworkServerControlApiTest.java @@ -22,6 +22,10 @@ Licensed to the Apache Software Foundation (ASF) under one or more package org.apache.derbyTesting.functionTests.tests.derbynet; import java.io.File; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import javax.net.SocketFactory; +import java.net.Socket; import java.net.InetAddress; import java.net.UnknownHostException; import java.security.AccessController; @@ -205,6 +209,138 @@ public void test_03_Ping() throws Exception // expected exception } } + + /* + * CVE-2018-1313: Attempt to pass arguments to COMMAND_TESTCONNECTION + */ + public void test_03_ping_args() throws Exception + { + String response = tryPingDbError("mydatabase", "myuser", "mypassword"); + //System.out.println(response); + // This once said: XJ004:Database 'mydatabase' not found. + assertEquals("Usage", response.substring(0,5)); + + response = tryPingDbError("some/sorta/db","someone","somecredentials"); + //System.out.println(response); + assertEquals("Usage", response.substring(0,5)); + + response = tryPingDbError("\\\\192.168.1.2\\guest\\db1","tata","tata"); + //System.out.println(response); + assertEquals("Usage", response.substring(0,5)); + + response = tryPingDbError("my/nocred/db", "", ""); + //System.out.println(response); + assertEquals("Usage", response.substring(0,5)); + + response = tryPingDbOK("", "scarface", "evildoer"); + //System.out.println(response); + assertEquals("OK", response.substring(0,2)); + } + + private Socket privilegedClientSocket(final String host, int port) + throws Exception + { + try { + return AccessController.doPrivileged( + new PrivilegedExceptionAction<Socket>() { + public Socket run() throws Exception { + return SocketFactory.getDefault().createSocket( + InetAddress.getByName(host), port); + } + }); + } catch (PrivilegedActionException pae) { + throw (Exception)pae.getCause(); + } + } + + private static String byteArrayToHex(byte[] ba, int l) + { + if (l < 0) return "STRING OF NEGATIVE LENGTH("+l+")"; + StringBuilder sb = new StringBuilder(l * 2); + for (int i = 0; i < l; i++) sb.append(String.format("%02x", ba[i])); + return sb.toString(); + } + + private String tryPingDbError(String d, String u, String p) + throws Exception + { + return tryPingDbTest(2, d, u, p); // Result 2: ERROR + } + + private String tryPingDbOK(String d, String u, String p) + throws Exception + { + return tryPingDbTest(0, d, u, p); // Result 0: OK + } + + private String tryPingDbTest(int rc, String d, String u, String p) + throws Exception + { + //System.out.println("database: '"+d+"' (len: "+d.length()+")"); + //System.out.println(" user: '"+u+"' (len: "+u.length()+")"); + //System.out.println("password: '"+p+"' (len: "+p.length()+")"); + + Socket clientSocket = privilegedClientSocket( + TestConfiguration.getCurrent().getHostName(), + TestConfiguration.getCurrent().getPort()); + ByteArrayOutputStream byteArrayOs = new ByteArrayOutputStream(); + DataOutputStream commandOs = new DataOutputStream(byteArrayOs); + + byte[] msgBytes = "CMD:".getBytes("UTF8"); + commandOs.write(msgBytes,0,msgBytes.length); + commandOs.writeByte((byte) 0); // default version: 02 + commandOs.writeByte((byte) 2); // default version: 02 + commandOs.writeByte((byte) 0); // default locale: 0 + commandOs.writeByte((byte) 0); // default codeset: 0 + commandOs.writeByte((byte) 4); // COMMAND_TESTCONNECTION + + msgBytes = d.getBytes("UTF8"); + commandOs.writeByte((byte)(msgBytes.length >> 8 )); + commandOs.writeByte((byte) msgBytes.length); + commandOs.write(msgBytes,0,msgBytes.length); + + msgBytes = u.getBytes("UTF8"); + commandOs.writeByte((byte)(msgBytes.length >> 8 )); + commandOs.writeByte((byte) msgBytes.length); + commandOs.write(msgBytes,0,msgBytes.length); + + msgBytes = p.getBytes("UTF8"); + commandOs.writeByte((byte)(msgBytes.length >> 8 )); + commandOs.writeByte((byte) msgBytes.length); + commandOs.write(msgBytes,0,msgBytes.length); + + byteArrayOs.writeTo(clientSocket.getOutputStream()); + commandOs.flush(); + byteArrayOs.reset(); + clientSocket.shutdownOutput(); + + byte[]result = new byte[1024]; + int resultLen = clientSocket.getInputStream().read(result); + + clientSocket.close(); + + //System.out.println( "Result was " + resultLen + " bytes long"); + //System.out.println( byteArrayToHex(result,resultLen) ); + + if (resultLen < 0) + return "DISCONNECT"; + + String r = "RPY:"; + int rl = r.length(); + assertTrue(resultLen > rl); + String header = new String(result, 0, rl, "UTF8"); + assertEquals(r, header); + assertEquals(rc, result[rl++]); // 0: OK, 2: ERROR, 3: SQLERROR, etc. + + if (rc == 0) + return "OK"; + + int l = ((result[rl++] & 0xff) << 8) + (result[rl++] & 0xff); + String response = new String(result, rl, l, "UTF8"); + + return response; + } + /** * Wraps InitAddress.getByName in privilege block. diff --git a/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/NetworkServerControlApiTest.policy b/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/NetworkServerControlApiTest.policy index 792bcea43f..50f894a718 100644 --- a/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/NetworkServerControlApiTest.policy +++ b/java/testing/org/apache/derbyTesting/functionTests/tests/derbynet/NetworkServerControlApiTest.policy @@ -186,6 +186,10 @@ grant codeBase "${derbyTesting.testjar}derbyTesting.jar" { // Needed by NetworkServerTestSetup when probing ports. permission java.net.SocketPermission "localhost", "listen"; + permission java.net.SocketPermission "127.0.0.1", "accept,connect,resolve"; + permission java.net.SocketPermission "localhost", "accept,connect,listen"; + permission java.net.SocketPermission "${derbyTesting.clienthost}", "accept,connect"; + permission java.net.SocketPermission "${derbyTesting.serverhost}", "accept,connect"; }; // diff --git a/java/tools/org/apache/derby/impl/tools/sysinfo/Main.java b/java/tools/org/apache/derby/impl/tools/sysinfo/Main.java index e332ded977..6e88063202 100644 --- a/java/tools/org/apache/derby/impl/tools/sysinfo/Main.java +++ b/java/tools/org/apache/derby/impl/tools/sysinfo/Main.java @@ -23,6 +23,8 @@ Licensed to the Apache Software Foundation (ASF) under one or more import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.Arrays; +import java.util.List; import java.util.Locale; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -889,6 +891,31 @@ private static String argumentMatches(String[] args, String ss) { ".properties", }; + private static final String jarNames[] = + { + "derby.jar", + "derbyclient.jar", + "derbynet.jar", + "derbyoptionaltools.jar", + "derbyrun.jar", + "derbyshared.jar", + "derbyTesting.jar", + "derbytools.jar", + "derbyLocale_cs.jar", + "derbyLocale_de_DE.jar", + "derbyLocale_es.jar", + "derbyLocale_ja_JP.jar", + "derbyLocale_ko_KR.jar", + "derbyLocale_pl.jar", + "derbyLocale_pt_BR.jar", + "derbyLocale_ru.jar", + "derbyLocale_fr.jar", + "derbyLocale_zh_CN.jar", + "derbyLocale_hu.jar", + "derbyLocale_zh_TW.jar", + "derbyLocale_it.jar" + }; + /** * Get all the info we can obtain from the local execution context * as to the availability of the Derby classes by attempting to load @@ -920,9 +947,23 @@ private static String argumentMatches(String[] args, String ss) { { if (classpath != null) { String cp [] = parseClasspath(classpath); + List<String> jarNamesList = Arrays.asList(jarNames); Vector<ZipInfoProperties> v = new Vector<ZipInfoProperties>(); for (int i = 0; i < cp.length; i++) { + boolean matches = false; + String candidate = cp[i]; + for (String jarName : jarNames) + { + if (candidate.endsWith(jarName)) + { + matches = true; + break; + } + } + if (!matches) + continue; + ZipInfoProperties zip = null; try { zip = checkForInfo(cp[i]);
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2