aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVegard Nossum <vegard.nossum@gmail.com>2008-12-01 22:38:47 -0500
committerDave Airlie <airlied@linux.ie>2008-12-29 02:47:22 -0500
commit1147c9cdd0f60f09a98702a9f865176af18a989f (patch)
tree4f3c33102566475cd145cf0235c1738d07b8b715
parent7c1c2871a6a3a114853ec6836e9035ac1c0c7f7a (diff)
drm: fix leak of uninitialized data to userspace
...so drm_getunique() is trying to copy some uninitialized data to userspace. The ECX register contains the number of words that are left to copy -- so there are 5 * 4 = 20 bytes left. The offset of the first uninitialized byte (counting from the start of the string) is also 20 (i.e. 0xf65d2294&((1 << 5)-1) == 20). So somebody tried to copy 40 bytes when the string was only 19 long. In drm_set_busid() we have this code: dev->unique_len = 40; dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER); ... len = snprintf(dev->unique, dev->unique_len, pci:%04x:%02x:%02x.%d", ...so it seems that dev->unique is never updated to reflect the actual length of the string. The remaining bytes (20 in this case) are random uninitialized bytes that are copied into userspace. This patch fixes the problem by setting dev->unique_len after the snprintf(). airlied- I've had to fix this up to store the alloced size so we have it for drm_free later. Reported-by: Sitsofe Wheeler <sitsofe@yahoo.com> Signed-off-by: Vegard Nossum <vegardno@thuin.ifi.uio.no> Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/drm_ioctl.c10
-rw-r--r--drivers/gpu/drm/drm_stub.c2
-rw-r--r--include/drm/drmP.h1
3 files changed, 9 insertions, 4 deletions
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index e35126a35093..1fad76289e66 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -92,7 +92,8 @@ int drm_setunique(struct drm_device *dev, void *data,
92 return -EINVAL; 92 return -EINVAL;
93 93
94 master->unique_len = u->unique_len; 94 master->unique_len = u->unique_len;
95 master->unique = drm_alloc(u->unique_len + 1, DRM_MEM_DRIVER); 95 master->unique_size = u->unique_len + 1;
96 master->unique = drm_alloc(master->unique_size, DRM_MEM_DRIVER);
96 if (!master->unique) 97 if (!master->unique)
97 return -ENOMEM; 98 return -ENOMEM;
98 if (copy_from_user(master->unique, u->unique, master->unique_len)) 99 if (copy_from_user(master->unique, u->unique, master->unique_len))
@@ -136,7 +137,8 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
136 return -EBUSY; 137 return -EBUSY;
137 138
138 master->unique_len = 40; 139 master->unique_len = 40;
139 master->unique = drm_alloc(master->unique_len + 1, DRM_MEM_DRIVER); 140 master->unique_size = master->unique_len;
141 master->unique = drm_alloc(master->unique_size, DRM_MEM_DRIVER);
140 if (master->unique == NULL) 142 if (master->unique == NULL)
141 return -ENOMEM; 143 return -ENOMEM;
142 144
@@ -145,8 +147,10 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
145 dev->pdev->bus->number, 147 dev->pdev->bus->number,
146 PCI_SLOT(dev->pdev->devfn), 148 PCI_SLOT(dev->pdev->devfn),
147 PCI_FUNC(dev->pdev->devfn)); 149 PCI_FUNC(dev->pdev->devfn));
148 if (len > master->unique_len) 150 if (len >= master->unique_len)
149 DRM_ERROR("buffer overflow"); 151 DRM_ERROR("buffer overflow");
152 else
153 master->unique_len = len;
150 154
151 dev->devname = 155 dev->devname =
152 drm_alloc(strlen(dev->driver->pci_driver.name) + master->unique_len + 156 drm_alloc(strlen(dev->driver->pci_driver.name) + master->unique_len +
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
index 0f24c2dcd517..f7985c303cb0 100644
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -117,7 +117,7 @@ static void drm_master_destroy(struct kref *kref)
117 dev->driver->master_destroy(dev, master); 117 dev->driver->master_destroy(dev, master);
118 118
119 if (master->unique) { 119 if (master->unique) {
120 drm_free(master->unique, strlen(master->unique) + 1, DRM_MEM_DRIVER); 120 drm_free(master->unique, master->unique_size, DRM_MEM_DRIVER);
121 master->unique = NULL; 121 master->unique = NULL;
122 master->unique_len = 0; 122 master->unique_len = 0;
123 } 123 }
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 4c6e8298b424..c9cc618dbcfc 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -627,6 +627,7 @@ struct drm_master {
627 627
628 char *unique; /**< Unique identifier: e.g., busid */ 628 char *unique; /**< Unique identifier: e.g., busid */
629 int unique_len; /**< Length of unique field */ 629 int unique_len; /**< Length of unique field */
630 int unique_size; /**< amount allocated */
630 631
631 int blocked; /**< Blocked due to VC switch? */ 632 int blocked; /**< Blocked due to VC switch? */
632 633