From c71ecd678e315e2072a747cc9da620b5d09810d0 Mon Sep 17 00:00:00 2001 From: Slavomir Date: Tue, 30 Jun 2020 10:45:03 +0300 Subject: [PATCH] Initial commit for: wrong use of package unsafe --- ql/src/experimental/Unsafe/Unsafe.ql | 153 +++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 ql/src/experimental/Unsafe/Unsafe.ql diff --git a/ql/src/experimental/Unsafe/Unsafe.ql b/ql/src/experimental/Unsafe/Unsafe.ql new file mode 100644 index 00000000000..e38042f2315 --- /dev/null +++ b/ql/src/experimental/Unsafe/Unsafe.ql @@ -0,0 +1,153 @@ +/** + * @kind path-problem + */ + +import go +import DataFlow::PathGraph + +Type getBaseType(Type typ) { + result = + getBaseType*(typ.getUnderlyingType*().(PointerType).getBaseType*().getUnderlyingType*()) + .getUnderlyingType*() + or + result = typ +} + +Type getFinalType(Type typ) { + result = getFinalType*(typ.getUnderlyingType*()) + or + result = typ +} + +class ConversionToUnsafePointer extends ConversionExpr { + ConversionToUnsafePointer() { getBaseType(getType()) instanceof UnsafePointerType } +} + +class ShortToLongerArrayConf extends TaintTracking::Configuration { + ShortToLongerArrayConf() { this = "ShortToLongerArrayConf" } + + predicate isSource(DataFlow::Node source, ConversionToUnsafePointer conv) { + source.asExpr() = conv + } + + predicate isSink(DataFlow::Node sink, ConversionExpr ca) { + ca.getOperand().getType() instanceof UnsafePointerType and + sink.asExpr() = ca + } + + override predicate isSource(DataFlow::Node source) { isSource(source, _) } + + override predicate isSink(DataFlow::Node sink) { isSink(sink, _) } +} + +predicate castShortArrayToLongerArray( + DataFlow::PathNode source, DataFlow::PathNode sink, string message +) { + exists( + ShortToLongerArrayConf cfg, ConversionExpr castBig, ConversionToUnsafePointer castLittle, + ArrayType arrTo, ArrayType arrFrom + | + cfg.hasFlowPath(source, sink) and + cfg.isSource(source.getNode(), castLittle) and + cfg.isSink(sink.getNode(), castBig) and + //castBig.getTypeExpr().getAChildExpr*().getType() instanceof ArrayType and + arrTo = getBaseType(castBig.getTypeExpr().getType()) and + arrFrom = getBaseType(castLittle.getOperand().getType()) and + arrTo.getLength() > 0 and //TODO + arrTo.getLength() > arrFrom.getLength() and + message = + "Dangerous array type casting to [" + arrTo.getLength() + "]" + arrTo.getElementType() + + " from [" + arrFrom.getLength() + "]" + arrFrom.getElementType() //and + //arrTo.getElementType() instanceof Uint8Type and + //arrFrom.getElementType() instanceof Uint8Type + ) +} + +predicate castTypeToArray(DataFlow::PathNode source, DataFlow::PathNode sink, string message) { + exists( + ShortToLongerArrayConf cfg, ConversionExpr castBig, ConversionToUnsafePointer castLittle, + ArrayType arrTo, Type typeFrom + | + cfg.hasFlowPath(source, sink) and + cfg.isSource(source.getNode(), castLittle) and + cfg.isSink(sink.getNode(), castBig) and + //castBig.getTypeExpr().getAChildExpr*().getType() instanceof ArrayType and + arrTo = getBaseType(castBig.getTypeExpr().getType()) and + not (typeFrom instanceof ArrayType or typeFrom.getUnderlyingType() instanceof ArrayType) and + not typeFrom instanceof PointerType and + typeFrom = getBaseType(castLittle.getOperand().getType()) and + //typeFrom = getBaseType(typeFrom) and + message = + "Dangerous type up-casting to [" + arrTo.getLength() + "]" + arrTo.getElementType() + " from " + + typeFrom //and + //arrTo.getElementType() instanceof Uint8Type and + //arrFrom.getElementType() instanceof Uint8Type + ) +} + +class NumberCastingFlowConf extends TaintTracking::Configuration { + NumberCastingFlowConf() { this = "NumberCastingFlowConf" } + + predicate isSource(DataFlow::Node source, ConversionToUnsafePointer conv) { + source.asExpr() = conv + } + + predicate isSink(DataFlow::Node sink, ConversionExpr ca) { + ca.getOperand().getType() instanceof UnsafePointerType and + sink.asExpr() = ca + } + + override predicate isSource(DataFlow::Node source) { isSource(source, _) } + + override predicate isSink(DataFlow::Node sink) { isSink(sink, _) } +} + +predicate castDifferentBitSizeNumbers( + DataFlow::PathNode source, DataFlow::PathNode sink, string message +) { + exists( + NumberCastingFlowConf cfg, ConversionExpr castBig, ConversionToUnsafePointer castLittle, + CustomNumericType numTo, CustomNumericType numFrom + | + cfg.hasFlowPath(source, sink) and + cfg.isSource(source.getNode(), castLittle) and + cfg.isSink(sink.getNode(), castBig) and + numTo = getBaseType(castBig.getTypeExpr().getType()) and + ( + numFrom = getBaseType(castLittle.getOperand().getType()) or + numFrom = + getBaseType(getBaseType(castLittle.getOperand().getType()) + .(StructType) + .getField(_) + .getType()) + ) and + // TODO: also consider cast from uint to int? + numTo.getSize() != numFrom.getSize() and + message = "Dangerous numeric type casting to " + numTo.getName() + " from " + numFrom.getName() + ) +} + +class CustomNumericType extends NumericType { + CustomNumericType() { this instanceof NumericType } + + override int getSize() { + ( + // If the numeric types have arch-specific + // bit sizes, then set the size to 0 to distinguish + // it from others. + this instanceof UintType + or + this instanceof IntType + ) and + result = 0 + or + result = this.(NumericType).getSize() + } +} + +from DataFlow::PathNode source, DataFlow::PathNode sink, string message +where + castShortArrayToLongerArray(source, sink, message) or + castTypeToArray(source, sink, message) or + castDifferentBitSizeNumbers(source, sink, message) +select sink.getNode(), source, sink, "$@.", source.getNode(), message