commit c9b76f3c27273eec5f2094017efe716d6c2b7fbd Author: Eric Yang Date: Fri Jul 19 13:45:01 2019 -0400 Fixed yarn.service.am.java.opts shell injection. diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/exceptions/RestApiErrorMessages.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/exceptions/RestApiErrorMessages.java index 57c6449..295f14a 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/exceptions/RestApiErrorMessages.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/exceptions/RestApiErrorMessages.java @@ -127,4 +127,5 @@ " not contain a hostname."; String ERROR_KERBEROS_PRINCIPAL_MISSING = "Kerberos principal or keytab is" + " missing."; + String ERROR_JVM_OPTS = "Invalid character in yarn.service.am.java.opts."; } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/utils/ServiceApiUtil.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/utils/ServiceApiUtil.java index 81f84b4..92567ae 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/utils/ServiceApiUtil.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/utils/ServiceApiUtil.java @@ -48,6 +48,7 @@ import org.apache.hadoop.yarn.service.api.records.Resource; import org.apache.hadoop.yarn.service.exceptions.SliderException; import org.apache.hadoop.yarn.service.conf.RestApiConstants; +import org.apache.hadoop.yarn.service.conf.YarnServiceConf; import org.apache.hadoop.yarn.service.exceptions.RestApiErrorMessages; import org.apache.hadoop.yarn.service.monitor.probe.MonitorUtils; import org.apache.hadoop.yarn.service.provider.AbstractClientProvider; @@ -64,6 +65,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static org.apache.hadoop.yarn.service.exceptions.RestApiErrorMessages.ERROR_COMP_DOES_NOT_NEED_UPGRADE; import static org.apache.hadoop.yarn.service.exceptions.RestApiErrorMessages.ERROR_COMP_INSTANCE_DOES_NOT_NEED_UPGRADE; @@ -204,6 +207,9 @@ public static void validateAndResolveService(Service service, // configuration comp.getConfiguration().mergeFrom(globalConf); } + // validate possible command injection. + validateJvmOpts(comp.getConfiguration().getProperties()); + } service.getComponents().removeAll(componentsToRemove); service.getComponents().addAll(componentsToAdd); @@ -246,6 +252,20 @@ public static void validateAndResolveService(Service service, } } + public static void validateJvmOpts(Map properties) + throws IllegalArgumentException { + Pattern pattern = Pattern.compile("[!~#?@*&%${}()<>\\[\\]|\"\\/,`;]"); + if (properties.containsKey(YarnServiceConf.JVM_OPTS)) { + Matcher matcher = pattern.matcher( + properties.get(YarnServiceConf.JVM_OPTS)); + if (matcher.find()) { + throw new IllegalArgumentException( + RestApiErrorMessages.ERROR_JVM_OPTS); + } + } + + } + public static void validateKerberosPrincipal( KerberosPrincipal kerberosPrincipal) throws IOException { if (!StringUtils.isEmpty(kerberosPrincipal.getPrincipalName())) { diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/test/java/org/apache/hadoop/yarn/service/utils/TestServiceApiUtil.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/test/java/org/apache/hadoop/yarn/service/utils/TestServiceApiUtil.java index 3c9b524..0ee5815 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/test/java/org/apache/hadoop/yarn/service/utils/TestServiceApiUtil.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/test/java/org/apache/hadoop/yarn/service/utils/TestServiceApiUtil.java @@ -31,6 +31,7 @@ import org.apache.hadoop.yarn.service.api.records.Resource; import org.apache.hadoop.yarn.service.api.records.Service; import org.apache.hadoop.yarn.service.api.records.ServiceState; +import org.apache.hadoop.yarn.service.conf.YarnServiceConf; import org.apache.hadoop.yarn.service.exceptions.RestApiErrorMessages; import org.junit.Assert; import org.junit.BeforeClass; @@ -43,7 +44,10 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Properties; import static org.assertj.core.api.Assertions.assertThat; import static org.apache.hadoop.yarn.service.conf.RestApiConstants.DEFAULT_UNLIMITED_LIFETIME; @@ -766,6 +770,13 @@ public void run() { Assert.assertTrue(thread.isAlive()); } + @Test(expected = IllegalArgumentException.class) + public void testJvmOpts() { + Map properties = new HashMap(); + properties.put(YarnServiceConf.JVM_OPTS, "`ping -c 3 example.com`"); + ServiceApiUtil.validateJvmOpts(properties); + } + public static Service createExampleApplication() { Service exampleApp = new Service();