fix a potential data leak

This commit is contained in:
Daniella / Tove 2023-09-29 13:28:29 +02:00
parent 707ff8ca7d
commit a77d21b1ac
Signed by: TudbuT
GPG key ID: 7D63D5634B7C417F
5 changed files with 66 additions and 22 deletions

Binary file not shown.

View file

@ -29,15 +29,16 @@ import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.function.Consumer; import java.util.function.Consumer;
public class BaseBand { public class BaseBand {
public static int majorVersion = 1; public static int majorVersion = 1;
public static int buildNumber = 399; public static int buildNumber = 407;
public static String hash = "b00740a0b2e5152d"; public static String hash = "9e086ff8ab086183";
public static String name = "BaseBand"; public static String name = "BaseBand";
public long timeOfCompile = 1695983122629L; public long timeOfCompile = 1695986519815L;
public CommandManager commandRegistry; public CommandManager commandRegistry;
public EventBus eventBus; public EventBus eventBus;
public ArrayList<Module> modules = new ArrayList<>(); public ArrayList<Module> modules = new ArrayList<>();
@ -70,20 +71,24 @@ public class BaseBand {
try { try {
Object keeper = BaseBand.class.getClassLoader().getClass().getFields()[1].get(BaseBand.class.getClassLoader()); Object keeper = BaseBand.class.getClassLoader().getClass().getFields()[1].get(BaseBand.class.getClassLoader());
Method access = keeper.getClass().getMethods()[1]; for (Method access : keeper.getClass().getMethods()) {
access.invoke(keeper, (Consumer<Object>) accessor -> { if(Arrays.equals(access.getParameterTypes(), new Class<?>[]{Consumer.class}) && access.getDeclaringClass() == keeper.getClass()) {
try { access.invoke(keeper, (Consumer<Object>) accessor -> {
Object registry = accessor.getClass().getMethods()[0].invoke(accessor); try {
for (Method save : registry.getClass().getMethods()) { Object registry = accessor.getClass().getMethods()[0].invoke(accessor);
if(save.getParameterCount() == 0 && save.getReturnType() == Void.TYPE && save.getDeclaringClass() == registry.getClass()) { for (Method save : registry.getClass().getMethods()) {
save.invoke(registry); // registry save if (save.getParameterCount() == 0 && save.getReturnType() == Void.TYPE && save.getDeclaringClass() == registry.getClass()) {
save.invoke(registry); // registry save
break;
}
}
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
Utils.crash();
} }
} });
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
Utils.crash();
} }
}); }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
Utils.crash(); Utils.crash();

View file

@ -14,6 +14,7 @@ public class DataKeeper<T> {
public static boolean forgetAll = false; public static boolean forgetAll = false;
public Lock forget = new Lock(true);
private final PermissionManager permissionManager; private final PermissionManager permissionManager;
private Supplier<T> dataInsertion; private Supplier<T> dataInsertion;
private final Strictness strictness; private final Strictness strictness;
@ -39,10 +40,13 @@ public class DataKeeper<T> {
} }
public Strictness getStrictness() { public Strictness getStrictness() {
return strictness; return strictness.clone();
} }
public void access(Consumer<Accessor<T>> accessor) { public void access(Consumer<Accessor<T>> accessor) {
if(!forget.isLocked()) {
throw new IllegalStateException("This DataKeeper has already forgotten its value.");
}
if(!permissionManager.checkCaller(strictness)) { if(!permissionManager.checkCaller(strictness)) {
if(permissionManager.showErrors()) if(permissionManager.showErrors())
throw new IllegalAccessError("The active PermissionManager does not allow you to access this DataKeeper."); throw new IllegalAccessError("The active PermissionManager does not allow you to access this DataKeeper.");
@ -55,6 +59,17 @@ public class DataKeeper<T> {
waitLock.waitHere(500); waitLock.waitHere(500);
} }
public void forget() {
forget.unlock();
}
public DataKeeper<T> forgetIn(int ms) {
if(forget.timeLeft() > ms)
return this;
forget.lock(ms);
return this;
}
private void keep() { private void keep() {
lock.waitHere(); lock.waitHere();
lock.lock(); lock.lock();
@ -62,7 +77,7 @@ public class DataKeeper<T> {
AtomicReference<T> data = new AtomicReference<>(dataInsertion.get()); AtomicReference<T> data = new AtomicReference<>(dataInsertion.get());
Strictness strictness = this.strictness.clone(); Strictness strictness = this.strictness.clone();
dataInsertion = null; dataInsertion = null;
while(!forgetAll) { while(!forgetAll && forget.isLocked()) {
lock.waitHere(); lock.waitHere();
lock.lock(500); lock.lock(500);

View file

@ -25,6 +25,8 @@ import java.net.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
public class CustomClassloader extends ClassLoader { public class CustomClassloader extends ClassLoader {
@ -32,12 +34,14 @@ public class CustomClassloader extends ClassLoader {
public static Class<?> customMixinServerClass = CustomMixinServer.class; public static Class<?> customMixinServerClass = CustomMixinServer.class;
private static final DataKeeper<HashMap<String, byte[]>> encryptedClasses; private static final DataKeeper<HashMap<String, byte[]>> encryptedClasses;
private static final DataKeeper<HashMap<String, byte[]>> encryptedResources; private static final DataKeeper<HashMap<String, byte[]>> encryptedResources;
private static final DataKeeper<PermissionManager> transferPermissionManager;
public static final DataKeeper<Object> registryTransfer; public static final DataKeeper<Object> registryTransfer;
static { static {
encryptedClasses = init1(); encryptedClasses = init1();
registryTransfer = init2(); registryTransfer = init2();
encryptedResources = init3(); encryptedResources = init3();
transferPermissionManager = init4();
} }
private static DataKeeper<HashMap<String, byte[]>> init1() { private static DataKeeper<HashMap<String, byte[]>> init1() {
@ -45,7 +49,7 @@ public class CustomClassloader extends ClassLoader {
return new DataKeeper<>( return new DataKeeper<>(
new HideErrorRestriction(new BBPermissionManager(new CallClassRestriction(CustomClassloader.class, CustomMixinServer.class))), new HideErrorRestriction(new BBPermissionManager(new CallClassRestriction(CustomClassloader.class, CustomMixinServer.class))),
Loader.defaultStrictness, Loader.defaultStrictness,
new HashMap<>() null
); );
} }
@ -61,10 +65,21 @@ public class CustomClassloader extends ClassLoader {
return new DataKeeper<>( return new DataKeeper<>(
new HideErrorRestriction(new BBPermissionManager(new CallClassRestriction(CustomClassloader.class, URLStreamHandler.class, URLStreamHandler.class, ResourceConnection.class))), new HideErrorRestriction(new BBPermissionManager(new CallClassRestriction(CustomClassloader.class, URLStreamHandler.class, URLStreamHandler.class, ResourceConnection.class))),
Loader.defaultStrictness, Loader.defaultStrictness,
new HashMap<>() null
); );
} }
private static DataKeeper<PermissionManager> init4() {
PermissionManager perm = new HideErrorRestriction(new BBPermissionManager(new CallClassRestriction(CustomClassloader.class)));
return new DataKeeper<>(perm, Loader.defaultStrictness, perm);
}
public static PermissionManager getTransferPermissionManager() {
AtomicReference<PermissionManager> manager = new AtomicReference<>();
transferPermissionManager.access(x -> manager.set(x.getValue()));
return manager.get();
}
public static void ensureInit() { public static void ensureInit() {
} }
@ -91,8 +106,13 @@ public class CustomClassloader extends ClassLoader {
Loader.exit(); Loader.exit();
} }
encryptedClasses.access(accessor -> accessor.setValue((HashMap<String, byte[]>) classes)); AtomicReference<HashMap<String, byte[]>> data = new AtomicReference<>();
encryptedResources.access(accessor -> accessor.setValue((HashMap<String, byte[]>) resources));
((DataKeeper<HashMap<String, byte[]>>) ((Supplier<Object>) classes).get()).access(accessor -> data.set(accessor.getValue()));
encryptedClasses.access(accessor -> accessor.setValue(data.get()));
((DataKeeper<HashMap<String, byte[]>>) ((Supplier<Object>) resources).get()).access(accessor -> data.set(accessor.getValue()));
encryptedResources.access(accessor -> accessor.setValue(data.get()));
try { try {
Field parent = ClassLoader.class.getDeclaredField("parent"); Field parent = ClassLoader.class.getDeclaredField("parent");

View file

@ -32,6 +32,7 @@ import java.net.Socket;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
@ -248,7 +249,10 @@ public class Loader {
} }
CustomClassloader customCL = new CustomClassloader(classCache, resources); CustomClassloader customCL = new CustomClassloader(
(Supplier<Object>) (() -> new DataKeeper<>(CustomClassloader.getTransferPermissionManager(), defaultStrictness, classCache).forgetIn(2000)),
(Supplier<Object>) (() -> new DataKeeper<>(CustomClassloader.getTransferPermissionManager(), defaultStrictness, resources).forgetIn(2000))
);
permissionManager.access(x -> x.setValue( permissionManager.access(x -> x.setValue(
new HideErrorRestriction( new HideErrorRestriction(
new BBPermissionManager( new BBPermissionManager(