qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PULL v2 05/25] error: add global &error_warn destination


From: Peter Maydell
Subject: Re: [PULL v2 05/25] error: add global &error_warn destination
Date: Thu, 6 Apr 2023 14:16:01 +0100

On Mon, 13 Mar 2023 at 11:47, <marcandre.lureau@redhat.com> wrote:
>
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>
> This can help debugging issues or develop, when error handling is
> introduced.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> Message-Id: <20230221124802.4103554-6-marcandre.lureau@redhat.com>

Hi; Coverity points out that this introduces a use-after-free
(CID 1507493):

> -static void error_handle_fatal(Error **errp, Error *err)
> +static void error_handle(Error **errp, Error *err)
>  {
>      if (errp == &error_abort) {
>          fprintf(stderr, "Unexpected error in %s() at %s:%d:\n",
> @@ -43,6 +44,9 @@ static void error_handle_fatal(Error **errp, Error *err)
>          error_report_err(err);
>          exit(1);
>      }
> +    if (errp == &error_warn) {
> +        warn_report_err(err);
> +    }
>  }

The old error_handle_fatal() either:
 * did not return
 * or it left the passed in 'err' alone

The new error_handle() introduces a new case, which
calls warn_report_err() and returns. warn_report_err()
prints the error and frees 'err'. Neither of the callsites
seems to expect the possibility "error_handle() returned
but 'err' is no longer valid":

>  G_GNUC_PRINTF(6, 0)
> @@ -71,7 +75,7 @@ static void error_setv(Error **errp,
>      err->line = line;
>      err->func = func;
>
> -    error_handle_fatal(errp, err);
> +    error_handle(errp, err);
>      *errp = err;

Here we stuff the now-invalid pointer into *errp
(ie into the global local_error). Probably harmless
but definitely rather odd.

>      errno = saved_errno;
> @@ -284,7 +288,7 @@ void error_propagate(Error **dst_errp, Error *local_err)
>      if (!local_err) {
>          return;
>      }
> -    error_handle_fatal(dst_errp, local_err);
> +    error_handle(dst_errp, local_err);
>      if (dst_errp && !*dst_errp) {
>          *dst_errp = local_err;
>      } else {

Here, if error_warn happens to be NULL then we'll
stuff the freed pointer into it. But if error_warn
is not NULL (eg because we've already had one use of
it) then the 'else' clause here does an error_free(local_err),
which is a double-free.

thanks
-- PMM



reply via email to

[Prev in Thread] Current Thread [Next in Thread]