[PATCH] agp/uninorth: fix out-of-bounds access with negative pg_start

From: moonafterrain

Date: Tue Oct 28 2025 - 12:25:43 EST


From: Junrui Luo <moonafterrain@xxxxxxxxxxx>

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 <danisjiang@xxxxxxxxx>
Reported-by: Junrui Luo <moonafterrain@xxxxxxxxxxx>
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Junrui Luo <moonafterrain@xxxxxxxxxxx>
---
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