lkml.org 
[lkml]   [2021]   [May]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.10 525/530] bpf: Prevent writable memory-mapping of read-only ringbuf pages
    Date
    From: Andrii Nakryiko <andrii@kernel.org>

    commit 04ea3086c4d73da7009de1e84962a904139af219 upstream.

    Only the very first page of BPF ringbuf that contains consumer position
    counter is supposed to be mapped as writeable by user-space. Producer
    position is read-only and can be modified only by the kernel code. BPF ringbuf
    data pages are read-only as well and are not meant to be modified by
    user-code to maintain integrity of per-record headers.

    This patch allows to map only consumer position page as writeable and
    everything else is restricted to be read-only. remap_vmalloc_range()
    internally adds VM_DONTEXPAND, so all the established memory mappings can't be
    extended, which prevents any future violations through mremap()'ing.

    Fixes: 457f44363a88 ("bpf: Implement BPF ring buffer and verifier support for it")
    Reported-by: Ryota Shiga (Flatt Security)
    Reported-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
    Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
    Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
    Acked-by: Alexei Starovoitov <ast@kernel.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    kernel/bpf/ringbuf.c | 21 ++++++++-------------
    1 file changed, 8 insertions(+), 13 deletions(-)

    --- a/kernel/bpf/ringbuf.c
    +++ b/kernel/bpf/ringbuf.c
    @@ -240,25 +240,20 @@ static int ringbuf_map_get_next_key(stru
    return -ENOTSUPP;
    }

    -static size_t bpf_ringbuf_mmap_page_cnt(const struct bpf_ringbuf *rb)
    -{
    - size_t data_pages = (rb->mask + 1) >> PAGE_SHIFT;
    -
    - /* consumer page + producer page + 2 x data pages */
    - return RINGBUF_POS_PAGES + 2 * data_pages;
    -}
    -
    static int ringbuf_map_mmap(struct bpf_map *map, struct vm_area_struct *vma)
    {
    struct bpf_ringbuf_map *rb_map;
    - size_t mmap_sz;

    rb_map = container_of(map, struct bpf_ringbuf_map, map);
    - mmap_sz = bpf_ringbuf_mmap_page_cnt(rb_map->rb) << PAGE_SHIFT;
    -
    - if (vma->vm_pgoff * PAGE_SIZE + (vma->vm_end - vma->vm_start) > mmap_sz)
    - return -EINVAL;

    + if (vma->vm_flags & VM_WRITE) {
    + /* allow writable mapping for the consumer_pos only */
    + if (vma->vm_pgoff != 0 || vma->vm_end - vma->vm_start != PAGE_SIZE)
    + return -EPERM;
    + } else {
    + vma->vm_flags &= ~VM_MAYWRITE;
    + }
    + /* remap_vmalloc_range() checks size and offset constraints */
    return remap_vmalloc_range(vma, rb_map->rb,
    vma->vm_pgoff + RINGBUF_PGOFF);
    }

    \
     
     \ /
      Last update: 2021-05-12 18:42    [W:4.042 / U:0.432 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site