[PATCH v4 5/7] fuzz: set bits in operand of write/out to zero

Qiuhao Li posted 7 patches 4 years, 10 months ago
Maintainers: Bandan Das <bsd@redhat.com>, Alexander Bulekov <alxndr@bu.edu>, Stefan Hajnoczi <stefanha@redhat.com>, Thomas Huth <thuth@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>
There is a newer version of this series
[PATCH v4 5/7] fuzz: set bits in operand of write/out to zero
Posted by Qiuhao Li 4 years, 10 months ago
Simplifying the crash cases by opportunistically setting bits in operands of
out/write to zero may help to debug, since usually bit one means turn on or
trigger a function while zero is the default turn-off setting.

Tested Bug 1908062.

Signed-off-by: Qiuhao Li <Qiuhao.Li@outlook.com>
---
 scripts/oss-fuzz/minimize_qtest_trace.py | 39 ++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/scripts/oss-fuzz/minimize_qtest_trace.py b/scripts/oss-fuzz/minimize_qtest_trace.py
index 378a7ccec6..70ac0c5366 100755
--- a/scripts/oss-fuzz/minimize_qtest_trace.py
+++ b/scripts/oss-fuzz/minimize_qtest_trace.py
@@ -164,6 +164,42 @@ def remove_minimizer(newtrace, outpath):
         i += 1
 
 
+def set_zero_minimizer(newtrace, outpath):
+    # try setting bits in operands of out/write to zero
+    i = 0
+    while i < len(newtrace):
+        if (not newtrace[i].startswith("write ") and not
+           newtrace[i].startswith("out")):
+           i += 1
+           continue
+        # write ADDR SIZE DATA
+        # outx ADDR VALUE
+        print("\nzero setting bits: {}".format(newtrace[i]))
+
+        prefix = " ".join(newtrace[i].split()[:-1])
+        data = newtrace[i].split()[-1]
+        data_bin = bin(int(data, 16))
+        data_bin_list = list(data_bin)
+
+        for j in range(2, len(data_bin_list)):
+            prior = newtrace[i]
+            if (data_bin_list[j] == '1'):
+                data_bin_list[j] = '0'
+                data_try = hex(int("".join(data_bin_list), 2))
+                # It seems qtest only accepts padded hex-values.
+                if len(data_try) % 2 == 1:
+                    data_try = data_try[:2] + "0" + data_try[2:-1]
+
+                newtrace[i] = "{prefix} {data_try}\n".format(
+                        prefix=prefix,
+                        data_try=data_try)
+
+                if not check_if_trace_crashes(newtrace, outpath):
+                    data_bin_list[j] = '1'
+                    newtrace[i] = prior
+        i += 1
+
+
 def minimize_trace(inpath, outpath):
     global TIMEOUT
     with open(inpath) as f:
@@ -184,7 +220,10 @@ def minimize_trace(inpath, outpath):
         old_len = len(newtrace)
         remove_minimizer(newtrace, outpath)
         newtrace = list(filter(lambda s: s != "", newtrace))
+    assert(check_if_trace_crashes(newtrace, outpath))
 
+    # set zero minimizer
+    set_zero_minimizer(newtrace, outpath)
     assert(check_if_trace_crashes(newtrace, outpath))
 
 
-- 
2.25.1


Re: [PATCH v4 5/7] fuzz: set bits in operand of write/out to zero
Posted by Alexander Bulekov 4 years, 10 months ago
On 201229 1240, Qiuhao Li wrote:
> Simplifying the crash cases by opportunistically setting bits in operands of
> out/write to zero may help to debug, since usually bit one means turn on or
> trigger a function while zero is the default turn-off setting.
> 
> Tested Bug 1908062.
> 
> Signed-off-by: Qiuhao Li <Qiuhao.Li@outlook.com>

Reviewed-by: Alexander Bulekov <alxndr@bu.edu>

> ---
>  scripts/oss-fuzz/minimize_qtest_trace.py | 39 ++++++++++++++++++++++++
>  1 file changed, 39 insertions(+)
> 
> diff --git a/scripts/oss-fuzz/minimize_qtest_trace.py b/scripts/oss-fuzz/minimize_qtest_trace.py
> index 378a7ccec6..70ac0c5366 100755
> --- a/scripts/oss-fuzz/minimize_qtest_trace.py
> +++ b/scripts/oss-fuzz/minimize_qtest_trace.py
> @@ -164,6 +164,42 @@ def remove_minimizer(newtrace, outpath):
>          i += 1
>  
>  
> +def set_zero_minimizer(newtrace, outpath):
> +    # try setting bits in operands of out/write to zero
> +    i = 0
> +    while i < len(newtrace):
> +        if (not newtrace[i].startswith("write ") and not
> +           newtrace[i].startswith("out")):
> +           i += 1
> +           continue
> +        # write ADDR SIZE DATA
> +        # outx ADDR VALUE
> +        print("\nzero setting bits: {}".format(newtrace[i]))
> +
> +        prefix = " ".join(newtrace[i].split()[:-1])
> +        data = newtrace[i].split()[-1]
> +        data_bin = bin(int(data, 16))
> +        data_bin_list = list(data_bin)
> +
> +        for j in range(2, len(data_bin_list)):
> +            prior = newtrace[i]
> +            if (data_bin_list[j] == '1'):
> +                data_bin_list[j] = '0'
> +                data_try = hex(int("".join(data_bin_list), 2))
> +                # It seems qtest only accepts padded hex-values.
> +                if len(data_try) % 2 == 1:
> +                    data_try = data_try[:2] + "0" + data_try[2:-1]
> +
> +                newtrace[i] = "{prefix} {data_try}\n".format(
> +                        prefix=prefix,
> +                        data_try=data_try)
> +
> +                if not check_if_trace_crashes(newtrace, outpath):
> +                    data_bin_list[j] = '1'
> +                    newtrace[i] = prior
> +        i += 1
> +
> +
>  def minimize_trace(inpath, outpath):
>      global TIMEOUT
>      with open(inpath) as f:
> @@ -184,7 +220,10 @@ def minimize_trace(inpath, outpath):
>          old_len = len(newtrace)
>          remove_minimizer(newtrace, outpath)
>          newtrace = list(filter(lambda s: s != "", newtrace))
> +    assert(check_if_trace_crashes(newtrace, outpath))
>  
> +    # set zero minimizer
> +    set_zero_minimizer(newtrace, outpath)
>      assert(check_if_trace_crashes(newtrace, outpath))
>  
>  
> -- 
> 2.25.1
>