diff mbox series

[v4] migration: Plug memory leak with migration URIs

Message ID 20231129204301.131228-1-het.gala@nutanix.com (mailing list archive)
State New, archived
Headers show
Series [v4] migration: Plug memory leak with migration URIs | expand

Commit Message

Het Gala Nov. 29, 2023, 8:43 p.m. UTC
migrate_uri_parse() allocates memory to 'channel' if the user
opts for old syntax - uri, which is leaked because there is no
code for freeing 'channel'.
So, free channel to avoid memory leak in case where 'channels'
is empty and uri parsing is required.

Fixes: 5994024f ("migration: Implement MigrateChannelList to qmp migration flow")
Signed-off-by: Het Gala <het.gala@nutanix.com>
Suggested-by: Markus Armbruster <armbru@redhat.com>
---
 migration/migration.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

Comments

Markus Armbruster Nov. 30, 2023, 7:21 a.m. UTC | #1
Het Gala <het.gala@nutanix.com> writes:

> migrate_uri_parse() allocates memory to 'channel' if the user
> opts for old syntax - uri, which is leaked because there is no
> code for freeing 'channel'.
> So, free channel to avoid memory leak in case where 'channels'
> is empty and uri parsing is required.
>
> Fixes: 5994024f ("migration: Implement MigrateChannelList to qmp migration flow")
> Signed-off-by: Het Gala <het.gala@nutanix.com>
> Suggested-by: Markus Armbruster <armbru@redhat.com>

Tested-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Peter Xu Nov. 30, 2023, 5:29 p.m. UTC | #2
On Wed, Nov 29, 2023 at 08:43:01PM +0000, Het Gala wrote:
> migrate_uri_parse() allocates memory to 'channel' if the user
> opts for old syntax - uri, which is leaked because there is no
> code for freeing 'channel'.
> So, free channel to avoid memory leak in case where 'channels'
> is empty and uri parsing is required.
> 
> Fixes: 5994024f ("migration: Implement MigrateChannelList to qmp migration flow")
> Signed-off-by: Het Gala <het.gala@nutanix.com>
> Suggested-by: Markus Armbruster <armbru@redhat.com>

Reviewed-by: Peter Xu <peterx@redhat.com>

> @@ -533,18 +533,18 @@ static void qemu_start_incoming_migration(const char *uri, bool has_channels,
>              error_setg(errp, "Channel list has more than one entries");
>              return;
>          }
> -        channel = channels->value;
> +        addr = channels->value->addr;
>      } else if (uri) {
>          /* caller uses the old URI syntax */
>          if (!migrate_uri_parse(uri, &channel, errp)) {
>              return;
>          }
> +        addr = channel->addr;
>      } else {
>          error_setg(errp, "neither 'uri' or 'channels' argument are "
>                     "specified in 'migrate-incoming' qmp command ");
>          return;
>      }
> -    addr = channel->addr;

Why these "addr" lines need change?  Won't that behave the same as before?

Thanks,
Markus Armbruster Nov. 30, 2023, 6:35 p.m. UTC | #3
Peter Xu <peterx@redhat.com> writes:

> On Wed, Nov 29, 2023 at 08:43:01PM +0000, Het Gala wrote:
>> migrate_uri_parse() allocates memory to 'channel' if the user
>> opts for old syntax - uri, which is leaked because there is no
>> code for freeing 'channel'.
>> So, free channel to avoid memory leak in case where 'channels'
>> is empty and uri parsing is required.
>> 
>> Fixes: 5994024f ("migration: Implement MigrateChannelList to qmp migration flow")
>> Signed-off-by: Het Gala <het.gala@nutanix.com>
>> Suggested-by: Markus Armbruster <armbru@redhat.com>
>
> Reviewed-by: Peter Xu <peterx@redhat.com>
>
>> @@ -533,18 +533,18 @@ static void qemu_start_incoming_migration(const char *uri, bool has_channels,
>>              error_setg(errp, "Channel list has more than one entries");
>>              return;
>>          }
>> -        channel = channels->value;
>> +        addr = channels->value->addr;
>>      } else if (uri) {
>>          /* caller uses the old URI syntax */
>>          if (!migrate_uri_parse(uri, &channel, errp)) {
>>              return;
>>          }
>> +        addr = channel->addr;
>>      } else {
>>          error_setg(errp, "neither 'uri' or 'channels' argument are "
>>                     "specified in 'migrate-incoming' qmp command ");
>>          return;
>>      }
>> -    addr = channel->addr;
>
> Why these "addr" lines need change?  Won't that behave the same as before?

In the first case, @channel is now null.  If we left the assignment to
@addr alone, it would crash.  Clearer now?
Peter Xu Nov. 30, 2023, 7:16 p.m. UTC | #4
On Thu, Nov 30, 2023 at 07:35:43PM +0100, Markus Armbruster wrote:
> Peter Xu <peterx@redhat.com> writes:
> 
> > On Wed, Nov 29, 2023 at 08:43:01PM +0000, Het Gala wrote:
> >> migrate_uri_parse() allocates memory to 'channel' if the user
> >> opts for old syntax - uri, which is leaked because there is no
> >> code for freeing 'channel'.
> >> So, free channel to avoid memory leak in case where 'channels'
> >> is empty and uri parsing is required.
> >> 
> >> Fixes: 5994024f ("migration: Implement MigrateChannelList to qmp migration flow")
> >> Signed-off-by: Het Gala <het.gala@nutanix.com>
> >> Suggested-by: Markus Armbruster <armbru@redhat.com>
> >
> > Reviewed-by: Peter Xu <peterx@redhat.com>
> >
> >> @@ -533,18 +533,18 @@ static void qemu_start_incoming_migration(const char *uri, bool has_channels,
> >>              error_setg(errp, "Channel list has more than one entries");
> >>              return;
> >>          }
> >> -        channel = channels->value;
> >> +        addr = channels->value->addr;
> >>      } else if (uri) {
> >>          /* caller uses the old URI syntax */
> >>          if (!migrate_uri_parse(uri, &channel, errp)) {
> >>              return;
> >>          }
> >> +        addr = channel->addr;
> >>      } else {
> >>          error_setg(errp, "neither 'uri' or 'channels' argument are "
> >>                     "specified in 'migrate-incoming' qmp command ");
> >>          return;
> >>      }
> >> -    addr = channel->addr;
> >
> > Why these "addr" lines need change?  Won't that behave the same as before?
> 
> In the first case, @channel is now null.  If we left the assignment to
> @addr alone, it would crash.  Clearer now?

Is it this one?

    if (uri && has_channels) {
        error_setg(errp, "'uri' and 'channels' arguments are mutually "
                   "exclusive; exactly one of the two should be present in "
                   "'migrate-incoming' qmp command ");
        return;
    }

It returns already?

Thanks,
Markus Armbruster Dec. 1, 2023, 6:19 a.m. UTC | #5
Peter Xu <peterx@redhat.com> writes:

> On Thu, Nov 30, 2023 at 07:35:43PM +0100, Markus Armbruster wrote:
>> Peter Xu <peterx@redhat.com> writes:
>> 
>> > On Wed, Nov 29, 2023 at 08:43:01PM +0000, Het Gala wrote:
>> >> migrate_uri_parse() allocates memory to 'channel' if the user
>> >> opts for old syntax - uri, which is leaked because there is no
>> >> code for freeing 'channel'.
>> >> So, free channel to avoid memory leak in case where 'channels'
>> >> is empty and uri parsing is required.
>> >> 
>> >> Fixes: 5994024f ("migration: Implement MigrateChannelList to qmp migration flow")
>> >> Signed-off-by: Het Gala <het.gala@nutanix.com>
>> >> Suggested-by: Markus Armbruster <armbru@redhat.com>
>> >
>> > Reviewed-by: Peter Xu <peterx@redhat.com>
>> >
>> >> @@ -533,18 +533,18 @@ static void qemu_start_incoming_migration(const char *uri, bool has_channels,
      -    MigrationChannel *channel = NULL;
      +    g_autoptr(MigrationChannel) channel = NULL;
           MigrationAddress *addr = NULL;
           MigrationIncomingState *mis = migration_incoming_get_current();

           /*
            * Having preliminary checks for uri and channel
            */
           if (uri && has_channels) {
               error_setg(errp, "'uri' and 'channels' arguments are mutually "
                          "exclusive; exactly one of the two should be present in "
                          "'migrate-incoming' qmp command ");
               return;
           } else if (channels) {
               /* To verify that Migrate channel list has only item */
               if (channels->next) {
>> >>              error_setg(errp, "Channel list has more than one entries");
>> >>              return;
>> >>          }
>> >> -        channel = channels->value;
>> >> +        addr = channels->value->addr;
>> >>      } else if (uri) {
>> >>          /* caller uses the old URI syntax */
>> >>          if (!migrate_uri_parse(uri, &channel, errp)) {
>> >>              return;
>> >>          }
>> >> +        addr = channel->addr;
>> >>      } else {
>> >>          error_setg(errp, "neither 'uri' or 'channels' argument are "
>> >>                     "specified in 'migrate-incoming' qmp command ");
>> >>          return;
>> >>      }
>> >> -    addr = channel->addr;
>> >
>> > Why these "addr" lines need change?  Won't that behave the same as before?
>> 
>> In the first case, @channel is now null.  If we left the assignment to
>> @addr alone, it would crash.  Clearer now?
>
> Is it this one?
>
>     if (uri && has_channels) {
>         error_setg(errp, "'uri' and 'channels' arguments are mutually "
>                    "exclusive; exactly one of the two should be present in "
>                    "'migrate-incoming' qmp command ");
>         return;
>     }
>
> It returns already?

I meant the first visible case, i.e. if (channels).  Sorry for being
less than clear!

The problem is to free the result of migrate_uri_parse().

The patch's solution is to use @channel *only* for holding that result,
so it can be g_autoptr: drop channel = channels->value from the if
(channels) conditional.

Since this breaks addr = channel->addr, we move that assignment into the
conditionals that reach it, which lets us unbreak it the if (channels)
one.
Peter Xu Dec. 1, 2023, 3:29 p.m. UTC | #6
On Fri, Dec 01, 2023 at 07:19:45AM +0100, Markus Armbruster wrote:
> I meant the first visible case, i.e. if (channels).  Sorry for being
> less than clear!
> 
> The problem is to free the result of migrate_uri_parse().
> 
> The patch's solution is to use @channel *only* for holding that result,
> so it can be g_autoptr: drop channel = channels->value from the if
> (channels) conditional.
> 
> Since this breaks addr = channel->addr, we move that assignment into the
> conditionals that reach it, which lets us unbreak it the if (channels)
> one.

My bad!  It also proved that my R-b was bold. :(  Thanks, Markus.
Since Juan's away, I'll prepare a pull.
diff mbox series

Patch

diff --git a/migration/migration.c b/migration/migration.c
index 28a34c9068..34340f3440 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -515,7 +515,7 @@  static void qemu_start_incoming_migration(const char *uri, bool has_channels,
                                           MigrationChannelList *channels,
                                           Error **errp)
 {
-    MigrationChannel *channel = NULL;
+    g_autoptr(MigrationChannel) channel = NULL;
     MigrationAddress *addr = NULL;
     MigrationIncomingState *mis = migration_incoming_get_current();
 
@@ -533,18 +533,18 @@  static void qemu_start_incoming_migration(const char *uri, bool has_channels,
             error_setg(errp, "Channel list has more than one entries");
             return;
         }
-        channel = channels->value;
+        addr = channels->value->addr;
     } else if (uri) {
         /* caller uses the old URI syntax */
         if (!migrate_uri_parse(uri, &channel, errp)) {
             return;
         }
+        addr = channel->addr;
     } else {
         error_setg(errp, "neither 'uri' or 'channels' argument are "
                    "specified in 'migrate-incoming' qmp command ");
         return;
     }
-    addr = channel->addr;
 
     /* transport mechanism not suitable for migration? */
     if (!migration_channels_and_transport_compatible(addr, errp)) {
@@ -1932,7 +1932,7 @@  void qmp_migrate(const char *uri, bool has_channels,
     bool resume_requested;
     Error *local_err = NULL;
     MigrationState *s = migrate_get_current();
-    MigrationChannel *channel = NULL;
+    g_autoptr(MigrationChannel) channel = NULL;
     MigrationAddress *addr = NULL;
 
     /*
@@ -1949,18 +1949,18 @@  void qmp_migrate(const char *uri, bool has_channels,
             error_setg(errp, "Channel list has more than one entries");
             return;
         }
-        channel = channels->value;
+        addr = channels->value->addr;
     } else if (uri) {
         /* caller uses the old URI syntax */
         if (!migrate_uri_parse(uri, &channel, errp)) {
             return;
         }
+        addr = channel->addr;
     } else {
         error_setg(errp, "neither 'uri' or 'channels' argument are "
                    "specified in 'migrate' qmp command ");
         return;
     }
-    addr = channel->addr;
 
     /* transport mechanism not suitable for migration? */
     if (!migration_channels_and_transport_compatible(addr, errp)) {