Skip to content

Commit

Permalink
Ban sun.misc.Unsafe
Browse files Browse the repository at this point in the history
  • Loading branch information
kiritofeng committed Dec 22, 2023
1 parent 3173587 commit c42f54b
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 32 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ Supported fields for the `option` list are:
* `nobigmath` — disables `BigInteger` and `BigDecimal`, raising [appropriate exceptions](https://github.com/DMOJ/java-sandbox-agent/blob/master/src/main/java/ca/dmoj/java/BigIntegerDisallowedException.java) if they are used
* `unicode` — encodes `System.out` as UTF-8 instead of ASCII, sacrificing performance for Unicode support
* `nobuf` — sets `System.out` as being line-buffered, for interactive problems
* `unsafe` — enables `sun.misc.Unsafe`, which is disabled by default
23 changes: 23 additions & 0 deletions src/main/java/ca/dmoj/java/DisallowedClassRule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package ca.dmoj.java;

public class DisallowedClassRule {
protected interface ExceptionFactory {
Exception create();
}

protected String className;
protected ExceptionFactory exception;

public DisallowedClassRule(String className, ExceptionFactory exception) {
this.className = className;
this.exception = exception;
}

public String getClassName() {
return className;
}

public Exception getException() {
return exception.create();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package ca.dmoj.java;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

public class DisallowedClassesClassFileTransformer implements ClassFileTransformer {
protected DisallowedClassRule[] rules;

public DisallowedClassesClassFileTransformer(DisallowedClassRule... rules) {
this.rules = rules;
}

@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer)
throws IllegalClassFormatException {
if (className == null) return classfileBuffer;

Exception disallowed = null;
for (DisallowedClassRule rule : rules) {
// If the class ever loaded it's because a submission used it
if (className.startsWith(rule.getClassName())) {
disallowed = rule.getException();
break;
}
}

if (disallowed != null) ExceptionHandler.dumpExceptionAndExit(disallowed);

// Don't actually retransform anything
return classfileBuffer;
}
}
9 changes: 9 additions & 0 deletions src/main/java/ca/dmoj/java/ExceptionHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package ca.dmoj.java;

class ExceptionHandler {
public static void dumpExceptionAndExit(Throwable exception) {
System.err.print("7257b50d-e37a-4664-b1a5-b1340b4206c0: ");
exception.printStackTrace();
System.exit(1);
}
}
45 changes: 13 additions & 32 deletions src/main/java/ca/dmoj/java/SubmissionAgent.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
package ca.dmoj.java;

import java.io.*;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import java.util.ArrayList;

public class SubmissionAgent {
public static void premain(String argv, Instrumentation inst) throws UnsupportedEncodingException {
boolean unsafe = false;
boolean unicode = false;
boolean noBigMath = false;
boolean noBuf = false;

if (argv != null) {
for (String opt : argv.split(",")) {
if (opt.equals("unsafe")) unsafe = true;
if (opt.equals("unicode")) unicode = true;
if (opt.equals("nobigmath")) noBigMath = true;
if (opt.equals("nobuf")) noBuf = true;
Expand All @@ -22,30 +22,17 @@ public static void premain(String argv, Instrumentation inst) throws Unsupported

final Thread selfThread = Thread.currentThread();

ArrayList<DisallowedClassRule> disallowedClassRules = new ArrayList<>();
if (!unsafe) {
disallowedClassRules.add(new DisallowedClassRule("sun/reflect/Unsafe", UnsafeDisallowedException::new));
disallowedClassRules.add(new DisallowedClassRule("sun/misc/Unsafe", UnsafeDisallowedException::new));
}
if (noBigMath) {
inst.addTransformer(new ClassFileTransformer() {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer)
throws IllegalClassFormatException {
if (className == null) return classfileBuffer;

RuntimeException disallowed = null;
// If the class ever loaded it's because a submission used it
if (className.startsWith("java/math/BigInteger") ||
className.startsWith("java/math/MutableBigInteger")) {
disallowed = new BigIntegerDisallowedException();
} else if (className.startsWith("java/math/BigDecimal")) {
disallowed = new BigDecimalDisallowedException();
}

if (disallowed != null) dumpExceptionAndExit(disallowed);

// Don't actually retransform anything
return classfileBuffer;
}
});
disallowedClassRules.add(new DisallowedClassRule("java/math/BigInteger", BigIntegerDisallowedException::new));
disallowedClassRules.add(new DisallowedClassRule("java/math/MutableBigInteger", BigIntegerDisallowedException::new));
disallowedClassRules.add(new DisallowedClassRule("java/math/BigDecimal", BigDecimalDisallowedException::new));
}
inst.addTransformer(new DisallowedClassesClassFileTransformer(disallowedClassRules.toArray(new DisallowedClassRule[0])));

if (noBuf) {
// Create output PrintStream set to autoflush:
Expand All @@ -61,7 +48,7 @@ public byte[] transform(ClassLoader loader, String className, Class<?> classBein
selfThread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, Throwable error) {
dumpExceptionAndExit(error);
ExceptionHandler.dumpExceptionAndExit(error);
}
});

Expand All @@ -75,10 +62,4 @@ public void run() {
}
}));
}

private static void dumpExceptionAndExit(Throwable exception) {
System.err.print("7257b50d-e37a-4664-b1a5-b1340b4206c0: ");
exception.printStackTrace();
System.exit(1);
}
}
4 changes: 4 additions & 0 deletions src/main/java/ca/dmoj/java/UnsafeDisallowedException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package ca.dmoj.java;

public class UnsafeDisallowedException extends RuntimeException {
}

0 comments on commit c42f54b

Please sign in to comment.