Two vulnerabilities are founded,please confirm.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Dear sir,

We are the ADLab, Venustech info Ltd CHINA. We have found two
vulnerabilities within linux kernel. The first one is Linux kernel IP
over ATM clip_mkip dereference freed pointer,and the second is Linux
kernel Filesystem Mount Dead Loop.Please check out the detailes about
the vulnerabilities at the end of this Email.

We are looking forward to hearing from you as soon as possible. If you
need any more information, please do not hesitate to contact us. Thank
you very much.

Best regards,
ADLab

Details:
*********************************************************
Linux kernel IP over ATM clip_mkip dereference freed pointer
[Security Advisory]

Advisory:[AD_LAB-06009] Linux kernel IP over ATM clip_mkip dereference
freed pointer
Class: Design Error
DATE:5/9/2006
CVEID:
Vulnerable:
    <=Linux-2.6.*
Vendor:
	http://www.kernel.org/

I.DESCRIPTION:
-------------
	Linux kernel is a open source operating system.
	The Linux kernel is prone to a denial-of-service vulnerability. This
issue is
due to a design error in the 'clip_mkip()' function.

II.DETAILS:
----------
	There is a vulnerability in function clip_mkip(). When re-processing
received data,
a struct sk_buff pointer skb may be dereferenced after a free operation.
It will lead to a
kernel panic and denying further service.

clip_mkip (clip.c):

502         while ((skb = skb_dequeue(&copy)) != NULL)
503                 if (!clip_devs) {
504                         atm_return(vcc,skb->truesize);
505                         kfree_skb(skb);
506                 }
507                 else {
508                         unsigned int len = skb->len;
509
510                         clip_push(vcc,skb);
511                         PRIV(skb->dev)->stats.rx_packets--;
512                         PRIV(skb->dev)->stats.rx_bytes -= len;
513                 }

	At line 511, PRIV(skb->dev) reference skb->dev; but after call
clip_push at line 510,
skb may be freed.

clip_push (clip.c):

198 static void clip_push(struct atm_vcc *vcc,struct sk_buff *skb)
199 {

	......

234         memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
235         netif_rx(skb);
236 }

netif_rx (dev.c):

1392 int netif_rx(struct sk_buff *skb)
1393 {

	......

1428         kfree_skb(skb);	//drop skb
1429         return NET_RX_DROP;
1430 }

	In netif_rx(), skb may be dropped during processing for congestion
control or by the
protocol layers; the return value NET_RX_DROP is used to identify skb
pointer arg is dropped(freed).
	
III.CREDIT:
----------
    Venustech AD-LAB discovery this vuln.Thank to all Venustech AD-Lab guys.

V.DISCLAIMS:
-----------

The information in this bulletin is provided "AS IS" without warranty of any
kind. In no event shall we be liable for any damages whatsoever
including direct,
indirect, incidental, consequential, loss of business profits or special
damages.

Copyright 1996-2006 VENUSTECH. All Rights Reserved. Terms of use.

VENUSTECH Security Lab
VENUSTECH INFORMATION TECHNOLOGY CO.,LTD(http://www.venustech.com.cn)

Security
Trusted {Solution} Provider
Service

*********************************************************
Linux kernel Filesystem Mount Dead Loop
[Security Advisory]

Advisory: [AD_LAB-06011] Linux kernel Filesystem Mount Dead Loop
Class: Design Error
DATE:5/9/2006
CVEID:
Vulnerable:
	Linux-2.6.*
Vendor:
	http://www.kernel.org/

I.DESCRIPTION:
-------------
	Linux kernel is an open source operating system.
	The Linux kernel is prone to a denial-of-service vulnerability. This
issue is
due to a design error in the '__getblk()' function.

II.DETAILS:
----------
	There is a vulnerability in function __getblk(). When mount a file
system image
with malformed block value, Linux kernel will fall in a dead loop. It
will lead to a
kernel hang and denying further service.

	Function __getblk() is used to seek a corresponding buffer_head of a
block in
a specific block device. When processing a block with a block number
more than
4G and not to be mapped to buffer pages (__find_get_block will return
NULL),
__getblk_slow will always run and never return.

1478 struct buffer_head *
1479 __getblk(struct block_device *bdev, sector_t block, int size)
1480 {
1481         struct buffer_head *bh = __find_get_block(bdev, block, size);
1482
1483         might_sleep();
1484         if (bh == NULL)
1485                 bh = __getblk_slow(bdev, block, size);
1486         return bh;
1487 }

	The endless for loop only has a exit point (at line 1213). It terminate
only when
__find_get_block return a non-NULL value. If the block is not mapped to
buffer pages,
the first __find_get_block calling will return a NULL bh and the
function grow_buffers()
will be called subsequently.

1194 __getblk_slow(struct block_device *bdev, sector_t block, int size)
1195 {
1196         /* Size must be multiple of hard sectorsize */
1197         if (unlikely(size & (bdev_hardsect_size(bdev)-1) ||
1198                         (size < 512 || size > PAGE_SIZE))) {
1199                 printk(KERN_ERR "getblk(): invalid block size %d
requested\n",
1200                                         size);
1201                 printk(KERN_ERR "hardsect size: %d\n",
1202                                         bdev_hardsect_size(bdev));
1203
1204                 dump_stack();
1205                 return NULL;
1206         }
1207
1208         for (;;) {
1209                 struct buffer_head * bh;
1210
1211                 bh = __find_get_block(bdev, block, size);	
1212                 if (bh)
1213                         return bh;
1214
1215                 if (!grow_buffers(bdev, block, size))		
1216                         free_more_memory();
1217         }
1218 }

	The function grow_buffers() is responsible for construct the
relationships among
page, buffer_head and block.
	On the 32-bit platform, the length of block and index are 64-bit and
32-bit respectively.
After the operations at line 1201 and 1202, the high 32 bits of block
will lost. Consequently, when
the block number is beyond 4G, new block number would be differently
with the original.

1189 static inline int
1190 grow_buffers(struct block_device *bdev, sector_t block, int size)
1191 {
1192         struct page *page;
1193         pgoff_t index;
1194         int sizebits;
1195
1196         sizebits = -1;
1197         do {
1198                 sizebits++;
1199         } while ((size << sizebits) < PAGE_SIZE);
1200
1201         index = block >> sizebits;
1202         block = index << sizebits;
1203
1204         /* Create a page with the proper size buffers.. */
1205         page = grow_dev_page(bdev, block, index, size);
1206         if (!page)
1207                 return 0;
1208         unlock_page(page);
1209         page_cache_release(page);
1210         return 1;
1211 }


	Follow the call sequence (grow_dev_page ==> init_page_buffers ==>
init_page_buffers).
In init_page_buffers(), a new buffer_head will be initialized, it's
block number (bh->b_blocknr)
corresponding to mapped block is assigned with the new block number.

static void
init_page_buffers(struct page *page, struct block_device *bdev,
                        sector_t block, int size)
{
	...
	...

        do {
                if (!buffer_mapped(bh)) {		
                        init_buffer(bh, NULL, NULL);
                        bh->b_bdev = bdev;
                        bh->b_blocknr = block;
                        if (uptodate)
                                set_buffer_uptodate(bh);
                        set_buffer_mapped(bh);
                }
                block++;
                bh = bh->b_this_page;
        } while (bh != head);
}

	However, __find_get_block seeks buffer head base on the original block
number in __getblk_slow ().
Because of wrong block number argument, __find_get_block will always
return NULL. As results,
system will fall in a dead loop and consume resource endlessly.

1194 __getblk_slow(struct block_device *bdev, sector_t block, int size)
1195 {
	...
	...
1207
1208         for (;;) {
1209                 struct buffer_head * bh;
1210
1211                 bh = __find_get_block(bdev, block, size);	
1212                 if (bh)
1213                         return bh;
1214
1215                 if (!grow_buffers(bdev, block, size))		
1216                         free_more_memory();
1217         }
1218 }


example:
	The vulnerability can be triggered by mount a malformed Reiser
filesystem image, the arguments of
__getblk() are:
	__getblk(0xcd0ed0c0, 0xffffffffa10020d9, 0x1000)

    call stack:
	sys_mount ->
	do_mount ->
	do_kern_mount ->
	get_super_block ->
	get_sb_bdev  ->
	reiserfs_fill_super ->
	reiserfs_read_locked_inode ->
	search_by_key ->
	__getblk ->
	__find_get_block

III.CREDIT:
----------
    Venustech AD-LAB discovery this vuln. Thank to all Venustech AD-Lab
guys.

V.DISCLAIMS:
-----------

The information in this bulletin is provided "AS IS" without warranty of any
kind. In no event shall we be liable for any damages whatsoever
including direct,
indirect, incidental, consequential, loss of business profits or special
damages.

Copyright 1996-2006 VENUSTECH. All Rights Reserved. Terms of use.

VENUSTECH Security Lab
VENUSTECH INFORMATION TECHNOLOGY CO.,LTD(http://www.venustech.com.cn)

Security
Trusted {Solution} Provider
Service

*********************************************************



-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux