/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library 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 2.1 of the License, or (at your option) * any later version. * * This library 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. */ package com.liferay.portal.security.pacl.checker; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.security.pacl.Reflection; import java.security.Permission; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @author Raymond Augé * @author Brian Wing Shun Chan */ public class RuntimeChecker extends BaseChecker { @Override public void afterPropertiesSet() { initAccessDeclaredMembers(); initCreateClassLoader(); initEnvironmentVariables(); initGetProtectionDomain(); initModifyThread(); initSetContextClassLoader(); } @Override public AuthorizationProperty generateAuthorizationProperty( Object... arguments) { if ((arguments == null) || (arguments.length != 1) || !(arguments[0] instanceof Permission)) { return null; } Permission permission = (Permission)arguments[0]; String name = permission.getName(); String key = null; String value = null; if (name.startsWith(RUNTIME_PERMISSION_ACCESS_DECLARED_MEMBERS)) { key = "security-manager-access-declared-members"; value = "true"; } else if (name.startsWith(RUNTIME_PERMISSION_CREATE_CLASS_LOADER)) { key = "security-manager-create-class-loader"; value = "true"; } else if (name.startsWith(RUNTIME_PERMISSION_GET_ENV)) { key = "security-manager-environment-variables"; value = name.substring(RUNTIME_PERMISSION_GET_ENV.length() + 1); // Since we are using a regular expression, we cannot allow a lone * // as the rule if (value.equals(StringPool.STAR)) { value = StringPool.DOUBLE_BACK_SLASH + value; } } else if (name.startsWith(RUNTIME_PERMISSION_GET_PROTECTION_DOMAIN)) { key = "security-manager-get-protection-domain"; value = "true"; } else if (name.equals(RUNTIME_PERMISSION_MODIFY_THREAD)) { key = "security-manager-modify-thread"; value = "true"; } else if (name.equals(RUNTIME_PERMISSION_SET_CONTEXT_CLASS_LOADER)) { key = "security-manager-set-context-class-loader"; value = "true"; } else { return null; } AuthorizationProperty authorizationProperty = new AuthorizationProperty(); authorizationProperty.setKey(key); authorizationProperty.setValue(value); return authorizationProperty; } @Override public boolean implies(Permission permission) { String name = permission.getName(); if (name.startsWith(RUNTIME_PERMISSION_ACCESS_CLASS_IN_PACKAGE)) { int pos = name.indexOf(StringPool.PERIOD); String pkg = name.substring(pos + 1); if (!hasAccessClassInPackage(pkg)) { logSecurityException( _log, "Attempted to access package " + pkg); return false; } } else if (name.equals(RUNTIME_PERMISSION_ACCESS_DECLARED_MEMBERS)) { if (!hasAccessDeclaredMembers(permission)) { logSecurityException( _log, "Attempted to access declared members"); return false; } } else if (name.equals(RUNTIME_PERMISSION_CREATE_CLASS_LOADER)) { if (!hasCreateClassLoader(permission)) { logSecurityException( _log, "Attempted to create a class loader"); return false; } } else if (name.equals(RUNTIME_PERMISSION_CREATE_SECURITY_MANAGER)) { if (!hasCreateSecurityManager(permission)) { logSecurityException( _log, "Attempted to create a security manager"); return false; } } else if (name.startsWith(RUNTIME_PERMISSION_GET_CLASSLOADER)) { if (!hasGetClassLoader(permission)) { logSecurityException(_log, "Attempted to get class loader"); return false; } } else if (name.startsWith(RUNTIME_PERMISSION_GET_PROTECTION_DOMAIN)) { if (!hasGetProtectionDomain(permission)) { logSecurityException( _log, "Attempted to get protection domain"); return false; } } else if (name.startsWith(RUNTIME_PERMISSION_GET_ENV)) { int pos = name.indexOf(StringPool.PERIOD); String envName = name.substring(pos + 1); if (!hasGetEnv(envName, permission)) { logSecurityException( _log, "Attempted to get environment name " + envName); return false; } } else if (name.startsWith(RUNTIME_PERMISSION_LOAD_LIBRARY)) { if (!hasLoadLibrary(permission)) { logSecurityException(_log, "Attempted to load library"); return false; } } else if (name.equals(RUNTIME_PERMISSION_MODIFY_THREAD)) { if (!hasModifyThread(permission)) { logSecurityException(_log, "Attempted to modify a thread"); return false; } } else if (name.equals(RUNTIME_PERMISSION_READ_FILE_DESCRIPTOR)) { if (!hasReadFileDescriptor(permission)) { logSecurityException(_log, "Attempted to read file descriptor"); return false; } } else if (name.equals(RUNTIME_PERMISSION_SET_CONTEXT_CLASS_LOADER)) { if (!hasSetContextClassLoader(permission)) { logSecurityException( _log, "Attempted to set the context class loader"); return false; } } else if (name.equals(RUNTIME_PERMISSION_SET_SECURITY_MANAGER)) { logSecurityException( _log, "Attempted to set another security manager"); return false; } else if (name.equals(RUNTIME_PERMISSION_WRITE_FILE_DESCRIPTOR)) { if (!hasWriteFileDescriptor(permission)) { logSecurityException( _log, "Attempted to write file descriptor"); return false; } } else { if (_log.isDebugEnabled()) { Thread.dumpStack(); } logSecurityException( _log, "Attempted to " + permission.getName() + " on " + permission.getActions()); return false; } return true; } protected boolean hasAccessClassInPackage(String pkg) { // TODO if (pkg.startsWith("sun.reflect")) { } return true; } protected boolean hasAccessDeclaredMembers(Permission permission) { if (_accessDeclaredMembers) { return true; } int stackIndex = Reflection.getStackIndex(6, 5); Class<?> callerClass = Reflection.getCallerClass(stackIndex); if (isTrustedCaller(callerClass, permission)) { return true; } return false; } protected boolean hasCreateClassLoader(Permission permission) { if (_createClassLoader) { return true; } int stackIndex = Reflection.getStackIndex(8, 4); Class<?> callerClass = Reflection.getCallerClass(stackIndex); if (isTrustedCaller(callerClass, permission)) { return true; } return false; } protected boolean hasCreateSecurityManager(Permission permission) { int stackIndex = Reflection.getStackIndex(4, 3); Class<?> callerClass = Reflection.getCallerClass(stackIndex); if (isTrustedCaller(callerClass, permission)) { return true; } return false; } protected boolean hasGetClassLoader(Permission permission) { int stackIndex = Reflection.getStackIndex( new int[] {5, 5, 6}, new int[] {4, 4, 4}); Class<?> callerClass = Reflection.getCallerClass(stackIndex); if (isTrustedCaller(callerClass, permission)) { return true; } return false; } protected boolean hasGetEnv(String name, Permission permission) { for (Pattern environmentVariablePattern : _environmentVariablePatterns) { Matcher matcher = environmentVariablePattern.matcher(name); if (matcher.matches()) { return true; } } int stackIndex = Reflection.getStackIndex(4, 3); Class<?> callerClass = Reflection.getCallerClass(stackIndex); if (isTrustedCaller(callerClass, permission)) { return true; } return false; } protected boolean hasGetProtectionDomain(Permission permission) { if (_getProtectionDomain) { return true; } int stackIndex = Reflection.getStackIndex(4, 3); Class<?> callerClass = Reflection.getCallerClass(stackIndex); if (isTrustedCaller(callerClass, permission)) { return true; } return false; } protected boolean hasLoadLibrary(Permission permission) { int stackIndex = Reflection.getStackIndex(6, 5); Class<?> callerClass = Reflection.getCallerClass(stackIndex); if (isTrustedCaller(callerClass, permission)) { return true; } return false; } protected boolean hasModifyThread(Permission permission) { if (_modifyThread) { return true; } int stackIndex = Reflection.getStackIndex(6, 5); Class<?> callerClass = Reflection.getCallerClass(stackIndex); if (isTrustedCaller(callerClass, permission)) { return true; } return false; } protected boolean hasReadFileDescriptor(Permission permission) { int stackIndex = Reflection.getStackIndex(5, 4); Class<?> callerClass = Reflection.getCallerClass(stackIndex); if (isTrustedCaller(callerClass, permission)) { return true; } return false; } protected boolean hasSetContextClassLoader(Permission permission) { if (_setContextClassLoader) { return true; } int stackIndex = Reflection.getStackIndex(4, 3); Class<?> callerClass = Reflection.getCallerClass(stackIndex); if (isTrustedCaller(callerClass, permission)) { return true; } return false; } protected boolean hasWriteFileDescriptor(Permission permission) { int stackIndex = Reflection.getStackIndex(5, 4); Class<?> callerClass = Reflection.getCallerClass(stackIndex); if (isTrustedCaller(callerClass, permission)) { return true; } return false; } protected void initAccessDeclaredMembers() { _accessDeclaredMembers = getPropertyBoolean( "security-manager-access-declared-members"); } protected void initCreateClassLoader() { _createClassLoader = getPropertyBoolean( "security-manager-create-class-loader"); } protected void initEnvironmentVariables() { Set<String> environmentVariables = getPropertySet( "security-manager-environment-variables"); _environmentVariablePatterns = new ArrayList<>( environmentVariables.size()); for (String environmentVariable : environmentVariables) { Pattern environmentVariablePattern = Pattern.compile( environmentVariable); _environmentVariablePatterns.add(environmentVariablePattern); if (_log.isDebugEnabled()) { _log.debug( "Allowing access to environment variables that match the " + "regular expression " + environmentVariable); } } } protected void initGetProtectionDomain() { _getProtectionDomain = getPropertyBoolean( "security-manager-get-protection-domain"); } protected void initModifyThread() { _modifyThread = getPropertyBoolean("security-manager-modify-thread"); } protected void initSetContextClassLoader() { _setContextClassLoader = getPropertyBoolean( "security-manager-set-context-class-loader"); } private static final Log _log = LogFactoryUtil.getLog(RuntimeChecker.class); private boolean _accessDeclaredMembers; private boolean _createClassLoader; private List<Pattern> _environmentVariablePatterns; private boolean _getProtectionDomain; private boolean _modifyThread; private boolean _setContextClassLoader; }