Return-Path: Delivered-To: apmail-hadoop-common-commits-archive@www.apache.org Received: (qmail 1266 invoked from network); 4 Mar 2011 04:29:30 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 4 Mar 2011 04:29:30 -0000 Received: (qmail 20877 invoked by uid 500); 4 Mar 2011 04:29:30 -0000 Delivered-To: apmail-hadoop-common-commits-archive@hadoop.apache.org Received: (qmail 20836 invoked by uid 500); 4 Mar 2011 04:29:30 -0000 Mailing-List: contact common-commits-help@hadoop.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: common-dev@hadoop.apache.org Delivered-To: mailing list common-commits@hadoop.apache.org Received: (qmail 20828 invoked by uid 99); 4 Mar 2011 04:29:30 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 04 Mar 2011 04:29:30 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 04 Mar 2011 04:29:25 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 2ED962388C18; Fri, 4 Mar 2011 04:29:05 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1077559 - in /hadoop/common/branches/branch-0.20-security-patches/src: mapred/org/apache/hadoop/mapred/ test/org/apache/hadoop/mapred/ Date: Fri, 04 Mar 2011 04:29:05 -0000 To: common-commits@hadoop.apache.org From: omalley@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20110304042905.2ED962388C18@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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 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() { public Void run() throws IOException { taskDistributedCacheManager = @@ -204,7 +228,7 @@ abstract class TaskRunner extends Thread stderr); Map env = new HashMap(); - 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 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 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 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 env = new HashMap(); + 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 vargs = new Vector(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 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")); + } +}