Remove parent's env vars from child processes
This commit is contained in:
parent
dd8aba3fad
commit
b0bcb4e728
@ -33,6 +33,7 @@
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.hadoop.classification.InterfaceAudience;
|
||||
import org.apache.hadoop.classification.InterfaceStability;
|
||||
import org.apache.hadoop.security.alias.AbstractJavaKeyStoreProvider;
|
||||
|
||||
/**
|
||||
* A base class for running a Unix command.
|
||||
@ -280,6 +281,8 @@ public static String[] getRunScriptCommand(File script) {
|
||||
/** If or not script timed out*/
|
||||
private AtomicBoolean timedOut;
|
||||
|
||||
/** Indicates if the parent env vars should be inherited or not*/
|
||||
protected boolean inheritParentEnv = true;
|
||||
|
||||
/** Centralized logic to discover and validate the sanity of the Hadoop
|
||||
* home directory. Returns either NULL or a directory that exists and
|
||||
@ -467,6 +470,20 @@ private void runCommand() throws IOException {
|
||||
if (environment != null) {
|
||||
builder.environment().putAll(this.environment);
|
||||
}
|
||||
|
||||
// Remove all env vars from the Builder to prevent leaking of env vars from
|
||||
// the parent process.
|
||||
if (!inheritParentEnv) {
|
||||
// branch-2: Only do this for HADOOP_CREDSTORE_PASSWORD
|
||||
// Sometimes daemons are configured to use the CredentialProvider feature
|
||||
// and given their jceks password via an environment variable. We need to
|
||||
// make sure to remove it so it doesn't leak to child processes, which
|
||||
// might be owned by a different user. For example, the NodeManager
|
||||
// running a User's container.
|
||||
builder.environment().remove(
|
||||
AbstractJavaKeyStoreProvider.CREDENTIAL_PASSWORD_NAME);
|
||||
}
|
||||
|
||||
if (dir != null) {
|
||||
builder.directory(this.dir);
|
||||
}
|
||||
@ -690,6 +707,11 @@ public ShellCommandExecutor(String[] execString, File dir,
|
||||
this(execString, dir, env , 0L);
|
||||
}
|
||||
|
||||
public ShellCommandExecutor(String[] execString, File dir,
|
||||
Map<String, String> env, long timeout) {
|
||||
this(execString, dir, env , timeout, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the ShellCommandExecutor to execute a command.
|
||||
*
|
||||
@ -702,10 +724,12 @@ public ShellCommandExecutor(String[] execString, File dir,
|
||||
* environment is not modified.
|
||||
* @param timeout Specifies the time in milliseconds, after which the
|
||||
* command will be killed and the status marked as timedout.
|
||||
* If 0, the command will not be timed out.
|
||||
* If 0, the command will not be timed out.
|
||||
* @param inheritParentEnv Indicates if the process should inherit the env
|
||||
* vars from the parent process or not.
|
||||
*/
|
||||
public ShellCommandExecutor(String[] execString, File dir,
|
||||
Map<String, String> env, long timeout) {
|
||||
Map<String, String> env, long timeout, boolean inheritParentEnv) {
|
||||
command = execString.clone();
|
||||
if (dir != null) {
|
||||
setWorkingDirectory(dir);
|
||||
@ -714,6 +738,7 @@ public ShellCommandExecutor(String[] execString, File dir,
|
||||
setEnvironment(env);
|
||||
}
|
||||
timeOutInterval = timeout;
|
||||
this.inheritParentEnv = inheritParentEnv;
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
package org.apache.hadoop.util;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.apache.hadoop.security.alias.AbstractJavaKeyStoreProvider;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
@ -27,8 +28,13 @@
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.ThreadInfo;
|
||||
import java.lang.management.ThreadMXBean;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.hadoop.fs.FileUtil;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestShell extends TestCase {
|
||||
|
||||
@ -111,6 +117,44 @@ public void testShellCommandTimeout() throws Throwable {
|
||||
shellFile.delete();
|
||||
assertTrue("Script didnt not timeout" , shexc.isTimedOut());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnvVarsWithInheritance() throws Exception {
|
||||
Assume.assumeFalse(Shell.WINDOWS);
|
||||
testEnvHelper(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnvVarsWithoutInheritance() throws Exception {
|
||||
Assume.assumeFalse(Shell.WINDOWS);
|
||||
testEnvHelper(false);
|
||||
}
|
||||
|
||||
private void testEnvHelper(boolean inheritParentEnv) throws Exception {
|
||||
Map<String, String> customEnv = Collections.singletonMap(
|
||||
AbstractJavaKeyStoreProvider.CREDENTIAL_PASSWORD_NAME, "foo");
|
||||
Shell.ShellCommandExecutor command = new Shell.ShellCommandExecutor(
|
||||
new String[]{"env"}, null, customEnv, 0L,
|
||||
inheritParentEnv);
|
||||
command.execute();
|
||||
String[] varsArr = command.getOutput().split("\n");
|
||||
Map<String, String> vars = new HashMap<>();
|
||||
for (String var : varsArr) {
|
||||
int eqIndex = var.indexOf('=');
|
||||
vars.put(var.substring(0, eqIndex), var.substring(eqIndex + 1));
|
||||
}
|
||||
Map<String, String> expectedEnv = new HashMap<>();
|
||||
expectedEnv.putAll(System.getenv());
|
||||
if (inheritParentEnv) {
|
||||
expectedEnv.putAll(customEnv);
|
||||
} else {
|
||||
assertFalse("child process environment should not have contained "
|
||||
+ AbstractJavaKeyStoreProvider.CREDENTIAL_PASSWORD_NAME,
|
||||
vars.containsKey(
|
||||
AbstractJavaKeyStoreProvider.CREDENTIAL_PASSWORD_NAME));
|
||||
}
|
||||
assertEquals(expectedEnv, vars);
|
||||
}
|
||||
|
||||
private static int countTimerThreads() {
|
||||
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
|
||||
|
@ -269,7 +269,9 @@ protected CommandExecutor buildCommandExecutor(String wrapperScriptPath,
|
||||
return new ShellCommandExecutor(
|
||||
command,
|
||||
wordDir,
|
||||
environment);
|
||||
environment,
|
||||
0L,
|
||||
false);
|
||||
}
|
||||
|
||||
protected LocalWrapperScriptBuilder getLocalWrapperScriptBuilder(
|
||||
|
@ -238,9 +238,11 @@ public int launchContainer(Container container,
|
||||
LOG.debug("launchContainer: " + commandStr + " " + Joiner.on(" ").join(command));
|
||||
}
|
||||
shExec = new ShellCommandExecutor(
|
||||
command,
|
||||
new File(containerWorkDir.toUri().getPath()),
|
||||
container.getLaunchContext().getEnvironment()); // sanitized env
|
||||
command,
|
||||
new File(containerWorkDir.toUri().getPath()),
|
||||
container.getLaunchContext().getEnvironment(), // sanitized env
|
||||
0L,
|
||||
false);
|
||||
if (isContainerActive(containerId)) {
|
||||
shExec.execute();
|
||||
} else {
|
||||
|
@ -228,7 +228,8 @@ public void startLocalizer(Path nmPrivateContainerTokensPath,
|
||||
}
|
||||
buildMainArgs(command, user, appId, locId, nmAddr, localDirs);
|
||||
String[] commandArray = command.toArray(new String[command.size()]);
|
||||
ShellCommandExecutor shExec = new ShellCommandExecutor(commandArray);
|
||||
ShellCommandExecutor shExec = new ShellCommandExecutor(commandArray,
|
||||
null, null, 0L, true);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("initApplication: " + Arrays.toString(commandArray));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user