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

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

commit a6a0ba59dff73f7ad27bf02a20da1ce06085d0b2
Author: Daniel Voros <daniel.vo...@gmail.com>
AuthorDate: Tue Mar 17 17:00:17 2020 +0000

    HIVE-22901: Variable substitution can lead to OOM on circular references 
(Daniel Voros via Zoltan Haindrich)
    
    Signed-off-by: Zoltan Haindrich <k...@rxd.hu>
---
 .../java/org/apache/hadoop/hive/conf/HiveConf.java |  3 +++
 .../apache/hadoop/hive/conf/SystemVariables.java   | 10 ++++++++
 .../hadoop/hive/conf/TestSystemVariables.java      | 29 ++++++++++++++++++++++
 .../org/apache/hive/jdbc/TestRestrictedList.java   |  1 +
 4 files changed, 43 insertions(+)

diff --git a/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java 
b/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java
index 54b33a3..d50912b 100644
--- a/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java
+++ b/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java
@@ -4791,6 +4791,7 @@ public class HiveConf extends Configuration {
             "hive.spark.client.rpc.max.size," +
             "hive.spark.client.rpc.threads," +
             "hive.spark.client.secret.bits," +
+            "hive.query.max.length," +
             "hive.spark.client.rpc.server.address," +
             "hive.spark.client.rpc.server.port," +
             "hive.spark.client.rpc.sasl.mechanisms," +
@@ -4827,6 +4828,8 @@ public class HiveConf extends Configuration {
         SPARK_CLIENT_TYPE.varname,
         "Comma separated list of variables which are related to remote spark 
context.\n" +
             "Changing these variables will result in re-creating the spark 
session."),
+    HIVE_QUERY_MAX_LENGTH("hive.query.max.length", "10Mb", new 
SizeValidator(), "The maximum" +
+            " size of a query string. Enforced after variable substitutions."),
     HIVE_QUERY_TIMEOUT_SECONDS("hive.query.timeout.seconds", "0s",
         new TimeValidator(TimeUnit.SECONDS),
         "Timeout for Running Query in seconds. A nonpositive value means 
infinite. " +
diff --git a/common/src/java/org/apache/hadoop/hive/conf/SystemVariables.java 
b/common/src/java/org/apache/hadoop/hive/conf/SystemVariables.java
index 695f3ec..89ea20e 100644
--- a/common/src/java/org/apache/hadoop/hive/conf/SystemVariables.java
+++ b/common/src/java/org/apache/hadoop/hive/conf/SystemVariables.java
@@ -88,6 +88,10 @@ public class SystemVariables {
   }
 
   protected final String substitute(Configuration conf, String expr, int 
depth) {
+    long maxLength = 0;
+    if (conf != null) {
+      maxLength = HiveConf.getSizeVar(conf, 
HiveConf.ConfVars.HIVE_QUERY_MAX_LENGTH);
+    }
     Matcher match = varPat.matcher("");
     String eval = expr;
     StringBuilder builder = new StringBuilder();
@@ -107,12 +111,18 @@ public class SystemVariables {
           found = true;
         }
         builder.append(eval.substring(prev, match.start())).append(substitute);
+        if (maxLength > 0 && builder.length() > maxLength) {
+          throw new IllegalStateException("Query length longer than 
hive.query.max.length ("+builder.length()+">"+maxLength+").");
+        }
         prev = match.end();
       }
       if (!found) {
         return eval;
       }
       builder.append(eval.substring(prev));
+      if (maxLength > 0 && builder.length() > maxLength) {
+        throw new IllegalStateException("Query length longer than 
hive.query.max.length ("+builder.length()+">"+maxLength+").");
+      }
       eval = builder.toString();
     }
     if (s > depth) {
diff --git 
a/common/src/test/org/apache/hadoop/hive/conf/TestSystemVariables.java 
b/common/src/test/org/apache/hadoop/hive/conf/TestSystemVariables.java
index 6004aba..3641020 100644
--- a/common/src/test/org/apache/hadoop/hive/conf/TestSystemVariables.java
+++ b/common/src/test/org/apache/hadoop/hive/conf/TestSystemVariables.java
@@ -17,6 +17,7 @@
  */
 package org.apache.hadoop.hive.conf;
 
+import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.LocalFileSystem;
 import org.apache.hadoop.fs.Path;
@@ -24,6 +25,7 @@ import org.junit.Test;
 
 import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertNull;
+import static org.junit.Assert.fail;
 
 public class TestSystemVariables {
   public static final String SYSTEM = "system";
@@ -74,4 +76,31 @@ public class TestSystemVariables {
     System.setProperty("java.io.tmpdir", "");
     assertEquals("", SystemVariables.substitute(systemJavaIoTmpDir));
   }
+
+  @Test
+  public void test_SubstituteLongSelfReference() {
+    String randomPart = RandomStringUtils.random(100_000);
+    String reference = "${hiveconf:myTestVariable}";
+
+    StringBuilder longStringWithReferences = new StringBuilder();
+    for(int i = 0; i < 10; i ++) {
+      longStringWithReferences.append(randomPart).append(reference);
+    }
+
+    SystemVariables uut = new SystemVariables();
+
+    HiveConf conf = new HiveConf();
+    conf.set(HiveConf.ConfVars.HIVE_QUERY_MAX_LENGTH.varname, "100Kb");
+    conf.set("myTestVariable", longStringWithReferences.toString());
+
+    try {
+      uut.substitute(conf, longStringWithReferences.toString(), 40);
+    } catch (Exception e) {
+      if (!e.getMessage().startsWith("Query length longer than 
hive.query.max.length")) {
+        fail("unexpected error message: " + e.getMessage());
+      }
+      return;
+    }
+    fail("should have thrown exception during substitution");
+  }
 }
diff --git 
a/itests/hive-unit/src/test/java/org/apache/hive/jdbc/TestRestrictedList.java 
b/itests/hive-unit/src/test/java/org/apache/hive/jdbc/TestRestrictedList.java
index 0890653..cc32a7e 100644
--- 
a/itests/hive-unit/src/test/java/org/apache/hive/jdbc/TestRestrictedList.java
+++ 
b/itests/hive-unit/src/test/java/org/apache/hive/jdbc/TestRestrictedList.java
@@ -93,6 +93,7 @@ public class TestRestrictedList {
     addToExpectedRestrictedMap("hive.spark.client.rpc.server.address");
     addToExpectedRestrictedMap("hive.spark.client.rpc.server.port");
     addToExpectedRestrictedMap("hive.spark.client.rpc.sasl.mechanisms");
+    addToExpectedRestrictedMap("hive.query.max.length");
     addToExpectedRestrictedMap("bonecp.test");
     addToExpectedRestrictedMap("hive.druid.broker.address.default");
     addToExpectedRestrictedMap("hive.druid.coordinator.address.default");

Reply via email to