lkml.org 
[lkml]   [2020]   [Jun]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.9 168/191] netfilter: ipset: fix unaligned atomic access
    Date
    From: Russell King <rmk+kernel@armlinux.org.uk>

    [ Upstream commit 715028460082d07a7ec6fcd87b14b46784346a72 ]

    When using ip_set with counters and comment, traffic causes the kernel
    to panic on 32-bit ARM:

    Alignment trap: not handling instruction e1b82f9f at [<bf01b0dc>]
    Unhandled fault: alignment exception (0x221) at 0xea08133c
    PC is at ip_set_match_extensions+0xe0/0x224 [ip_set]

    The problem occurs when we try to update the 64-bit counters - the
    faulting address above is not 64-bit aligned. The problem occurs
    due to the way elements are allocated, for example:

    set->dsize = ip_set_elem_len(set, tb, 0, 0);
    map = ip_set_alloc(sizeof(*map) + elements * set->dsize);

    If the element has a requirement for a member to be 64-bit aligned,
    and set->dsize is not a multiple of 8, but is a multiple of four,
    then every odd numbered elements will be misaligned - and hitting
    an atomic64_add() on that element will cause the kernel to panic.

    ip_set_elem_len() must return a size that is rounded to the maximum
    alignment of any extension field stored in the element. This change
    ensures that is the case.

    Fixes: 95ad1f4a9358 ("netfilter: ipset: Fix extension alignment")
    Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
    Acked-by: Jozsef Kadlecsik <kadlec@netfilter.org>
    Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    net/netfilter/ipset/ip_set_core.c | 2 ++
    1 file changed, 2 insertions(+)

    diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
    index f64660e9ff879..511496278262c 100644
    --- a/net/netfilter/ipset/ip_set_core.c
    +++ b/net/netfilter/ipset/ip_set_core.c
    @@ -379,6 +379,8 @@ ip_set_elem_len(struct ip_set *set, struct nlattr *tb[], size_t len,
    for (id = 0; id < IPSET_EXT_ID_MAX; id++) {
    if (!add_extension(id, cadt_flags, tb))
    continue;
    + if (align < ip_set_extensions[id].align)
    + align = ip_set_extensions[id].align;
    len = ALIGN(len, ip_set_extensions[id].align);
    set->offset[id] = len;
    set->extensions |= ip_set_extensions[id].type;
    --
    2.25.1
    \
     
     \ /
      Last update: 2020-06-29 22:22    [W:2.736 / U:0.092 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site