mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-09-10 04:16:02 -04:00
Extract the log4j patch to the HMCL directory
This commit is contained in:
parent
130c8d0e89
commit
cfa1eedae7
@ -328,7 +328,7 @@ public class HMCLGameRepository extends DefaultGameRepository {
|
|||||||
vs.setUsesGlobal(true);
|
vs.setUsesGlobal(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public LaunchOptions getLaunchOptions(String version, JavaVersion javaVersion, File gameDir, boolean makeLaunchScript) {
|
public LaunchOptions getLaunchOptions(String version, JavaVersion javaVersion, File gameDir, List<String> javaAgents, boolean makeLaunchScript) {
|
||||||
VersionSetting vs = getVersionSetting(version);
|
VersionSetting vs = getVersionSetting(version);
|
||||||
|
|
||||||
LaunchOptions.Builder builder = new LaunchOptions.Builder()
|
LaunchOptions.Builder builder = new LaunchOptions.Builder()
|
||||||
@ -359,7 +359,8 @@ public class HMCLGameRepository extends DefaultGameRepository {
|
|||||||
.setProcessPriority(vs.getProcessPriority())
|
.setProcessPriority(vs.getProcessPriority())
|
||||||
.setUseNativeGLFW(vs.isUseNativeGLFW())
|
.setUseNativeGLFW(vs.isUseNativeGLFW())
|
||||||
.setUseNativeOpenAL(vs.isUseNativeOpenAL())
|
.setUseNativeOpenAL(vs.isUseNativeOpenAL())
|
||||||
.setDaemon(!makeLaunchScript && vs.getLauncherVisibility().isDaemon());
|
.setDaemon(!makeLaunchScript && vs.getLauncherVisibility().isDaemon())
|
||||||
|
.setJavaAgents(javaAgents);
|
||||||
if (config().hasProxy()) {
|
if (config().hasProxy()) {
|
||||||
builder.setProxy(ProxyManager.getProxy());
|
builder.setProxy(ProxyManager.getProxy());
|
||||||
if (config().hasProxyAuth()) {
|
if (config().hasProxyAuth()) {
|
||||||
|
@ -20,6 +20,7 @@ package org.jackhuang.hmcl.game;
|
|||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.jackhuang.hmcl.Launcher;
|
import org.jackhuang.hmcl.Launcher;
|
||||||
|
import org.jackhuang.hmcl.Metadata;
|
||||||
import org.jackhuang.hmcl.auth.*;
|
import org.jackhuang.hmcl.auth.*;
|
||||||
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorDownloadException;
|
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorDownloadException;
|
||||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||||
@ -55,9 +56,13 @@ import org.jackhuang.hmcl.util.versioning.VersionNumber;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.file.AccessDeniedException;
|
import java.nio.file.AccessDeniedException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
@ -124,9 +129,12 @@ public final class LauncherHelper {
|
|||||||
Optional<String> gameVersion = repository.getGameVersion(version);
|
Optional<String> gameVersion = repository.getGameVersion(version);
|
||||||
boolean integrityCheck = repository.unmarkVersionLaunchedAbnormally(selectedVersion);
|
boolean integrityCheck = repository.unmarkVersionLaunchedAbnormally(selectedVersion);
|
||||||
CountDownLatch launchingLatch = new CountDownLatch(1);
|
CountDownLatch launchingLatch = new CountDownLatch(1);
|
||||||
|
List<String> javaAgents = new ArrayList<>(0);
|
||||||
|
|
||||||
AtomicReference<JavaVersion> javaVersionRef = new AtomicReference<>();
|
AtomicReference<JavaVersion> javaVersionRef = new AtomicReference<>();
|
||||||
|
|
||||||
|
getLog4jPatch(version).ifPresent(javaAgents::add);
|
||||||
|
|
||||||
TaskExecutor executor = checkGameState(profile, setting, version)
|
TaskExecutor executor = checkGameState(profile, setting, version)
|
||||||
.thenComposeAsync(javaVersion -> {
|
.thenComposeAsync(javaVersion -> {
|
||||||
javaVersionRef.set(Objects.requireNonNull(javaVersion));
|
javaVersionRef.set(Objects.requireNonNull(javaVersion));
|
||||||
@ -172,7 +180,7 @@ public final class LauncherHelper {
|
|||||||
}
|
}
|
||||||
}).withStage("launch.state.logging_in"))
|
}).withStage("launch.state.logging_in"))
|
||||||
.thenComposeAsync(authInfo -> Task.supplyAsync(() -> {
|
.thenComposeAsync(authInfo -> Task.supplyAsync(() -> {
|
||||||
LaunchOptions launchOptions = repository.getLaunchOptions(selectedVersion, javaVersionRef.get(), profile.getGameDir(), scriptFile != null);
|
LaunchOptions launchOptions = repository.getLaunchOptions(selectedVersion, javaVersionRef.get(), profile.getGameDir(), javaAgents, scriptFile != null);
|
||||||
return new HMCLGameLauncher(
|
return new HMCLGameLauncher(
|
||||||
repository,
|
repository,
|
||||||
version,
|
version,
|
||||||
@ -598,6 +606,47 @@ public final class LauncherHelper {
|
|||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Optional<String> getLog4jPatch(Version version) {
|
||||||
|
Optional<String> log4jVersion = version.getLibraries().stream()
|
||||||
|
.filter(it -> it.is("org.apache.logging.log4j", "log4j-core")
|
||||||
|
&& (VersionNumber.VERSION_COMPARATOR.compare(it.getVersion(), "2.17") < 0 || "2.0-beta9".equals(it.getVersion())))
|
||||||
|
.map(Library::getVersion)
|
||||||
|
.findFirst();
|
||||||
|
|
||||||
|
if (log4jVersion.isPresent()) {
|
||||||
|
final String agentFileName = "log4j-patch-agent-1.0.jar";
|
||||||
|
|
||||||
|
Path agentFile = Metadata.HMCL_DIRECTORY.resolve(agentFileName).toAbsolutePath();
|
||||||
|
String agentFilePath = agentFile.toString();
|
||||||
|
if (agentFilePath.indexOf('=') >= 0) {
|
||||||
|
LOG.warning("Invalid character '=' in the HMCL directory path, unable to attach log4j-patch");
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Files.notExists(agentFile)) {
|
||||||
|
try (InputStream input = DefaultLauncher.class.getResourceAsStream("/assets/game/" + agentFileName)) {
|
||||||
|
LOG.info("Extract log4j patch to " + agentFilePath);
|
||||||
|
Files.createDirectories(agentFile.getParent());
|
||||||
|
Files.copy(input, agentFile, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.log(Level.WARNING, "Failed to extract log4j patch");
|
||||||
|
try {
|
||||||
|
Files.deleteIfExists(agentFile);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOG.log(Level.WARNING, "Failed to delete incomplete log4j patch", ex);
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isBeta = log4jVersion.get().startsWith("2.0-beta");
|
||||||
|
return Optional.of(agentFilePath + "=" + isBeta);
|
||||||
|
} else {
|
||||||
|
LOG.info("No log4j with security vulnerabilities found");
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void checkExit() {
|
private void checkExit() {
|
||||||
switch (launcherVisibility) {
|
switch (launcherVisibility) {
|
||||||
case HIDE_AND_REOPEN:
|
case HIDE_AND_REOPEN:
|
||||||
|
@ -42,7 +42,6 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.StandardCopyOption;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
@ -126,8 +125,6 @@ public class DefaultLauncher extends Launcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<Library> log4j = findLog4j();
|
|
||||||
|
|
||||||
// JVM Args
|
// JVM Args
|
||||||
if (!options.isNoGeneratedJVMArgs()) {
|
if (!options.isNoGeneratedJVMArgs()) {
|
||||||
appendJvmArgs(res);
|
appendJvmArgs(res);
|
||||||
@ -192,13 +189,6 @@ public class DefaultLauncher extends Launcher {
|
|||||||
|
|
||||||
res.addDefault("-Dfml.ignoreInvalidMinecraftCertificates=", "true");
|
res.addDefault("-Dfml.ignoreInvalidMinecraftCertificates=", "true");
|
||||||
res.addDefault("-Dfml.ignorePatchDiscrepancies=", "true");
|
res.addDefault("-Dfml.ignorePatchDiscrepancies=", "true");
|
||||||
|
|
||||||
if (log4j.isPresent()) {
|
|
||||||
String enableJndi = res.addDefault("-Dlog4j2.enableJndi=", "false");
|
|
||||||
if (!"-Dlog4j2.enableJndi=true".equals(enableJndi)) {
|
|
||||||
res.add("-javaagent:" + repository.getLibraryFile(version, LOG4J_PATCH_AGENT).getAbsolutePath() + "=" + log4j.get().getVersion().startsWith("2.0-beta"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix RCE vulnerability of log4j2
|
// Fix RCE vulnerability of log4j2
|
||||||
@ -207,7 +197,7 @@ public class DefaultLauncher extends Launcher {
|
|||||||
res.addDefault("-Dcom.sun.jndi.cosnaming.object.trustURLCodebase=", "false");
|
res.addDefault("-Dcom.sun.jndi.cosnaming.object.trustURLCodebase=", "false");
|
||||||
|
|
||||||
String formatMsgNoLookups = res.addDefault("-Dlog4j2.formatMsgNoLookups=", "true");
|
String formatMsgNoLookups = res.addDefault("-Dlog4j2.formatMsgNoLookups=", "true");
|
||||||
if (!"-Dlog4j2.formatMsgNoLookups=false".equals(formatMsgNoLookups) && log4j.isPresent()) {
|
if (!"-Dlog4j2.formatMsgNoLookups=false".equals(formatMsgNoLookups) && isUsingLog4j()) {
|
||||||
res.addDefault("-Dlog4j.configurationFile=", getLog4jConfigurationFile().getAbsolutePath());
|
res.addDefault("-Dlog4j.configurationFile=", getLog4jConfigurationFile().getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,17 +359,8 @@ public class DefaultLauncher extends Launcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Library LOG4J_PATCH_AGENT = new Library(new Artifact("org.glavo", "log4j-patch-agent", "1.0"));
|
private boolean isUsingLog4j() {
|
||||||
|
return VersionNumber.VERSION_COMPARATOR.compare(repository.getGameVersion(version).orElse("1.7"), "1.7") >= 0;
|
||||||
private Optional<Library> findLog4j() {
|
|
||||||
return version.getLibraries().stream()
|
|
||||||
.filter(it -> it.is("org.apache.logging.log4j", "log4j-core")
|
|
||||||
&& (VersionNumber.VERSION_COMPARATOR.compare(it.getVersion(), "2.17") < 0 || "2.0-beta9".equals(it.getVersion())))
|
|
||||||
.findFirst();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isLog4jUnsafe(Library log4j) {
|
|
||||||
return VersionNumber.VERSION_COMPARATOR.compare(log4j.getVersion(), "2.17") < 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getLog4jConfigurationFile() {
|
public File getLog4jConfigurationFile() {
|
||||||
@ -400,17 +381,6 @@ public class DefaultLauncher extends Launcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void extractLog4jAgent() throws IOException {
|
|
||||||
Path log4jPatchPath = repository.getLibraryFile(version, LOG4J_PATCH_AGENT).toPath();
|
|
||||||
String patchName = LOG4J_PATCH_AGENT.getArtifactId() + "-" + LOG4J_PATCH_AGENT.getVersion();
|
|
||||||
if (Files.notExists(log4jPatchPath)) {
|
|
||||||
try (InputStream input = DefaultLauncher.class.getResourceAsStream("/assets/game/" + patchName + ".jar")) {
|
|
||||||
Files.createDirectories(log4jPatchPath.getParent());
|
|
||||||
Files.copy(input, log4jPatchPath, StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Map<String, String> getConfigurations() {
|
protected Map<String, String> getConfigurations() {
|
||||||
return mapOf(
|
return mapOf(
|
||||||
// defined by Minecraft official launcher
|
// defined by Minecraft official launcher
|
||||||
@ -470,12 +440,8 @@ public class DefaultLauncher extends Launcher {
|
|||||||
decompressNatives(nativeFolder);
|
decompressNatives(nativeFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<Library> log4j = findLog4j();
|
if (isUsingLog4j())
|
||||||
if (log4j.isPresent()) {
|
|
||||||
extractLog4jConfigurationFile();
|
extractLog4jConfigurationFile();
|
||||||
if (isLog4jUnsafe(log4j.get()))
|
|
||||||
extractLog4jAgent();
|
|
||||||
}
|
|
||||||
|
|
||||||
File runDirectory = repository.getRunDirectory(version.getId());
|
File runDirectory = repository.getRunDirectory(version.getId());
|
||||||
|
|
||||||
@ -546,12 +512,8 @@ public class DefaultLauncher extends Launcher {
|
|||||||
decompressNatives(nativeFolder);
|
decompressNatives(nativeFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<Library> log4j = findLog4j();
|
if (isUsingLog4j())
|
||||||
if (log4j.isPresent()) {
|
|
||||||
extractLog4jConfigurationFile();
|
extractLog4jConfigurationFile();
|
||||||
if (isLog4jUnsafe(log4j.get()))
|
|
||||||
extractLog4jAgent();
|
|
||||||
}
|
|
||||||
|
|
||||||
String scriptExtension = FileUtils.getExtension(scriptFile);
|
String scriptExtension = FileUtils.getExtension(scriptFile);
|
||||||
boolean usePowerShell = "ps1".equals(scriptExtension);
|
boolean usePowerShell = "ps1".equals(scriptExtension);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user