This is an automated email from the ASF dual-hosted git repository. yufei pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/polaris.git
The following commit(s) were added to refs/heads/main by this push: new 6137e42bb Core: Prevent AIOOBE for negative codes in PolarisEntityType, PolarisPrivilege, ReturnStatus (#2490) 6137e42bb is described below commit 6137e42bb3d1a71274375e3efa49bf8edb5aa29f Author: Honah (Jonas) J. <hon...@apache.org> AuthorDate: Tue Sep 2 20:01:58 2025 -0500 Core: Prevent AIOOBE for negative codes in PolarisEntityType, PolarisPrivilege, ReturnStatus (#2490) --- .../polaris/core/entity/PolarisEntityType.java | 2 +- .../polaris/core/entity/PolarisPrivilege.java | 2 +- .../core/persistence/dao/entity/BaseResult.java | 4 +- .../polaris/core/entity/PolarisEntityTypeTest.java | 51 +++++++++ .../polaris/core/entity/PolarisPrivilegeTest.java | 124 +++++++++++++++++++++ .../persistence/dao/entity/ReturnStatusTest.java | 57 ++++++++++ 6 files changed, 237 insertions(+), 3 deletions(-) diff --git a/polaris-core/src/main/java/org/apache/polaris/core/entity/PolarisEntityType.java b/polaris-core/src/main/java/org/apache/polaris/core/entity/PolarisEntityType.java index fae2d66eb..e0e5990d2 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/entity/PolarisEntityType.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/entity/PolarisEntityType.java @@ -111,7 +111,7 @@ public enum PolarisEntityType { @JsonCreator public static @Nullable PolarisEntityType fromCode(int entityTypeCode) { // ensure it is within bounds - if (entityTypeCode >= REVERSE_MAPPING_ARRAY.length) { + if (entityTypeCode < 0 || entityTypeCode >= REVERSE_MAPPING_ARRAY.length) { return null; } diff --git a/polaris-core/src/main/java/org/apache/polaris/core/entity/PolarisPrivilege.java b/polaris-core/src/main/java/org/apache/polaris/core/entity/PolarisPrivilege.java index 88cf6083b..b7a51565b 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/entity/PolarisPrivilege.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/entity/PolarisPrivilege.java @@ -272,7 +272,7 @@ public enum PolarisPrivilege { @JsonCreator public static @Nullable PolarisPrivilege fromCode(int code) { // ensure it is within bounds - if (code >= REVERSE_MAPPING_ARRAY.length) { + if (code < 0 || code >= REVERSE_MAPPING_ARRAY.length) { return null; } diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/entity/BaseResult.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/entity/BaseResult.java index a8f3d5aef..e747a2f80 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/entity/BaseResult.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/entity/BaseResult.java @@ -156,7 +156,9 @@ public class BaseResult { } static ReturnStatus getStatus(int code) { - return code >= REVERSE_MAPPING_ARRAY.length ? null : REVERSE_MAPPING_ARRAY[code]; + return (code < 0 || code >= REVERSE_MAPPING_ARRAY.length) + ? null + : REVERSE_MAPPING_ARRAY[code]; } } } diff --git a/polaris-core/src/test/java/org/apache/polaris/core/entity/PolarisEntityTypeTest.java b/polaris-core/src/test/java/org/apache/polaris/core/entity/PolarisEntityTypeTest.java new file mode 100644 index 000000000..c2b9cd6ea --- /dev/null +++ b/polaris-core/src/test/java/org/apache/polaris/core/entity/PolarisEntityTypeTest.java @@ -0,0 +1,51 @@ +/* + * 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.polaris.core.entity; + +import java.util.stream.Stream; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class PolarisEntityTypeTest { + + static Stream<Arguments> entityTypes() { + return Stream.of( + Arguments.of(-1, null), + Arguments.of(0, PolarisEntityType.NULL_TYPE), + Arguments.of(1, PolarisEntityType.ROOT), + Arguments.of(2, PolarisEntityType.PRINCIPAL), + Arguments.of(3, PolarisEntityType.PRINCIPAL_ROLE), + Arguments.of(4, PolarisEntityType.CATALOG), + Arguments.of(5, PolarisEntityType.CATALOG_ROLE), + Arguments.of(6, PolarisEntityType.NAMESPACE), + Arguments.of(7, PolarisEntityType.TABLE_LIKE), + Arguments.of(8, PolarisEntityType.TASK), + Arguments.of(9, PolarisEntityType.FILE), + Arguments.of(10, PolarisEntityType.POLICY), + Arguments.of(11, null)); + } + + @ParameterizedTest + @MethodSource("entityTypes") + public void testFromCode(int code, PolarisEntityType expected) { + Assertions.assertThat(PolarisEntityType.fromCode(code)).isEqualTo(expected); + } +} diff --git a/polaris-core/src/test/java/org/apache/polaris/core/entity/PolarisPrivilegeTest.java b/polaris-core/src/test/java/org/apache/polaris/core/entity/PolarisPrivilegeTest.java new file mode 100644 index 000000000..70c52e911 --- /dev/null +++ b/polaris-core/src/test/java/org/apache/polaris/core/entity/PolarisPrivilegeTest.java @@ -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.polaris.core.entity; + +import java.util.stream.Stream; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class PolarisPrivilegeTest { + + static Stream<Arguments> polarisPrivileges() { + return Stream.of( + Arguments.of(-1, null), + Arguments.of(1, PolarisPrivilege.SERVICE_MANAGE_ACCESS), + Arguments.of(2, PolarisPrivilege.CATALOG_MANAGE_ACCESS), + Arguments.of(3, PolarisPrivilege.CATALOG_ROLE_USAGE), + Arguments.of(4, PolarisPrivilege.PRINCIPAL_ROLE_USAGE), + Arguments.of(5, PolarisPrivilege.NAMESPACE_CREATE), + Arguments.of(6, PolarisPrivilege.TABLE_CREATE), + Arguments.of(7, PolarisPrivilege.VIEW_CREATE), + Arguments.of(8, PolarisPrivilege.NAMESPACE_DROP), + Arguments.of(9, PolarisPrivilege.TABLE_DROP), + Arguments.of(10, PolarisPrivilege.VIEW_DROP), + Arguments.of(11, PolarisPrivilege.NAMESPACE_LIST), + Arguments.of(12, PolarisPrivilege.TABLE_LIST), + Arguments.of(13, PolarisPrivilege.VIEW_LIST), + Arguments.of(14, PolarisPrivilege.NAMESPACE_READ_PROPERTIES), + Arguments.of(15, PolarisPrivilege.TABLE_READ_PROPERTIES), + Arguments.of(16, PolarisPrivilege.VIEW_READ_PROPERTIES), + Arguments.of(17, PolarisPrivilege.NAMESPACE_WRITE_PROPERTIES), + Arguments.of(18, PolarisPrivilege.TABLE_WRITE_PROPERTIES), + Arguments.of(19, PolarisPrivilege.VIEW_WRITE_PROPERTIES), + Arguments.of(20, PolarisPrivilege.TABLE_READ_DATA), + Arguments.of(21, PolarisPrivilege.TABLE_WRITE_DATA), + Arguments.of(22, PolarisPrivilege.NAMESPACE_FULL_METADATA), + Arguments.of(23, PolarisPrivilege.TABLE_FULL_METADATA), + Arguments.of(24, PolarisPrivilege.VIEW_FULL_METADATA), + Arguments.of(25, PolarisPrivilege.CATALOG_CREATE), + Arguments.of(26, PolarisPrivilege.CATALOG_DROP), + Arguments.of(27, PolarisPrivilege.CATALOG_LIST), + Arguments.of(28, PolarisPrivilege.CATALOG_READ_PROPERTIES), + Arguments.of(29, PolarisPrivilege.CATALOG_WRITE_PROPERTIES), + Arguments.of(30, PolarisPrivilege.CATALOG_FULL_METADATA), + Arguments.of(31, PolarisPrivilege.CATALOG_MANAGE_METADATA), + Arguments.of(32, PolarisPrivilege.CATALOG_MANAGE_CONTENT), + Arguments.of(33, PolarisPrivilege.PRINCIPAL_LIST_GRANTS), + Arguments.of(34, PolarisPrivilege.PRINCIPAL_ROLE_LIST_GRANTS), + Arguments.of(35, PolarisPrivilege.CATALOG_ROLE_LIST_GRANTS), + Arguments.of(36, PolarisPrivilege.CATALOG_LIST_GRANTS), + Arguments.of(37, PolarisPrivilege.NAMESPACE_LIST_GRANTS), + Arguments.of(38, PolarisPrivilege.TABLE_LIST_GRANTS), + Arguments.of(39, PolarisPrivilege.VIEW_LIST_GRANTS), + Arguments.of(40, PolarisPrivilege.CATALOG_MANAGE_GRANTS_ON_SECURABLE), + Arguments.of(41, PolarisPrivilege.NAMESPACE_MANAGE_GRANTS_ON_SECURABLE), + Arguments.of(42, PolarisPrivilege.TABLE_MANAGE_GRANTS_ON_SECURABLE), + Arguments.of(43, PolarisPrivilege.VIEW_MANAGE_GRANTS_ON_SECURABLE), + Arguments.of(44, PolarisPrivilege.PRINCIPAL_CREATE), + Arguments.of(45, PolarisPrivilege.PRINCIPAL_DROP), + Arguments.of(46, PolarisPrivilege.PRINCIPAL_LIST), + Arguments.of(47, PolarisPrivilege.PRINCIPAL_READ_PROPERTIES), + Arguments.of(48, PolarisPrivilege.PRINCIPAL_WRITE_PROPERTIES), + Arguments.of(49, PolarisPrivilege.PRINCIPAL_FULL_METADATA), + Arguments.of(50, PolarisPrivilege.PRINCIPAL_MANAGE_GRANTS_ON_SECURABLE), + Arguments.of(51, PolarisPrivilege.PRINCIPAL_MANAGE_GRANTS_FOR_GRANTEE), + Arguments.of(52, PolarisPrivilege.PRINCIPAL_ROTATE_CREDENTIALS), + Arguments.of(53, PolarisPrivilege.PRINCIPAL_RESET_CREDENTIALS), + Arguments.of(54, PolarisPrivilege.PRINCIPAL_ROLE_CREATE), + Arguments.of(55, PolarisPrivilege.PRINCIPAL_ROLE_DROP), + Arguments.of(56, PolarisPrivilege.PRINCIPAL_ROLE_LIST), + Arguments.of(57, PolarisPrivilege.PRINCIPAL_ROLE_READ_PROPERTIES), + Arguments.of(58, PolarisPrivilege.PRINCIPAL_ROLE_WRITE_PROPERTIES), + Arguments.of(59, PolarisPrivilege.PRINCIPAL_ROLE_FULL_METADATA), + Arguments.of(60, PolarisPrivilege.PRINCIPAL_ROLE_MANAGE_GRANTS_ON_SECURABLE), + Arguments.of(61, PolarisPrivilege.PRINCIPAL_ROLE_MANAGE_GRANTS_FOR_GRANTEE), + Arguments.of(62, PolarisPrivilege.CATALOG_ROLE_CREATE), + Arguments.of(63, PolarisPrivilege.CATALOG_ROLE_DROP), + Arguments.of(64, PolarisPrivilege.CATALOG_ROLE_LIST), + Arguments.of(65, PolarisPrivilege.CATALOG_ROLE_READ_PROPERTIES), + Arguments.of(66, PolarisPrivilege.CATALOG_ROLE_WRITE_PROPERTIES), + Arguments.of(67, PolarisPrivilege.CATALOG_ROLE_FULL_METADATA), + Arguments.of(68, PolarisPrivilege.CATALOG_ROLE_MANAGE_GRANTS_ON_SECURABLE), + Arguments.of(69, PolarisPrivilege.CATALOG_ROLE_MANAGE_GRANTS_FOR_GRANTEE), + Arguments.of(70, PolarisPrivilege.POLICY_CREATE), + Arguments.of(71, PolarisPrivilege.POLICY_READ), + Arguments.of(72, PolarisPrivilege.POLICY_DROP), + Arguments.of(73, PolarisPrivilege.POLICY_WRITE), + Arguments.of(74, PolarisPrivilege.POLICY_LIST), + Arguments.of(75, PolarisPrivilege.POLICY_FULL_METADATA), + Arguments.of(76, PolarisPrivilege.POLICY_ATTACH), + Arguments.of(77, PolarisPrivilege.POLICY_DETACH), + Arguments.of(78, PolarisPrivilege.CATALOG_ATTACH_POLICY), + Arguments.of(79, PolarisPrivilege.NAMESPACE_ATTACH_POLICY), + Arguments.of(80, PolarisPrivilege.TABLE_ATTACH_POLICY), + Arguments.of(81, PolarisPrivilege.CATALOG_DETACH_POLICY), + Arguments.of(82, PolarisPrivilege.NAMESPACE_DETACH_POLICY), + Arguments.of(83, PolarisPrivilege.TABLE_DETACH_POLICY), + Arguments.of(84, PolarisPrivilege.POLICY_MANAGE_GRANTS_ON_SECURABLE), + Arguments.of(85, null)); + } + + @ParameterizedTest + @MethodSource("polarisPrivileges") + public void testFromCode(int code, PolarisPrivilege expected) { + Assertions.assertThat(PolarisPrivilege.fromCode(code)).isEqualTo(expected); + } +} diff --git a/polaris-core/src/test/java/org/apache/polaris/core/persistence/dao/entity/ReturnStatusTest.java b/polaris-core/src/test/java/org/apache/polaris/core/persistence/dao/entity/ReturnStatusTest.java new file mode 100644 index 000000000..a8fe83bc0 --- /dev/null +++ b/polaris-core/src/test/java/org/apache/polaris/core/persistence/dao/entity/ReturnStatusTest.java @@ -0,0 +1,57 @@ +/* + * 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.polaris.core.persistence.dao.entity; + +import java.util.stream.Stream; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class ReturnStatusTest { + + static Stream<Arguments> returnStatuses() { + return Stream.of( + Arguments.of(-1, null), + Arguments.of(1, BaseResult.ReturnStatus.SUCCESS), + Arguments.of(2, BaseResult.ReturnStatus.UNEXPECTED_ERROR_SIGNALED), + Arguments.of(3, BaseResult.ReturnStatus.CATALOG_PATH_CANNOT_BE_RESOLVED), + Arguments.of(4, BaseResult.ReturnStatus.ENTITY_CANNOT_BE_RESOLVED), + Arguments.of(5, BaseResult.ReturnStatus.ENTITY_NOT_FOUND), + Arguments.of(6, BaseResult.ReturnStatus.GRANT_NOT_FOUND), + Arguments.of(7, BaseResult.ReturnStatus.ENTITY_ALREADY_EXISTS), + Arguments.of(8, BaseResult.ReturnStatus.ENTITY_UNDROPPABLE), + Arguments.of(9, BaseResult.ReturnStatus.NAMESPACE_NOT_EMPTY), + Arguments.of(10, BaseResult.ReturnStatus.CATALOG_NOT_EMPTY), + Arguments.of(11, BaseResult.ReturnStatus.TARGET_ENTITY_CONCURRENTLY_MODIFIED), + Arguments.of(12, BaseResult.ReturnStatus.ENTITY_CANNOT_BE_RENAMED), + Arguments.of(13, BaseResult.ReturnStatus.SUBSCOPE_CREDS_ERROR), + Arguments.of(14, BaseResult.ReturnStatus.POLICY_MAPPING_NOT_FOUND), + Arguments.of(15, BaseResult.ReturnStatus.POLICY_MAPPING_OF_SAME_TYPE_ALREADY_EXISTS), + Arguments.of(16, BaseResult.ReturnStatus.POLICY_HAS_MAPPINGS), + Arguments.of(17, null)); + } + + @ParameterizedTest + @MethodSource("returnStatuses") + public void testReturnStatusFromCode(int code, BaseResult.ReturnStatus expected) { + BaseResult.ReturnStatus actual = BaseResult.ReturnStatus.getStatus(code); + Assertions.assertThat(actual).isEqualTo(expected); + } +}