On Thu, Sep 21, 2023 at 10:22:08PM +0100, Richard W.M. Jones wrote:
On Thu, Sep 21, 2023 at 03:58:01PM -0500, Eric Blake wrote:
> When fuzzing, it is more desirable to always provoke the server into
> sending a response, rather than sometimes accidentally skipping a wire
> call because a client-side strictness test failed.
>
> [Our fuzzer could probably be made even more powerful by changing the
> fuzzer input file to be a series of records, where each record is the
> API to call and then the server's response; right now, the sequence of
> APIs called is hard-coded, which is not as powerful at testing
> potential cross-command coupling. But that's a project for another
> day.]
Intrigued by how this would work exactly. The current file is just a
stream of bytes from the "server" (the output from libnbd is
discarded). Would the input file be of the form:
( [ request + args ] [ stream of bytes from server ] )*
where [ request + args ] would be a simple serialized representation
of a synchronous nbd_* API call? I think that would work ...
Actually I don't think this would work. The stream of bytes is
variable length so it would need a sentinel to indicate the end of one
stream (hard to do in-stream) or a length field up front. However
fuzzing doesn't work well with length + data since the fuzzer doesn't
understand the relationship.
This could work (I've abbreviated "request + args" to just
"request"
and "stream ..." to "stream"):
( [ request ] )* [ sentinel ] [ stream ] (* case B *)
where [ sentinel ] is some sentinel that can be distinguished from a
request.
The idea here is the fuzzing wrapper would read the set of requests
into an internal structure, then process the stream as it does now
while issuing the requests.
However I still don't think the fuzzer would work well with this. The
problem is that the stream of bytes is still related to the set of
requests. For example if a new request was inserted then some later
point in the stream would need to change, but the fuzzer wouldn't
understand this relationship. [Now I'm thinking if only we could use
an AI transformer it would solve this problem too! Transformers can
find these kind of long-range moving dependencies.]
This seems better still:
[ request ] [ stream ] (* case C *)
There's a single request (which can represent exactly one nbd_*
request), and a single associated stream. The fuzzer would generate
alternate nbd_* APIs as it mutated the request field.
However the problem here is we no longer have any way to describe
multiple dependent requests.
So ...
I think my answer is to go back to case B:
( [ request ] )* [ sentinel ] [ stream ]
but make the starting test cases all look (nearly) like case C:
[ request ] [ sentinel ] [ stream ]
The fuzzer would start by finding the simple test cases looking like
C, and then might create longer test cases looking like B later in the
run (or might not, we'd need to examine the output after a long run).
Anyway, something for a rainy day.
Rich.
Rich.
> Signed-off-by: Eric Blake <eblake(a)redhat.com>
> Reviewed-by: Richard W.M. Jones <rjones(a)redhat.com>
> Reviewed-by: Laszlo Ersek <lersek(a)redhat.com>
> ---
> fuzzing/libnbd-fuzz-wrapper.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/fuzzing/libnbd-fuzz-wrapper.c b/fuzzing/libnbd-fuzz-wrapper.c
> index cbd55380..fcd1d04c 100644
> --- a/fuzzing/libnbd-fuzz-wrapper.c
> +++ b/fuzzing/libnbd-fuzz-wrapper.c
> @@ -193,8 +193,11 @@ client (int sock)
> }
>
> /* Note we ignore errors in these calls because we are only
> - * interested in whether the process crashes.
> + * interested in whether the process crashes. Likewise, we don't
> + * want to accidentally avoid sending traffic to the server merely
> + * because client side strictness sees a problem.
> */
> + nbd_set_strict_mode (nbd, 0);
>
> /* Enable a metadata context, for block status below. */
> nbd_add_meta_context (nbd, LIBNBD_CONTEXT_BASE_ALLOCATION);
> --
> 2.41.0
--
Richard Jones, Virtualization Group, Red Hat
http://people.redhat.com/~rjones
Read my programming and virtualization blog:
http://rwmj.wordpress.com
virt-top is 'top' for virtual machines. Tiny program with many
powerful monitoring features, net stats, disk stats, logging, etc.
http://people.redhat.com/~rjones/virt-top
--
Richard Jones, Virtualization Group, Red Hat
http://people.redhat.com/~rjones
Read my programming and virtualization blog:
http://rwmj.wordpress.com
virt-p2v converts physical machines to virtual machines. Boot with a
live CD or over the network (PXE) and turn machines into KVM guests.
http://libguestfs.org/virt-v2v