All of lore.kernel.org
 help / color / mirror / Atom feed
From: Markus Armbruster <armbru@redhat.com>
To: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
Cc: Denis Lunev <den@virtuozzo.com>,
	Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>,
	"mdroth@linux.vnet.ibm.com" <mdroth@linux.vnet.ibm.com>,
	"qemu-devel@nongnu.org" <qemu-devel@nongnu.org>
Subject: Re: [Qemu-devel] [PATCH v2] make check-unit: use after free in test-opts-visitor
Date: Tue, 06 Aug 2019 07:25:33 +0200	[thread overview]
Message-ID: <87mugmsw4y.fsf@dusky.pond.sub.org> (raw)
In-Reply-To: <c11463f0-6cf1-7249-f4c6-2af8ae10ad19@virtuozzo.com> (Andrey Shinkevich's message of "Mon, 5 Aug 2019 15:09:30 +0000")

Andrey Shinkevich <andrey.shinkevich@virtuozzo.com> writes:

> On 02/08/2019 14:34, Markus Armbruster wrote:
>> Andrey Shinkevich <andrey.shinkevich@virtuozzo.com> writes:
>> 
>>> In struct OptsVisitor, repeated_opts member points to a list in the
>>> unprocessed_opts hash table after the list has been destroyed. A
>>> subsequent call to visit_type_int() references the deleted list. It
>>> results in use-after-free issue.
>> 
>> Let's mention the reproducer: valgrind tests/test/opts-visitor.
>> 
>>>                                   Also, the Visitor object call back
>>> functions are supposed to set the Error parameter in case of failure.
>> 
>> As far as I can tell, they all do.  The only place where you set an
>> error is the new failure you add to lookup_scalar().
>> 
>
> The story behind the comment is that the original 
> tests/test-opts-visitor fails being run under the Valgrind with the 
> error message:
>
> test-opts-visitor: util/error.c:276: error_free_or_abort: Assertion 
> `errp && *errp' failed.
>
> coming from
>
> assert(errp && *errp);
> error_free_or_abort (util/error.c:276)
> test_opts_range_beyond (tests/test-opts-visitor.c:241)
>
> because g_queue_peek_head() returns NULL under the Valgrind and errp 
> stays unset.
>
> Without the Valgrind, the g_queue_peek_head() returns a non-zero pointer 
> and the opts_type_int64() sets the following error:
>
> "Parameter '\340F\212\274\267U' expects an int64 value or range", 
> err_class = ERROR_CLASS_GENERIC_ERROR, src = 0x55b7bbc02163 
> "qapi/opts-visitor.c",
>    func = 0x55b7bbc02410 <__func__.14916> "opts_type_int64", line = 433, 
> hint = 0x0}
>
> so, error_free_or_abort() doesn't abort and the test case passes.
>
> I will remove the comment in v3.

Thanks.

[...]
>>> diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c
>>> index 324b197..23ac383 100644
>>> --- a/qapi/opts-visitor.c
>>> +++ b/qapi/opts-visitor.c
[...]
>>> @@ -289,8 +302,11 @@ opts_end_list(Visitor *v, void **obj)
>>>   
>>>       assert(ov->list_mode == LM_IN_PROGRESS ||
>>>              ov->list_mode == LM_SIGNED_INTERVAL ||
>>> -           ov->list_mode == LM_UNSIGNED_INTERVAL);
>>> -    ov->repeated_opts = NULL;
>>> +           ov->list_mode == LM_UNSIGNED_INTERVAL ||
>>> +           ov->list_mode == LM_TRAVERSED);
>>> +    if (ov->list_mode != LM_TRAVERSED) {
>>> +        ov->repeated_opts = NULL;
>>> +    }
>> 
>> What's wrong with zapping ov->repeated_opts unconditionally?
>> 
>>>       ov->list_mode = LM_NONE;
>>>   }
>>>   
>>> @@ -306,6 +322,10 @@ lookup_scalar(const OptsVisitor *ov, const char *name, Error **errp)
>>>           list = lookup_distinct(ov, name, errp);
>>>           return list ? g_queue_peek_tail(list) : NULL;
>>>       }
>>> +    if (ov->list_mode == LM_TRAVERSED) {
>>> +        error_setg(errp, QERR_INVALID_PARAMETER, name);
>> 
>> Beware, @name is null when visiting list members.  The test still passes
>> for me, since g_strdup_vprintf() formats a null argument to %s as
>> "(null)".
>> 
>> For what it's worth, the qobject input visitor uses
>> QERR_MISSING_PARAMETER with a made-up name.  Computing the name is
>> pretty elaborate, see full_name_nth().  I'd rather not duplicate that
>> here.
>> 
>> Suggest something like
>> 
>>             error_setg(errp, "Fewer list elements than expected");
>> 
>> The error message fails to mention the name of the list.  Bad, but the
>> error is a corner case; we don't normally visit beyond the end of the
>> list.  For a better message, we'd have to have start_list() store its
>> @name in struct OptsVisitor.  I'm not asking you to do that now.
>> 
>
> Will I do that work to add the @name of the list to the struct 
> OptsVisitor in a following series?

Entirely up to you.  To be honest, I'm not sure it's worth the trouble.

>>> +        return NULL;
>>> +    }
>>>       assert(ov->list_mode == LM_IN_PROGRESS);
>>>       return g_queue_peek_head(ov->repeated_opts);
>>>   }
>> 
>> I checked the remaining uses of ->list_mode, and I think they are okay.
>> 
> Thank you. I also had not noticed any potential issue with the list_mode.

Good :)


      reply	other threads:[~2019-08-06  5:26 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-08-01 18:42 [Qemu-devel] [PATCH v2] make check-unit: use after free in test-opts-visitor Andrey Shinkevich
2019-08-02 11:34 ` Markus Armbruster
2019-08-05 15:09   ` Andrey Shinkevich
2019-08-06  5:25     ` Markus Armbruster [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87mugmsw4y.fsf@dusky.pond.sub.org \
    --to=armbru@redhat.com \
    --cc=andrey.shinkevich@virtuozzo.com \
    --cc=den@virtuozzo.com \
    --cc=mdroth@linux.vnet.ibm.com \
    --cc=qemu-devel@nongnu.org \
    --cc=vsementsov@virtuozzo.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.