Skip to content

Commit

Permalink
[JBLOGGING-190] When required, use a privileged action to find the cl…
Browse files Browse the repository at this point in the history
…ass in the lookup.

https://issues.redhat.com/browse/JBLOGGING-190
Signed-off-by: James R. Perkins <[email protected]>
  • Loading branch information
jamezp committed Sep 6, 2024
1 parent 51864b2 commit 0d04688
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 74 deletions.
125 changes: 88 additions & 37 deletions src/main/java/org/jboss/logging/Logger.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Locale;

/**
Expand Down Expand Up @@ -2532,7 +2534,7 @@ public static <T> T getMessageLogger(Lookup lookup, Class<T> type, String catego
* @return the typed logger
*/
public static <T> T getMessageLogger(final Lookup lookup, final Class<T> type, final String category, final Locale locale) {
return doGetMessageLogger(lookup, type, category, locale);
return doGetMessageLogger(lookup, type, category, locale, false);
}

/**
Expand Down Expand Up @@ -2561,14 +2563,17 @@ public static <T> T getMessageLogger(Class<T> type, String category) {
*/
@Deprecated(forRemoval = true, since = "3.6")
public static <T> T getMessageLogger(final Class<T> type, final String category, final Locale locale) {
boolean usePrivilegedAction;
Lookup lookup;
if (System.getSecurityManager() == null) {
try {
usePrivilegedAction = false;
lookup = MethodHandles.privateLookupIn(type, MethodHandles.lookup());
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("This library does not have private access to " + type);
}
} else {
usePrivilegedAction = true;
lookup = doPrivileged(new PrivilegedAction<Lookup>() {
public Lookup run() {
try {
Expand All @@ -2579,11 +2584,11 @@ public Lookup run() {
}
});
}
return doGetMessageLogger(lookup, type, category, locale);
return doGetMessageLogger(lookup, type, category, locale, usePrivilegedAction);
}

private static <T> T doGetMessageLogger(final Lookup lookup, final Class<T> type, final String category,
final Locale locale) {
final Locale locale, final boolean usePrivilegedAction) {
if (!type.isInterface()) {
throw new IllegalArgumentException("Given type " + type + " is not an interface");
}
Expand All @@ -2594,53 +2599,58 @@ private static <T> T doGetMessageLogger(final Lookup lookup, final Class<T> type
Class<? extends T> loggerClass = null;
final String typeName = type.getName();
if (variant != null && !variant.isEmpty()) {
try {
loggerClass = lookup.findClass(join(typeName, "$logger", language, country, variant)).asSubclass(type);
} catch (ClassNotFoundException e) {
// ignore
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("The given lookup does not have access to the implementation");
}
loggerClass = findClass(lookup, type, join(typeName, "$logger", language, country, variant), usePrivilegedAction,
false);
}
if (loggerClass == null && country != null && !country.isEmpty()) {
try {
loggerClass = lookup.findClass(join(typeName, "$logger", language, country, null)).asSubclass(type);
} catch (ClassNotFoundException e) {
// ignore
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("The given lookup does not have access to the implementation class");
}
loggerClass = findClass(lookup, type, join(typeName, "$logger", language, country, null), usePrivilegedAction,
false);
}
if (loggerClass == null && language != null && !language.isEmpty()) {
try {
loggerClass = lookup.findClass(join(typeName, "$logger", language, null, null)).asSubclass(type);
} catch (ClassNotFoundException e) {
// ignore
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("The given lookup does not have access to the implementation class");
}
loggerClass = findClass(lookup, type, join(typeName, "$logger", language, null, null), usePrivilegedAction, false);
}
if (loggerClass == null) {
loggerClass = findClass(lookup, type, join(typeName, "$logger", null, null, null), usePrivilegedAction, true);
}
// Shouldn't happen, but be safe
if (loggerClass == null) {
throw new IllegalArgumentException("Invalid logger " + type + " (implementation not found)");
}
final Class<? extends T> resolvedType = loggerClass;
MethodHandle ctorHandle;
if (usePrivilegedAction) {
try {
loggerClass = lookup.findClass(join(typeName, "$logger", null, null, null)).asSubclass(type);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Invalid logger " + type + " (implementation not found)");
ctorHandle = doPrivileged((PrivilegedExceptionAction<MethodHandle>) () -> {
return lookup.findConstructor(resolvedType, MethodType.methodType(void.class, Logger.class));
});
} catch (PrivilegedActionException e) {
final Throwable cause = e.getCause();
if (cause instanceof NoSuchMethodException) {
throw new IllegalArgumentException(
"Logger implementation " + resolvedType + " has no matching constructor");
} else if (cause instanceof IllegalAccessException) {
throw new IllegalArgumentException(
"The given lookup does not have access to the implementation class constructor");
} else if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else {
throw new RuntimeException("Logger implementation " + resolvedType + " has no matching constructor", cause);
}
}
} else {
try {
ctorHandle = lookup.findConstructor(resolvedType, MethodType.methodType(void.class, Logger.class));
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Logger implementation " + resolvedType + " has no matching constructor");
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("The given lookup does not have access to the implementation class");
throw new IllegalArgumentException(
"The given lookup does not have access to the implementation class constructor");
}
}
MethodHandle ctorHandle;
try {
ctorHandle = lookup.findConstructor(loggerClass, MethodType.methodType(void.class, Logger.class));
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Logger implementation " + loggerClass + " has no matching constructor");
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("The given lookup does not have access to the implementation class constructor");
}
try {
return type.cast(ctorHandle.invoke(Logger.getLogger(category)));
} catch (Throwable e) {
throw new IllegalArgumentException("Logger implementation " + loggerClass + " could not be instantiated", e);
throw new IllegalArgumentException("Logger implementation " + resolvedType + " could not be instantiated", e);
}
}

Expand All @@ -2661,4 +2671,45 @@ private static String join(String interfaceName, String a, String b, String c, S
}
return build.toString();
}

private static <T> Class<? extends T> findClass(final Lookup lookup, final Class<T> type, final String name,
final boolean usePrivilegedAction, final boolean throwException) {
if (usePrivilegedAction) {
try {
return doPrivileged(createFindClassAction(lookup, type, name));
} catch (PrivilegedActionException e) {
final Throwable cause = e.getCause();
if (cause instanceof ClassNotFoundException) {
if (throwException) {
throw new IllegalArgumentException("Invalid logger " + type + " (implementation not found)");
}
// ignore
return null;
} else if (cause instanceof IllegalAccessException) {
throw new IllegalArgumentException("The given lookup does not have access to the implementation class");
} else if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else {
throw new RuntimeException("Failed to lookup bundle for type " + type, cause);
}
}
} else {
try {
return lookup.findClass(name).asSubclass(type);
} catch (ClassNotFoundException e) {
if (throwException) {
throw new IllegalArgumentException("Invalid logger " + type + " (implementation not found)");
}
// ignore
return null;
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("The given lookup does not have access to the implementation");
}
}
}

private static <T> PrivilegedExceptionAction<Class<? extends T>> createFindClassAction(final Lookup lookup,
final Class<T> type, final String name) {
return () -> lookup.findClass(name).asSubclass(type);
}
}
133 changes: 96 additions & 37 deletions src/main/java/org/jboss/logging/Messages.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Locale;

/**
Expand Down Expand Up @@ -61,14 +63,17 @@ public static <T> T getBundle(Class<T> type) {
*/
@Deprecated(forRemoval = true, since = "3.6")
public static <T> T getBundle(final Class<T> type, final Locale locale) {
boolean usePrivilegedAction;
Lookup lookup;
if (System.getSecurityManager() == null) {
try {
usePrivilegedAction = false;
lookup = MethodHandles.privateLookupIn(type, MethodHandles.lookup());
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("This library does not have private access to " + type);
}
} else {
usePrivilegedAction = true;
lookup = doPrivileged(new PrivilegedAction<Lookup>() {
public Lookup run() {
try {
Expand All @@ -79,7 +84,7 @@ public Lookup run() {
}
});
}
return doGetBundle(lookup, type, locale);
return doGetBundle(lookup, type, locale, usePrivilegedAction);
}

/**
Expand All @@ -105,60 +110,73 @@ public static <T> T getBundle(Lookup lookup, Class<T> type) {
* @return the bundle
*/
public static <T> T getBundle(final Lookup lookup, final Class<T> type, final Locale locale) {
return doGetBundle(lookup, type, locale);
return doGetBundle(lookup, type, locale, false);
}

private static <T> T doGetBundle(final Lookup lookup, final Class<T> type, final Locale locale) {
private static <T> T doGetBundle(final Lookup lookup, final Class<T> type, final Locale locale,
final boolean usePrivilegedAction) {
String language = locale.getLanguage();
String country = locale.getCountry();
String variant = locale.getVariant();

Class<? extends T> bundleClass = null;
if (variant != null && !variant.isEmpty()) {
try {
bundleClass = lookup.findClass(join(type.getName(), "$bundle", language, country, variant)).asSubclass(type);
} catch (ClassNotFoundException e) {
// ignore
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("The given lookup does not have access to the implementation class");
}
bundleClass = findClass(lookup, type, join(type.getName(), "$bundle", language, country, variant),
usePrivilegedAction, false);
}
if (bundleClass == null && country != null && !country.isEmpty()) {
try {
bundleClass = lookup.findClass(join(type.getName(), "$bundle", language, country, null)).asSubclass(type);
} catch (ClassNotFoundException e) {
// ignore
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("The given lookup does not have access to the implementation class");
}
bundleClass = findClass(lookup, type, join(type.getName(), "$bundle", language, country, null), usePrivilegedAction,
false);
}
if (bundleClass == null && language != null && !language.isEmpty()) {
try {
bundleClass = lookup.findClass(join(type.getName(), "$bundle", language, null, null)).asSubclass(type);
} catch (ClassNotFoundException e) {
// ignore
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("The given lookup does not have access to the implementation class");
}
bundleClass = findClass(lookup, type, join(type.getName(), "$bundle", language, null, null), usePrivilegedAction,
false);
}
if (bundleClass == null) {
bundleClass = findClass(lookup, type, join(type.getName(), "$bundle", null, null, null), usePrivilegedAction, true);
}
// Shouldn't happen, but be safe
if (bundleClass == null) {
throw new IllegalArgumentException("Invalid bundle " + type + " (implementation not found)");
}
final Class<? extends T> resolvedType = bundleClass;
final MethodHandle getter;
if (usePrivilegedAction) {
try {
bundleClass = lookup.findClass(join(type.getName(), "$bundle", null, null, null)).asSubclass(type);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Invalid bundle " + type + " (implementation not found)");
getter = doPrivileged((PrivilegedExceptionAction<MethodHandle>) () -> {
try {
return lookup.findStaticGetter(resolvedType, "INSTANCE", resolvedType);
} catch (NoSuchFieldException e) {
throw new IllegalArgumentException("Bundle implementation " + resolvedType + " has no instance field");
} catch (IllegalAccessException e) {
throw new IllegalArgumentException(
"The given lookup does not have access to the implementation class instance field");
}
});
} catch (PrivilegedActionException e) {
final Throwable cause = e.getCause();
if (cause instanceof NoSuchMethodException) {
throw new IllegalArgumentException("Bundle implementation " + resolvedType + " has no instance field");
} else if (cause instanceof IllegalAccessException) {
throw new IllegalArgumentException(
"The given lookup does not have access to the implementation class instance field");
} else if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else {
throw new IllegalArgumentException("Bundle implementation " + resolvedType + " has no instance field",
cause);
}
}
} else {
try {
getter = lookup.findStaticGetter(resolvedType, "INSTANCE", resolvedType);
} catch (NoSuchFieldException e) {
throw new IllegalArgumentException("Bundle implementation " + resolvedType + " has no instance field");
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("The given lookup does not have access to the implementation class");
throw new IllegalArgumentException(
"The given lookup does not have access to the implementation class instance field");
}
}
final MethodHandle getter;
try {
getter = lookup.findStaticGetter(bundleClass, "INSTANCE", bundleClass);
} catch (NoSuchFieldException e) {
throw new IllegalArgumentException("Bundle implementation " + bundleClass + " has no instance field");
} catch (IllegalAccessException e) {
throw new IllegalArgumentException(
"The given lookup does not have access to the implementation class instance field");
}
try {
return type.cast(getter.invoke());
} catch (Throwable e) {
Expand All @@ -183,4 +201,45 @@ private static String join(String interfaceName, String a, String b, String c, S
}
return build.toString();
}

private static <T> Class<? extends T> findClass(final Lookup lookup, final Class<T> type, final String name,
final boolean usePrivilegedAction, final boolean throwException) {
if (usePrivilegedAction) {
try {
return doPrivileged(createFindClassAction(lookup, type, name));
} catch (PrivilegedActionException e) {
final Throwable cause = e.getCause();
if (cause instanceof ClassNotFoundException) {
if (throwException) {
throw new IllegalArgumentException("Invalid bundle " + type + " (implementation not found)");
}
// ignore
return null;
} else if (cause instanceof IllegalAccessException) {
throw new IllegalArgumentException("The given lookup does not have access to the implementation class");
} else if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else {
throw new RuntimeException("Failed to lookup bundle for type " + type, cause);
}
}
} else {
try {
return lookup.findClass(name).asSubclass(type);
} catch (ClassNotFoundException e) {
if (throwException) {
throw new IllegalArgumentException("Invalid bundle " + type + " (implementation not found)");
}
// ignore
return null;
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("The given lookup does not have access to the implementation class");
}
}
}

private static <T> PrivilegedExceptionAction<Class<? extends T>> createFindClassAction(final Lookup lookup,
final Class<T> type, final String name) {
return () -> lookup.findClass(name).asSubclass(type);
}
}

0 comments on commit 0d04688

Please sign in to comment.