From a99d50d868530e84939490bae959dccfbd4416c0 Mon Sep 17 00:00:00 2001 From: rtrimana Date: Tue, 7 Feb 2017 16:57:37 -0800 Subject: [PATCH] Adding Java Checker Framework to flag error when java.net and java.lang.reflect libraries are used in user's code --- checker/Makefile | 13 ++ checker/astubs/IoTRelation.astub | 33 ++++ checker/astubs/IoTSet.astub | 26 +++ checker/iotchecker/IoTJavaChecker.java | 14 ++ checker/iotchecker/IoTJavaVisitor.java | 256 +++++++++++++++++++++++++ checker/iotchecker/messages.properties | 4 + checker/iotchecker/package-info.java | 6 + 7 files changed, 352 insertions(+) create mode 100644 checker/Makefile create mode 100644 checker/astubs/IoTRelation.astub create mode 100644 checker/astubs/IoTSet.astub create mode 100644 checker/iotchecker/IoTJavaChecker.java create mode 100644 checker/iotchecker/IoTJavaVisitor.java create mode 100644 checker/iotchecker/messages.properties create mode 100644 checker/iotchecker/package-info.java diff --git a/checker/Makefile b/checker/Makefile new file mode 100644 index 0000000..e2e429c --- /dev/null +++ b/checker/Makefile @@ -0,0 +1,13 @@ +BASE := .. + +include $(BASE)/common.mk + +all: checker + +PHONY += checker + +checker: + $(JAVAC) -d $(BASE)/bin -classpath .:$(BASE)/bin:$(CHECKERJARS) iotchecker/*.java + cp iotchecker/messages.properties $(BASE)/bin/iotchecker + +.PHONY: $(PHONY) diff --git a/checker/astubs/IoTRelation.astub b/checker/astubs/IoTRelation.astub new file mode 100644 index 0000000..57380ee --- /dev/null +++ b/checker/astubs/IoTRelation.astub @@ -0,0 +1,33 @@ +import java.lang.UnsupportedOperationException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import iotchecker.qual.LocalRemote; +import iotchecker.qual.NonLocalRemote; +import iotchecker.qual.Normal; +import iotchecker.qual.CanBeRemote; +import iotchecker.qual.Bottom; + +package iotruntime.slave; +/** Class IoTRelation stub file for IoTJavaChecker + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-19-04 + */ +public final class IoTRelation<@CanBeRemote K,@CanBeRemote V> { + + private Map > mapRelation; + private int iSize; + + public IoTRelation(Map > mapRel, int _iSize); + public boolean containsKey(K key); + public Set>> entrySet(); + public Set keySet(); + public HashSet get(K key); + public boolean isEmpty(); + public int size(); +} diff --git a/checker/astubs/IoTSet.astub b/checker/astubs/IoTSet.astub new file mode 100644 index 0000000..2da67d0 --- /dev/null +++ b/checker/astubs/IoTSet.astub @@ -0,0 +1,26 @@ +import java.lang.UnsupportedOperationException; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.Spliterator; + +import iotchecker.qual.LocalRemote; +import iotchecker.qual.NonLocalRemote; +import iotchecker.qual.CanBeRemote; +import iotchecker.qual.Normal; + +package iotruntime.slave; + +public final class IoTSet<@CanBeRemote T> { + private Set set; + + public IoTSet(Set s); + public boolean contains(T o); + public boolean isEmpty(); + public Iterator iterator(); + public int size(); + public Set values(); +} + diff --git a/checker/iotchecker/IoTJavaChecker.java b/checker/iotchecker/IoTJavaChecker.java new file mode 100644 index 0000000..134ca1d --- /dev/null +++ b/checker/iotchecker/IoTJavaChecker.java @@ -0,0 +1,14 @@ +package iotchecker; + +import org.checkerframework.common.basetype.BaseTypeChecker; + +/** Class IoTJavaChecker is a class that extends + * BaseTypeChecker. + * + * @author Rahmadi Trimananda + * @author Bin Xu + * @version 1.0 + * @since 2016-03-25 + */ +public final class IoTJavaChecker extends BaseTypeChecker { +} diff --git a/checker/iotchecker/IoTJavaVisitor.java b/checker/iotchecker/IoTJavaVisitor.java new file mode 100644 index 0000000..7ea39b2 --- /dev/null +++ b/checker/iotchecker/IoTJavaVisitor.java @@ -0,0 +1,256 @@ +package iotchecker; + +import iotchecker.qual.*; + +import org.checkerframework.common.basetype.BaseTypeChecker; +import org.checkerframework.common.basetype.BaseTypeVisitor; +import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; +import org.checkerframework.framework.source.Result; +import org.checkerframework.framework.type.AnnotatedTypeMirror; +import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType; +import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType; +import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType; +import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable; +import org.checkerframework.framework.type.AnnotatedTypeParameterBounds; +import org.checkerframework.framework.type.AnnotatedTypeFactory; +import org.checkerframework.framework.util.AnnotatedTypes; +import org.checkerframework.javacutil.AnnotationUtils; +import org.checkerframework.javacutil.ElementUtils; +import org.checkerframework.javacutil.Pair; +import org.checkerframework.javacutil.TreeUtils; +import org.checkerframework.javacutil.InternalUtils; +import org.checkerframework.dataflow.qual.Pure; +import org.checkerframework.dataflow.util.PurityChecker; +import org.checkerframework.dataflow.util.PurityChecker.PurityResult; +import org.checkerframework.dataflow.util.PurityUtils; +import org.checkerframework.framework.qual.FieldIsExpression; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.HashSet; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Set; +import java.util.Iterator; +import java.util.HashSet; +import java.util.Arrays; +import java.util.Collection; +import java.lang.annotation.Annotation; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.PrimitiveType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.SimpleElementVisitor7; +import javax.lang.model.util.SimpleTypeVisitor7; +import javax.lang.model.element.Modifier; +import javax.tools.Diagnostic.Kind; + +import com.sun.source.tree.NewArrayTree; +import com.sun.source.tree.NewClassTree; +import com.sun.source.tree.MethodTree; +import com.sun.source.tree.AssignmentTree; +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.MethodInvocationTree; +import com.sun.source.tree.Tree; +import com.sun.source.tree.TypeCastTree; +import com.sun.source.tree.VariableTree; +import com.sun.source.tree.LambdaExpressionTree; +import com.sun.source.tree.ReturnTree; + +import java.io.Serializable; +import java.lang.reflect.*; +import java.net.*; +import java.rmi.Remote; +import java.rmi.server.UnicastRemoteObject; + +/** Class IoTJavaVisitor is a class that extends + * BaseTypeVisitor. The purpose of this class is to + * annotate variables/objects with the right annotations, + * i.e. Normal, LocalRemote, NonLocalRemote, or CanBeRemote + * + * @author Rahmadi Trimananda + * @author Bin Xu + * @version 1.0 + * @since 2016-03-25 + */ +public final class IoTJavaVisitor extends BaseTypeVisitor { + + public IoTJavaVisitor(BaseTypeChecker checker) { + super(checker); + } + + + /** + * This visitVariable() method is taken directly from BaseTypeVisitor + *

+ * We need to override the checkArguments() to not complain about the switch + * from @LocalRemote to @NonLocalRemote. + */ + @Override + public Void visitVariable(VariableTree node, Void p) { + Pair preAssCtxt = visitorState.getAssignmentContext(); + visitorState.setAssignmentContext(Pair.of((Tree) node, atypeFactory.getAnnotatedType(node))); + + try { + // Check and reject any existence/declaration of Java Reflection and Java Networking + checkIfJavaReflection(node); + checkIfJavaNetworking(node); + + return null; + } finally { + visitorState.setAssignmentContext(preAssCtxt); + } + } + + + /** + * Return the AnnotatedTypeMirror of the node + * This handles normal variables and array type + */ + protected AnnotatedTypeMirror getAnnotatedTypeUniversal(Tree treeNode) { + AnnotatedTypeMirror atmType = atypeFactory.getAnnotatedType(treeNode); + // Check the object annotation - an array type is treated differently + + return (atmType.getKind() == TypeKind.ARRAY?((AnnotatedArrayType) atmType).getComponentType():atmType); + } + + + /** + * Helper function to check if the variable is a part of Java Reflection + */ + protected Void checkIfJavaReflection(VariableTree varTree) { + if (isJavaReflection(varTree)) { + checker.report(Result.failure("reflection.found", varTree), varTree); + } + + return null; + } + + + /** + * Helper function to check if the variable is a part of Java Networking + */ + protected Void checkIfJavaNetworking(VariableTree varTree) { + if (isJavaNetworking(varTree)) { + checker.report(Result.failure("java.net.found", varTree), varTree); + } + + return null; + } + + + /** + * Helper function to check if the variable is a part of Java Networking library + *

+ * i.e. java.net.XXX classes + */ + protected boolean isJavaNetworking(VariableTree varTree) { + AnnotatedTypeMirror typeVar = getAnnotatedTypeUniversal(varTree); + Class varClass = typeMirrorToClass(typeVar.getUnderlyingType()); + + /* An alternative is to list down the class names + like the following + + if ((varClass == InetAddress.class) || + (varClass == DatagramSocket.class) || + (varClass == DatagramPacket.class) || + (varClass == URL.class) || + (varClass == HttpURLConnection.class) || + (varClass == Socket.class) || + (varClass == ServerSocket.class)) { + */ + + // We still allow the java.net.*Exception classes + // to be allowed in a try { } catch { } structure + return ((varClass != null) && + varClass.toString().contains("java.net") && + !varClass.toString().contains("Exception")); + } + + + /** + * Helper function to check if the variable is a part of Java Reflection + *

+ * i.e. java.lang.reflect.XXX classes + */ + protected boolean isJavaReflection(VariableTree varTree) { + AnnotatedTypeMirror typeVar = getAnnotatedTypeUniversal(varTree); + Class varClass = typeMirrorToClass(typeVar.getUnderlyingType()); + + /* An alternative is to list down the class names + like the following + + if ((varClass == Class.class) || + (varClass == Constructor.class) || + (varClass == Method.class) || + (varClass == Type.class)) { + */ + + return ((varClass != null) && + (varClass.toString().contains("java.lang.reflect"))); + } + + + /** + * Helper method/function adapted from FormatterTreeUtil.java / I18nFormatterTreeUtil.java + * to find a basic type of a variable + */ + protected final Class typeMirrorToClass(final TypeMirror type) { + return type.accept(new SimpleTypeVisitor7, Class >() { + @Override + public Class visitPrimitive(PrimitiveType t, Class v) { + switch (t.getKind()) { + case BOOLEAN: + return Boolean.class; + + case BYTE: + return Byte.class; + + case CHAR: + return Character.class; + + case SHORT: + return Short.class; + + case INT: + return Integer.class; + + case LONG: + return Long.class; + + case FLOAT: + return Float.class; + + case DOUBLE: + return Double.class; + + default: + return null; + } + } + + @Override + public Class visitDeclared(DeclaredType dt, Class v) { + return dt.asElement().accept(new SimpleElementVisitor7, Class >() { + @Override + public Class visitType(TypeElement e, Class v) { + try { + return Class.forName(e.getQualifiedName().toString()); + } catch (ClassNotFoundException e1) { + return null; // the lookup should work for all the + // classes we care about + } + } + }, Void.TYPE); + } + }, Void.TYPE); + } +} diff --git a/checker/iotchecker/messages.properties b/checker/iotchecker/messages.properties new file mode 100644 index 0000000..5b6b521 --- /dev/null +++ b/checker/iotchecker/messages.properties @@ -0,0 +1,4 @@ +### Error/warning messages for the IoTJava Checker +reflection.found=Accessing java.lang.reflect classes is not allowed. +java.net.found=Accessing java.net classes is not allowed (please use IoTJava network classes instead). + diff --git a/checker/iotchecker/package-info.java b/checker/iotchecker/package-info.java new file mode 100644 index 0000000..a570ccf --- /dev/null +++ b/checker/iotchecker/package-info.java @@ -0,0 +1,6 @@ +/** + * Provides a type-checker plug-in for the IoTJavaChecker + * qualifier that traces callback functions. + * + */ +package iotchecker; -- 2.34.1