hgarrereyn / GraphFuzz

GraphFuzz is an experimental framework for building structure-aware, library API fuzzers.
https://hgarrereyn.github.io/GraphFuzz
MIT License
254 stars 25 forks source link

Limitation? Functions with Standard Template Library C++ #20

Closed yheechan closed 1 year ago

yheechan commented 1 year ago

Hello I was trying to make schema for a function with STL as its input parameter.

My attempt was as following:

Foo:
  type: struct
  name: Foo
  default_destructor: false
  headers:
  - foo.h
  methods:
  - myfunction(set<int> x):
      inputs: ['Foo']
      outputs: ['Foo']
      args: [set<int>]
      exec:
        $i0->myfunction($a0);
        $o0 = $i0;

with following code gfuzz gen cpp schema.yaml . , it bring up following error:

Missing refs:
- set<int> (1)

[Results]:
- Parsed 1 / 1 (100.0%)
- Generated 0 / 1 (0.0%)

by any chance, is there an exsiting turn around (another possible way) to use such STL as inputs? or does it not support such types (STL, set<>, queue<> etc)?

hgarrereyn commented 1 year ago

Hi @yheechan, the args part of an endpoint can currently only be a primitive type or a fixed size array. However, it is possible to manually define a conversion into a set<int> depending on how you want to fuzz test it.

For example, you could do something like this:

Foo:
  type: struct
  name: Foo
  default_destructor: false
  headers:
  - foo.h
  methods:
  - myfunction(set<int> x):
      inputs: ['Foo']
      outputs: ['Foo']
      args: ['int[100]', 'uint32_t']
      exec:
        std::set<int> s;
        for (int i = 0; i < ($a1 % 100); ++i) {
            s.insert($a0[i]);
        }
        $i0->myfunction(s);
        $o0 = $i0;

At runtime the mutation engine can change the backing data for the set $a0 and the size of the set $a1.

yheechan commented 1 year ago

I have understood that this prevents from more diverse mutations since such variable as std::set<int> type is only initiated within exec. Thank you for the helpful reply!

hgarrereyn commented 1 year ago

Hi @yheechan, it is possible to also treat set<int> as a live object, such as in the following schema:

Foo:
  type: struct
  name: Foo
  default_destructor: false
  headers:
  - foo.h
  methods:
  - myfunction(set<int> x):
      inputs: ['Foo', 'std::set<int>']
      outputs: ['Foo', 'std::set<int>']
      exec:
        $i0->myfunction($i1);
        $o0 = $i0;
        $o1 = $i1;

struct_set<int>:
  type: struct
  name: std::set<int>
  default_destructor: true
  headers:
  - <set>
  methods:
  - init:
      outputs: ['std::set<int>']
      args: ['int[100]', 'uint32_t']
      exec: |
        std::set<int> *s = new std::set<int>();
        for (int i = 0; i < ($a1 % 100); ++i) {
          s->insert($a0[i]);
        }
        $o0 = s;

However, I wouldn't recommend doing this since it imposes a stronger limitation on what you are allowed to do with set<int> than what might be possible in a real "attack scenario." For example, in most APIs I can think of, if a function actually takes a set<int> as an input, those values are probably coming directly from user data, and hence could be fully attacker controlled.