YARN-9132. Added file permission check for auxiliary services manifest file.

Contributed by Billie Rinaldi
This commit is contained in:
Eric Yang 2018-12-21 14:56:39 -05:00
parent f659485ee8
commit ea724181d6
2 changed files with 92 additions and 2 deletions

View File

@ -41,6 +41,7 @@ import java.util.regex.Pattern;
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.hadoop.fs.FSDataInputStream; 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.AuxServiceConfiguration;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.records.AuxServiceFile; import org.apache.hadoop.yarn.server.nodemanager.containermanager.records.AuxServiceFile;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.records.AuxServiceRecord; import org.apache.hadoop.yarn.server.nodemanager.containermanager.records.AuxServiceRecord;
@ -481,6 +482,35 @@ public class AuxServices extends AbstractService
loadManifest(getConfig(), true); 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 * Reads the manifest file if it is configured, exists, and has not been
* modified since the last read. * modified since the last read.
@ -494,14 +524,20 @@ public class AuxServices extends AbstractService
return null; return null;
} }
if (!manifestFS.exists(manifest)) { if (!manifestFS.exists(manifest)) {
LOG.info("Manifest file " + manifest + " doesn't exist"); LOG.warn("Manifest file " + manifest + " doesn't exist");
return null; return null;
} }
FileStatus status; FileStatus status;
try { try {
status = manifestFS.getFileStatus(manifest); status = manifestFS.getFileStatus(manifest);
} catch (FileNotFoundException e) { } 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; return null;
} }
if (status.getModificationTime() == manifestModifyTS) { if (status.getModificationTime() == manifestModifyTS) {
@ -721,6 +757,9 @@ public class AuxServices extends AbstractService
serviceMap.clear(); serviceMap.clear();
serviceRecordMap.clear(); serviceRecordMap.clear();
serviceMetaData.clear(); serviceMetaData.clear();
if (manifestFS != null) {
manifestFS.close();
}
if (manifestReloadTimer != null) { if (manifestReloadTimer != null) {
manifestReloadTimer.cancel(); manifestReloadTimer.cancel();
} }

View File

@ -34,9 +34,11 @@ import static org.mockito.Mockito.verify;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper; 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.AuxServiceRecord;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.records.AuxServiceRecords; import org.apache.hadoop.yarn.server.nodemanager.containermanager.records.AuxServiceRecords;
import org.junit.After; import org.junit.After;
import org.junit.Assume;
import org.junit.Before; import org.junit.Before;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Parameterized; import org.junit.runners.Parameterized;
@ -834,4 +836,53 @@ public class TestAuxServices {
aux.stop(); 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());
}
} }