Skip to content

Commit

Permalink
drm: fix leak of uninitialized data to userspace
Browse files Browse the repository at this point in the history
...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>
  • Loading branch information
Vegard Nossum authored and Dave Airlie committed Dec 29, 2008
1 parent 7c1c287 commit 1147c9c
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 4 deletions.
10 changes: 7 additions & 3 deletions drivers/gpu/drm/drm_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ int drm_setunique(struct drm_device *dev, void *data,
return -EINVAL;

master->unique_len = u->unique_len;
master->unique = drm_alloc(u->unique_len + 1, DRM_MEM_DRIVER);
master->unique_size = u->unique_len + 1;
master->unique = drm_alloc(master->unique_size, DRM_MEM_DRIVER);
if (!master->unique)
return -ENOMEM;
if (copy_from_user(master->unique, u->unique, master->unique_len))
Expand Down Expand Up @@ -136,7 +137,8 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
return -EBUSY;

master->unique_len = 40;
master->unique = drm_alloc(master->unique_len + 1, DRM_MEM_DRIVER);
master->unique_size = master->unique_len;
master->unique = drm_alloc(master->unique_size, DRM_MEM_DRIVER);
if (master->unique == NULL)
return -ENOMEM;

Expand All @@ -145,8 +147,10 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
dev->pdev->bus->number,
PCI_SLOT(dev->pdev->devfn),
PCI_FUNC(dev->pdev->devfn));
if (len > master->unique_len)
if (len >= master->unique_len)
DRM_ERROR("buffer overflow");
else
master->unique_len = len;

dev->devname =
drm_alloc(strlen(dev->driver->pci_driver.name) + master->unique_len +
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/drm_stub.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ static void drm_master_destroy(struct kref *kref)
dev->driver->master_destroy(dev, master);

if (master->unique) {
drm_free(master->unique, strlen(master->unique) + 1, DRM_MEM_DRIVER);
drm_free(master->unique, master->unique_size, DRM_MEM_DRIVER);
master->unique = NULL;
master->unique_len = 0;
}
Expand Down
1 change: 1 addition & 0 deletions include/drm/drmP.h
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,7 @@ struct drm_master {

char *unique; /**< Unique identifier: e.g., busid */
int unique_len; /**< Length of unique field */
int unique_size; /**< amount allocated */

int blocked; /**< Blocked due to VC switch? */

Expand Down

0 comments on commit 1147c9c

Please sign in to comment.