You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by om...@apache.org on 2011/03/04 05:29:05 UTC

svn commit: r1077559 - in /hadoop/common/branches/branch-0.20-security-patches/src: mapred/org/apache/hadoop/mapred/ test/org/apache/hadoop/mapred/

Author: omalley
Date: Fri Mar  4 04:29:04 2011
New Revision: 1077559

URL: http://svn.apache.org/viewvc?rev=1077559&view=rev
Log:
commit 06585af93b7081098a0ae5e83c1957c7a20eb8f0
Author: Arun C Murthy <ac...@apache.org>
Date:   Tue Jul 20 10:05:33 2010 -0700

    MAPREDUCE-1207. Sanitize user environment of map/reduce tasks and allow admins to set environment and java options. Contributed by Krishna Ramachandran.
    
    +++ b/YAHOO-CHANGES.txt
    +    MAPREDUCE-1207. Sanitize user environment of map/reduce tasks and allow
    +    admins to set environment and java options. (Krishna Ramachandran via
    +    acmurthy)
    +

Added:
    hadoop/common/branches/branch-0.20-security-patches/src/test/org/apache/hadoop/mapred/TestTaskEnvironment.java
Modified:
    hadoop/common/branches/branch-0.20-security-patches/src/mapred/org/apache/hadoop/mapred/MapTaskRunner.java
    hadoop/common/branches/branch-0.20-security-patches/src/mapred/org/apache/hadoop/mapred/ReduceTaskRunner.java
    hadoop/common/branches/branch-0.20-security-patches/src/mapred/org/apache/hadoop/mapred/TaskRunner.java

Modified: hadoop/common/branches/branch-0.20-security-patches/src/mapred/org/apache/hadoop/mapred/MapTaskRunner.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-0.20-security-patches/src/mapred/org/apache/hadoop/mapred/MapTaskRunner.java?rev=1077559&r1=1077558&r2=1077559&view=diff
==============================================================================
--- hadoop/common/branches/branch-0.20-security-patches/src/mapred/org/apache/hadoop/mapred/MapTaskRunner.java (original)
+++ hadoop/common/branches/branch-0.20-security-patches/src/mapred/org/apache/hadoop/mapred/MapTaskRunner.java Fri Mar  4 04:29:04 2011
@@ -46,11 +46,16 @@ class MapTaskRunner extends TaskRunner {
 
   @Override
   public String getChildJavaOpts(JobConf jobConf, String defaultValue) {
-    return jobConf.get(JobConf.MAPRED_MAP_TASK_JAVA_OPTS, 
-                       super.getChildJavaOpts(jobConf, 
-                           JobConf.DEFAULT_MAPRED_TASK_JAVA_OPTS));
+    String user = 
+      jobConf.get(JobConf.MAPRED_MAP_TASK_JAVA_OPTS, 
+        super.getChildJavaOpts(jobConf, 
+            JobConf.DEFAULT_MAPRED_TASK_JAVA_OPTS));
+    String admin = 
+      jobConf.get(TaskRunner.MAPRED_MAP_ADMIN_JAVA_OPTS,
+        TaskRunner.DEFAULT_MAPRED_ADMIN_JAVA_OPTS);
+    return user + " " + admin;
   }
-  
+
   @Override
   public int getChildUlimit(JobConf jobConf) {
     return jobConf.getInt(JobConf.MAPRED_MAP_TASK_ULIMIT, 

Modified: hadoop/common/branches/branch-0.20-security-patches/src/mapred/org/apache/hadoop/mapred/ReduceTaskRunner.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-0.20-security-patches/src/mapred/org/apache/hadoop/mapred/ReduceTaskRunner.java?rev=1077559&r1=1077558&r2=1077559&view=diff
==============================================================================
--- hadoop/common/branches/branch-0.20-security-patches/src/mapred/org/apache/hadoop/mapred/ReduceTaskRunner.java (original)
+++ hadoop/common/branches/branch-0.20-security-patches/src/mapred/org/apache/hadoop/mapred/ReduceTaskRunner.java Fri Mar  4 04:29:04 2011
@@ -48,14 +48,18 @@ class ReduceTaskRunner extends TaskRunne
     getTask().getProgress().setStatus("closed");
     mapOutputFile.removeAll();
   }
-
+  
   @Override
   public String getChildJavaOpts(JobConf jobConf, String defaultValue) {
-    return jobConf.get(JobConf.MAPRED_REDUCE_TASK_JAVA_OPTS, 
-                       super.getChildJavaOpts(jobConf, 
-                           JobConf.DEFAULT_MAPRED_TASK_JAVA_OPTS));
+    String user = 
+      jobConf.get(JobConf.MAPRED_REDUCE_TASK_JAVA_OPTS, 
+        super.getChildJavaOpts(jobConf, 
+            JobConf.DEFAULT_MAPRED_TASK_JAVA_OPTS));
+    String admin = jobConf.get(TaskRunner.MAPRED_REDUCE_ADMIN_JAVA_OPTS,
+        TaskRunner.DEFAULT_MAPRED_ADMIN_JAVA_OPTS);
+    return user + " " + admin;
   }
- 
+
   @Override
   public int getChildUlimit(JobConf jobConf) {
     return jobConf.getInt(JobConf.MAPRED_REDUCE_TASK_ULIMIT, 

Modified: hadoop/common/branches/branch-0.20-security-patches/src/mapred/org/apache/hadoop/mapred/TaskRunner.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-0.20-security-patches/src/mapred/org/apache/hadoop/mapred/TaskRunner.java?rev=1077559&r1=1077558&r2=1077559&view=diff
==============================================================================
--- hadoop/common/branches/branch-0.20-security-patches/src/mapred/org/apache/hadoop/mapred/TaskRunner.java (original)
+++ hadoop/common/branches/branch-0.20-security-patches/src/mapred/org/apache/hadoop/mapred/TaskRunner.java Fri Mar  4 04:29:04 2011
@@ -53,6 +53,29 @@ import org.apache.hadoop.mapreduce.JobCo
  * user supplied map and reduce functions.
  */
 abstract class TaskRunner extends Thread {
+
+  static final String MAPRED_MAP_ADMIN_JAVA_OPTS =
+    "mapreduce.admin.map.child.java.opts";
+
+  static final String MAPRED_REDUCE_ADMIN_JAVA_OPTS =
+    "mapreduce.admin.reduce.child.java.opts";
+
+  static final String DEFAULT_MAPRED_ADMIN_JAVA_OPTS =
+    "-Djava.net.preferIPv4Stack=true";
+
+  static final String MAPRED_ADMIN_USER_SHELL =
+    "mapreduce.admin.user.shell";
+  
+  static final String DEFAULT_SHELL = "/bin/bash";
+  
+  static final String MAPRED_ADMIN_USER_HOME_DIR =
+    "mapreduce.admin.user.home.dir";
+
+  static final String DEFAULT_HOME_DIR= "/homes/";
+  
+  static final String MAPRED_ADMIN_USER_ENV =
+    "mapreduce.admin.user.env";
+
   public static final Log LOG =
     LogFactory.getLog(TaskRunner.class);
 
@@ -162,6 +185,7 @@ abstract class TaskRunner extends Thread
       
       // We don't create any symlinks yet, so presence/absence of workDir
       // actually on the file system doesn't matter.
+      String user = tip.getUGI().getUserName();
       tip.getUGI().doAs(new PrivilegedExceptionAction<Void>() {
         public Void run() throws IOException {
           taskDistributedCacheManager =
@@ -204,7 +228,7 @@ abstract class TaskRunner extends Thread
                  stderr);
       
       Map<String, String> env = new HashMap<String, String>();
-      errorInfo = getVMEnvironment(errorInfo, workDir, conf, env, taskid,
+      errorInfo = getVMEnvironment(errorInfo, user, workDir, conf, env, taskid,
                                    logSize);
 
       launchJvmAndWait(setup, vargs, stdout, stderr, logSize, workDir, env);
@@ -510,14 +534,7 @@ abstract class TaskRunner extends Thread
     return classPaths;
   }
 
-  /**
-   * @param errorInfo
-   * @param workDir
-   * @param env
-   * @return
-   * @throws Throwable
-   */
-  private String getVMEnvironment(String errorInfo, File workDir, JobConf conf,
+  private String getVMEnvironment(String errorInfo, String user, File workDir, JobConf conf,
       Map<String, String> env, TaskAttemptID taskid, long logSize)
       throws Throwable {
     StringBuffer ldLibraryPath = new StringBuffer();
@@ -529,11 +546,11 @@ abstract class TaskRunner extends Thread
       ldLibraryPath.append(oldLdLibraryPath);
     }
     env.put("LD_LIBRARY_PATH", ldLibraryPath.toString());
-
+    //update user configured login-shell properties
+    updateUserLoginEnv(errorInfo, user, conf, env);
     String jobTokenFile = conf.get(TokenCache.JOB_TOKENS_FILENAME);
     LOG.debug("putting jobToken file name into environment fn=" + jobTokenFile);
-    env.put(UserGroupInformation.HADOOP_TOKEN_FILE_LOCATION, jobTokenFile);
-    
+    env.put(UserGroupInformation.HADOOP_TOKEN_FILE_LOCATION, jobTokenFile);    
     // for the child of task jvm, set hadoop.root.logger
     env.put("HADOOP_ROOT_LOGGER","INFO,TLA");
     String hadoopClientOpts = System.getenv("HADOOP_CLIENT_OPTS");
@@ -549,6 +566,30 @@ abstract class TaskRunner extends Thread
 
     // add the env variables passed by the user
     String mapredChildEnv = getChildEnv(conf);
+    return setEnvFromInputString(errorInfo, env, mapredChildEnv);
+  }
+
+  void updateUserLoginEnv(String errorInfo, String user, JobConf config, 
+      Map<String, String> env) 
+      throws Throwable {
+    env.put("USER",user);
+    env.put("SHELL", config.get(MAPRED_ADMIN_USER_SHELL, DEFAULT_SHELL));
+    env.put("LOGNAME", user);
+    env.put("HOME", config.get(MAPRED_ADMIN_USER_HOME_DIR, DEFAULT_HOME_DIR));
+    // additional user configured login properties
+    String customEnv = config.get(MAPRED_ADMIN_USER_ENV);
+    setEnvFromInputString(errorInfo, env, customEnv);
+  }
+
+  /**
+   * @param errorInfo
+   * @param env
+   * @param mapredChildEnv
+   * @return
+   * @throws Throwable
+   */
+  private String setEnvFromInputString(String errorInfo, Map<String, String> env,
+      String mapredChildEnv) throws Throwable {
     if (mapredChildEnv != null && mapredChildEnv.length() > 0) {
       String childEnvs[] = mapredChildEnv.split(",");
       for (String cEnv : childEnvs) {
@@ -560,7 +601,7 @@ abstract class TaskRunner extends Thread
             // example LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/tmp
             value = parts[1].replace("$" + parts[0], value);
           } else {
-            // this key is not configured by the tt for the child .. get it 
+            // this key is not configured by the tt for the child .. get it
             // from the tt's env
             // example PATH=$PATH:/tmp
             value = System.getenv(parts[0]);
@@ -576,9 +617,9 @@ abstract class TaskRunner extends Thread
           env.put(parts[0], value);
         } catch (Throwable t) {
           // set the error msg
-          errorInfo = "Invalid User environment settings : " + mapredChildEnv 
-                      + ". Failed to parse user-passed environment param."
-                      + " Expecting : env1=value1,env2=value2...";
+          errorInfo = "Invalid User environment settings : " + mapredChildEnv
+              + ". Failed to parse user-passed environment param."
+              + " Expecting : env1=value1,env2=value2...";
           LOG.warn(errorInfo);
           throw t;
         }

Added: hadoop/common/branches/branch-0.20-security-patches/src/test/org/apache/hadoop/mapred/TestTaskEnvironment.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-0.20-security-patches/src/test/org/apache/hadoop/mapred/TestTaskEnvironment.java?rev=1077559&view=auto
==============================================================================
--- hadoop/common/branches/branch-0.20-security-patches/src/test/org/apache/hadoop/mapred/TestTaskEnvironment.java (added)
+++ hadoop/common/branches/branch-0.20-security-patches/src/test/org/apache/hadoop/mapred/TestTaskEnvironment.java Fri Mar  4 04:29:04 2011
@@ -0,0 +1,124 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.mapred;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Vector;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileUtil;
+import org.apache.hadoop.mapred.JvmManager.JvmManagerForType;
+import org.apache.hadoop.mapred.JvmManager.JvmManagerForType.JvmRunner;
+import org.apache.hadoop.mapred.JvmManager.JvmEnv;
+import org.apache.hadoop.mapred.TaskTracker.TaskInProgress;
+import org.apache.hadoop.mapreduce.TaskType;
+import org.apache.hadoop.mapreduce.server.tasktracker.userlogs.UserLogManager;
+import org.junit.After;
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestTaskEnvironment {
+  private static File TEST_DIR = new File(System.getProperty("test.build.data",
+      "/tmp"), TestJvmManager.class.getSimpleName());
+  private static int MAP_SLOTS = 1;
+  private static int REDUCE_SLOTS = 1;
+  private TaskTracker tt;
+  private JvmManager jvmManager;
+  private JobConf ttConf;
+
+  @Before
+  public void setUp() {
+    TEST_DIR.mkdirs();
+  }
+
+  @After
+  public void tearDown() throws IOException {
+    FileUtil.fullyDelete(TEST_DIR);
+  }
+
+  public TestTaskEnvironment() throws Exception {
+    tt = new TaskTracker();
+    ttConf = new JobConf();
+    ttConf.setLong("mapred.tasktracker.tasks.sleeptime-before-sigkill", 2000);
+    tt.setConf(ttConf);
+    tt.setMaxMapSlots(MAP_SLOTS);
+    tt.setMaxReduceSlots(REDUCE_SLOTS);
+    tt.setTaskController(new DefaultTaskController());
+    jvmManager = new JvmManager(tt);
+    tt.setJvmManagerInstance(jvmManager);
+    tt.setUserLogManager(new UserLogManager(ttConf));
+  }
+
+  // write a shell script to execute the command.
+  private File writeScript(String fileName, String cmd, File pidFile) throws IOException {
+    File script = new File(TEST_DIR, fileName);
+    FileOutputStream out = new FileOutputStream(script);
+    // write pid into a file
+    out.write(("echo $$ >" + pidFile.toString() + ";").getBytes());
+    // ignore SIGTERM
+    out.write(("trap '' 15\n").getBytes());
+    // write the actual command it self.
+    out.write(cmd.getBytes());
+    out.close();
+    script.setExecutable(true);
+    return script;
+  }
+
+  @Test
+  public void testTaskEnv() throws Throwable {
+    ttConf.set("mapreduce.admin.user.shell", "/bin/testshell");
+    ttConf.set("mapreduce.admin.user.env", "key1=value1,key2=value2");
+    final Map<String, String> env = new HashMap<String, String>();
+    String user = "test";
+    JobConf taskConf = new JobConf(ttConf);
+    TaskAttemptID attemptID = new TaskAttemptID("test", 0, true, 0, 0);
+    Task task = new MapTask(null, attemptID, 0, null, MAP_SLOTS);
+    task.setConf(taskConf);
+    TaskInProgress tip = tt.new TaskInProgress(task, taskConf);
+    final TaskRunner taskRunner = task.createRunner(tt, tip);
+    String errorInfo = "Child error";
+    taskRunner.updateUserLoginEnv(errorInfo, user, taskConf, env);
+
+    final Vector<String> vargs = new Vector<String>(1);
+    File pidFile = new File(TEST_DIR, "pid");
+    vargs.add(writeScript("ENV", "/bin/env ", pidFile).getAbsolutePath());
+    final File workDir = new File(TEST_DIR, "work");
+    workDir.mkdir();
+    final File stdout = new File(TEST_DIR, "stdout");
+    final File stderr = new File(TEST_DIR, "stderr");
+    JvmEnv jenv = jvmManager.constructJvmEnv(null, vargs,
+      stdout,stderr, 100, workDir, env, taskConf);
+    Map<String, String> jvmenvmap = jenv.env;
+    String javaOpts = taskRunner.getChildJavaOpts(ttConf, 
+      JobConf.MAPRED_MAP_TASK_JAVA_OPTS);
+
+    assertTrue(jvmenvmap.containsKey("SHELL"));
+    assertTrue(jvmenvmap.containsValue("/bin/testshell"));
+    assertTrue(jvmenvmap.containsKey("key2"));
+    assertTrue(jvmenvmap.containsValue("value2"));
+    assertTrue(javaOpts, javaOpts.contains("Xmx"));
+    assertTrue(javaOpts, javaOpts.contains("IPv4"));
+  }
+}