Blob Blame History Raw
From 3675a0dde74f890404f392e194f1adc6b24285f7 Mon Sep 17 00:00:00 2001
From: Glauber Costa <glommer@redhat.com>
Date: Wed, 23 Sep 2009 09:49:43 +0100
Subject: [PATCH] Correctly free nd structure

When we "free" a NICInfo structure, we can leak pointers, since we don't do
much more than setting used = 0.

We free() the model parameter, but we don't set it to NULL. This means that
a new user of this structure will see garbage in there. It was not noticed
before because reusing a NICInfo is not that common, but it can be, for
users of device pci hotplug.

A user hit it, described at https://bugzilla.redhat.com/524022

This patch memset's the whole structure, guaranteeing that anyone reusing it
will see a fresh NICinfo. Also, we free some other strings that are currently
leaking.

This codebase is quite old, so this patch should feed all stable trees.

Signed-off-by: Glauber Costa <glommer@redhat.com>
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Fedora-patch: qemu-correctly-free-nic-info-structure.patch
---
 net.c |   16 +++++++++++-----
 net.h |    8 ++++----
 vl.c  |    2 +-
 3 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/net.c b/net.c
index a1c1111..da2f428 100644
--- a/net.c
+++ b/net.c
@@ -2559,7 +2559,7 @@ void qemu_check_nic_model_list(NICInfo *nd, const char * const *models,
     int i, exit_status = 0;
 
     if (!nd->model)
-        nd->model = strdup(default_model);
+        nd->model = qemu_strdup(default_model);
 
     if (strcmp(nd->model, "?") != 0) {
         for (i = 0 ; models[i]; i++)
@@ -2629,6 +2629,7 @@ int net_client_init(Monitor *mon, const char *device, const char *p)
             goto out;
         }
         nd = &nd_table[idx];
+        memset(nd, 0, sizeof(*nd));
         macaddr = nd->macaddr;
         macaddr[0] = 0x52;
         macaddr[1] = 0x54;
@@ -2645,13 +2646,13 @@ int net_client_init(Monitor *mon, const char *device, const char *p)
             }
         }
         if (get_param_value(buf, sizeof(buf), "model", p)) {
-            nd->model = strdup(buf);
+            nd->model = qemu_strdup(buf);
         }
         if (get_param_value(buf, sizeof(buf), "addr", p)) {
-            nd->devaddr = strdup(buf);
+            nd->devaddr = qemu_strdup(buf);
         }
         if (get_param_value(buf, sizeof(buf), "id", p)) {
-            nd->id = strdup(buf);
+            nd->id = qemu_strdup(buf);
         }
         nd->nvectors = NIC_NVECTORS_UNSPECIFIED;
         if (get_param_value(buf, sizeof(buf), "vectors", p)) {
@@ -2998,8 +2999,13 @@ void net_client_uninit(NICInfo *nd)
 {
     nd->vlan->nb_guest_devs--;
     nb_nics--;
+
+    qemu_free(nd->model);
+    qemu_free(nd->name);
+    qemu_free(nd->devaddr);
+    qemu_free(nd->id);
+
     nd->used = 0;
-    free((void *)nd->model);
 }
 
 static int net_host_check_device(const char *device)
diff --git a/net.h b/net.h
index 57ab031..94db0d7 100644
--- a/net.h
+++ b/net.h
@@ -101,10 +101,10 @@ enum {
 
 struct NICInfo {
     uint8_t macaddr[6];
-    const char *model;
-    const char *name;
-    const char *devaddr;
-    const char *id;
+    char *model;
+    char *name;
+    char *devaddr;
+    char *id;
     VLANState *vlan;
     VLANClientState *vc;
     void *private;
diff --git a/vl.c b/vl.c
index 26bced8..d7c7ab1 100644
--- a/vl.c
+++ b/vl.c
@@ -2594,7 +2594,7 @@ static int usb_device_add(const char *devname, int is_hotplug)
 
         if (net_client_init(NULL, "nic", p) < 0)
             return -1;
-        nd_table[nic].model = "usb";
+        nd_table[nic].model = qemu_strdup("usb");
         dev = usb_net_init(&nd_table[nic]);
     } else if (!strcmp(devname, "bt") || strstart(devname, "bt:", &p)) {
         dev = usb_bt_init(devname[2] ? hci_init(p) :
-- 
1.6.2.5