patch-1.3.72 linux/arch/i386/kernel/ldt.c

Next file: linux/arch/i386/kernel/time.c
Previous file: linux/arch/i386/kernel/irq.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.71/linux/arch/i386/kernel/ldt.c linux/arch/i386/kernel/ldt.c
@@ -34,11 +34,35 @@
 	return size;
 }
 
+static inline int limits_ok(struct modify_ldt_ldt_s *ldt_info)
+{
+	unsigned long base, limit;
+	/* linear address of first and last accessible byte */
+	unsigned long first, last;
+
+	base = ldt_info->base_addr;
+	limit = ldt_info->limit;
+	if (ldt_info->limit_in_pages)
+		limit = limit * PAGE_SIZE + PAGE_SIZE - 1;
+
+	first = base;
+	last = limit + base;
+
+	/* segment grows down? */
+	if (ldt_info->contents == 1) {
+		/* data segment grows down */
+		first = base+limit+1;
+		last = base+65535;
+		if (ldt_info->seg_32bit)
+			last = base-1;
+	}
+	return (last >= first && last < TASK_SIZE);
+}
+
 static int write_ldt(void * ptr, unsigned long bytecount)
 {
 	struct modify_ldt_ldt_s ldt_info;
 	unsigned long *lp;
-	unsigned long base, limit;
 	int error, i;
 
 	if (bytecount != sizeof(ldt_info))
@@ -52,13 +76,7 @@
 	if (ldt_info.contents == 3 || ldt_info.entry_number >= LDT_ENTRIES)
 		return -EINVAL;
 
-	limit = ldt_info.limit;
-	base = ldt_info.base_addr;
-	if (ldt_info.limit_in_pages)
-		limit *= PAGE_SIZE;
-
-	limit += base;
-	if (limit < base || limit >= 0xC0000000)
+	if (!limits_ok(&ldt_info))
 		return -EINVAL;
 
 	if (!current->ldt) {

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this