Skip to content

Commit

Permalink
Remove parent's env vars from child processes
Browse files Browse the repository at this point in the history
(cherry picked from commit b0bcb4e)
  • Loading branch information
rkanter authored and sjlee committed Sep 15, 2016
1 parent a1272d5 commit c3b7425
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,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.
Expand Down Expand Up @@ -279,6 +280,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
Expand Down Expand Up @@ -466,6 +469,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);
}
Expand Down Expand Up @@ -683,6 +700,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.
*
Expand All @@ -695,10 +717,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);
Expand All @@ -707,6 +731,7 @@ public ShellCommandExecutor(String[] execString, File dir,
setEnvironment(env);
}
timeOutInterval = timeout;
this.inheritParentEnv = inheritParentEnv;
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {

Expand Down Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,9 @@ protected CommandExecutor buildCommandExecutor(String wrapperScriptPath,
return new ShellCommandExecutor(
command,
wordDir,
environment);
environment,
0L,
false);
}

protected LocalWrapperScriptBuilder getLocalWrapperScriptBuilder(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,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));
}
Expand Down

0 comments on commit c3b7425

Please sign in to comment.