diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/AsmPatcher.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/AsmPatcher.java deleted file mode 100644 index e7f3cb9ab..000000000 --- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/AsmPatcher.java +++ /dev/null @@ -1,44 +0,0 @@ -package edu.columbia.cs.psl.phosphor.agent; - -import edu.columbia.cs.psl.phosphor.Configuration; -import edu.columbia.cs.psl.phosphor.instrumenter.TaintMethodRecord; -import org.objectweb.asm.*; - -public class AsmPatcher extends ClassVisitor { - private static final String ASM_PREFIX = "edu/columbia/cs/psl/phosphor/org/objectweb/asm/"; - private static final Type OBJECT_TYPE = Type.getType(Object.class); - - public AsmPatcher(ClassWriter cw) { - super(Configuration.ASM_VERSION, cw); - } - - @Override - public MethodVisitor visitMethod( - int access, String name, String descriptor, String signature, String[] exceptions) { - MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); - return new MethodVisitor(api, mv) { - - @Override - public void visitMethodInsn( - int opcode, String owner, String name, String descriptor, boolean isInterface) { - super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); - // Ensure that the return value is unwrapped if necessary - if (owner.startsWith("java/") && OBJECT_TYPE.equals(Type.getReturnType(descriptor))) { - TaintMethodRecord.TAINTED_REFERENCE_ARRAY_UNWRAP.delegateVisit(mv); - } - } - }; - } - - public static byte[] patch(byte[] classFileBuffer) { - ClassReader cr = new ClassReader(classFileBuffer); - ClassWriter cw = new ClassWriter(cr, 0); - ClassVisitor cv = new AsmPatcher(cw); - cr.accept(cv, 0); - return cw.toByteArray(); - } - - public static boolean isApplicable(String className) { - return className.startsWith(ASM_PREFIX); - } -} \ No newline at end of file diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/AsmPatchingCV.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/AsmPatchingCV.java new file mode 100644 index 000000000..340a3eaff --- /dev/null +++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/AsmPatchingCV.java @@ -0,0 +1,42 @@ +package edu.columbia.cs.psl.phosphor.agent; + +import edu.columbia.cs.psl.phosphor.Configuration; +import edu.columbia.cs.psl.phosphor.instrumenter.TaintMethodRecord; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Type; + +public final class AsmPatchingCV extends ClassVisitor { + private static final String ASM_PREFIX = "edu/columbia/cs/psl/phosphor/org/objectweb/asm/"; + private static final Type OBJECT_TYPE = Type.getType(Object.class); + + public AsmPatchingCV(ClassVisitor classVisitor) { + super(Configuration.ASM_VERSION, classVisitor); + } + + @Override + public MethodVisitor visitMethod( + int access, String name, String descriptor, String signature, String[] exceptions) { + MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); + return new AsmPatchingMV(mv); + } + + public static boolean isApplicable(String className) { + return className.startsWith(ASM_PREFIX); + } + + private static class AsmPatchingMV extends MethodVisitor { + public AsmPatchingMV(MethodVisitor mv) { + super(Configuration.ASM_VERSION, mv); + } + + @Override + public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) { + super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); + // Ensure that the return value is unwrapped if necessary + if (owner.startsWith("java/") && OBJECT_TYPE.equals(Type.getReturnType(descriptor))) { + TaintMethodRecord.TAINTED_REFERENCE_ARRAY_UNWRAP.delegateVisit(mv); + } + } + } +} \ No newline at end of file diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/ConfigurationEmbeddingCV.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/ConfigurationEmbeddingCV.java new file mode 100644 index 000000000..4cbad5815 --- /dev/null +++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/ConfigurationEmbeddingCV.java @@ -0,0 +1,100 @@ +package edu.columbia.cs.psl.phosphor.agent; + +import edu.columbia.cs.psl.phosphor.Configuration; +import edu.columbia.cs.psl.phosphor.instrumenter.TaintMethodRecord; +import edu.columbia.cs.psl.phosphor.struct.harmony.util.Set; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +import static org.objectweb.asm.Opcodes.*; + +/** + * Embeds the current values for the field of {@link Configuration} into the class file for {@link Configuration}. + */ +public class ConfigurationEmbeddingCV extends ClassVisitor { + private static final String TARGET_METHOD_NAME = ""; + + protected ConfigurationEmbeddingCV(ClassVisitor classVisitor) { + super(Configuration.ASM_VERSION, classVisitor); + } + + @Override + public MethodVisitor visitMethod( + int access, String name, String descriptor, String signature, String[] exceptions) { + MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); + return !name.equals(TARGET_METHOD_NAME) ? mv : new ConfigurationEmbeddingMV(mv); + } + + public static boolean isApplicable(String className) { + return Type.getInternalName(Configuration.class).equals(className); + } + + private static class ConfigurationEmbeddingMV extends MethodVisitor { + protected ConfigurationEmbeddingMV(MethodVisitor methodVisitor) { + super(Configuration.ASM_VERSION, methodVisitor); + } + + @Override + public void visitFieldInsn(int opcode, String owner, String name, String descriptor) { + if (opcode == Opcodes.PUTSTATIC) { + try { + Field f = Configuration.class.getField(name); + f.setAccessible(true); + if (Modifier.isPublic(f.getModifiers()) || !Modifier.isFinal(f.getModifiers())) { + replaceValue(Type.getType(descriptor), f.get(null)); + } + } catch (ReflectiveOperationException e) { + throw new RuntimeException("Failed to access field owned by " + Configuration.class, e); + } + } + super.visitFieldInsn(opcode, owner, name, descriptor); + } + + private void replaceValue(Type type, Object newValue) { + switch (type.getSort()) { + case Type.VOID: + case Type.ARRAY: + case Type.METHOD: + return; + } + // Pop the original value + super.visitInsn(type.getSize() == 1 ? POP : POP2); + // Push the new value + if (type.getSort() != Type.OBJECT || newValue instanceof String) { + super.visitLdcInsn(newValue); + } else if (newValue == null) { + super.visitInsn(ACONST_NULL); + } else if (newValue instanceof Class) { + mv.visitLdcInsn(Type.getType((Class) newValue)); + } else if (newValue instanceof Set) { + Set set = (Set) newValue; + newInstance(newValue.getClass()); + for (Object element : set) { + super.visitInsn(DUP); + super.visitLdcInsn(element); + TaintMethodRecord.SET_ADD.delegateVisit(mv); + super.visitInsn(POP); + } + } else { + newInstance(newValue.getClass()); + } + } + + private void newInstance(Class clazz) { + try { + clazz.getConstructor(); + } catch (NoSuchMethodException e) { + throw new IllegalArgumentException("Public, zero-argument constructor not found for: " + clazz); + } + String className = Type.getInternalName(clazz); + super.visitTypeInsn(Opcodes.NEW, className); + super.visitInsn(DUP); + super.visitMethodInsn(INVOKESPECIAL, className, "", "()V", false); + } + } +} diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/ConfigurationEmbeddingMV.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/ConfigurationEmbeddingMV.java deleted file mode 100644 index e204be3a7..000000000 --- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/ConfigurationEmbeddingMV.java +++ /dev/null @@ -1,80 +0,0 @@ -package edu.columbia.cs.psl.phosphor.agent; - -import edu.columbia.cs.psl.phosphor.Configuration; -import edu.columbia.cs.psl.phosphor.instrumenter.TaintMethodRecord; -import edu.columbia.cs.psl.phosphor.struct.harmony.util.Set; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; - -import static org.objectweb.asm.Opcodes.*; - -/** - * Embeds the current values for the field of {@link Configuration} into the class file for {@link Configuration}. - */ -public class ConfigurationEmbeddingMV extends MethodVisitor { - public ConfigurationEmbeddingMV(MethodVisitor mv) { - super(Configuration.ASM_VERSION, mv); - } - - @Override - public void visitFieldInsn(int opcode, String owner, String name, String descriptor) { - if (opcode == Opcodes.PUTSTATIC) { - try { - Field f = Configuration.class.getField(name); - f.setAccessible(true); - if (Modifier.isPublic(f.getModifiers()) || !Modifier.isFinal(f.getModifiers())) { - replaceValue(Type.getType(descriptor), f.get(null)); - } - } catch (ReflectiveOperationException e) { - throw new RuntimeException("Failed to access field owned by " + Configuration.class, e); - } - } - super.visitFieldInsn(opcode, owner, name, descriptor); - } - - public void replaceValue(Type type, Object newValue) { - switch (type.getSort()) { - case Type.VOID: - case Type.ARRAY: - case Type.METHOD: - return; - } - // Pop the original value - super.visitInsn(type.getSize() == 1 ? POP : POP2); - // Push the new value - if (type.getSort() != Type.OBJECT || newValue instanceof String) { - super.visitLdcInsn(newValue); - } else if (newValue == null) { - super.visitInsn(ACONST_NULL); - } else if (newValue instanceof Class) { - mv.visitLdcInsn(Type.getType((Class) newValue)); - } else if (newValue instanceof Set) { - Set set = (Set) newValue; - newInstance(newValue.getClass()); - for (Object element : set) { - super.visitInsn(DUP); - super.visitLdcInsn(element); - TaintMethodRecord.SET_ADD.delegateVisit(mv); - super.visitInsn(POP); - } - } else { - newInstance(newValue.getClass()); - } - } - - private void newInstance(Class clazz) { - try { - clazz.getConstructor(); - } catch (NoSuchMethodException e) { - throw new IllegalArgumentException("Public, zero-argument constructor not found for: " + clazz); - } - String className = Type.getInternalName(clazz); - super.visitTypeInsn(Opcodes.NEW, className); - super.visitInsn(DUP); - super.visitMethodInsn(INVOKESPECIAL, className, "", "()V", false); - } -} diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/EmbeddedPhosphorPatcher.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/EmbeddedPhosphorPatcher.java index 373d18a55..0ad58e9c2 100644 --- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/EmbeddedPhosphorPatcher.java +++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/EmbeddedPhosphorPatcher.java @@ -1,35 +1,26 @@ package edu.columbia.cs.psl.phosphor.agent; -import edu.columbia.cs.psl.phosphor.Configuration; -import edu.columbia.cs.psl.phosphor.runtime.jdk.unsupported.UnsafeProxy; -import org.objectweb.asm.*; +import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; - /** - * Performs patching of embedded Phosphors (for Java 9+). + * Performs patching of embedded Phosphor JAR (for Java 9+). */ public class EmbeddedPhosphorPatcher { private final boolean patchUnsafeNames; public EmbeddedPhosphorPatcher(byte[] unsafeClassFileBuffer) { - this(shouldPatchUnsafeNames(unsafeClassFileBuffer)); - } - - public EmbeddedPhosphorPatcher(boolean patchUnsafeNames) { - this.patchUnsafeNames = patchUnsafeNames; + this.patchUnsafeNames = shouldPatchUnsafeNames(unsafeClassFileBuffer); } - public byte[] patch(String name, byte[] content) throws IOException { - if (name.equals("edu/columbia/cs/psl/phosphor/Configuration.class")) { - return setConfigurationVersion(new ByteArrayInputStream(content)); - } else if (name.equals("edu/columbia/cs/psl/phosphor/runtime/RuntimeJDKInternalUnsafePropagator.class")) { - return transformUnsafePropagator( - new ByteArrayInputStream(content), "jdk/internal/misc/Unsafe", patchUnsafeNames); + public byte[] patch(String name, byte[] content) { + name = name.replace(".class", ""); + if (ConfigurationEmbeddingCV.isApplicable(name)) { + return PhosphorPatcher.apply(content, ConfigurationEmbeddingCV::new); + } else if (name.equals("edu/columbia/cs/psl/phosphor/runtime/RuntimeJDKInternalUnsafePropagator")) { + return PhosphorPatcher.apply( + content, cv -> new UnsafePatchingCV(cv, "jdk/internal/misc/Unsafe", patchUnsafeNames)); } else { return content; } @@ -45,112 +36,4 @@ private static boolean shouldPatchUnsafeNames(byte[] in) { } return true; } - - /** - * Modify {@link Configuration} to set {@link Configuration#IS_JAVA_8} to false. - * This flag must be set correctly in order to boot the JVM. - */ - private static byte[] setConfigurationVersion(InputStream is) throws IOException { - ClassReader cr = new ClassReader(is); - ClassWriter cw = new ClassWriter(cr, 0); - ClassVisitor cv = new ClassVisitor(Configuration.ASM_VERSION, cw) { - @Override - public MethodVisitor visitMethod( - int access, String name, String descriptor, String signature, String[] exceptions) { - MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); - if (name.equals("")) { - return new ConfigurationEmbeddingMV(mv); - } else { - return mv; - } - } - }; - cr.accept(cv, 0); - return cw.toByteArray(); - } - - public static byte[] transformUnsafePropagator(InputStream in, String unsafeInternalName, boolean patchUnsafeNames) - throws IOException { - ClassReader cr = new ClassReader(in); - ClassWriter cw = new ClassWriter(cr, 0); - ClassVisitor cv = new UnsafePatchingCV(cw, unsafeInternalName, patchUnsafeNames); - cr.accept(cv, 0); - return cw.toByteArray(); - } - - private static class UnsafePatchingCV extends ClassVisitor { - private static final String UNSAFE_PROXY_INTERNAL_NAME = Type.getInternalName(UnsafeProxy.class); - private static final String UNSAFE_PROXY_DESC = Type.getDescriptor(UnsafeProxy.class); - private final String unsafeDesc; - private final boolean patchNames; - private final String unsafeInternalName; - - public UnsafePatchingCV(ClassWriter cw, String unsafeInternalName, boolean patchNames) { - super(Configuration.ASM_VERSION, cw); - this.unsafeInternalName = unsafeInternalName; - this.unsafeDesc = "L" + unsafeInternalName + ";"; - this.patchNames = patchNames; - } - - private String patchInternalName(String name) { - return UNSAFE_PROXY_INTERNAL_NAME.equals(name) ? unsafeInternalName : name; - } - - private String patchDesc(String desc) { - return desc == null ? null : desc.replace(UNSAFE_PROXY_DESC, unsafeDesc); - } - - private String patchMethodName(String owner, String name) { - return patchNames && owner.equals(UNSAFE_PROXY_INTERNAL_NAME) ? name.replace("Reference", "Object") : name; - } - - @Override - public MethodVisitor visitMethod( - int access, String name, String descriptor, String signature, String[] exceptions) { - MethodVisitor mv = super.visitMethod(access, name, patchDesc(descriptor), patchDesc(signature), exceptions); - return new MethodVisitor(api, mv) { - @Override - public void visitFrame(int type, int numLocal, Object[] local, int numStack, Object[] stack) { - for (int i = 0; i < numLocal; i++) { - if (local[i] instanceof String) { - local[i] = patchInternalName((String) local[i]); - } - } - for (int i = 0; i < numStack; i++) { - if (stack[i] instanceof String) { - stack[i] = patchInternalName((String) stack[i]); - } - } - super.visitFrame(type, numLocal, local, numStack, stack); - } - - @Override - public void visitFieldInsn(int opcode, String owner, String name, String descriptor) { - super.visitFieldInsn(opcode, patchInternalName(owner), name, patchDesc(descriptor)); - } - - @Override - public void visitMethodInsn( - int opcode, String owner, String name, String descriptor, boolean isInterface) { - super.visitMethodInsn( - opcode, - patchInternalName(owner), - patchMethodName(owner, name), - patchDesc(descriptor), - isInterface); - } - - @Override - public void visitTypeInsn(int opcode, String type) { - super.visitTypeInsn(opcode, patchInternalName(type)); - } - - @Override - public void visitLocalVariable( - String name, String descriptor, String signature, Label start, Label end, int index) { - super.visitLocalVariable(name, patchDesc(descriptor), signature, start, end, index); - } - }; - } - } } diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/InstrumentedJREProxyGenerator.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/InstrumentedJREProxyGenerator.java index b0f5ff366..5ce61e8fa 100644 --- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/InstrumentedJREProxyGenerator.java +++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/InstrumentedJREProxyGenerator.java @@ -1,48 +1,53 @@ package edu.columbia.cs.psl.phosphor.agent; - import edu.columbia.cs.psl.phosphor.Configuration; import org.objectweb.asm.*; import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.util.CheckClassAdapter; -import java.io.FileInputStream; +import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Paths; public class InstrumentedJREProxyGenerator { - static String[] CLASSES = {"edu.columbia.cs.psl.phosphor.runtime.proxied.InstrumentedJREFieldHelper", - "edu.columbia.cs.psl.phosphor.runtime.proxied.InstrumentedJREMethodHelper"}; + static String[] CLASSES = { + "edu.columbia.cs.psl.phosphor.runtime.proxied.InstrumentedJREFieldHelper", + "edu.columbia.cs.psl.phosphor.runtime.proxied.InstrumentedJREMethodHelper" + }; public static void main(String[] args) throws IOException { String outputDir = args[0]; - String version = System.getProperty("java.version"); - - String pathToUnsafePropagator = outputDir + "/edu/columbia/cs/psl/phosphor/runtime/jdk/unsupported/RuntimeSunMiscUnsafePropagator.class"; - InputStream sunMiscUnsafeIn = new FileInputStream(pathToUnsafePropagator); - byte[] instrumentedUnsafe = EmbeddedPhosphorPatcher.transformUnsafePropagator(sunMiscUnsafeIn, - "sun/misc/Unsafe", false); + String pathToUnsafePropagator = outputDir + + "/edu/columbia/cs/psl/phosphor/runtime/jdk/unsupported/RuntimeSunMiscUnsafePropagator.class"; + byte[] buffer = InstrumentUtil.readAllBytes(new File(pathToUnsafePropagator)); + byte[] instrumentedUnsafe = + PhosphorPatcher.apply(buffer, cv -> new UnsafePatchingCV(cv, "sun/misc/Unsafe", false)); Files.write(Paths.get(pathToUnsafePropagator), instrumentedUnsafe); - for (String clazz : CLASSES) { String classLocation = outputDir + '/' + clazz.replace('.', '/') + ".class"; - ClassReader cr = new ClassReader(new FileInputStream(classLocation)); + ClassReader cr = new ClassReader(InstrumentUtil.readAllBytes(new File(classLocation))); ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS); cr.accept( new CheckClassAdapter( new ClassVisitor(Configuration.ASM_VERSION, cw) { @Override - public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { - MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); + public MethodVisitor visitMethod( + int access, + String name, + String descriptor, + String signature, + String[] exceptions) { + MethodVisitor mv = + super.visitMethod(access, name, descriptor, signature, exceptions); GeneratorAdapter ga = new GeneratorAdapter(mv, access, name, descriptor); ga.visitCode(); if (name.equals("")) { } else if (name.equals("")) { ga.visitVarInsn(Opcodes.ALOAD, 0); - ga.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V", false); + ga.visitMethodInsn( + Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V", false); } else if (name.equals("_crash")) { ga.visitInsn(Opcodes.ACONST_NULL); } else if (clazz.endsWith("FieldHelper")) { @@ -55,7 +60,9 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, Str ga.visitMaxs(0, 0); return ga; } - }, false), ClassReader.SKIP_CODE); + }, + false), + ClassReader.SKIP_CODE); byte[] ret = cw.toByteArray(); Files.write(Paths.get(classLocation), ret); } @@ -69,10 +76,13 @@ public static void generateFieldHelper(GeneratorAdapter ga, String name, String } String fieldName = name.substring(3); Type actualFieldType = null; - if (name.startsWith("get")) { ga.visitVarInsn(Opcodes.ALOAD, 0); - ga.visitFieldInsn(Opcodes.GETFIELD, fieldOwner, fieldName, (actualFieldType != null ? actualFieldType.getDescriptor() : returnType.getDescriptor())); + ga.visitFieldInsn( + Opcodes.GETFIELD, + fieldOwner, + fieldName, + (actualFieldType != null ? actualFieldType.getDescriptor() : returnType.getDescriptor())); } else { Type argType = Type.getArgumentTypes(descriptor)[1]; ga.visitVarInsn(Opcodes.ALOAD, 0); @@ -80,7 +90,11 @@ public static void generateFieldHelper(GeneratorAdapter ga, String name, String if (actualFieldType != null) { ga.visitTypeInsn(Opcodes.CHECKCAST, actualFieldType.getInternalName()); } - ga.visitFieldInsn(Opcodes.PUTFIELD, fieldOwner, fieldName, (actualFieldType != null ? actualFieldType.getDescriptor() : argType.getDescriptor())); + ga.visitFieldInsn( + Opcodes.PUTFIELD, + fieldOwner, + fieldName, + (actualFieldType != null ? actualFieldType.getDescriptor() : argType.getDescriptor())); } } @@ -106,7 +120,7 @@ public static void generateMethodHelper(GeneratorAdapter ga, String name, String if (isInstanceMethod) { descriptorToInvoke = "(" + descriptor.substring(descriptor.indexOf(';') + 1); try { - Class c = Class.forName(owner.replace('/', '.')); + Class c = Class.forName(owner.replace('/', '.')); if (c.isInterface()) { isIface = true; opcode = Opcodes.INVOKEVIRTUAL; @@ -115,12 +129,11 @@ public static void generateMethodHelper(GeneratorAdapter ga, String name, String e.printStackTrace(); } } - Type[] args = Type.getArgumentTypes(descriptor); int argIdx = 0; - for (int i = 0; i < args.length; i++) { - ga.visitVarInsn(args[i].getOpcode(Opcodes.ILOAD), argIdx); - argIdx += args[i].getSize(); + for (Type arg : args) { + ga.visitVarInsn(arg.getOpcode(Opcodes.ILOAD), argIdx); + argIdx += arg.getSize(); } ga.visitMethodInsn(opcode, owner, methodName, descriptorToInvoke, isIface); } diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/MaskRegistryPatchingCV.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/MaskRegistryPatchingCV.java new file mode 100644 index 000000000..26e919ac4 --- /dev/null +++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/MaskRegistryPatchingCV.java @@ -0,0 +1,125 @@ +package edu.columbia.cs.psl.phosphor.agent; + +import edu.columbia.cs.psl.phosphor.Configuration; +import edu.columbia.cs.psl.phosphor.Phosphor; +import edu.columbia.cs.psl.phosphor.instrumenter.MethodRecordImpl; +import edu.columbia.cs.psl.phosphor.instrumenter.TaintMethodRecord; +import edu.columbia.cs.psl.phosphor.mask.MaskRegistry; +import edu.columbia.cs.psl.phosphor.runtime.mask.Mask; +import edu.columbia.cs.psl.phosphor.runtime.mask.SunUnsafeMasker; +import edu.columbia.cs.psl.phosphor.struct.harmony.util.HashMap; +import edu.columbia.cs.psl.phosphor.struct.harmony.util.Map; +import org.objectweb.asm.*; +import org.objectweb.asm.tree.AnnotationNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +public class MaskRegistryPatchingCV extends ClassVisitor { + private static final String MASK_REGISTRY_INTERNAL_NAME = Type.getInternalName(MaskRegistry.class); + private static final String TARGET_METHOD_NAME = "initialize"; + private static final String MONITOR_DESC = Type.getDescriptor(Mask.class); + private static final Class[] MASKERS = new Class[] {SunUnsafeMasker.class}; + + public MaskRegistryPatchingCV(ClassVisitor cv) { + super(Configuration.ASM_VERSION, cv); + } + + public static Map readMasks() { + Map map = new HashMap<>(); + for (Class clazz : MASKERS) { + ClassNode cn = getClassNode(clazz); + for (MethodNode mn : cn.methods) { + readMasks(cn.name, mn, map); + } + } + return map; + } + + private static ClassNode getClassNode(Class clazz) { + try { + ClassNode cn = new ClassNode(); + String name = clazz.getName().replace('.', '/') + ".class"; + ClassLoader classLoader = clazz.getClassLoader(); + try (InputStream in = classLoader == null || Phosphor.RUNTIME_INST + ? ClassLoader.getSystemResourceAsStream(name) + : classLoader.getResourceAsStream(name)) { + if (in == null) { + throw new IllegalStateException("Failed to read class: " + clazz); + } + new ClassReader(in).accept(cn, ClassReader.SKIP_CODE); + } + return cn; + } catch (IOException e) { + throw new IllegalStateException("Failed to read class: " + clazz, e); + } + } + + private static void readMasks(String className, MethodNode mn, Map map) { + if ((mn.access & Opcodes.ACC_STATIC) != 0 && mn.invisibleAnnotations != null) { + MethodRecordImpl record = new MethodRecordImpl(Opcodes.INVOKESTATIC, className, mn.name, mn.desc, false); + for (AnnotationNode an : mn.invisibleAnnotations) { + if (MONITOR_DESC.equals(an.desc)) { + map.put(createKey(mn, an), new MaskRegistry.MaskInfo(record)); + } + } + } + } + + private static String createKey(MethodNode mn, AnnotationNode an) { + List values = an.values; + String className = ((Type) values.get(1)).getInternalName(); + String methodName = mn.name; + boolean isStatic = false; + if (values.size() == 4) { + isStatic = (boolean) values.get(3); + } + String descriptor = isStatic ? mn.desc : removeFirstParameter(mn.desc); + return MaskRegistry.getKey(className, methodName, descriptor); + } + + private static String removeFirstParameter(String descriptor) { + int index = descriptor.indexOf(';'); + return '(' + descriptor.substring(index + 1); + } + + @Override + public MethodVisitor visitMethod( + int access, String name, String descriptor, String signature, String[] exceptions) { + MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); + return !name.equals(TARGET_METHOD_NAME) ? mv : new MaskRegistryPatchingMV(mv); + } + + public static boolean isApplicable(String className) { + return className.equals(MASK_REGISTRY_INTERNAL_NAME); + } + + private static class MaskRegistryPatchingMV extends MethodVisitor { + private final MethodVisitor target; + + public MaskRegistryPatchingMV(MethodVisitor mv) { + super(Configuration.ASM_VERSION, null); + target = mv; + } + + @Override + public void visitCode() { + target.visitCode(); + Map masks = readMasks(); + for (String key : masks.keySet()) { + MaskRegistry.MaskInfo mask = masks.get(key); + target.visitLdcInsn(key); + target.visitLdcInsn(mask.getRecord().getOwner()); + target.visitLdcInsn(mask.getRecord().getName()); + target.visitLdcInsn(mask.getRecord().getDescriptor()); + TaintMethodRecord.ADD_MASK.delegateVisit(target); + } + target.visitInsn(Opcodes.RETURN); + target.visitMaxs(-1, -1); + target.visitEnd(); + } + } +} diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/PhosphorPatcher.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/PhosphorPatcher.java index eeb834e50..e7c956f3e 100644 --- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/PhosphorPatcher.java +++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/PhosphorPatcher.java @@ -1,8 +1,13 @@ package edu.columbia.cs.psl.phosphor.agent; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; + import java.io.File; import java.io.IOException; import java.nio.file.Files; +import java.util.function.Function; import java.util.zip.CRC32; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -28,13 +33,6 @@ public static void main(String[] args) throws IOException { } } - private static byte[] patch(String name, byte[] classFileBuffer) { - if (AsmPatcher.isApplicable(name)) { - return AsmPatcher.patch(classFileBuffer); - } - return classFileBuffer; - } - private static void writeEntry(ZipOutputStream zos, ZipEntry entry, byte[] content) throws IOException { ZipEntry outEntry = new ZipEntry(entry.getName()); outEntry.setMethod(entry.getMethod()); @@ -50,4 +48,22 @@ private static void writeEntry(ZipOutputStream zos, ZipEntry entry, byte[] conte zos.write(content); zos.closeEntry(); } + + private static byte[] patch(String name, byte[] classFileBuffer) { + name = name.replace(".class", ""); + if (AsmPatchingCV.isApplicable(name)) { + return apply(classFileBuffer, AsmPatchingCV::new); + } else if (MaskRegistryPatchingCV.isApplicable(name)) { + return apply(classFileBuffer, MaskRegistryPatchingCV::new); + } + return classFileBuffer; + } + + public static byte[] apply(byte[] classFileBuffer, Function visitorFactory) { + ClassReader cr = new ClassReader(classFileBuffer); + ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS); + ClassVisitor cv = visitorFactory.apply(cw); + cr.accept(cv, ClassReader.EXPAND_FRAMES); + return cw.toByteArray(); + } } diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/UnsafePatchingCV.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/UnsafePatchingCV.java new file mode 100644 index 000000000..1be139f38 --- /dev/null +++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/UnsafePatchingCV.java @@ -0,0 +1,83 @@ +package edu.columbia.cs.psl.phosphor.agent; + +import edu.columbia.cs.psl.phosphor.Configuration; +import edu.columbia.cs.psl.phosphor.runtime.jdk.unsupported.UnsafeProxy; +import org.objectweb.asm.*; + +class UnsafePatchingCV extends ClassVisitor { + private static final String UNSAFE_PROXY_INTERNAL_NAME = Type.getInternalName(UnsafeProxy.class); + private static final String UNSAFE_PROXY_DESC = Type.getDescriptor(UnsafeProxy.class); + private final String unsafeDesc; + private final boolean patchNames; + private final String unsafeInternalName; + + public UnsafePatchingCV(ClassVisitor cv, String unsafeInternalName, boolean patchNames) { + super(Configuration.ASM_VERSION, cv); + this.unsafeInternalName = unsafeInternalName; + this.unsafeDesc = "L" + unsafeInternalName + ";"; + this.patchNames = patchNames; + } + + private String patchInternalName(String name) { + return UNSAFE_PROXY_INTERNAL_NAME.equals(name) ? unsafeInternalName : name; + } + + private String patchDesc(String desc) { + return desc == null ? null : + desc.replace(UNSAFE_PROXY_DESC, unsafeDesc); + } + + private String patchMethodName(String owner, String name) { + return patchNames && owner.equals(UNSAFE_PROXY_INTERNAL_NAME) ? + name.replace("Reference", "Object") : name; + } + + @Override + public MethodVisitor visitMethod( + int access, String name, String descriptor, String signature, String[] exceptions) { + MethodVisitor mv = super.visitMethod(access, name, patchDesc(descriptor), patchDesc(signature), exceptions); + return new MethodVisitor(api, mv) { + @Override + public void visitFrame(int type, int numLocal, Object[] local, int numStack, Object[] stack) { + for (int i = 0; i < numLocal; i++) { + if (local[i] instanceof String) { + local[i] = patchInternalName((String) local[i]); + } + } + for (int i = 0; i < numStack; i++) { + if (stack[i] instanceof String) { + stack[i] = patchInternalName((String) stack[i]); + } + } + super.visitFrame(type, numLocal, local, numStack, stack); + } + + @Override + public void visitFieldInsn(int opcode, String owner, String name, String descriptor) { + super.visitFieldInsn(opcode, patchInternalName(owner), name, patchDesc(descriptor)); + } + + @Override + public void visitMethodInsn( + int opcode, String owner, String name, String descriptor, boolean isInterface) { + super.visitMethodInsn( + opcode, + patchInternalName(owner), + patchMethodName(owner, name), + patchDesc(descriptor), + isInterface); + } + + @Override + public void visitTypeInsn(int opcode, String type) { + super.visitTypeInsn(opcode, patchInternalName(type)); + } + + @Override + public void visitLocalVariable( + String name, String descriptor, String signature, Label start, Label end, int index) { + super.visitLocalVariable(name, patchDesc(descriptor), signature, start, end, index); + } + }; + } +} diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/control/standard/ControlMethodRecord.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/control/standard/ControlMethodRecord.java index 7c066930e..4906671be 100644 --- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/control/standard/ControlMethodRecord.java +++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/control/standard/ControlMethodRecord.java @@ -93,11 +93,4 @@ public boolean isInterface() { return isInterface; } - /** - * {@inheritDoc} - */ - @Override - public Class getReturnType() { - return returnType; - } } diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/MethodRecord.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/MethodRecord.java index e4fdf6771..097fa64bf 100644 --- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/MethodRecord.java +++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/MethodRecord.java @@ -33,11 +33,6 @@ public interface MethodRecord { */ boolean isInterface(); - /** - * @return this method's return type - */ - Class getReturnType(); - /** * Tells the specified method visitor to visit a method instruction for this method. * diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/MethodRecordImpl.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/MethodRecordImpl.java new file mode 100644 index 000000000..e826c977b --- /dev/null +++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/MethodRecordImpl.java @@ -0,0 +1,57 @@ +package edu.columbia.cs.psl.phosphor.instrumenter; + +public final class MethodRecordImpl implements MethodRecord { + private final int opcode; + private final String owner; + private final String name; + private final String descriptor; + private final boolean isInterface; + + public MethodRecordImpl(int opcode, String owner, String name, String descriptor, boolean isInterface) { + this.opcode = opcode; + this.owner = owner; + this.name = name; + this.isInterface = isInterface; + this.descriptor = descriptor; + } + + /** + * {@inheritDoc} + */ + @Override + public int getOpcode() { + return opcode; + } + + /** + * {@inheritDoc} + */ + @Override + public String getOwner() { + return owner; + } + + /** + * {@inheritDoc} + */ + @Override + public String getName() { + return name; + } + + /** + * {@inheritDoc} + */ + @Override + public String getDescriptor() { + return descriptor; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isInterface() { + return isInterface; + } +} diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/TaintMethodRecord.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/TaintMethodRecord.java index c9670a594..784a83969 100644 --- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/TaintMethodRecord.java +++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/TaintMethodRecord.java @@ -3,6 +3,7 @@ import edu.columbia.cs.psl.phosphor.Phosphor; import edu.columbia.cs.psl.phosphor.TaintUtils; import edu.columbia.cs.psl.phosphor.control.ControlFlowStack; +import edu.columbia.cs.psl.phosphor.mask.MaskRegistry; import edu.columbia.cs.psl.phosphor.runtime.*; import edu.columbia.cs.psl.phosphor.struct.*; import edu.columbia.cs.psl.phosphor.struct.harmony.util.Set; @@ -124,14 +125,16 @@ public enum TaintMethodRecord implements MethodRecord { // TaggedReferenceArray TAINTED_REFERENCE_ARRAY_UNWRAP(INVOKESTATIC, TaggedReferenceArray.class, "unwrap", Object.class, false, Object.class), // Set - SET_ADD(INVOKEVIRTUAL, Set.class, "add", boolean.class, true, Object.class); + SET_ADD(INVOKEVIRTUAL, Set.class, "add", boolean.class, true, Object.class), + // MaskRegistry + ADD_MASK(INVOKESTATIC, MaskRegistry.class, "addMask", void.class, false, String.class, String.class, + String.class, String.class); private final int opcode; private final String owner; private final String name; private final String descriptor; private final boolean isInterface; - private final Class returnType; /** * Constructs a new method. @@ -149,7 +152,6 @@ public enum TaintMethodRecord implements MethodRecord { this.name = name; this.isInterface = isInterface; this.descriptor = MethodRecord.createDescriptor(returnType, parameterTypes); - this.returnType = returnType; } /** @@ -192,14 +194,6 @@ public boolean isInterface() { return isInterface; } - /** - * {@inheritDoc} - */ - @Override - public Class getReturnType() { - return returnType; - } - public static TaintMethodRecord getArgWrapperMethod(Type arrayType) { if (arrayType.getDimensions() > 1) { return GET_ARG_WRAPPER_OBJECT; diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/TaintPassingMV.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/TaintPassingMV.java index 9a9ba8c94..ed6c42077 100644 --- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/TaintPassingMV.java +++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/TaintPassingMV.java @@ -1157,7 +1157,8 @@ private void visitArrayLoad(int opcode) { loadStackTopShadowVar(); pushPhosphorStackFrame(); getMethod.delegateVisit(mv); - if (Object.class.equals(getMethod.getReturnType()) && referenceArrayTarget != null) { + Type returnType = Type.getReturnType(getMethod.getDescriptor()); + if (Type.getType(Object.class).equals(returnType) && referenceArrayTarget != null) { Type originalArrayType = Type.getType(referenceArrayTarget.getOriginalArrayType()); String castTo = Type.getType(originalArrayType.getDescriptor().substring(1)).getInternalName(); if (originalArrayType.getDimensions() == 2) { diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/mask/MaskRegistry.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/mask/MaskRegistry.java new file mode 100644 index 000000000..c6fb6e63e --- /dev/null +++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/mask/MaskRegistry.java @@ -0,0 +1,62 @@ +package edu.columbia.cs.psl.phosphor.mask; + +import edu.columbia.cs.psl.phosphor.Phosphor; +import edu.columbia.cs.psl.phosphor.agent.MaskRegistryPatchingCV; +import edu.columbia.cs.psl.phosphor.instrumenter.InvokedViaInstrumentation; +import edu.columbia.cs.psl.phosphor.instrumenter.MethodRecordImpl; +import edu.columbia.cs.psl.phosphor.instrumenter.TaintMethodRecord; +import edu.columbia.cs.psl.phosphor.struct.harmony.util.HashMap; +import edu.columbia.cs.psl.phosphor.struct.harmony.util.Map; +import org.objectweb.asm.Opcodes; + +public final class MaskRegistry { + private static final Map masks = new HashMap<>(); + + private MaskRegistry() { + throw new AssertionError(); + } + + static { + initialize(); + } + + public static MaskInfo getMask(String className, String methodName, String descriptor) { + return masks.get(getKey(className, methodName, descriptor)); + } + + public static String getKey(String className, String methodName, String descriptor) { + return className + "." + methodName + descriptor; + } + + /** + * The body of this method is replaced by {@link MaskRegistryPatchingCV} when the Phosphor is + * JAR is patched. + */ + private static void initialize() { + masks.putAll(MaskRegistryPatchingCV.readMasks()); + if (Phosphor.RUNTIME_INST) { + throw new AssertionError("Calling unpatched method body"); + } + } + + @InvokedViaInstrumentation(record = TaintMethodRecord.ADD_MASK) + private static void addMask(String key, String owner, String name, String descriptor) { + MethodRecordImpl record = new MethodRecordImpl(Opcodes.INVOKESTATIC, owner, name, descriptor, false); + masks.put(key, new MaskInfo(record)); + } + + public static class MaskInfo { + private final MethodRecordImpl record; + + public MaskInfo(MethodRecordImpl record) { + if (record == null) { + throw new NullPointerException(); + } + this.record = record; + } + + public MethodRecordImpl getRecord() { + return record; + } + } +} diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/mask/ReflectionMVFactory.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/mask/ReflectionMVFactory.java index 4ee38ae9c..e7e65792d 100644 --- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/mask/ReflectionMVFactory.java +++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/mask/ReflectionMVFactory.java @@ -8,6 +8,8 @@ public final class ReflectionMVFactory { public static ReflectionMV create(MethodVisitor mv, String className, String methodName) { + // TODO + MaskRegistry.MaskInfo mask = MaskRegistry.getMask(className, methodName, "()V"); if (ObjectStreamReflectionMV.isApplicable(className, methodName)) { return new ObjectStreamReflectionMV(mv, className, methodName); } else if (DisabledReflectionMV.isApplicable(className, methodName)) { diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/runtime/jdk/unsupported/RuntimeSunMiscUnsafePropagator.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/runtime/jdk/unsupported/RuntimeSunMiscUnsafePropagator.java index 7c6d10864..b22915a40 100644 --- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/runtime/jdk/unsupported/RuntimeSunMiscUnsafePropagator.java +++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/runtime/jdk/unsupported/RuntimeSunMiscUnsafePropagator.java @@ -128,7 +128,7 @@ private static void findLastInstanceFieldOnJavaLangClass(UnsafeProxy unsafe) { /* If prealloc is a wrapped primitive type, set it's taint to be the value of the field at the specified offset in the * other specified object. Otherwise returns the value of the field at the specified offset in the specified object. */ - private static void getTag(UnsafeProxy unsafe, Object obj, long originalOffset, PhosphorStackFrame stackFrame, SpecialAccessPolicy policy) { + public static void getTag(UnsafeProxy unsafe, Object obj, long originalOffset, PhosphorStackFrame stackFrame, SpecialAccessPolicy policy) { stackFrame.returnTaint = Taint.emptyTaint(); OffsetPair pair = getOffsetPair(unsafe, obj, originalOffset); if(pair != null && pair.tagFieldOffset != UnsafeProxy.INVALID_FIELD_OFFSET) { @@ -142,7 +142,7 @@ private static void getTag(UnsafeProxy unsafe, Object obj, long originalOffset, /* If the specified Object value is a wrapped primitive type, puts it's taint into the field at the specified offset in the * other specified object. Otherwise if the specified Object value is null or a lazy array wrapper put the specified Object * value into the field at the specified offset in the other specified object. */ - private static void putTag(UnsafeProxy unsafe, Object obj, long offset, Taint tag, SpecialAccessPolicy policy) { + public static void putTag(UnsafeProxy unsafe, Object obj, long offset, Taint tag, SpecialAccessPolicy policy) { OffsetPair pair = null; if(obj != null) { pair = getOffsetPair(unsafe, obj, offset); @@ -164,7 +164,7 @@ private static void putTag(UnsafeProxy unsafe, Object obj, long offset, Taint ta /* If the specified TaintedPrimitiveWithObjTag and TaggedArray's component types match sets a tag * in the specified TaggedArray at a calculated index. * type's match. */ - private static void swapArrayElementTag(UnsafeProxy unsafe, TaggedArray tags, long offset, Taint valueTaint) { + public static void swapArrayElementTag(UnsafeProxy unsafe, TaggedArray tags, long offset, Taint valueTaint) { if(tags.getVal() != null && tags.getVal().getClass().isArray()) { Class clazz = tags.getVal().getClass(); long baseOffset = unsafe.arrayBaseOffset(clazz); @@ -283,7 +283,7 @@ public static boolean compareAndSwapLong(UnsafeProxy unsafe, Object obj, long of return ret; } - private static int unsafeIndexFor(UnsafeProxy unsafe, TaggedArray array, long offset) { + public static int unsafeIndexFor(UnsafeProxy unsafe, TaggedArray array, long offset) { Class clazz = array.getVal().getClass(); long baseOffset = unsafe.arrayBaseOffset(clazz); long scale = unsafe.arrayIndexScale(clazz); @@ -796,7 +796,8 @@ public static Class defineClass(UnsafeProxy unsafe, String var1, byte[] var2, in byte[] instrumented = Phosphor.instrumentClassBytes(var2); return unsafe.defineClass(var1, instrumented, 0, instrumented.length, var5, var6); } - private enum SpecialAccessPolicy { + + public enum SpecialAccessPolicy { VOLATILE, ORDERED, NONE diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/runtime/mask/Mask.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/runtime/mask/Mask.java new file mode 100644 index 000000000..716a726a7 --- /dev/null +++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/runtime/mask/Mask.java @@ -0,0 +1,26 @@ +package edu.columbia.cs.psl.phosphor.runtime.mask; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicates that calls to the annotated method should be added during instrumentation to + * replace calls to replace compatible method calls. + * Methods with this annotation must be static. + * A method call is compatible with a mask if the method being called is owned by the mask's specified + * {@link Mask#owner}, has the same name as the method with the mask annotation, and it descriptor is compatible + * with that the of method with the mask annotation. + * If {@link Mask#isStatic()} is true then a descriptor is compatible if it is equal to descriptor of the method with + * the mask annotation. + * Otherwise, a descriptor is compatible if it is equal to the descriptor of the method with the mask annotation with + * the first parameter removed. + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.CLASS) +public @interface Mask { + Class owner(); + + boolean isStatic() default false; +} diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/runtime/mask/SunUnsafeMasker.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/runtime/mask/SunUnsafeMasker.java new file mode 100644 index 000000000..28e62ada7 --- /dev/null +++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/runtime/mask/SunUnsafeMasker.java @@ -0,0 +1,1008 @@ +package edu.columbia.cs.psl.phosphor.runtime.mask; + +import edu.columbia.cs.psl.phosphor.Phosphor; +import edu.columbia.cs.psl.phosphor.runtime.MultiDArrayUtils; +import edu.columbia.cs.psl.phosphor.runtime.PhosphorStackFrame; +import edu.columbia.cs.psl.phosphor.runtime.RuntimeJDKInternalUnsafePropagator; +import edu.columbia.cs.psl.phosphor.runtime.Taint; +import edu.columbia.cs.psl.phosphor.runtime.jdk.unsupported.RuntimeSunMiscUnsafePropagator; +import edu.columbia.cs.psl.phosphor.runtime.jdk.unsupported.UnsafeProxy; +import edu.columbia.cs.psl.phosphor.struct.TaggedArray; +import edu.columbia.cs.psl.phosphor.struct.TaggedIntArray; +import edu.columbia.cs.psl.phosphor.struct.TaggedLongArray; +import edu.columbia.cs.psl.phosphor.struct.TaggedReferenceArray; +import sun.misc.Unsafe; + +import java.security.ProtectionDomain; + +import static edu.columbia.cs.psl.phosphor.runtime.jdk.unsupported.RuntimeSunMiscUnsafePropagator.*; + +@SuppressWarnings("unused") +public final class SunUnsafeMasker { + private static UnsafeAdapter adapter; + + @Mask(owner = Unsafe.class) + public static Class defineClass( + Unsafe unsafe, + String name, + byte[] b, + int off, + int len, + ClassLoader loader, + ProtectionDomain protectionDomain, + PhosphorStackFrame frame) { + if (b != null && off >= 0 && len >= 0 && off + len <= b.length) { + byte[] buffer = new byte[len]; + System.arraycopy(b, off, buffer, 0, len); + byte[] instrumented = Phosphor.instrumentClassBytes(buffer); + return adapter.defineClass(name, instrumented, 0, instrumented.length, loader, protectionDomain); + } + return adapter.defineClass(name, b, off, len, loader, protectionDomain); + } + + @Mask(owner = Unsafe.class) + public static Object getObject(Unsafe unsafe, Object o, long offset, PhosphorStackFrame frame) { + return null; + } + + public static Object getObject(UnsafeProxy unsafe, Object o, long offset, PhosphorStackFrame frame) { + if (o instanceof TaggedReferenceArray) { + // Push the taint from the `offset` argument to the `idx` argument for get + return ((TaggedReferenceArray) o) + .get(unsafeIndexFor(unsafe, (TaggedArray) o, offset), frame.getArgTaint(1), frame); + } else { + // Is this trying to return a field that is wrapped? + RuntimeJDKInternalUnsafePropagator.OffsetPair pair = getOffsetPair(unsafe, o, offset); + if (pair != null && pair.wrappedFieldOffset != UnsafeProxy.INVALID_FIELD_OFFSET) { + offset = pair.wrappedFieldOffset; + } + getTag(unsafe, o, offset, frame, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + return unsafe.getObject(o, offset); + } + } + + @Mask(owner = Unsafe.class) + public static Object getObjectVolatile(Unsafe unsafe, Object o, long offset, PhosphorStackFrame frame) { + return null; + } + + public static Object getObjectVolatile(UnsafeProxy unsafe, Object obj, long offset, PhosphorStackFrame stackFrame) { + if (obj instanceof TaggedReferenceArray) { + // Push the taint from the `offset` argument to the `idx` argument for get + return ((TaggedReferenceArray) obj) + .get(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), stackFrame.getArgTaint(1), stackFrame); + } else { + // Is this trying to return a field that is wrapped? + RuntimeJDKInternalUnsafePropagator.OffsetPair pair = getOffsetPair(unsafe, obj, offset); + if (pair != null && pair.wrappedFieldOffset != UnsafeProxy.INVALID_FIELD_OFFSET) { + offset = pair.wrappedFieldOffset; + } + getTag(unsafe, obj, offset, stackFrame, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.VOLATILE); + return unsafe.getObjectVolatile(obj, offset); + } + } + + public static boolean compareAndSwapInt( + UnsafeProxy unsafe, + Object obj, + long offset, + int expected, + int value, + PhosphorStackFrame phosphorStackFrame) { + phosphorStackFrame.returnTaint = Taint.emptyTaint(); + boolean ret = false; + if (obj instanceof TaggedIntArray) { + ret = unsafe.compareAndSwapInt(((TaggedIntArray) obj).val, offset, expected, value); + if (ret) { + swapArrayElementTag(unsafe, (TaggedArray) obj, offset, phosphorStackFrame.getArgTaint(4)); + } + } else { + ret = unsafe.compareAndSwapInt(obj, offset, expected, value); + RuntimeJDKInternalUnsafePropagator.OffsetPair pair = null; + if (obj != null) { + pair = getOffsetPair(unsafe, obj, offset); + } + if (pair != null && ret) { + if (pair.tagFieldOffset != UnsafeProxy.INVALID_FIELD_OFFSET) { + unsafe.putObjectVolatile(obj, pair.tagFieldOffset, phosphorStackFrame.getArgTaint(4)); + } + } + } + return ret; + } + + @Mask(owner = Unsafe.class) + public static boolean compareAndSwapInt( + Unsafe unsafe, Object o, long offset, int expected, int x, PhosphorStackFrame frame) { + return false; + } + + public static boolean compareAndSwapLong( + UnsafeProxy unsafe, + Object obj, + long offset, + long expected, + long value, + PhosphorStackFrame phosphorStackFrame) { + phosphorStackFrame.returnTaint = Taint.emptyTaint(); + boolean ret; + if (obj instanceof TaggedLongArray) { + ret = unsafe.compareAndSwapLong(((TaggedLongArray) obj).val, offset, expected, value); + if (ret) { + swapArrayElementTag(unsafe, (TaggedArray) obj, offset, phosphorStackFrame.getArgTaint(4)); + } + } else { + ret = unsafe.compareAndSwapLong(obj, offset, expected, value); + RuntimeJDKInternalUnsafePropagator.OffsetPair pair = null; + if (obj != null) { + pair = getOffsetPair(unsafe, obj, offset); + } + if (pair != null && ret) { + if (pair.tagFieldOffset != UnsafeProxy.INVALID_FIELD_OFFSET) { + unsafe.putObjectVolatile(obj, pair.tagFieldOffset, phosphorStackFrame.getArgTaint(4)); + } + } + } + return ret; + } + + @Mask(owner = Unsafe.class) + public static boolean compareAndSwapLong( + Unsafe unsafe, Object o, long offset, long expected, long x, PhosphorStackFrame frame) { + return false; + } + + public static boolean compareAndSwapObject( + UnsafeProxy unsafe, Object obj, long offset, Object expected, Object value, PhosphorStackFrame stackFrame) { + stackFrame.returnTaint = Taint.emptyTaint(); + boolean ret = false; + if (obj instanceof TaggedReferenceArray) { + Taint valueTaint = stackFrame.getArgTaint(4); + ret = unsafe.compareAndSwapObject(((TaggedReferenceArray) obj).val, offset, expected, value); + if (ret) { + swapArrayElementTag(unsafe, (TaggedArray) obj, offset, valueTaint); + } + } else { + RuntimeJDKInternalUnsafePropagator.OffsetPair pair = null; + boolean didCAS = false; + if (value instanceof TaggedArray || expected instanceof TaggedArray) { + // Need to be careful - maybe we are hitting a 1D primitive array field + if (obj != null) { + pair = getOffsetPair(unsafe, obj, offset); + } + if (pair != null && pair.wrappedFieldOffset != UnsafeProxy.INVALID_FIELD_OFFSET) { + // We are doing a CAS on a 1d primitive array field + ret = unsafe.compareAndSwapObject( + obj, + offset, + MultiDArrayUtils.unbox1DOrNull(expected), + MultiDArrayUtils.unbox1DOrNull(value)); + didCAS = true; + } + } + if (!didCAS) { + // Either this is not a wrapped array, or we are storing it to the place where it should be stored + // without unwrapping + ret = unsafe.compareAndSwapObject(obj, offset, expected, value); + if (pair == null && obj != null) { + pair = getOffsetPair(unsafe, obj, offset); + } + } + if (pair != null && ret) { + if (pair.tagFieldOffset != UnsafeProxy.INVALID_FIELD_OFFSET) { + unsafe.putObjectVolatile(obj, pair.tagFieldOffset, stackFrame.getArgTaint(4)); + } + if (pair.wrappedFieldOffset != UnsafeProxy.INVALID_FIELD_OFFSET) { + unsafe.putObjectVolatile(obj, pair.wrappedFieldOffset, value); + } + } + } + return ret; + } + + @Mask(owner = Unsafe.class) + public static boolean compareAndSwapObject( + Unsafe unsafe, Object o, long offset, Object expected, Object x, PhosphorStackFrame frame) { + return false; + } + + @Mask(owner = Unsafe.class) + public static boolean getBoolean(Unsafe unsafe, Object o, long offset, PhosphorStackFrame frame) { + return false; + } + + public static boolean getBoolean(UnsafeProxy unsafe, Object obj, long offset, PhosphorStackFrame stackFrame) { + if (obj instanceof TaggedArray) { + stackFrame.returnTaint = + ((TaggedArray) obj).getTaintOrEmpty(unsafeIndexFor(unsafe, (TaggedArray) obj, offset)); + return unsafe.getBoolean(((TaggedArray) obj).getVal(), offset); + } else { + getTag(unsafe, obj, offset, stackFrame, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + return unsafe.getBoolean(obj, offset); + } + } + + public static boolean getBooleanVolatile( + UnsafeProxy unsafe, Object obj, long offset, PhosphorStackFrame stackFrame) { + if (obj instanceof TaggedArray) { + stackFrame.returnTaint = + ((TaggedArray) obj).getTaintOrEmpty(unsafeIndexFor(unsafe, (TaggedArray) obj, offset)); + return unsafe.getBooleanVolatile(((TaggedArray) obj).getVal(), offset); + } else { + getTag(unsafe, obj, offset, stackFrame, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.VOLATILE); + return unsafe.getBooleanVolatile(obj, offset); + } + } + + @Mask(owner = Unsafe.class) + public static boolean getBooleanVolatile(Unsafe unsafe, Object o, long offset, PhosphorStackFrame frame) { + return false; + } + + @Mask(owner = Unsafe.class) + public static byte getByte(Unsafe unsafe, Object o, long offset, PhosphorStackFrame frame) { + return 0; + } + + public static byte getByte(UnsafeProxy unsafe, Object obj, long offset, PhosphorStackFrame stackFrame) { + if (obj instanceof TaggedArray) { + stackFrame.returnTaint = + ((TaggedArray) obj).getTaintOrEmpty(unsafeIndexFor(unsafe, (TaggedArray) obj, offset)); + return unsafe.getByte(((TaggedArray) obj).getVal(), offset); + } else { + getTag(unsafe, obj, offset, stackFrame, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + return unsafe.getByte(obj, offset); + } + } + + @Mask(owner = Unsafe.class) + public static byte getByte(Unsafe unsafe, long address, PhosphorStackFrame frame) { + return 0; + } + + @Mask(owner = Unsafe.class) + public static byte getByteVolatile(Unsafe unsafe, Object o, long offset, PhosphorStackFrame frame) { + return 0; + } + + public static byte getByteVolatile(UnsafeProxy unsafe, Object obj, long offset, PhosphorStackFrame stackFrame) { + if (obj instanceof TaggedArray) { + stackFrame.returnTaint = + ((TaggedArray) obj).getTaintOrEmpty(unsafeIndexFor(unsafe, (TaggedArray) obj, offset)); + return unsafe.getByteVolatile(((TaggedArray) obj).getVal(), offset); + } else { + getTag(unsafe, obj, offset, stackFrame, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.VOLATILE); + return unsafe.getByteVolatile(obj, offset); + } + } + + @Mask(owner = Unsafe.class) + public static char getChar(Unsafe unsafe, Object o, long offset, PhosphorStackFrame frame) { + return 0; + } + + public static char getChar(UnsafeProxy unsafe, Object obj, long offset, PhosphorStackFrame stackFrame) { + if (obj instanceof TaggedArray) { + stackFrame.returnTaint = + ((TaggedArray) obj).getTaintOrEmpty(unsafeIndexFor(unsafe, (TaggedArray) obj, offset)); + return unsafe.getChar(((TaggedArray) obj).getVal(), offset); + } else { + getTag(unsafe, obj, offset, stackFrame, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + return unsafe.getChar(obj, offset); + } + } + + @Mask(owner = Unsafe.class) + public static char getChar(Unsafe unsafe, long address, PhosphorStackFrame frame) { + return 0; + } + + @Mask(owner = Unsafe.class) + public static char getCharVolatile(Unsafe unsafe, Object o, long offset, PhosphorStackFrame frame) { + return 0; + } + + public static char getCharVolatile(UnsafeProxy unsafe, Object obj, long offset, PhosphorStackFrame stackFrame) { + if (obj instanceof TaggedArray) { + stackFrame.returnTaint = + ((TaggedArray) obj).getTaintOrEmpty(unsafeIndexFor(unsafe, (TaggedArray) obj, offset)); + return unsafe.getCharVolatile(((TaggedArray) obj).getVal(), offset); + } else { + getTag(unsafe, obj, offset, stackFrame, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.VOLATILE); + return unsafe.getCharVolatile(obj, offset); + } + } + + @Mask(owner = Unsafe.class) + public static double getDouble(Unsafe unsafe, Object o, long offset, PhosphorStackFrame frame) { + return 0; + } + + public static double getDouble(UnsafeProxy unsafe, Object obj, long offset, PhosphorStackFrame stackFrame) { + if (obj instanceof TaggedArray) { + stackFrame.returnTaint = + ((TaggedArray) obj).getTaintOrEmpty(unsafeIndexFor(unsafe, (TaggedArray) obj, offset)); + return unsafe.getDouble(((TaggedArray) obj).getVal(), offset); + } else { + getTag(unsafe, obj, offset, stackFrame, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + return unsafe.getDouble(obj, offset); + } + } + + @Mask(owner = Unsafe.class) + public static double getDouble(Unsafe unsafe, long address, PhosphorStackFrame frame) { + return 0; + } + + @Mask(owner = Unsafe.class) + public static double getDoubleVolatile(Unsafe unsafe, Object o, long offset, PhosphorStackFrame frame) { + return 0; + } + + public static double getDoubleVolatile(UnsafeProxy unsafe, Object obj, long offset, PhosphorStackFrame stackFrame) { + if (obj instanceof TaggedArray) { + stackFrame.returnTaint = + ((TaggedArray) obj).getTaintOrEmpty(unsafeIndexFor(unsafe, (TaggedArray) obj, offset)); + return unsafe.getDoubleVolatile(((TaggedArray) obj).getVal(), offset); + } else { + getTag(unsafe, obj, offset, stackFrame, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.VOLATILE); + return unsafe.getDoubleVolatile(obj, offset); + } + } + + @Mask(owner = Unsafe.class) + public static float getFloat(Unsafe unsafe, Object o, long offset, PhosphorStackFrame frame) { + return 0; + } + + public static float getFloat(UnsafeProxy unsafe, Object obj, long offset, PhosphorStackFrame stackFrame) { + if (obj instanceof TaggedArray) { + stackFrame.returnTaint = + ((TaggedArray) obj).getTaintOrEmpty(unsafeIndexFor(unsafe, (TaggedArray) obj, offset)); + return unsafe.getFloat(((TaggedArray) obj).getVal(), offset); + } else { + getTag(unsafe, obj, offset, stackFrame, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + return unsafe.getFloat(obj, offset); + } + } + + @Mask(owner = Unsafe.class) + public static float getFloat(Unsafe unsafe, long address, PhosphorStackFrame frame) { + return 0; + } + + @Mask(owner = Unsafe.class) + public static float getFloatVolatile(Unsafe unsafe, Object o, long offset, PhosphorStackFrame frame) { + return 0; + } + + public static float getFloatVolatile(UnsafeProxy unsafe, Object obj, long offset, PhosphorStackFrame stackFrame) { + if (obj instanceof TaggedArray) { + stackFrame.returnTaint = + ((TaggedArray) obj).getTaintOrEmpty(unsafeIndexFor(unsafe, (TaggedArray) obj, offset)); + return unsafe.getFloatVolatile(((TaggedArray) obj).getVal(), offset); + } else { + getTag(unsafe, obj, offset, stackFrame, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.VOLATILE); + return unsafe.getFloatVolatile(obj, offset); + } + } + + @Mask(owner = Unsafe.class) + public static int getInt(Unsafe unsafe, Object o, long offset, PhosphorStackFrame frame) { + return 0; + } + + public static int getInt(UnsafeProxy unsafe, Object obj, long offset, PhosphorStackFrame stackFrame) { + if (obj instanceof TaggedArray) { + stackFrame.returnTaint = + ((TaggedArray) obj).getTaintOrEmpty(unsafeIndexFor(unsafe, (TaggedArray) obj, offset)); + return unsafe.getInt(((TaggedArray) obj).getVal(), offset); + } else { + getTag(unsafe, obj, offset, stackFrame, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + return unsafe.getInt(obj, offset); + } + } + + @Mask(owner = Unsafe.class) + public static int getInt(Unsafe unsafe, long address, PhosphorStackFrame frame) { + return 0; + } + + @Mask(owner = Unsafe.class) + public static int getIntVolatile(Unsafe unsafe, Object o, long offset, PhosphorStackFrame frame) { + return 0; + } + + public static int getIntVolatile(UnsafeProxy unsafe, Object obj, long offset, PhosphorStackFrame stackFrame) { + if (obj instanceof TaggedArray) { + stackFrame.returnTaint = + ((TaggedArray) obj).getTaintOrEmpty(unsafeIndexFor(unsafe, (TaggedArray) obj, offset)); + return unsafe.getIntVolatile(((TaggedArray) obj).getVal(), offset); + } else { + getTag(unsafe, obj, offset, stackFrame, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.VOLATILE); + return unsafe.getIntVolatile(obj, offset); + } + } + + @Mask(owner = Unsafe.class) + public static int getLoadAverage(Unsafe unsafe, double[] loadavg, int nelems, PhosphorStackFrame frame) { + return 0; + } + + @Mask(owner = Unsafe.class) + public static long getLong(Unsafe unsafe, Object o, long offset, PhosphorStackFrame frame) { + return 0; + } + + public static long getLong(UnsafeProxy unsafe, Object obj, long offset, PhosphorStackFrame stackFrame) { + if (obj instanceof TaggedArray) { + stackFrame.returnTaint = + ((TaggedArray) obj).getTaintOrEmpty(unsafeIndexFor(unsafe, (TaggedArray) obj, offset)); + return unsafe.getLong(((TaggedArray) obj).getVal(), offset); + } else { + getTag(unsafe, obj, offset, stackFrame, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + return unsafe.getLong(obj, offset); + } + } + + @Mask(owner = Unsafe.class) + public static long getLong(Unsafe unsafe, long address, PhosphorStackFrame frame) { + return 0; + } + + @Mask(owner = Unsafe.class) + public static long getLongVolatile(Unsafe unsafe, Object o, long offset, PhosphorStackFrame frame) { + return 0; + } + + public static long getLongVolatile(UnsafeProxy unsafe, Object obj, long offset, PhosphorStackFrame stackFrame) { + if (obj instanceof TaggedArray) { + stackFrame.returnTaint = + ((TaggedArray) obj).getTaintOrEmpty(unsafeIndexFor(unsafe, (TaggedArray) obj, offset)); + return unsafe.getLongVolatile(((TaggedArray) obj).getVal(), offset); + } else { + getTag(unsafe, obj, offset, stackFrame, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.VOLATILE); + return unsafe.getLongVolatile(obj, offset); + } + } + + @Mask(owner = Unsafe.class) + public static short getShort(Unsafe unsafe, Object o, long offset, PhosphorStackFrame frame) { + return 0; + } + + public static short getShort(UnsafeProxy unsafe, Object obj, long offset, PhosphorStackFrame stackFrame) { + if (obj instanceof TaggedArray) { + stackFrame.returnTaint = + ((TaggedArray) obj).getTaintOrEmpty(unsafeIndexFor(unsafe, (TaggedArray) obj, offset)); + return unsafe.getShort(((TaggedArray) obj).getVal(), offset); + } else { + getTag(unsafe, obj, offset, stackFrame, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + return unsafe.getShort(obj, offset); + } + } + + @Mask(owner = Unsafe.class) + public static short getShort(Unsafe unsafe, long address, PhosphorStackFrame frame) { + return 0; + } + + @Mask(owner = Unsafe.class) + public static short getShortVolatile(Unsafe unsafe, Object o, long offset, PhosphorStackFrame frame) { + return 0; + } + + public static short getShortVolatile(UnsafeProxy unsafe, Object obj, long offset, PhosphorStackFrame stackFrame) { + if (obj instanceof TaggedArray) { + stackFrame.returnTaint = + ((TaggedArray) obj).getTaintOrEmpty(unsafeIndexFor(unsafe, (TaggedArray) obj, offset)); + return unsafe.getShortVolatile(((TaggedArray) obj).getVal(), offset); + } else { + getTag(unsafe, obj, offset, stackFrame, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.VOLATILE); + return unsafe.getShortVolatile(obj, offset); + } + } + + public static void copyMemory( + UnsafeProxy unsafe, + Object src, + long srcAddress, + Object dest, + long destAddress, + long length, + PhosphorStackFrame stackFrame) { + if (src instanceof TaggedArray) { + src = ((TaggedArray) src).getVal(); + } + if (dest instanceof TaggedArray) { + dest = ((TaggedArray) dest).getVal(); + } + unsafe.copyMemory(src, srcAddress, dest, destAddress, length); + } + + public static void copyMemory( + UnsafeProxy unsafe, long srcAddress, long destAddress, long length, PhosphorStackFrame stackFrame) { + unsafe.copyMemory(srcAddress, destAddress, length); + } + + @Mask(owner = Unsafe.class) + public static void copyMemory( + Unsafe unsafe, + Object srcBase, + long srcOffset, + Object destBase, + long destOffset, + long bytes, + PhosphorStackFrame frame) { + // + } + + public void copyMemory(Unsafe unsafe, long var1, long var3, long var5, PhosphorStackFrame frame) { + copyMemory(unsafe, null, var1, null, var3, var5, frame); + } + + public static void putBoolean( + UnsafeProxy unsafe, Object obj, long offset, boolean val, PhosphorStackFrame stackFrame) { + Taint valTaint = stackFrame.getArgTaint(3); + if (obj instanceof TaggedArray) { + unsafe.putBoolean(((TaggedArray) obj).getVal(), offset, val); + if ((valTaint != null && !valTaint.isEmpty()) || ((TaggedArray) obj).taints != null) { + ((TaggedArray) obj).setTaint(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), valTaint); + } + } else { + unsafe.putBoolean(obj, offset, val); + putTag(unsafe, obj, offset, valTaint, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + } + } + + @Mask(owner = Unsafe.class) + public static void putBoolean(Unsafe unsafe, Object o, long offset, boolean x, PhosphorStackFrame frame) { + // + } + + public static void putBooleanVolatile( + UnsafeProxy unsafe, Object obj, long offset, boolean val, PhosphorStackFrame stackFrame) { + Taint valTaint = stackFrame.getArgTaint(3); + if (obj instanceof TaggedArray) { + unsafe.putBooleanVolatile(((TaggedArray) obj).getVal(), offset, val); + if ((valTaint != null && !valTaint.isEmpty()) || ((TaggedArray) obj).taints != null) { + ((TaggedArray) obj).setTaint(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), valTaint); + } + } else { + unsafe.putBoolean(obj, offset, val); + putTag(unsafe, obj, offset, valTaint, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + } + } + + @Mask(owner = Unsafe.class) + public static void putBooleanVolatile(Unsafe unsafe, Object o, long offset, boolean x, PhosphorStackFrame frame) { + // + } + + @Mask(owner = Unsafe.class) + public static void putByte(Unsafe unsafe, Object o, long offset, byte x, PhosphorStackFrame frame) { + // + } + + public static void putByte(UnsafeProxy unsafe, Object obj, long offset, byte val, PhosphorStackFrame stackFrame) { + Taint valTaint = stackFrame.getArgTaint(3); + if (obj instanceof TaggedArray) { + unsafe.putByte(((TaggedArray) obj).getVal(), offset, val); + if ((valTaint != null && !valTaint.isEmpty()) || ((TaggedArray) obj).taints != null) { + ((TaggedArray) obj).setTaint(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), valTaint); + } + } else { + unsafe.putByte(obj, offset, val); + putTag(unsafe, obj, offset, valTaint, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + } + } + + @Mask(owner = Unsafe.class) + public static void putByte(Unsafe unsafe, long address, byte x, PhosphorStackFrame frame) { + // + } + + public static void putByteVolatile( + UnsafeProxy unsafe, Object obj, long offset, byte val, PhosphorStackFrame stackFrame) { + Taint valTaint = stackFrame.getArgTaint(3); + if (obj instanceof TaggedArray) { + unsafe.putByteVolatile(((TaggedArray) obj).getVal(), offset, val); + if ((valTaint != null && !valTaint.isEmpty()) || ((TaggedArray) obj).taints != null) { + ((TaggedArray) obj).setTaint(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), valTaint); + } + } else { + unsafe.putByte(obj, offset, val); + putTag(unsafe, obj, offset, valTaint, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + } + } + + @Mask(owner = Unsafe.class) + public static void putByteVolatile(Unsafe unsafe, Object o, long offset, byte x, PhosphorStackFrame frame) { + // + } + + @Mask(owner = Unsafe.class) + public static void putChar(Unsafe unsafe, Object o, long offset, char x, PhosphorStackFrame frame) { + // + } + + public static void putChar(UnsafeProxy unsafe, Object obj, long offset, char val, PhosphorStackFrame stackFrame) { + Taint valTaint = stackFrame.getArgTaint(3); + if (obj instanceof TaggedArray) { + unsafe.putChar(((TaggedArray) obj).getVal(), offset, val); + if ((valTaint != null && !valTaint.isEmpty()) || ((TaggedArray) obj).taints != null) { + ((TaggedArray) obj).setTaint(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), valTaint); + } + } else { + unsafe.putChar(obj, offset, val); + putTag(unsafe, obj, offset, valTaint, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + } + } + + @Mask(owner = Unsafe.class) + public static void putChar(Unsafe unsafe, long address, char x, PhosphorStackFrame frame) { + // + } + + public static void putCharVolatile( + UnsafeProxy unsafe, Object obj, long offset, char val, PhosphorStackFrame stackFrame) { + Taint valTaint = stackFrame.getArgTaint(3); + if (obj instanceof TaggedArray) { + unsafe.putCharVolatile(((TaggedArray) obj).getVal(), offset, val); + if ((valTaint != null && !valTaint.isEmpty()) || ((TaggedArray) obj).taints != null) { + ((TaggedArray) obj).setTaint(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), valTaint); + } + } else { + unsafe.putChar(obj, offset, val); + putTag(unsafe, obj, offset, valTaint, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + } + } + + @Mask(owner = Unsafe.class) + public static void putCharVolatile(Unsafe unsafe, Object o, long offset, char x, PhosphorStackFrame frame) { + // + } + + public static void putDouble( + UnsafeProxy unsafe, Object obj, long offset, double val, PhosphorStackFrame stackFrame) { + Taint valTaint = stackFrame.getArgTaint(3); + if (obj instanceof TaggedArray) { + unsafe.putDouble(((TaggedArray) obj).getVal(), offset, val); + if ((valTaint != null && !valTaint.isEmpty()) || ((TaggedArray) obj).taints != null) { + ((TaggedArray) obj).setTaint(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), valTaint); + } + } else { + unsafe.putDouble(obj, offset, val); + putTag(unsafe, obj, offset, valTaint, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + } + } + + @Mask(owner = Unsafe.class) + public static void putDouble(Unsafe unsafe, Object o, long offset, double x, PhosphorStackFrame frame) { + // + } + + @Mask(owner = Unsafe.class) + public static void putDouble(Unsafe unsafe, long address, double x, PhosphorStackFrame frame) { + // + } + + public static void putDoubleVolatile( + UnsafeProxy unsafe, Object obj, long offset, double val, PhosphorStackFrame stackFrame) { + Taint valTaint = stackFrame.getArgTaint(3); + if (obj instanceof TaggedArray) { + unsafe.putDoubleVolatile(((TaggedArray) obj).getVal(), offset, val); + if ((valTaint != null && !valTaint.isEmpty()) || ((TaggedArray) obj).taints != null) { + ((TaggedArray) obj).setTaint(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), valTaint); + } + } else { + unsafe.putDouble(obj, offset, val); + putTag(unsafe, obj, offset, valTaint, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + } + } + + @Mask(owner = Unsafe.class) + public static void putDoubleVolatile(Unsafe unsafe, Object o, long offset, double x, PhosphorStackFrame frame) { + // + } + + @Mask(owner = Unsafe.class) + public static void putFloat(Unsafe unsafe, Object o, long offset, float x, PhosphorStackFrame frame) { + // + } + + public static void putFloat(UnsafeProxy unsafe, Object obj, long offset, float val, PhosphorStackFrame stackFrame) { + Taint valTaint = stackFrame.getArgTaint(3); + if (obj instanceof TaggedArray) { + unsafe.putFloat(((TaggedArray) obj).getVal(), offset, val); + if ((valTaint != null && !valTaint.isEmpty()) || ((TaggedArray) obj).taints != null) { + ((TaggedArray) obj).setTaint(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), valTaint); + } + } else { + unsafe.putFloat(obj, offset, val); + putTag(unsafe, obj, offset, valTaint, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + } + } + + @Mask(owner = Unsafe.class) + public static void putFloat(Unsafe unsafe, long address, float x, PhosphorStackFrame frame) { + // + } + + public static void putFloatVolatile( + UnsafeProxy unsafe, Object obj, long offset, float val, PhosphorStackFrame stackFrame) { + Taint valTaint = stackFrame.getArgTaint(3); + if (obj instanceof TaggedArray) { + unsafe.putFloatVolatile(((TaggedArray) obj).getVal(), offset, val); + if ((valTaint != null && !valTaint.isEmpty()) || ((TaggedArray) obj).taints != null) { + ((TaggedArray) obj).setTaint(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), valTaint); + } + } else { + unsafe.putFloat(obj, offset, val); + putTag(unsafe, obj, offset, valTaint, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + } + } + + @Mask(owner = Unsafe.class) + public static void putFloatVolatile(Unsafe unsafe, Object o, long offset, float x, PhosphorStackFrame frame) { + // + } + + @Mask(owner = Unsafe.class) + public static void putInt(Unsafe unsafe, Object o, long offset, int x, PhosphorStackFrame frame) { + // + } + + public static void putInt(UnsafeProxy unsafe, Object obj, long offset, int val, PhosphorStackFrame stackFrame) { + Taint valTaint = stackFrame.getArgTaint(3); + if (obj instanceof TaggedArray) { + unsafe.putInt(((TaggedArray) obj).getVal(), offset, val); + if ((valTaint != null && !valTaint.isEmpty()) || ((TaggedArray) obj).taints != null) { + ((TaggedArray) obj).setTaint(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), valTaint); + } + } else { + unsafe.putInt(obj, offset, val); + putTag(unsafe, obj, offset, valTaint, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + } + } + + @Mask(owner = Unsafe.class) + public static void putInt(Unsafe unsafe, long address, int x, PhosphorStackFrame frame) { + // + } + + public static void putIntVolatile( + UnsafeProxy unsafe, Object obj, long offset, int val, PhosphorStackFrame stackFrame) { + Taint valTaint = stackFrame.getArgTaint(3); + if (obj instanceof TaggedArray) { + unsafe.putIntVolatile(((TaggedArray) obj).getVal(), offset, val); + if ((valTaint != null && !valTaint.isEmpty()) || ((TaggedArray) obj).taints != null) { + ((TaggedArray) obj).setTaint(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), valTaint); + } + } else { + unsafe.putInt(obj, offset, val); + putTag(unsafe, obj, offset, valTaint, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + } + } + + @Mask(owner = Unsafe.class) + public static void putIntVolatile(Unsafe unsafe, Object o, long offset, int x, PhosphorStackFrame frame) { + // + } + + @Mask(owner = Unsafe.class) + public static void putLong(Unsafe unsafe, Object o, long offset, long x, PhosphorStackFrame frame) { + // + } + + public static void putLong(UnsafeProxy unsafe, Object obj, long offset, long val, PhosphorStackFrame stackFrame) { + Taint valTaint = stackFrame.getArgTaint(3); + if (obj instanceof TaggedArray) { + unsafe.putLong(((TaggedArray) obj).getVal(), offset, val); + if ((valTaint != null && !valTaint.isEmpty()) || ((TaggedArray) obj).taints != null) { + ((TaggedArray) obj).setTaint(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), valTaint); + } + } else { + unsafe.putLong(obj, offset, val); + putTag(unsafe, obj, offset, valTaint, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + } + } + + @Mask(owner = Unsafe.class) + public static void putLong(Unsafe unsafe, long address, long x, PhosphorStackFrame frame) { + // + } + + public static void putLongVolatile( + UnsafeProxy unsafe, Object obj, long offset, long val, PhosphorStackFrame stackFrame) { + Taint valTaint = stackFrame.getArgTaint(3); + if (obj instanceof TaggedArray) { + unsafe.putLongVolatile(((TaggedArray) obj).getVal(), offset, val); + if ((valTaint != null && !valTaint.isEmpty()) || ((TaggedArray) obj).taints != null) { + ((TaggedArray) obj).setTaint(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), valTaint); + } + } else { + unsafe.putLong(obj, offset, val); + putTag(unsafe, obj, offset, valTaint, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + } + } + + @Mask(owner = Unsafe.class) + public static void putLongVolatile(Unsafe unsafe, Object o, long offset, long x, PhosphorStackFrame frame) { + // + } + + public static void putObject( + UnsafeProxy unsafe, Object obj, long offset, Object val, PhosphorStackFrame phosphorStackFrame) { + if (obj instanceof TaggedReferenceArray) { + ((TaggedReferenceArray) obj) + .set(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), val, phosphorStackFrame.getArgTaint(3)); + } else { + RuntimeJDKInternalUnsafePropagator.OffsetPair pair = null; + if (obj != null) { + pair = getOffsetPair(unsafe, obj, offset); + } + if (pair != null) { + if (pair.tagFieldOffset != UnsafeProxy.INVALID_FIELD_OFFSET) { + unsafe.putObject(obj, pair.tagFieldOffset, phosphorStackFrame.getArgTaint(3)); + } + if (pair.wrappedFieldOffset != UnsafeProxy.INVALID_FIELD_OFFSET) { + unsafe.putObject(obj, pair.wrappedFieldOffset, val); + unsafe.putObject(obj, offset, MultiDArrayUtils.unbox1DOrNull(val)); + } else { + unsafe.putObject(obj, offset, val); + } + } else { + unsafe.putObject(obj, offset, MultiDArrayUtils.unbox1DOrNull(val)); + } + } + } + + @Mask(owner = Unsafe.class) + public static void putObject(Unsafe unsafe, Object o, long offset, Object x, PhosphorStackFrame frame) { + // + } + + public static void putObjectVolatile( + UnsafeProxy unsafe, Object obj, long offset, Object val, PhosphorStackFrame phosphorStackFrame) { + if (obj instanceof TaggedReferenceArray) { + ((TaggedReferenceArray) obj) + .set(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), val, phosphorStackFrame.getArgTaint(3)); + } else { + unsafe.putObjectVolatile(obj, offset, MultiDArrayUtils.unbox1DOrNull(val)); + RuntimeJDKInternalUnsafePropagator.OffsetPair pair = null; + if (obj != null) { + pair = getOffsetPair(unsafe, obj, offset); + } + if (pair != null) { + if (pair.tagFieldOffset != UnsafeProxy.INVALID_FIELD_OFFSET) { + unsafe.putObjectVolatile(obj, pair.tagFieldOffset, phosphorStackFrame.getArgTaint(3)); + } + if (pair.wrappedFieldOffset != UnsafeProxy.INVALID_FIELD_OFFSET) { + unsafe.putObjectVolatile(obj, pair.wrappedFieldOffset, val); + unsafe.putObjectVolatile(obj, offset, MultiDArrayUtils.unbox1DOrNull(val)); + } else { + unsafe.putObjectVolatile(obj, offset, val); + } + } else { + unsafe.putObjectVolatile(obj, offset, MultiDArrayUtils.unbox1DOrNull(val)); + } + } + } + + @Mask(owner = Unsafe.class) + public static void putObjectVolatile(Unsafe unsafe, Object o, long offset, Object x, PhosphorStackFrame frame) { + // + } + + public static void putOrderedInt( + UnsafeProxy unsafe, Object obj, long offset, int val, PhosphorStackFrame stackFrame) { + Taint valTaint = stackFrame.getArgTaint(3); + if (obj instanceof TaggedArray) { + unsafe.putOrderedInt(((TaggedArray) obj).getVal(), offset, val); + if ((valTaint != null && !valTaint.isEmpty()) || ((TaggedArray) obj).taints != null) { + ((TaggedArray) obj).setTaint(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), valTaint); + } + } else { + unsafe.putOrderedInt(obj, offset, val); + putTag(unsafe, obj, offset, valTaint, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.ORDERED); + } + } + + @Mask(owner = Unsafe.class) + public static void putOrderedInt(Unsafe unsafe, Object o, long offset, int x, PhosphorStackFrame frame) { + // + } + + public static void putOrderedLong( + UnsafeProxy unsafe, Object obj, long offset, long val, PhosphorStackFrame stackFrame) { + Taint valTaint = stackFrame.getArgTaint(3); + if (obj instanceof TaggedArray) { + unsafe.putOrderedLong(((TaggedArray) obj).getVal(), offset, val); + if ((valTaint != null && !valTaint.isEmpty()) || ((TaggedArray) obj).taints != null) { + ((TaggedArray) obj).setTaint(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), valTaint); + } + } else { + unsafe.putOrderedLong(obj, offset, val); + putTag(unsafe, obj, offset, valTaint, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.ORDERED); + } + } + + @Mask(owner = Unsafe.class) + public static void putOrderedLong(Unsafe unsafe, Object o, long offset, long x, PhosphorStackFrame frame) { + // + } + + public static void putOrderedObject( + UnsafeProxy unsafe, Object obj, long offset, Object val, PhosphorStackFrame phosphorStackFrame) { + if (obj instanceof TaggedReferenceArray) { + ((TaggedReferenceArray) obj) + .set(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), val, phosphorStackFrame.getArgTaint(3)); + } else { + RuntimeJDKInternalUnsafePropagator.OffsetPair pair = null; + if (obj != null) { + pair = getOffsetPair(unsafe, obj, offset); + } + if (pair != null) { + if (pair.tagFieldOffset != UnsafeProxy.INVALID_FIELD_OFFSET) { + unsafe.putOrderedObject(obj, pair.tagFieldOffset, phosphorStackFrame.getArgTaint(3)); + } + if (pair.wrappedFieldOffset != UnsafeProxy.INVALID_FIELD_OFFSET) { + unsafe.putOrderedObject(obj, pair.wrappedFieldOffset, val); + unsafe.putOrderedObject(obj, offset, MultiDArrayUtils.unbox1DOrNull(val)); + } else { + unsafe.putOrderedObject(obj, offset, val); + } + } else { + unsafe.putOrderedObject(obj, offset, MultiDArrayUtils.unbox1DOrNull(val)); + } + } + } + + @Mask(owner = Unsafe.class) + public static void putOrderedObject(Unsafe unsafe, Object o, long offset, Object x, PhosphorStackFrame frame) { + // + } + + @Mask(owner = Unsafe.class) + public static void putShort(Unsafe unsafe, Object o, long offset, short x, PhosphorStackFrame frame) { + // + } + + public static void putShort(UnsafeProxy unsafe, Object obj, long offset, short val, PhosphorStackFrame stackFrame) { + Taint valTaint = stackFrame.getArgTaint(3); + if (obj instanceof TaggedArray) { + unsafe.putShort(((TaggedArray) obj).getVal(), offset, val); + if ((valTaint != null && !valTaint.isEmpty()) || ((TaggedArray) obj).taints != null) { + ((TaggedArray) obj).setTaint(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), valTaint); + } + } else { + unsafe.putShort(obj, offset, val); + putTag(unsafe, obj, offset, valTaint, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + } + } + + @Mask(owner = Unsafe.class) + public static void putShort(Unsafe unsafe, long address, short x, PhosphorStackFrame frame) { + // + } + + public static void putShortVolatile( + UnsafeProxy unsafe, Object obj, long offset, short val, PhosphorStackFrame stackFrame) { + Taint valTaint = stackFrame.getArgTaint(3); + if (obj instanceof TaggedArray) { + unsafe.putShortVolatile(((TaggedArray) obj).getVal(), offset, val); + if ((valTaint != null && !valTaint.isEmpty()) || ((TaggedArray) obj).taints != null) { + ((TaggedArray) obj).setTaint(unsafeIndexFor(unsafe, (TaggedArray) obj, offset), valTaint); + } + } else { + unsafe.putShort(obj, offset, val); + putTag(unsafe, obj, offset, valTaint, RuntimeSunMiscUnsafePropagator.SpecialAccessPolicy.NONE); + } + } + + @Mask(owner = Unsafe.class) + public static void putShortVolatile(Unsafe unsafe, Object o, long offset, short x, PhosphorStackFrame frame) { + // + } +} \ No newline at end of file diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/runtime/mask/UnsafeAdapter.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/runtime/mask/UnsafeAdapter.java new file mode 100644 index 000000000..fa53df1de --- /dev/null +++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/runtime/mask/UnsafeAdapter.java @@ -0,0 +1,10 @@ +package edu.columbia.cs.psl.phosphor.runtime.mask; + +import java.security.ProtectionDomain; + +public class UnsafeAdapter { + public Class defineClass(String name, byte[] b, int off, int len, ClassLoader loader, + ProtectionDomain protectionDomain) { + return null; + } +} diff --git a/README.md b/README.md index b28da1e92..1aefaf035 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ Remaining tasks for this branch before promotion: A JDK can be downloaded from [Oracle](https://www.oracle.com/java/technologies/downloads/) or the [Adoptium Working Group](https://adoptium.net/temurin/releases/). 3. Set the JAVA_HOME environmental variable to the path of this JDK installation. - On Linux and Mac this can be done by running `export JAVA_HOME=`, where <PATH-TO-JDK> is the path + On Linux and Mac, this can be done by running `export JAVA_HOME=`, where <PATH-TO-JDK> is the path of the JDK installation. 4. Ensure that you have installed Apache Maven 3.6.0+. Directions for [downloading](https://maven.apache.org/download.cgi)