diff options
author | Duarte Meneses <duarte.meneses@sonarsource.com> | 2019-09-18 10:52:44 -0500 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2019-09-20 10:42:52 +0200 |
commit | 10a1454ce0e0b97f00e2792942f1e2131bc877db (patch) | |
tree | f543f2743f780320816f832de88cf36d6246edba /server/sonar-process | |
parent | 0443794329122f49b910eb58cb505349ab116414 (diff) | |
download | sonarqube-10a1454ce0e0b97f00e2792942f1e2131bc877db.tar.gz sonarqube-10a1454ce0e0b97f00e2792942f1e2131bc877db.zip |
SSF-92 Code injection from SonarQube plugins
Diffstat (limited to 'server/sonar-process')
-rw-r--r-- | server/sonar-process/src/main/java/org/sonar/process/SecurityManagement.java | 65 | ||||
-rw-r--r-- | server/sonar-process/src/test/java/org/sonar/process/SecurityManagementTest.java | 70 |
2 files changed, 135 insertions, 0 deletions
diff --git a/server/sonar-process/src/main/java/org/sonar/process/SecurityManagement.java b/server/sonar-process/src/main/java/org/sonar/process/SecurityManagement.java new file mode 100644 index 00000000000..e8f49e0d6d8 --- /dev/null +++ b/server/sonar-process/src/main/java/org/sonar/process/SecurityManagement.java @@ -0,0 +1,65 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.process; + +import java.lang.reflect.ReflectPermission; +import java.security.Permission; +import java.security.Policy; +import java.security.ProtectionDomain; +import java.security.SecurityPermission; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public class SecurityManagement { + private SecurityManagement() { + // static only + } + + public static void restrictPlugins() { + SecurityManager sm = new SecurityManager(); + Policy.setPolicy(new CustomPolicy()); + System.setSecurityManager(sm); + } + + static class CustomPolicy extends Policy { + private static final Set<String> ALLOWED_RUNTIME_PERMISSIONS = new HashSet<>(Arrays.asList("getFileSystemAttributes", "readFileDescriptor", "writeFileDescriptor", + "getStackTrace", "setDefaultUncaughtExceptionHandler", "manageProcess", "localeServiceProvider", "LoggerFinder")); + + @Override + public boolean implies(ProtectionDomain domain, Permission permission) { + // classloader used to load plugins + String clName = getDomainClassLoaderName(domain); + if ("org.sonar.classloader.ClassRealm".equals(clName)) { + if (permission instanceof RuntimePermission && !ALLOWED_RUNTIME_PERMISSIONS.contains(permission.getName())) { + return false; + } + if (permission instanceof ReflectPermission || permission instanceof SecurityPermission) { + return false; + } + } + return true; + } + + String getDomainClassLoaderName(ProtectionDomain domain) { + return domain.getClassLoader().getClass().getName(); + } + } +} diff --git a/server/sonar-process/src/test/java/org/sonar/process/SecurityManagementTest.java b/server/sonar-process/src/test/java/org/sonar/process/SecurityManagementTest.java new file mode 100644 index 00000000000..afe142b4ea6 --- /dev/null +++ b/server/sonar-process/src/test/java/org/sonar/process/SecurityManagementTest.java @@ -0,0 +1,70 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.process; + +import java.lang.reflect.ReflectPermission; +import java.security.Permission; +import java.security.ProtectionDomain; +import java.security.SecurityPermission; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; +import static org.mockito.Mockito.mock; + +public class SecurityManagementTest { + private ClassLoader classRealm = mock(ClassLoader.class, RETURNS_DEEP_STUBS); + private ProtectionDomain pd = new ProtectionDomain(null, null, classRealm, null); + + private Permission allowedRuntime = new RuntimePermission("getFileSystemAttributes"); + private Permission deniedRuntime = new RuntimePermission("getClassLoader"); + private Permission reflect = new ReflectPermission("suppressAccessChecks"); + private Permission security = new SecurityPermission("setPolicy"); + + @Test + public void policy_restricts_class_realm() { + SecurityManagement.CustomPolicy policy = new SecurityManagement.CustomPolicy() { + @Override + String getDomainClassLoaderName(ProtectionDomain domain) { + return "org.sonar.classloader.ClassRealm"; + } + }; + + assertThat(policy.implies(pd, allowedRuntime)).isTrue(); + assertThat(policy.implies(pd, deniedRuntime)).isFalse(); + assertThat(policy.implies(pd, reflect)).isFalse(); + assertThat(policy.implies(pd, security)).isFalse(); + } + + @Test + public void policy_does_not_restrict_other_classloaders() { + SecurityManagement.CustomPolicy policy = new SecurityManagement.CustomPolicy() { + @Override + String getDomainClassLoaderName(ProtectionDomain domain) { + return "classloader"; + } + }; + + assertThat(policy.implies(pd, allowedRuntime)).isTrue(); + assertThat(policy.implies(pd, deniedRuntime)).isTrue(); + assertThat(policy.implies(pd, reflect)).isTrue(); + assertThat(policy.implies(pd, security)).isTrue(); + } +} |