All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.joern.scanners.c.MissingLengthCheck.scala Maven / Gradle / Ivy

There is a newer version: 1.2.44
Show newest version
package io.joern.scanners.c

import io.shiftleft.semanticcpg.language.{ICallResolver, NoResolve}
import io.joern.scanners._
import io.joern.console._
import io.joern.console._
import io.shiftleft.codepropertygraph.generated.nodes
import io.joern.dataflowengineoss.queryengine.EngineContext
import io.shiftleft.semanticcpg.language._
import io.joern.macros.QueryMacros._
import io.shiftleft.semanticcpg.language.operatorextension._
import QueryLangExtensions._

object MissingLengthCheck extends QueryBundle {

  implicit val resolver: ICallResolver = NoResolve

  @q
  def constantArrayAccessNoCheck()(implicit context: EngineContext): Query =
    Query.make(
      name = "constant-array-access-no-check",
      author = Crew.fabs,
      title = "Array access at fixed offset but sufficient length check not determined",
      description = """
          |
          |""".stripMargin,
      score = 3,
      withStrRep({ cpg =>
        cpg.method.arrayAccess
          .filter { access =>
            val arrName = access.simpleName
            arrName.isDefined && !arrName.forall(x => access.method.local.nameExact(x).nonEmpty)
          }
          .usesConstantOffset
          .flatMap { arrayAccess =>
            val lenFields =
              potentialLengthFields(arrayAccess, arrayAccess.method)
            if (lenFields.nonEmpty) {
              List((arrayAccess, lenFields))
            } else {
              List()
            }
          }
          .collect {
            case (arrayAccess, lenFields) if !checked(arrayAccess, lenFields) =>
              arrayAccess
          }
      }),
      tags = List(QueryTags.default)
    )

  /**
    * Names of potential length fields for the array named `arrayName` in the
    * method `method`. Determined heuristically via name matching.
    * */
  private def potentialLengthFields(arrayAccess: opnodes.ArrayAccess, method: nodes.Method): List[String] = {
    val arrayName = arrayAccess.simpleName.get
    List(arrayName).flatMap { name =>
      val normalizedName = name.replaceAll("s$", "")
      val regex = s"(?i)$normalizedName(s?)(_?)(len|siz).*"
      method.parameter.name(regex).name.l ++
        method.local.name(regex).name.l
    }
  }

  /**
    * For a given array access with a single constant offset and a set of variable names of
    * potential length fields of the array, determine whether a check
    * of at least one of the potential length fields exist for each
    * literal
    * */
  def checked(arrayAccess: opnodes.ArrayAccess, lens: List[String]): Boolean = {
    val arrayIndex = arrayAccess.argument(2).ast.isLiteral.toInt.head
    val lowerBounds = arrayAccess.method.controlStructure.condition
      .where(_.ast.isIdentifier.name.filter { n =>
        lens.contains(n)
      })
      .ast
      .isLiteral
      .toInt ++ {
      if (arrayAccess.method.controlStructure.condition
            .codeExact(arrayAccess.array.code)
            .nonEmpty) {
        List(0)
      } else {
        List()
      }
    }
    lowerBounds.exists { bound =>
      bound >= arrayIndex
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy