From 1c218010fe6d27d987dbd128dd7992532c1dfcb2 Mon Sep 17 00:00:00 2001 From: zpj80231 Date: Tue, 9 Jun 2026 15:01:43 +0800 Subject: [PATCH] feat: differentiate core and plugin classes by ClassLoader to avoid shadowing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 改用 StackWalker(RETAIN_CLASS_REFERENCE) 在判定时获取栈帧真实 Class 的 ClassLoader,仅 PluginClassLoader 加载的类才可能判为可疑;伪造官方包名的插件被拦截,官方同名类不再被连坐。编译目标升至 Java 11。 --- pom.xml | 18 ++++++---- .../com/novitechie/rules/StackTraceRule.java | 35 ++++++++++++------- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/pom.xml b/pom.xml index 9071a85..4807ccf 100644 --- a/pom.xml +++ b/pom.xml @@ -6,11 +6,11 @@ com.novitechie plugin-privacy - 1.1.0 + 1.2.0 - 8 - 8 + 11 + 11 UTF-8 @@ -20,8 +20,8 @@ maven-compiler-plugin 3.7.0 - 8 - 8 + 11 + 11 UTF-8 -XDignore.symbol.file true @@ -65,7 +65,13 @@ ja-netfilter 2025.3.0 provided + + + com.sun + tools + + - \ No newline at end of file + diff --git a/src/main/java/com/novitechie/rules/StackTraceRule.java b/src/main/java/com/novitechie/rules/StackTraceRule.java index 613fc46..b870601 100644 --- a/src/main/java/com/novitechie/rules/StackTraceRule.java +++ b/src/main/java/com/novitechie/rules/StackTraceRule.java @@ -12,6 +12,9 @@ import java.util.regex.Pattern; public class StackTraceRule { private static final Pattern PACKAGE_NAME_PATTERN = Pattern.compile("\\A\\p{ASCII}*\\z"); + private static final String PLUGIN_CLASS_LOADER_NAME = "com.intellij.ide.plugins.cl.PluginClassLoader"; + private static final StackWalker WALKER = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); + private static List traceCheckPackageRules = Collections.emptyList(); public static void initRules(List traceCheckPackageRules) { @@ -21,24 +24,30 @@ public class StackTraceRule { } public static boolean check() { - StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); - for (StackTraceElement stackTraceElement : stackTrace) { - if (isSuspiciousFrame(stackTraceElement)) { - return true; - } + return WALKER.walk(frames -> frames.anyMatch(StackTraceRule::isSuspiciousFrame)); + } + + static boolean isSuspiciousFrame(StackWalker.StackFrame frame) { + Class declaringClass = frame.getDeclaringClass(); + return isSuspicious(frame.getMethodName(), declaringClass.getName(), declaringClass.getClassLoader()); + } + + static boolean isSuspicious(String methodName, String className, ClassLoader classLoader) { + if (!PACKAGE_NAME_PATTERN.matcher(methodName).matches()) { + return true; + } + if (methodName.length() <= 1 && checkTracePackage(className) && isLoadedByPluginClassLoader(classLoader)) { + return true; } return false; } - static boolean isSuspiciousFrame(StackTraceElement stackTraceElement) { - String methodName = stackTraceElement.getMethodName(); - if (!PACKAGE_NAME_PATTERN.matcher(methodName).matches()) { - return true; + static boolean isLoadedByPluginClassLoader(ClassLoader classLoader) { + if (classLoader == null) { + return false; } - if (methodName.length() <= 1) { - String className = stackTraceElement.getClassName(); - if (checkTracePackage(className)) { - // DebugInfo.info("short method frame, className: " + className + ", methodName: " + methodName); + for (Class type = classLoader.getClass(); type != null; type = type.getSuperclass()) { + if (PLUGIN_CLASS_LOADER_NAME.equals(type.getName())) { return true; } }