On Thu, 2011-05-05 at 17:11 -0700, Greg KH wrote:
> 2.6.38-stable review patch.  If anyone has any objections, please let us know.
> 
> ------------------
> 
> From: Timo Warns <[email protected]>
> 
> commit c340b1d640001c8c9ecff74f68fd90422ae2448a upstream.
> 
> The kernel automatically evaluates partition tables of storage devices.
> The code for evaluating LDM partitions (in fs/partitions/ldm.c) contains
> a bug that causes a kernel oops on certain corrupted LDM partitions.
> A kernel subsystem seems to crash, because, after the oops, the kernel no
> longer recognizes newly connected storage devices.
> 
> The patch validates the value of vblk_size.

I don't think this actually fixes the vulnerability, and I don't think
this code works at all.

> [[email protected]: coding-style fixes]
> Signed-off-by: Timo Warns <[email protected]>
> Cc: Eugene Teo <[email protected]>
> Cc: Harvey Harrison <[email protected]>
> Cc: Richard Russon <[email protected]>
> Signed-off-by: Andrew Morton <[email protected]>
> Signed-off-by: Linus Torvalds <[email protected]>
> Signed-off-by: Greg Kroah-Hartman <[email protected]>
> 
> ---
>  fs/partitions/ldm.c |   16 ++++++++++++----
>  1 file changed, 12 insertions(+), 4 deletions(-)
> 
> --- a/fs/partitions/ldm.c
> +++ b/fs/partitions/ldm.c
> @@ -1299,6 +1299,11 @@ static bool ldm_frag_add (const u8 *data
>  
>       BUG_ON (!data || !frags);
>  
> +     if (size < 2 * VBLK_SIZE_HEAD) {
> +             ldm_error("Value of size is to small.");
> +             return false;
> +     }
> +
>       group = get_unaligned_be32(data + 0x08);
>       rec   = get_unaligned_be16(data + 0x0C);
>       num   = get_unaligned_be16(data + 0x0E);
> @@ -1306,6 +1311,10 @@ static bool ldm_frag_add (const u8 *data
>               ldm_error ("A VBLK claims to have %d parts.", num);
>               return false;
>       }
> +     if (rec >= num) {
> +             ldm_error("REC value (%d) exceeds NUM value (%d)", rec, num);
> +             return false;
> +     }

This is fine for the first fragment we find, when we allocate memory
based on 'num'.  However, when we add another fragment, we need to
compare with f->num.  So there still seems to be the possibility of a
buffer overflow.

>       list_for_each (item, frags) {
>               f = list_entry (item, struct frag, list);
> @@ -1334,10 +1343,9 @@ found:
>  
>       f->map |= (1 << rec);
>  
> -     if (num > 0) {
> -             data += VBLK_SIZE_HEAD;
> -             size -= VBLK_SIZE_HEAD;
> -     }
> +     data += VBLK_SIZE_HEAD;
> +     size -= VBLK_SIZE_HEAD;
> +
>
>       memcpy (f->data+rec*(size-VBLK_SIZE_HEAD)+VBLK_SIZE_HEAD, data, size);
> 
>       return true;

The offset used for the destination means that the first VBLK_SIZE_HEAD
bytes of f->data are never initialised!

I suspect (without any knowledge of LDM) that the intent was to use the
header from the first fragment and drop it from the subsequent
fragments, like this:

        if (rec == 0)
                memcpy(f->data, data, VBLK_SIZE_HEAD);
        data += VBLK_SIZE_HEAD;
        size -= VBLK_SIZE_HEAD;
        memcpy(f->data + VBLK_SIZE_HEAD + rec * size, data, size);

Ben.

-- 
Ben Hutchings
Once a job is fouled up, anything done to improve it makes it worse.

Attachment: signature.asc
Description: This is a digitally signed message part

_______________________________________________
stable mailing list
[email protected]
http://linux.kernel.org/mailman/listinfo/stable

Reply via email to