YARN-9132. Added file permission check for auxiliary services manifest file.
Contributed by Billie Rinaldi
This commit is contained in:
parent
f659485ee8
commit
ea724181d6
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue