lkml.org 
[lkml]   [2013]   [Dec]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.10 29/52] parisc: fix mmap(MAP_FIXED|MAP_SHARED) to already mmapped address
    Date
    3.10-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Helge Deller <deller@gmx.de>

    commit 0576da2c08e3d332f1b0653030d28ab804585ab6 upstream.

    locale-gen on Debian showed a strange problem on parisc:
    mmap2(NULL, 536870912, PROT_NONE, MAP_SHARED, 3, 0) = 0x42a54000
    mmap2(0x42a54000, 103860, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, 3, 0) = -1 EINVAL (Invalid argument)

    Basically it was just trying to re-mmap() a file at the same address
    which it was given by a previous mmap() call. But this remapping failed
    with EINVAL.

    The problem is, that when MAP_FIXED and MAP_SHARED flags were used, we didn't
    included the mapping-based offset when we verified the alignment of the given
    fixed address against the offset which we calculated it in the previous call.

    Signed-off-by: Helge Deller <deller@gmx.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    arch/parisc/kernel/sys_parisc.c | 25 +++++++++++++++----------
    1 file changed, 15 insertions(+), 10 deletions(-)

    --- a/arch/parisc/kernel/sys_parisc.c
    +++ b/arch/parisc/kernel/sys_parisc.c
    @@ -61,8 +61,15 @@ static int get_offset(struct address_spa
    return (unsigned long) mapping >> 8;
    }

    -static unsigned long get_shared_area(struct address_space *mapping,
    - unsigned long addr, unsigned long len, unsigned long pgoff)
    +static unsigned long shared_align_offset(struct file *filp, unsigned long pgoff)
    +{
    + struct address_space *mapping = filp ? filp->f_mapping : NULL;
    +
    + return (get_offset(mapping) + pgoff) << PAGE_SHIFT;
    +}
    +
    +static unsigned long get_shared_area(struct file *filp, unsigned long addr,
    + unsigned long len, unsigned long pgoff)
    {
    struct vm_unmapped_area_info info;

    @@ -71,7 +78,7 @@ static unsigned long get_shared_area(str
    info.low_limit = PAGE_ALIGN(addr);
    info.high_limit = TASK_SIZE;
    info.align_mask = PAGE_MASK & (SHMLBA - 1);
    - info.align_offset = (get_offset(mapping) + pgoff) << PAGE_SHIFT;
    + info.align_offset = shared_align_offset(filp, pgoff);
    return vm_unmapped_area(&info);
    }

    @@ -82,20 +89,18 @@ unsigned long arch_get_unmapped_area(str
    return -ENOMEM;
    if (flags & MAP_FIXED) {
    if ((flags & MAP_SHARED) &&
    - (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
    + (addr - shared_align_offset(filp, pgoff)) & (SHMLBA - 1))
    return -EINVAL;
    return addr;
    }
    if (!addr)
    addr = TASK_UNMAPPED_BASE;

    - if (filp) {
    - addr = get_shared_area(filp->f_mapping, addr, len, pgoff);
    - } else if(flags & MAP_SHARED) {
    - addr = get_shared_area(NULL, addr, len, pgoff);
    - } else {
    + if (filp || (flags & MAP_SHARED))
    + addr = get_shared_area(filp, addr, len, pgoff);
    + else
    addr = get_unshared_area(addr, len);
    - }
    +
    return addr;
    }




    \
     
     \ /
      Last update: 2013-12-10 10:41    [W:4.142 / U:0.268 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site