From: Junrui Luo <[email protected]>

The uninorth_insert_memory and uninorth_remove_memory functions lack
proper validation of the pg_start parameter before using it as an array
index into the GATT (Graphics Address Translation Table).

The current bounds check fails to reject negative
pg_start values and potentially causes out-of-bounds writes.

Fix by explicitly checking that pg_start is non-negative before
performing bounds checking. This makes the security requirement clear
and does not rely on implicit type conversion behavior.

The uninorth_remove_memory function has no bounds checking at all, so
add the same validation there.

Reported-by: Yuhao Jiang <[email protected]>
Reported-by: Junrui Luo <[email protected]>
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: [email protected]
Signed-off-by: Junrui Luo <[email protected]>
---
 drivers/char/agp/uninorth-agp.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index b8d7115b8c9e..4e0b949016f7 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -169,7 +169,9 @@ static int uninorth_insert_memory(struct agp_memory *mem, 
off_t pg_start, int ty
        temp = agp_bridge->current_size;
        num_entries = A_SIZE_32(temp)->num_entries;
 
-       if ((pg_start + mem->page_count) > num_entries)
+       if (pg_start < 0 ||
+          (pg_start + mem->page_count) > num_entries ||
+          (pg_start + mem->page_count) < pg_start)
                return -EINVAL;
 
        gp = (u32 *) &agp_bridge->gatt_table[pg_start];
@@ -200,6 +202,9 @@ static int uninorth_insert_memory(struct agp_memory *mem, 
off_t pg_start, int ty
 static int uninorth_remove_memory(struct agp_memory *mem, off_t pg_start, int 
type)
 {
        size_t i;
+       int num_entries;
+       void *temp;
+
        u32 *gp;
        int mask_type;
 
@@ -215,6 +220,14 @@ static int uninorth_remove_memory(struct agp_memory *mem, 
off_t pg_start, int ty
        if (mem->page_count == 0)
                return 0;
 
+       temp = agp_bridge->current_size;
+       num_entries = A_SIZE_32(temp)->num_entries;
+
+       if (pg_start < 0 ||
+          (pg_start + mem->page_count) > num_entries ||
+          (pg_start + mem->page_count) < pg_start)
+               return -EINVAL;
+
        gp = (u32 *) &agp_bridge->gatt_table[pg_start];
        for (i = 0; i < mem->page_count; ++i) {
                gp[i] = scratch_value;
-- 
2.51.1.dirty

Reply via email to