Re: [PATCH v5 3/5] migration: process_incoming_migration_co(): fix reporting s->error

2024-04-30 Thread Vladimir Sementsov-Ogievskiy

On 30.04.24 11:09, Vladimir Sementsov-Ogievskiy wrote:

On 30.04.24 11:06, Vladimir Sementsov-Ogievskiy wrote:

On 29.04.24 22:32, Peter Xu wrote:

On Mon, Apr 29, 2024 at 10:14:24PM +0300, Vladimir Sementsov-Ogievskiy wrote:

It's bad idea to leave critical section with error object freed, but
s->error still set, this theoretically may lead to use-after-free
crash. Let's avoid it.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
  migration/migration.c | 24 
  1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/migration/migration.c b/migration/migration.c
index 0d26db47f7..58fd5819bc 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -732,9 +732,19 @@ static void process_incoming_migration_bh(void *opaque)
  migration_incoming_state_destroy();
  }
+static void migrate_error_free(MigrationState *s)
+{
+    QEMU_LOCK_GUARD(&s->error_mutex);
+    if (s->error) {
+    error_free(s->error);
+    s->error = NULL;
+    }
+}
+
  static void coroutine_fn
  process_incoming_migration_co(void *opaque)
  {
+    MigrationState *s = migrate_get_current();
  MigrationIncomingState *mis = migration_incoming_get_current();
  PostcopyState ps;
  int ret;
@@ -779,11 +789,9 @@ process_incoming_migration_co(void *opaque)
  }
  if (ret < 0) {
-    MigrationState *s = migrate_get_current();
-
  if (migrate_has_error(s)) {
  WITH_QEMU_LOCK_GUARD(&s->error_mutex) {
-    error_report_err(s->error);
+    error_report_err(error_copy(s->error));


This looks like a bugfix, agreed.


  }
  }
  error_report("load of migration failed: %s", strerror(-ret));
@@ -801,6 +809,7 @@ fail:
    MIGRATION_STATUS_FAILED);
  migration_incoming_state_destroy();
+    migrate_error_free(s);


Would migration_incoming_state_destroy() be a better place?


Hmm. But we want to call migration_incoming_state_destroy() in case when 
exit-on-error=false too. And in this case we want to keep the error for further 
query-migrate commands.


Actually, I think we shouldn't care about freeing the error for exit() case. I 
think, we skip a lot of other cleanups which we normally do in main() in case 
of this exit().



Or, just do the simplest fix of potential use-after-free, and don't care:

WITH_QEMU_LOCK_GUARD(&s->error_mutex) {
   error_report_err(s->error);
   s->error = NULL;
}

- I'll send v6 with it.





One thing weird is we actually reuses MigrationState*'s error for incoming
too, but so far it looks ok as long as QEMU can't be both src & dst.  Then
calling migrate_error_free even in incoming_state_destroy() looks ok.

This patch still looks like containing two changes.  Better split them (or
just fix the bug only)?

Thanks,


  exit(EXIT_FAILURE);
  }
@@ -1433,15 +1442,6 @@ bool migrate_has_error(MigrationState *s)
  return qatomic_read(&s->error);
  }
-static void migrate_error_free(MigrationState *s)
-{
-    QEMU_LOCK_GUARD(&s->error_mutex);
-    if (s->error) {
-    error_free(s->error);
-    s->error = NULL;
-    }
-}
-
  static void migrate_fd_error(MigrationState *s, const Error *error)
  {
  assert(s->to_dst_file == NULL);
--
2.34.1









--
Best regards,
Vladimir




Re: [PATCH v5 3/5] migration: process_incoming_migration_co(): fix reporting s->error

2024-04-30 Thread Vladimir Sementsov-Ogievskiy

On 30.04.24 11:06, Vladimir Sementsov-Ogievskiy wrote:

On 29.04.24 22:32, Peter Xu wrote:

On Mon, Apr 29, 2024 at 10:14:24PM +0300, Vladimir Sementsov-Ogievskiy wrote:

It's bad idea to leave critical section with error object freed, but
s->error still set, this theoretically may lead to use-after-free
crash. Let's avoid it.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
  migration/migration.c | 24 
  1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/migration/migration.c b/migration/migration.c
index 0d26db47f7..58fd5819bc 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -732,9 +732,19 @@ static void process_incoming_migration_bh(void *opaque)
  migration_incoming_state_destroy();
  }
+static void migrate_error_free(MigrationState *s)
+{
+    QEMU_LOCK_GUARD(&s->error_mutex);
+    if (s->error) {
+    error_free(s->error);
+    s->error = NULL;
+    }
+}
+
  static void coroutine_fn
  process_incoming_migration_co(void *opaque)
  {
+    MigrationState *s = migrate_get_current();
  MigrationIncomingState *mis = migration_incoming_get_current();
  PostcopyState ps;
  int ret;
@@ -779,11 +789,9 @@ process_incoming_migration_co(void *opaque)
  }
  if (ret < 0) {
-    MigrationState *s = migrate_get_current();
-
  if (migrate_has_error(s)) {
  WITH_QEMU_LOCK_GUARD(&s->error_mutex) {
-    error_report_err(s->error);
+    error_report_err(error_copy(s->error));


This looks like a bugfix, agreed.


  }
  }
  error_report("load of migration failed: %s", strerror(-ret));
@@ -801,6 +809,7 @@ fail:
    MIGRATION_STATUS_FAILED);
  migration_incoming_state_destroy();
+    migrate_error_free(s);


Would migration_incoming_state_destroy() be a better place?


Hmm. But we want to call migration_incoming_state_destroy() in case when 
exit-on-error=false too. And in this case we want to keep the error for further 
query-migrate commands.


Actually, I think we shouldn't care about freeing the error for exit() case. I 
think, we skip a lot of other cleanups which we normally do in main() in case 
of this exit().





One thing weird is we actually reuses MigrationState*'s error for incoming
too, but so far it looks ok as long as QEMU can't be both src & dst.  Then
calling migrate_error_free even in incoming_state_destroy() looks ok.

This patch still looks like containing two changes.  Better split them (or
just fix the bug only)?

Thanks,


  exit(EXIT_FAILURE);
  }
@@ -1433,15 +1442,6 @@ bool migrate_has_error(MigrationState *s)
  return qatomic_read(&s->error);
  }
-static void migrate_error_free(MigrationState *s)
-{
-    QEMU_LOCK_GUARD(&s->error_mutex);
-    if (s->error) {
-    error_free(s->error);
-    s->error = NULL;
-    }
-}
-
  static void migrate_fd_error(MigrationState *s, const Error *error)
  {
  assert(s->to_dst_file == NULL);
--
2.34.1







--
Best regards,
Vladimir




Re: [PATCH v5 3/5] migration: process_incoming_migration_co(): fix reporting s->error

2024-04-30 Thread Vladimir Sementsov-Ogievskiy

On 29.04.24 22:32, Peter Xu wrote:

On Mon, Apr 29, 2024 at 10:14:24PM +0300, Vladimir Sementsov-Ogievskiy wrote:

It's bad idea to leave critical section with error object freed, but
s->error still set, this theoretically may lead to use-after-free
crash. Let's avoid it.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
  migration/migration.c | 24 
  1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/migration/migration.c b/migration/migration.c
index 0d26db47f7..58fd5819bc 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -732,9 +732,19 @@ static void process_incoming_migration_bh(void *opaque)
  migration_incoming_state_destroy();
  }
  
+static void migrate_error_free(MigrationState *s)

+{
+QEMU_LOCK_GUARD(&s->error_mutex);
+if (s->error) {
+error_free(s->error);
+s->error = NULL;
+}
+}
+
  static void coroutine_fn
  process_incoming_migration_co(void *opaque)
  {
+MigrationState *s = migrate_get_current();
  MigrationIncomingState *mis = migration_incoming_get_current();
  PostcopyState ps;
  int ret;
@@ -779,11 +789,9 @@ process_incoming_migration_co(void *opaque)
  }
  
  if (ret < 0) {

-MigrationState *s = migrate_get_current();
-
  if (migrate_has_error(s)) {
  WITH_QEMU_LOCK_GUARD(&s->error_mutex) {
-error_report_err(s->error);
+error_report_err(error_copy(s->error));


This looks like a bugfix, agreed.


  }
  }
  error_report("load of migration failed: %s", strerror(-ret));
@@ -801,6 +809,7 @@ fail:
MIGRATION_STATUS_FAILED);
  migration_incoming_state_destroy();
  
+migrate_error_free(s);


Would migration_incoming_state_destroy() be a better place?


Hmm. But we want to call migration_incoming_state_destroy() in case when 
exit-on-error=false too. And in this case we want to keep the error for further 
query-migrate commands.



One thing weird is we actually reuses MigrationState*'s error for incoming
too, but so far it looks ok as long as QEMU can't be both src & dst.  Then
calling migrate_error_free even in incoming_state_destroy() looks ok.

This patch still looks like containing two changes.  Better split them (or
just fix the bug only)?

Thanks,


  exit(EXIT_FAILURE);
  }
  
@@ -1433,15 +1442,6 @@ bool migrate_has_error(MigrationState *s)

  return qatomic_read(&s->error);
  }
  
-static void migrate_error_free(MigrationState *s)

-{
-QEMU_LOCK_GUARD(&s->error_mutex);
-if (s->error) {
-error_free(s->error);
-s->error = NULL;
-}
-}
-
  static void migrate_fd_error(MigrationState *s, const Error *error)
  {
  assert(s->to_dst_file == NULL);
--
2.34.1





--
Best regards,
Vladimir




Re: [PATCH v5 3/5] migration: process_incoming_migration_co(): fix reporting s->error

2024-04-29 Thread Peter Xu
On Mon, Apr 29, 2024 at 10:14:24PM +0300, Vladimir Sementsov-Ogievskiy wrote:
> It's bad idea to leave critical section with error object freed, but
> s->error still set, this theoretically may lead to use-after-free
> crash. Let's avoid it.
> 
> Signed-off-by: Vladimir Sementsov-Ogievskiy 
> ---
>  migration/migration.c | 24 
>  1 file changed, 12 insertions(+), 12 deletions(-)
> 
> diff --git a/migration/migration.c b/migration/migration.c
> index 0d26db47f7..58fd5819bc 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -732,9 +732,19 @@ static void process_incoming_migration_bh(void *opaque)
>  migration_incoming_state_destroy();
>  }
>  
> +static void migrate_error_free(MigrationState *s)
> +{
> +QEMU_LOCK_GUARD(&s->error_mutex);
> +if (s->error) {
> +error_free(s->error);
> +s->error = NULL;
> +}
> +}
> +
>  static void coroutine_fn
>  process_incoming_migration_co(void *opaque)
>  {
> +MigrationState *s = migrate_get_current();
>  MigrationIncomingState *mis = migration_incoming_get_current();
>  PostcopyState ps;
>  int ret;
> @@ -779,11 +789,9 @@ process_incoming_migration_co(void *opaque)
>  }
>  
>  if (ret < 0) {
> -MigrationState *s = migrate_get_current();
> -
>  if (migrate_has_error(s)) {
>  WITH_QEMU_LOCK_GUARD(&s->error_mutex) {
> -error_report_err(s->error);
> +error_report_err(error_copy(s->error));

This looks like a bugfix, agreed.

>  }
>  }
>  error_report("load of migration failed: %s", strerror(-ret));
> @@ -801,6 +809,7 @@ fail:
>MIGRATION_STATUS_FAILED);
>  migration_incoming_state_destroy();
>  
> +migrate_error_free(s);

Would migration_incoming_state_destroy() be a better place?

One thing weird is we actually reuses MigrationState*'s error for incoming
too, but so far it looks ok as long as QEMU can't be both src & dst.  Then
calling migrate_error_free even in incoming_state_destroy() looks ok.

This patch still looks like containing two changes.  Better split them (or
just fix the bug only)?

Thanks,

>  exit(EXIT_FAILURE);
>  }
>  
> @@ -1433,15 +1442,6 @@ bool migrate_has_error(MigrationState *s)
>  return qatomic_read(&s->error);
>  }
>  
> -static void migrate_error_free(MigrationState *s)
> -{
> -QEMU_LOCK_GUARD(&s->error_mutex);
> -if (s->error) {
> -error_free(s->error);
> -s->error = NULL;
> -}
> -}
> -
>  static void migrate_fd_error(MigrationState *s, const Error *error)
>  {
>  assert(s->to_dst_file == NULL);
> -- 
> 2.34.1
> 

-- 
Peter Xu