diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/AuxServices.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/AuxServices.java index ba936d6b866..d2e1d1130d3 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/AuxServices.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/AuxServices.java @@ -41,6 +41,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.hadoop.fs.FSDataInputStream; +import org.apache.hadoop.security.authorize.AccessControlList; import org.apache.hadoop.yarn.server.nodemanager.containermanager.records.AuxServiceConfiguration; import org.apache.hadoop.yarn.server.nodemanager.containermanager.records.AuxServiceFile; import org.apache.hadoop.yarn.server.nodemanager.containermanager.records.AuxServiceRecord; @@ -481,6 +482,35 @@ private void reloadManifest() throws IOException { loadManifest(getConfig(), true); } + private boolean checkManifestPermissions(FileStatus status) throws + IOException { + if ((status.getPermission().toShort() & 0022) != 0) { + LOG.error("Manifest file and parents must not be writable by group or " + + "others. The current Permission of " + status.getPath() + "is " + + status.getPermission()); + return false; + } + Path parent = status.getPath().getParent(); + if (parent == null) { + return true; + } + return checkManifestPermissions(manifestFS.getFileStatus(parent)); + } + + private boolean checkManifestOwnerAndPermissions(FileStatus status) throws + IOException { + AccessControlList yarnAdminAcl = new AccessControlList(getConfig().get( + YarnConfiguration.YARN_ADMIN_ACL, + YarnConfiguration.DEFAULT_YARN_ADMIN_ACL)); + if (!yarnAdminAcl.isUserAllowed( + UserGroupInformation.createRemoteUser(status.getOwner()))) { + LOG.error("Manifest must be owned by YARN admin: " + manifest); + return false; + } + + return checkManifestPermissions(status); + } + /** * Reads the manifest file if it is configured, exists, and has not been * modified since the last read. @@ -494,14 +524,20 @@ private synchronized AuxServiceRecords maybeReadManifestFile() throws return null; } if (!manifestFS.exists(manifest)) { - LOG.info("Manifest file " + manifest + " doesn't exist"); + LOG.warn("Manifest file " + manifest + " doesn't exist"); return null; } FileStatus status; try { status = manifestFS.getFileStatus(manifest); } catch (FileNotFoundException e) { - LOG.info("Manifest file " + manifest + " doesn't exist"); + LOG.warn("Manifest file " + manifest + " doesn't exist"); + return null; + } + if (!status.isFile()) { + LOG.warn("Manifest file " + manifest + " is not a file"); + } + if (!checkManifestOwnerAndPermissions(status)) { return null; } if (status.getModificationTime() == manifestModifyTS) { @@ -721,6 +757,9 @@ public synchronized void serviceStop() throws Exception { serviceMap.clear(); serviceRecordMap.clear(); serviceMetaData.clear(); + if (manifestFS != null) { + manifestFS.close(); + } if (manifestReloadTimer != null) { manifestReloadTimer.cancel(); } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/TestAuxServices.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/TestAuxServices.java index ece8d9bfb0e..1f944b49780 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/TestAuxServices.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/TestAuxServices.java @@ -34,9 +34,11 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.yarn.server.nodemanager.containermanager.records.AuxServiceRecord; import org.apache.hadoop.yarn.server.nodemanager.containermanager.records.AuxServiceRecords; import org.junit.After; +import org.junit.Assume; import org.junit.Before; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -834,4 +836,53 @@ public void testAuxServicesConfChange() throws IOException { aux.stop(); } + + @Test + public void testAuxServicesManifestPermissions() throws IOException { + Assume.assumeTrue(useManifest); + Configuration conf = getABConf(); + FileSystem fs = FileSystem.get(conf); + fs.setPermission(new Path(manifest.getAbsolutePath()), FsPermission + .createImmutable((short) 0777)); + AuxServices aux = new AuxServices(MOCK_AUX_PATH_HANDLER, + MOCK_CONTEXT, MOCK_DEL_SERVICE); + aux.init(conf); + assertEquals(0, aux.getServices().size()); + + fs.setPermission(new Path(manifest.getAbsolutePath()), FsPermission + .createImmutable((short) 0775)); + aux = new AuxServices(MOCK_AUX_PATH_HANDLER, + MOCK_CONTEXT, MOCK_DEL_SERVICE); + aux.init(conf); + assertEquals(0, aux.getServices().size()); + + fs.setPermission(new Path(manifest.getAbsolutePath()), FsPermission + .createImmutable((short) 0755)); + fs.setPermission(new Path(rootDir.getAbsolutePath()), FsPermission + .createImmutable((short) 0775)); + aux = new AuxServices(MOCK_AUX_PATH_HANDLER, + MOCK_CONTEXT, MOCK_DEL_SERVICE); + aux.init(conf); + assertEquals(0, aux.getServices().size()); + + fs.setPermission(new Path(rootDir.getAbsolutePath()), FsPermission + .createImmutable((short) 0755)); + aux = new AuxServices(MOCK_AUX_PATH_HANDLER, + MOCK_CONTEXT, MOCK_DEL_SERVICE); + aux.init(conf); + assertEquals(2, aux.getServices().size()); + + conf.set(YarnConfiguration.YARN_ADMIN_ACL, ""); + aux = new AuxServices(MOCK_AUX_PATH_HANDLER, + MOCK_CONTEXT, MOCK_DEL_SERVICE); + aux.init(conf); + assertEquals(0, aux.getServices().size()); + + conf.set(YarnConfiguration.YARN_ADMIN_ACL, UserGroupInformation + .getCurrentUser().getShortUserName()); + aux = new AuxServices(MOCK_AUX_PATH_HANDLER, + MOCK_CONTEXT, MOCK_DEL_SERVICE); + aux.init(conf); + assertEquals(2, aux.getServices().size()); + } }