Re: [PATCH 3/3] ARM: dma-mapping: fix array out of bound access

From: Ajeet Yadav
Date: Wed Feb 22 2012 - 06:21:16 EST


My old replies were from mobile messenger, hence were short, would say sorry
for the same.
Please find my response below

On Fri, Feb 17, 2012 at 10:49 PM, Russell King - ARM Linux
<linux@xxxxxxxxxxxxxxxx> wrote:
> On Fri, Feb 17, 2012 at 09:26:00PM +0530, Ajeet Yadav wrote:
>> In __dma_alloc_remap(*,size,*,*)/ __dma_free_remap(*,size) functions
>> if virtual address is in the last consistent mapping region
>> i.e idx == ((CONSISTENT_END - base) >> PMD_SHIFT) - 1
>> and off == PTRS_PER_PTE.
>> then we have array out of bound access condition.
>
> How? ÂWhere?
>
> At the first loop, off will _never_ be PTRS_PER_PTE.
>
> Â Â Â Â Â Â Â Âu32 off = CONSISTENT_OFFSET(c->vm_start) &
> (PTRS_PER_PTE-1);
>
> There is _absolutely_ _no_ _way_ that off could ever be PTRS_PER_PTE
> here.

True, so offset can be off = (PTRS_PER_PTE - 1);
And say idx = CONSISTENT_PTE_INDEX(c->vm_start); provide us with last vaild
element in consistent_pte[];
Also __dma_alloc_remap() request 1 page, i.e size = ÂPAGE_SIZE.

Because size, off, idx are vaild values with respect to consistent mapping
region, and its a do{}while loop, so it will exit loop after first pass. All
fine

But their is a catch, we do off++, so
do{
    do_all_important_stuff
    off++;    Â>>>>>>>>>>>>>>>>>>>>>>>>>>> now off = PTRS_PER_PTE
     if (off >= PTRS_PER_PTE) {         >>>>>> condition TRUE
       Âoff = 0;
       Âpte = consistent_pte[++idx];     >>>>> we did idx++ but
idx was already pointing to last element, so we are trying to access array
out of bound
    Â}
} while (size -= PAGE_SIZE); Â ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ >>>>>>> conditon FALSE,
but its too late

The proposed solution, do off++ but move the rest i.e if body from last to
begining of do{}while.
In this case we will prevent out of bound acess, without effecting the flow
on first entry and also exit from do{}while loop.
Moving the if body to begining of do{}while ensured that on first entry to
do{}while loop the if condition fails hence not effecting the first entry
condition.
on subsequent iternation of do{}while loop the while condition will be
checked before we execute the if conditon.

Given functions __dma_alloc_remap()/ __dma_free_remap() already haves
necessary checks to ensure that size is valid, so again if we analyse from
given example

do{
     if (off >= PTRS_PER_PTE) {         >>>>>> condition FALSE
       Âoff = 0;
       Âpte = consistent_pte[++idx];ÂÂÂÂÂÂÂÂÂÂÂ>>>>>>Âwe avoid
this
    Â}
    do_all_important_stuff
    off++;    Â>>>>>>>>>>>>>>>>>>>>>>>>>>> now off = PTRS_PER_PTE
} while (size -= PAGE_SIZE); Â Â Â Â Â Â Â Â Â Â Â >>>>>>> condition FAILS,
we exit the do{}while, effectively prevented the out of bound access of
consistent_pte[]

ÂNOTE: size is valid so, in proposed solution while conditon is effectively
preventing the out of bound array access to occur.
ÂIf we review the code from normal access point of view, we are not changing
any flow logic, also after the exit from do{}while no access to off, idx is
performed
So we do not need to worry about post do{}while statments.

>
> If 'base' is CONSISTENT_END, then we have far bigger problems, because
> it means that we have a zero sized region - it certainly can't be any
> larger than zero size because then we'd be overflowing the DMA region
>> into something else.
>>
>> Plus, we know that 'end of region' allocations work fine, because the
>> code allocates from the top of the region downwards.
>>
>> So, I don't think there's a problem here.
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/