Date: Sun, 12 May 2002 23:36:58 -0700 (PDT) From: David Xu <davidx@viasoft.com.cn> To: freebsd-gnats-submit@FreeBSD.org Subject: i386/38021: i386_set_ldt can be cheated Message-ID: <200205130636.g4D6awRF036378@www.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 38021 >Category: i386 >Synopsis: i386_set_ldt can be cheated >Confidential: no >Severity: critical >Priority: high >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Sun May 12 23:40:01 PDT 2002 >Closed-Date: >Last-Modified: >Originator: David Xu >Release: FreeBSD 5.0-CURRENT >Organization: Viatech >Environment: FreeBSD davidbsd.viasoft.com.cn 5.0-CURRENT FreeBSD 5.0-CURRENT #25: Mon May 13 13:54:20 CST 2002 davidx@davidbsd.viasoft.com.cn:/usr/src/sys/i386/compile/xu i386 >Description: i386_set_ldt() in sys_machdep.c can be cheated by user, it uses two step to copy LDT descriptors from user space, first, security check is made, second, copying descriptors from user space. there exists a race condition that multi-processes or multi-threads program can pass a shared memory address to kernel, call i386_set_ldt() with the address argument on one CPU, and modify the descriptors on another cpu, kernel can be cheated in the race condition and causes invalid descriptors be installed in kernel LDT table. >How-To-Repeat: >Fix: --- /usr/src/sys/i386/i386/sys_machdep.c Mon May 13 14:00:33 2002 +++ /usr/src/sys/i386/i386/sys_machdep.c.new2 Mon May 13 14:00:24 2002 @@ -412,6 +412,8 @@ caddr_t old_ldt_base; int old_ldt_len; register_t savecrit; + union descriptor *descs; + int descs_size; if ((error = copyin(args, uap, sizeof(struct i386_ldt_args))) < 0) return(error); @@ -465,17 +467,24 @@ #endif } + descs_size = uap->num * sizeof(union descriptor); + descs = (union descriptor *)kmem_alloc(kernel_map, descs_size); + if (descs == NULL) + return ENOMEM; + if ((error = copyin(&uap->descs[0], descs, descs_size)) < 0) + { + kmem_free(kernel_map, (vm_offset_t)descs, descs_size); + return error; + } + /* Check descriptors for access violations */ for (i = 0, n = uap->start; i < uap->num; i++, n++) { - union descriptor desc, *dp; - dp = &uap->descs[i]; - error = copyin(dp, &desc, sizeof(union descriptor)); - if (error) - return(error); + union descriptor *dp; + dp = &descs[i]; - switch (desc.sd.sd_type) { + switch (dp->sd.sd_type) { case SDT_SYSNULL: /* system null */ - desc.sd.sd_p = 0; + dp->sd.sd_p = 0; break; case SDT_SYS286TSS: /* system 286 TSS available */ case SDT_SYSLDT: /* system local descriptor table */ @@ -496,6 +505,7 @@ * to create a segment of these types. They are * for OS use only. */ + kmem_free(kernel_map, (vm_offset_t)descs, descs_size); return EACCES; /*NOTREACHED*/ @@ -505,8 +515,11 @@ case SDT_MEMERC: /* memory execute read conforming */ case SDT_MEMERAC: /* memory execute read accessed conforming */ /* Must be "present" if executable and conforming. */ - if (desc.sd.sd_p == 0) + if (dp->sd.sd_p == 0) + { + kmem_free(kernel_map, (vm_offset_t)descs, descs_size); return (EACCES); + } break; case SDT_MEMRO: /* memory read only */ case SDT_MEMROA: /* memory read only accessed */ @@ -522,23 +535,26 @@ case SDT_MEMERA: /* memory execute read accessed */ break; default: + kmem_free(kernel_map, (vm_offset_t)descs, descs_size); return(EINVAL); /*NOTREACHED*/ } /* Only user (ring-3) descriptors may be present. */ - if ((desc.sd.sd_p != 0) && (desc.sd.sd_dpl != SEL_UPL)) + if ((dp->sd.sd_p != 0) && (dp->sd.sd_dpl != SEL_UPL)) + { + kmem_free(kernel_map, (vm_offset_t)descs, descs_size); return (EACCES); + } } /* Fill in range */ savecrit = intr_disable(); - error = copyin(uap->descs, - &((union descriptor *)(pldt->ldt_base))[uap->start], - uap->num * sizeof(union descriptor)); + error = copyin(descs, + &((union descriptor *)(pldt->ldt_base))[uap->start], descs_size); if (!error) td->td_retval[0] = uap->start; intr_restore(savecrit); - + kmem_free(kernel_map, (vm_offset_t)descs, descs_size); return(error); } >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200205130636.g4D6awRF036378>