[PATCH 1/1] drivers/vga: check decodes for vgaarb lock/unlock

From: Li, Zhen-Hua
Date: Mon Oct 28 2013 - 03:33:40 EST


There is a bug that X windows system may use an invalid decodes iostat
on the VGA Arbiter device when lock and unlock. this may cause system
crash. So we must validate the value of iostat.

Signed-off-by: Li, Zhen-Hua <zhen-hual@xxxxxx>
---
drivers/gpu/vga/vgaarb.c | 55 ++++++++++++++++++++++++++++++++----------------
1 file changed, 37 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c
index af02597..4772367 100644
--- a/drivers/gpu/vga/vgaarb.c
+++ b/drivers/gpu/vga/vgaarb.c
@@ -906,8 +906,9 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
struct vga_arb_private *priv = file->private_data;
struct vga_arb_user_card *uc = NULL;
struct pci_dev *pdev;
+ struct vga_device *vgadev = NULL;

- unsigned int io_state;
+ unsigned int io_state = 0;

char *kbuf, *curr_pos;
size_t remaining = count;
@@ -927,6 +928,19 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
curr_pos = kbuf;
kbuf[count] = '\0'; /* Just to make sure... */

+ pdev = priv->target;
+ if (priv->target == NULL) {
+ pr_debug("No device found");
+ ret_val = -ENODEV;
+ goto done;
+ }
+ vgadev = vgadev_find(pdev);
+ if (vgadev == NULL) {
+ pr_debug("Could not find vga device for %s", pci_name(pdev));
+ ret_val = -ENODEV;
+ goto done;
+ }
+
if (strncmp(curr_pos, "lock ", 5) == 0) {
curr_pos += 5;
remaining -= 5;
@@ -937,14 +951,15 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
ret_val = -EPROTO;
goto done;
}
- if (io_state == VGA_RSRC_NONE) {
+ if ((vgadev->owns & io_state) != io_state) {
+ pr_debug("iostate (%x and %x ) do not match",
+ io_state, vgadev->owns);
+
ret_val = -EPROTO;
goto done;
}
-
- pdev = priv->target;
- if (priv->target == NULL) {
- ret_val = -ENODEV;
+ if (io_state == VGA_RSRC_NONE) {
+ ret_val = -EPROTO;
goto done;
}

@@ -969,14 +984,21 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,

pr_debug("client 0x%p called 'unlock'\n", priv);

- if (strncmp(curr_pos, "all", 3) == 0)
+ if (strncmp(curr_pos, "all", 3) == 0) {
io_state = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM;
- else {
+ } else {
if (!vga_str_to_iostate
(curr_pos, remaining, &io_state)) {
ret_val = -EPROTO;
goto done;
}
+ if ((vgadev->owns & io_state) != io_state) {
+ pr_debug("iostate (%x and %x ) do not match",
+ io_state, vgadev->owns);
+
+ ret_val = -EPROTO;
+ goto done;
+ }
/* TODO: Add this?
if (io_state == VGA_RSRC_NONE) {
ret_val = -EPROTO;
@@ -985,11 +1007,6 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
*/
}

- pdev = priv->target;
- if (priv->target == NULL) {
- ret_val = -ENODEV;
- goto done;
- }
for (i = 0; i < MAX_USER_CARDS; i++) {
if (priv->cards[i].pdev == pdev)
uc = &priv->cards[i];
@@ -1029,6 +1046,13 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
ret_val = -EPROTO;
goto done;
}
+ if ((vgadev->owns & io_state) != io_state) {
+ pr_debug("iostate (%x and %x ) do not match",
+ io_state, vgadev->owns);
+
+ ret_val = -EPROTO;
+ goto done;
+ }
/* TODO: Add this?
if (io_state == VGA_RSRC_NONE) {
ret_val = -EPROTO;
@@ -1036,11 +1060,6 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
}
*/

- pdev = priv->target;
- if (priv->target == NULL) {
- ret_val = -ENODEV;
- goto done;
- }

if (vga_tryget(pdev, io_state)) {
/* Update the client's locks lists... */
--
1.8.4.rc3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/