Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use After Free: Tracking alias #18791

Open
ArtiomKr opened this issue Feb 14, 2025 · 1 comment
Open

Use After Free: Tracking alias #18791

ArtiomKr opened this issue Feb 14, 2025 · 1 comment
Labels
question Further information is requested

Comments

@ArtiomKr
Copy link

ArtiomKr commented Feb 14, 2025

As I already asked, I want to understand, how can I track alias to detect use after free vulnerability? Are there any libraries, which can help track such CWEs? Here some examples:

#include <stdlib.h>
#include <time.h>

int main() {
  char *a = (char *)malloc(sizeof(char)); // Memory allocation
  char *b = a;
  if (a != NULL) {
    free(a); // Free allocated memory
  }
  *b = 'b'; // Use after free
  return 0;
}
#include <stdlib.h>
#include <time.h>

struct char2 {
  char *a;
  char *b;
};

int main() {
  struct char2 *c2_alias;
  struct char2 *c2 = (struct char2 *)malloc(sizeof(struct char2));
  c2->a = (char *)malloc(sizeof(char)); // Memory allocation
  c2_alias = c2;
  time_t seconds = time(NULL) % 3;
  free(c2->a); // Free memory which was allocated in 'c2->a'
  if (seconds >= 0 && seconds <= 2)
    *(c2_alias->a) = 'a'; // Use after free
  if (seconds >= 3)
    *(c2_alias->b) = 'b';
  free(c2);
  return 0;
}

I want to track malloc function and then find all alias (start tracking them). After that I want to make all arguments of free become sources and make them about alias. How is it can be shown?
For now I have code, that find only CWEs that are related only to the function argument:

/**
 * @name Use after free
 * @kind path-problem
 * @id cpp/use-after-free
 */

 import cpp
 import semmle.code.cpp.dataflow.DataFlow
 import semmle.code.cpp.dataflow.TaintTracking
 import Configs::PathGraph
 
 module Config implements DataFlow::ConfigSig {
   predicate isSource(DataFlow::Node arg) {
     exists(FunctionCall call |
       arg.asDefiningArgument() = call.getArgument(0) and
       call.getTarget().hasGlobalOrStdName("free")
     )
   }
 
   predicate isSink(DataFlow::Node sink) {
    exists(PointerDereferenceExpr star |
     star.getOperand() = sink.asExpr()
    )
    or
    exists(FormattingFunctionCall call |
     call.getArgument(0) = sink.asExpr()
    )
   }
 }
 
 module Configs = TaintTracking::Global<Config>;
 
 from Configs::PathNode source, Configs::PathNode sink
 where Configs::hasFlowPath(source, sink)
 select sink, source, sink,
        "Memory is freed here and used here, causing a potential vulnerability.",
        source, "freed here", sink, "used here"

Maybe is it possible to track this nit by arg.asDefiningArgument() = call.getArgument(0), but as relation to the memory? So, that I could somehow track memory, not argument?

Can isAdditionalFlowStep help?

@ArtiomKr ArtiomKr added the question Further information is requested label Feb 14, 2025
@jketema
Copy link
Contributor

jketema commented Feb 17, 2025

Hi @ArtiomKr,

There are no libraries available for this. I sketched out a solution for you here already: #18771 (comment). I understand that the solution there might not be easy to implement, but you must somehow observe that the aliasing occurred, and that information is not contained in the call to free somehow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants