HDFS-7582. Enforce maximum number of ACL entries separately per access and default. (Contributed by Vinayakumar B)

(cherry picked from commit 29cf887b22)
This commit is contained in:
Vinayakumar B 2015-07-21 15:16:52 +05:30
parent 8ef3821356
commit cd3692fe4b
3 changed files with 76 additions and 12 deletions

View File

@ -719,6 +719,9 @@ Release 2.8.0 - UNRELEASED
HDFS-8344. NameNode doesn't recover lease for files with missing blocks HDFS-8344. NameNode doesn't recover lease for files with missing blocks
(raviprak) (raviprak)
HDFS-7582. Enforce maximum number of ACL entries separately per access
and default. (vinayakumarb)
Release 2.7.2 - UNRELEASED Release 2.7.2 - UNRELEASED
INCOMPATIBLE CHANGES INCOMPATIBLE CHANGES

View File

@ -271,10 +271,6 @@ final class AclTransformation {
*/ */
private static List<AclEntry> buildAndValidateAcl( private static List<AclEntry> buildAndValidateAcl(
ArrayList<AclEntry> aclBuilder) throws AclException { ArrayList<AclEntry> aclBuilder) throws AclException {
if (aclBuilder.size() > MAX_ENTRIES) {
throw new AclException("Invalid ACL: ACL has " + aclBuilder.size() +
" entries, which exceeds maximum of " + MAX_ENTRIES + ".");
}
aclBuilder.trimToSize(); aclBuilder.trimToSize();
Collections.sort(aclBuilder, ACL_ENTRY_COMPARATOR); Collections.sort(aclBuilder, ACL_ENTRY_COMPARATOR);
// Full iteration to check for duplicates and invalid named entries. // Full iteration to check for duplicates and invalid named entries.
@ -292,9 +288,12 @@ final class AclTransformation {
} }
prevEntry = entry; prevEntry = entry;
} }
ScopedAclEntries scopedEntries = new ScopedAclEntries(aclBuilder);
checkMaxEntries(scopedEntries);
// Search for the required base access entries. If there is a default ACL, // Search for the required base access entries. If there is a default ACL,
// then do the same check on the default entries. // then do the same check on the default entries.
ScopedAclEntries scopedEntries = new ScopedAclEntries(aclBuilder);
for (AclEntryType type: EnumSet.of(USER, GROUP, OTHER)) { for (AclEntryType type: EnumSet.of(USER, GROUP, OTHER)) {
AclEntry accessEntryKey = new AclEntry.Builder().setScope(ACCESS) AclEntry accessEntryKey = new AclEntry.Builder().setScope(ACCESS)
.setType(type).build(); .setType(type).build();
@ -316,6 +315,22 @@ final class AclTransformation {
return Collections.unmodifiableList(aclBuilder); return Collections.unmodifiableList(aclBuilder);
} }
// Check the max entries separately on access and default entries
// HDFS-7582
private static void checkMaxEntries(ScopedAclEntries scopedEntries)
throws AclException {
List<AclEntry> accessEntries = scopedEntries.getAccessEntries();
List<AclEntry> defaultEntries = scopedEntries.getDefaultEntries();
if (accessEntries.size() > MAX_ENTRIES) {
throw new AclException("Invalid ACL: ACL has " + accessEntries.size()
+ " access entries, which exceeds maximum of " + MAX_ENTRIES + ".");
}
if (defaultEntries.size() > MAX_ENTRIES) {
throw new AclException("Invalid ACL: ACL has " + defaultEntries.size()
+ " default entries, which exceeds maximum of " + MAX_ENTRIES + ".");
}
}
/** /**
* Calculates mask entries required for the ACL. Mask calculation is performed * Calculates mask entries required for the ACL. Mask calculation is performed
* separately for each scope: access and default. This method is responsible * separately for each scope: access and default. This method is responsible
@ -444,11 +459,8 @@ final class AclTransformation {
* @throws AclException if validation fails * @throws AclException if validation fails
*/ */
public ValidatedAclSpec(List<AclEntry> aclSpec) throws AclException { public ValidatedAclSpec(List<AclEntry> aclSpec) throws AclException {
if (aclSpec.size() > MAX_ENTRIES) {
throw new AclException("Invalid ACL: ACL spec has " + aclSpec.size() +
" entries, which exceeds maximum of " + MAX_ENTRIES + ".");
}
Collections.sort(aclSpec, ACL_ENTRY_COMPARATOR); Collections.sort(aclSpec, ACL_ENTRY_COMPARATOR);
checkMaxEntries(new ScopedAclEntries(aclSpec));
this.aclSpec = aclSpec; this.aclSpec = aclSpec;
} }

View File

@ -31,11 +31,8 @@ import com.google.common.collect.Lists;
import org.junit.Test; import org.junit.Test;
import org.apache.hadoop.fs.permission.AclEntry; import org.apache.hadoop.fs.permission.AclEntry;
import org.apache.hadoop.fs.permission.AclEntryScope;
import org.apache.hadoop.fs.permission.AclEntryType;
import org.apache.hadoop.fs.permission.FsAction; import org.apache.hadoop.fs.permission.FsAction;
import org.apache.hadoop.hdfs.protocol.AclException; import org.apache.hadoop.hdfs.protocol.AclException;
import org.apache.hadoop.hdfs.server.namenode.AclTransformation;
/** /**
* Tests operations that modify ACLs. All tests in this suite have been * Tests operations that modify ACLs. All tests in this suite have been
@ -45,10 +42,13 @@ import org.apache.hadoop.hdfs.server.namenode.AclTransformation;
public class TestAclTransformation { public class TestAclTransformation {
private static final List<AclEntry> ACL_SPEC_TOO_LARGE; private static final List<AclEntry> ACL_SPEC_TOO_LARGE;
private static final List<AclEntry> ACL_SPEC_DEFAULT_TOO_LARGE;
static { static {
ACL_SPEC_TOO_LARGE = Lists.newArrayListWithCapacity(33); ACL_SPEC_TOO_LARGE = Lists.newArrayListWithCapacity(33);
ACL_SPEC_DEFAULT_TOO_LARGE = Lists.newArrayListWithCapacity(33);
for (int i = 0; i < 33; ++i) { for (int i = 0; i < 33; ++i) {
ACL_SPEC_TOO_LARGE.add(aclEntry(ACCESS, USER, "user" + i, ALL)); ACL_SPEC_TOO_LARGE.add(aclEntry(ACCESS, USER, "user" + i, ALL));
ACL_SPEC_DEFAULT_TOO_LARGE.add(aclEntry(DEFAULT, USER, "user" + i, ALL));
} }
} }
@ -351,6 +351,17 @@ public class TestAclTransformation {
filterAclEntriesByAclSpec(existing, ACL_SPEC_TOO_LARGE); filterAclEntriesByAclSpec(existing, ACL_SPEC_TOO_LARGE);
} }
@Test(expected = AclException.class)
public void testFilterDefaultAclEntriesByAclSpecInputTooLarge()
throws AclException {
List<AclEntry> existing = new ImmutableList.Builder<AclEntry>()
.add(aclEntry(DEFAULT, USER, ALL))
.add(aclEntry(DEFAULT, GROUP, READ))
.add(aclEntry(DEFAULT, OTHER, NONE))
.build();
filterAclEntriesByAclSpec(existing, ACL_SPEC_DEFAULT_TOO_LARGE);
}
@Test @Test
public void testFilterDefaultAclEntries() throws AclException { public void testFilterDefaultAclEntries() throws AclException {
List<AclEntry> existing = new ImmutableList.Builder<AclEntry>() List<AclEntry> existing = new ImmutableList.Builder<AclEntry>()
@ -719,6 +730,16 @@ public class TestAclTransformation {
mergeAclEntries(existing, ACL_SPEC_TOO_LARGE); mergeAclEntries(existing, ACL_SPEC_TOO_LARGE);
} }
@Test(expected=AclException.class)
public void testMergeAclDefaultEntriesInputTooLarge() throws AclException {
List<AclEntry> existing = new ImmutableList.Builder<AclEntry>()
.add(aclEntry(DEFAULT, USER, ALL))
.add(aclEntry(DEFAULT, GROUP, READ))
.add(aclEntry(DEFAULT, OTHER, NONE))
.build();
mergeAclEntries(existing, ACL_SPEC_DEFAULT_TOO_LARGE);
}
@Test(expected=AclException.class) @Test(expected=AclException.class)
public void testMergeAclEntriesResultTooLarge() throws AclException { public void testMergeAclEntriesResultTooLarge() throws AclException {
ImmutableList.Builder<AclEntry> aclBuilder = ImmutableList.Builder<AclEntry> aclBuilder =
@ -737,6 +758,24 @@ public class TestAclTransformation {
mergeAclEntries(existing, aclSpec); mergeAclEntries(existing, aclSpec);
} }
@Test(expected = AclException.class)
public void testMergeAclDefaultEntriesResultTooLarge() throws AclException {
ImmutableList.Builder<AclEntry> aclBuilder =
new ImmutableList.Builder<AclEntry>()
.add(aclEntry(DEFAULT, USER, ALL));
for (int i = 1; i <= 28; ++i) {
aclBuilder.add(aclEntry(DEFAULT, USER, "user" + i, READ));
}
aclBuilder
.add(aclEntry(DEFAULT, GROUP, READ))
.add(aclEntry(DEFAULT, MASK, READ))
.add(aclEntry(DEFAULT, OTHER, NONE));
List<AclEntry> existing = aclBuilder.build();
List<AclEntry> aclSpec = Lists.newArrayList(
aclEntry(DEFAULT, USER, "bruce", READ));
mergeAclEntries(existing, aclSpec);
}
@Test(expected=AclException.class) @Test(expected=AclException.class)
public void testMergeAclEntriesDuplicateEntries() throws AclException { public void testMergeAclEntriesDuplicateEntries() throws AclException {
List<AclEntry> existing = new ImmutableList.Builder<AclEntry>() List<AclEntry> existing = new ImmutableList.Builder<AclEntry>()
@ -1091,6 +1130,16 @@ public class TestAclTransformation {
replaceAclEntries(existing, ACL_SPEC_TOO_LARGE); replaceAclEntries(existing, ACL_SPEC_TOO_LARGE);
} }
@Test(expected=AclException.class)
public void testReplaceAclDefaultEntriesInputTooLarge() throws AclException {
List<AclEntry> existing = new ImmutableList.Builder<AclEntry>()
.add(aclEntry(DEFAULT, USER, ALL))
.add(aclEntry(DEFAULT, GROUP, READ))
.add(aclEntry(DEFAULT, OTHER, NONE))
.build();
replaceAclEntries(existing, ACL_SPEC_DEFAULT_TOO_LARGE);
}
@Test(expected=AclException.class) @Test(expected=AclException.class)
public void testReplaceAclEntriesResultTooLarge() throws AclException { public void testReplaceAclEntriesResultTooLarge() throws AclException {
List<AclEntry> existing = new ImmutableList.Builder<AclEntry>() List<AclEntry> existing = new ImmutableList.Builder<AclEntry>()