CVE:CVE-2006-4178
CNNVD:CNNVD-200609-428
FreeBSD就是一种运行在Intel平台上、可以自由使用的开放源码Unix类系统。
FreeBSD中的i386_set_ldt()调用允许用户系统的程序动态管理每个进程的本地描述符表。由于使用了有符号的整数且缺少输入验证，内核中bzero可能会被要求处理很大的参数，漏洞代码如下：
415         int error = 0, i;
416         int largest_ld;
..
449                 largest_ld = uap->start + uap->num;
450                 if (largest_ld > pldt->ldt_len)
451                         largest_ld = pldt->ldt_len;
452                 i = largest_ld - uap->start;
453                 bzero( &((union descriptor *)(pldt->ldt_base))[uap->start],
454                     sizeof(union descriptor) * i);
在415和416行，"i"和"largest_ld"变量都是有符的整数。在449行，同时添加了uap->start和uap->num，这两个变量都是用户控制的且没有经过正确的检查。在452行，可以将"i"设置为很大的负值，导致在453行以很大的长度参数调用bzero。无效的内存访问会导致内核忙碌。
i386_set_ldt()系统调用会在LDT中设置当前进程的i386描述符列表。该调用接受一个开始选择器数(start)、包含有将要设置描述符的内存数组(descs)，以及将要设置的条目数(num)。用户在通过sysarch()调用i386_set_ldt()时，如果将start参数设置为很低的整数值、将descs设置为非空的值，并将num设置为很高的无符整数值，就会触发largest_ld和descs_size(533和540行)中的整数溢出，导致耗尽所有可用的系统资源(541行)。此外还可以将start参数设置为低整数值、descs设置为空、num设置为很高的无符整数值触发largest_ld(515行)中的整数溢出，导致删除系统中的敏感数据(519和520行)。有漏洞的函数如下：
476 static int
477 i386_set_ldt(td, args)
478         struct thread *td;
479         char *args;
480 {
481         int error = 0, i;
482         int largest_ld;
483         struct mdproc *mdp =  &td->td_proc->p_md;
484         struct proc_ldt *pldt = 0;
485         struct i386_ldt_args ua, *uap =  &ua;
486         union descriptor *descs, *dp;
487         int descs_size;
488
489         if ((error = copyin(args, uap, sizeof(struct
i386_ldt_args))) < 0)
490                 return(error);
491
492 #ifdef  DEBUG
493         printf("i386_set_ldt: start=%d num=%d descs=%p\n",
494             uap->start, uap->num, (void *)uap->descs);
495 #endif
496
497         if (uap->descs == NULL) {
498                 /* Free descriptors */
499                 if (uap->start == 0  & & uap->num == 0) {
500                         /*
501                          * Treat this as a special case, so userland
needn't
502                          * know magic number NLDT.
503                          */
504                         uap->start = NLDT;
505                         uap->num = MAX_LD - NLDT;
506                 }
507                 if (uap->start <= LUDATA_SEL || uap->num <= 0)508                         return (EINVAL);
509                 mtx_lock_spin( &sched_lock);
510                 pldt = mdp->md_ldt;
511                 if (pldt == NULL || uap->start >= pldt->ldt_len) {
512                         mtx_unlock_spin( &sched_lock);
513                         return (0);
514                 }
515                 largest_ld = uap->start + uap->num;
516                 if (largest_ld > pldt->ldt_len)
517                         largest_ld = pldt->ldt_len;
518                 i = largest_ld - uap->start;
519                 bzero( &((union descriptor
*)(pldt->ldt_base))[uap->start],
520                     sizeof(union descriptor) * i);
521                 mtx_unlock_spin( &sched_lock);
522                 return (0);
523         }
524
525         if (!(uap->start == LDT_AUTO_ALLOC  & & uap->num == 1)) {
526                 /* complain a for a while if using old methods */
527                 if (ldt_warnings++ < NUM_LDT_WARNINGS) {
528                         printf("Warning: pid %d used static ldt
allocation.\n",
529                             td->td_proc->p_pid);
530                         printf("See the i386_set_ldt man page for
more info\n");
531                 }
532                 /* verify range of descriptors to modify */
533                 largest_ld = uap->start + uap->num;
534                 if (uap->start >= MAX_LD ||
535                     uap->num < 0 || largest_ld > MAX_LD) {
536                         return (EINVAL);
537                 }
538         }
539
540         descs_size = uap->num * sizeof(union descriptor);
541         descs = (union descriptor *)kmem_alloc(kernel_map, descs_size);
542         if (descs == NULL)
543                 return (ENOMEM);
544         error = copyin(uap->descs
solution:Upgrade freebsd freebsd to a higher version than 5.5,5.2,5.2.1,5.3,5.4,and avoid the version (,5.5],5.2,5.2.1,5.3,5.4