FreeBSD I386SetLDT()多个本地拒绝服务漏洞 -电脑资料

电脑资料 时间:2019-01-01 我要投稿
【www.unjs.com - 电脑资料】

    受影响系统:FreeBSD FreeBSD 5.5

    FreeBSD FreeBSD 5.4

    FreeBSD FreeBSD 5.3

    FreeBSD FreeBSD 5.2描述:


BUGTRAQ  ID: 20158

    CVE(CAN) ID: CVE-2006-4178,CVE-2006-4172

    FreeBSD就是一种运行在Intel平台上、可以自由使用的开放源码Unix类系统,

FreeBSD I386SetLDT()多个本地拒绝服务漏洞

    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, descs, descs_size);

    545        if (error) {

    546                kmem_free(kernel_map, (vm_offset_t)descs, descs_size);

    547                return (error);

    548        }

    549

    <*来源:Adriano Lima (adriano@risesecurity.org)

    Rodrigo Rubira Branco (rodrigo@risesecurity.org)

    链接:http://marc.theaimsgroup.com/?l=bugtraq&m=115919812814071&w=2

    http://www.idefense.com/intelligence/vulnerabilities/display.php?id=415

    http://www.idefense.com/intelligence/vulnerabilities/display.php?id=414

    *>

    建议:


厂商补丁:

    FreeBSD

    -------

    目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:

    http://www.freebsd.org/security/

最新文章