Log4JExploitFix

基本信息

修复 Log4Shell(CVE-2021-44228)利用。配置开关 log4jExploitFix (默认 true,分组 bugfixes)。

目标:无目标类 → 全局补丁

addPatcher(new Log4JLoggerWrapperPatcher("Log4JExploitFix"));

补丁构造:super(name, "", "", "") —— 目标类名为空串, 因此在 addPatcher() 中落入 globalPatchers 分支, 对每一个被加载的类执行检查(代价很高,见下)。

三重版本探测

启用前先判断 log4j 是否含 org/apache/logging/log4j/core/lookup/JndiLookup:

判定 常量 长度
Mojang 官方已修补版 JNDILOOKUP_MOJANG_SIZE 738
MultiMC 修补版 JNDILOOKUP_MULTIMC_SIZE 983

流程:

  1. 取 JndiLookup.class 字节流,读入 8192 字节缓冲;
  2. 按长度匹配 → 选定预期 SHA-256;
  3. 算实际 SHA-256 比对 —— 一致则打日志 \<source\> JndiLookup class detected; skipping Log4JExploitFix... 并置 vulnerableJndiLookupFound = false;
  4. 类不存在则 Class.forName 兜底判否;
  5. 仍未判定为安全才 addPatcher。

⚠️ 资源流未关闭

异常分支里 jndiLookupStream.close() 只在 catch 内调用, 正常读完的路径不关闭流(BugfixModClassTransformer.java:477-490)。 每个日志级别仅执行一次,影响有限,但属资源泄漏。

⚠️ 全局补丁的性能代价

因为目标类名为空,本补丁进入 globalPatchers, transform() 对每个类都调用一次 patch()。 AbstractPatcher.patch 首步即 new ClassReader(bytes)(失败静默返回), 在不支持的类(如 LiteLoader 相关)上会抛 NullPointerException 并被吞掉。

相关条目

源码

  • src/main/java/pl/asie/foamfix/coremod/patchers/Log4JLoggerWrapperPatcher.java
  • src/main/java/pl/asie/foamfix/bugfixmod/coremod/BugfixModClassTransformer.java:432-488