Subject: Bugs in i386_get_ldt, i386_set_ldt
To: None <netbsd-bugs@NetBSD.ORG>
From: None <r_friedl@informatik.uni-kl.de>
List: netbsd-bugs
Date: 10/12/1995 16:27:13
Function i386_get_ldt contains splx(s), where s is uninitialized.

Function i386_set_ldt has a bug when reallocating the LDT.  It uses
the new length to free the old LDT.

This is ficed by the following patch.

--- arch/i386/i386/sys_machdep.c.orig	Sun May  7 12:05:34 1995
+++ arch/i386/i386/sys_machdep.c	Sat Oct  7 02:55:16 1995
@@ -143,7 +143,6 @@
 	struct pcb *pcb = &p->p_addr->u_pcb;
 	int nldt, num;
 	union descriptor *lp;
-	int s;
 	struct i386_get_ldt_args ua, *uap;
 
 	if ((error = copyin(args, &ua, sizeof(struct i386_get_ldt_args))) < 0)
@@ -166,10 +165,8 @@
 		nldt = NLDT;
 		lp = ldt;
 	}
-	if (uap->start > nldt) {
-		splx(s);
+	if (uap->start > nldt)
 		return (EINVAL);
-	}
 	lp += uap->start;
 	num = min(uap->num, nldt - uap->start);
 
@@ -211,23 +208,25 @@
 	/* allocate user ldt */
 	if (!pcb->pcb_ldt || (uap->start + uap->num) > pcb->pcb_ldt_len) {
 		size_t oldlen, len;
-		union descriptor *new_ldt;
+		union descriptor *old_ldt, *new_ldt;
 
-		if (!pcb->pcb_ldt)
+		if (!pcb->pcb_ldt) {
 			pcb->pcb_ldt_len = 512;
+			oldlen = NLDT * sizeof(union descriptor);
+			old_ldt = ldt;
+		}
+		else {
+			oldlen = pcb->pcb_ldt_len * sizeof(union descriptor);
+			old_ldt = (union descriptor *)pcb->pcb_ldt;
+		}
 		while ((uap->start + uap->num) > pcb->pcb_ldt_len)
 			pcb->pcb_ldt_len *= 2;
 		len = pcb->pcb_ldt_len * sizeof(union descriptor);
 		new_ldt = (union descriptor *)kmem_alloc(kernel_map, len);
-		if (!pcb->pcb_ldt) {
-			oldlen = NLDT * sizeof(union descriptor);
-			bcopy(ldt, new_ldt, oldlen);
-		} else {
-			oldlen = pcb->pcb_ldt_len * sizeof(union descriptor);
-			bcopy(pcb->pcb_ldt, new_ldt, oldlen);
+		bcopy(old_ldt, new_ldt, oldlen);
+		if (pcb->pcb_ldt)
 			kmem_free(kernel_map, (vm_offset_t)pcb->pcb_ldt,
 			    oldlen);
-		}
 		bzero((caddr_t)new_ldt + oldlen, len - oldlen);
 		pcb->pcb_ldt = (caddr_t)new_ldt;
 		gdt_segs[GUSERLDT_SEL].ssd_base = (unsigned)new_ldt;