Files
codeql/java/ql/test/query-tests/security/CWE-190/semmle/tests/Test.java
Chris Smowton e3cf5c235e Add support for Commons-Lang's RandomUtils
This is realised by somewhat generalising our interfaces for modelling RNGs. We also add tests for randomness-related queries that didn't have any, and addtest cases checking the Apache random-number generators are interchangeable with the stdlib ones.
2021-03-05 12:09:33 +00:00

292 lines
6.0 KiB
Java

// Semmle test case for CWE-190: Integer Overflow or Wraparound
// http://cwe.mitre.org/data/definitions/190.html
package test.cwe190.semmle.tests;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.HashMap;
import org.apache.commons.lang3.RandomUtils;
class Test {
public static void main(String[] args) {
// IntMultToLong
{
int timeInSeconds = 1000000;
// BAD: result of multiplication will be too large for
// int, and will overflow before being stored in the long
long timeInNanos = timeInSeconds * 1000000000;
}
{
int timeInSeconds = 1000000;
// BAD
long timeInNanos = timeInSeconds * 1000000000 + 4;
}
{
int timeInSeconds = 1000000;
// BAD
long timeInNanos = true ? timeInSeconds * 1000000000 + 4 : 0;
}
{
long timeInSeconds = 10000000L;
// same problem, but with longs; not reported as the conversion to double is not sufficient indication of a large number
double timeInNanos = timeInSeconds * 10000000L;
}
{
int timeInSeconds = 1000000;
// GOOD: one of the arguments is cast to long before multiplication
// so the multiplication will take place in the long
long timeInNanos = (long) timeInSeconds * 1000000000;
}
{
int timeInSeconds = 1;
// GOOD: both arguments are constants that are small
// enough to allow the multiplication in int without
// overflow
long timeInNanos = timeInSeconds * 1000000000;
}
// InformationLoss
{
int i = 0;
while (i < 1000000) {
// BAD: getLargeNumber is implicitly narrowed to an integer
// which will result in overflows if it is large
i += getLargeNumber();
}
}
{
long i = 0;
while (i < 1000000) {
// GOOD: i is a long, so no narrowing occurs
i += getLargeNumber();
}
}
{
int i = 0;
long j = 100;
// FALSE POSITIVE: the query check purely based on the type, it
// can't try to
// determine whether the value may in fact always be in bounds
i += j;
}
// ArithmeticWithExtremeValues
{
int i = 0;
i = Integer.MAX_VALUE;
int j = 0;
// BAD: overflow
j = i + 1;
}
{
int i = 0;
i = Integer.MAX_VALUE;
int j = 0;
i = 0;
// GOOD: reassigned before usage
j = i + 1;
}
{
long i = Long.MIN_VALUE;
// BAD: overflow
long j = i - 1;
}
{
long i = Long.MAX_VALUE;
// GOOD: no overflow
long j = i - 1;
}
{
int i = Integer.MAX_VALUE;
// GOOD: no overflow
long j = (long) i - 1;
}
{
int i = Integer.MAX_VALUE;
// GOOD: guarded
if (i < Integer.MAX_VALUE) {
long j = i + 1;
}
}
{
int i = Integer.MAX_VALUE;
if (i < Integer.MAX_VALUE) {
// BAD: reassigned after guard
i = Integer.MAX_VALUE;
long j = i + 1;
}
}
{
int i = Integer.MAX_VALUE;
// BAD: guarded the wrong way
if (i > Integer.MIN_VALUE) {
long j = i + 1;
}
}
{
int i = Integer.MAX_VALUE;
// GOOD: The query can detect custom guards.
if (properlyBounded(i)) {
long j = i + 1;
}
}
{
byte b = Byte.MAX_VALUE;
// GOOD: extreme byte value is widened to type int, thus avoiding
// overflow
// (see binary numeric promotions in JLS 5.6.2)
int i = b + 1;
}
{
short s = Short.MAX_VALUE;
// GOOD: extreme short value is widened to type int, thus avoiding
// overflow
// (see binary numeric promotions in JLS 5.6.2)
int i = s + 1;
}
{
int i = Integer.MAX_VALUE;
// GOOD: extreme int value is widened to type long, thus avoiding
// overflow
// (see binary numeric promotions in JLS 5.6.2)
long l = i + 1L;
}
{
byte b = Byte.MAX_VALUE;
// BAD: extreme byte value is widened to type int, but subsequently
// cast to narrower type byte
byte widenedThenNarrowed = (byte) (b + 1);
}
{
short s = Short.MAX_VALUE;
// BAD: extreme short value is widened to type int, but subsequently
// cast to narrower type short
short widenedThenNarrowed = (short) (s + 1);
}
{
int i = Integer.MAX_VALUE;
// BAD: extreme int value is widened to type long, but subsequently
// cast to narrower type int
int widenedThenNarrowed = (int) (i + 1L);
}
// ArithmeticUncontrolled
int data = (new java.security.SecureRandom()).nextInt();
{
// BAD: may overflow if data is large
int output = data + 1;
}
{
// GOOD: guarded
if (data < Integer.MAX_VALUE) {
int output = data + 1;
}
}
{
// guard against underflow
if (data > Integer.MIN_VALUE) {
int stillLarge = data - 1;
// FALSE NEGATIVE: stillLarge could still be very large, even
// after
// it has had arithmetic done on it
int output = stillLarge + 100;
}
}
{
// GOOD: uncontrolled int value is widened to type long, thus
// avoiding overflow
// (see binary numeric promotions in JLS 5.6.2)
long widened = data + 10L;
}
{
// BAD: uncontrolled int value is widened to type long, but
// subsequently cast to narrower type int
int widenedThenNarrowed = (int) (data + 10L);
}
// ArithmeticUncontrolled using Apache RandomUtils
int data2 = RandomUtils.nextInt();
{
// BAD: may overflow if data is large
int output = data2 + 1;
}
{
// GOOD: guarded
if (data2 < Integer.MAX_VALUE) {
int output = data2 + 1;
}
}
{
// guard against underflow
if (data2 > Integer.MIN_VALUE) {
int stillLarge = data2 - 1;
// FALSE NEGATIVE: stillLarge could still be very large, even
// after
// it has had arithmetic done on it
int output = stillLarge + 100;
}
}
{
// GOOD: uncontrolled int value is widened to type long, thus
// avoiding overflow
// (see binary numeric promotions in JLS 5.6.2)
long widened = data2 + 10L;
}
{
// BAD: uncontrolled int value is widened to type long, but
// subsequently cast to narrower type int
int widenedThenNarrowed = (int) (data2 + 10L);
}
}
public static long getLargeNumber() {
return Long.MAX_VALUE / 2;
}
public static boolean properlyBounded(int i) {
return i < Integer.MAX_VALUE;
}
}