lkml.org 
[lkml]   [2022]   [Aug]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.19 040/287] arm64: fix oops in concurrently setting insn_emulation sysctls
    Date
    From: haibinzhang (张海斌) <haibinzhang@tencent.com>

    [ Upstream commit af483947d472eccb79e42059276c4deed76f99a6 ]

    emulation_proc_handler() changes table->data for proc_dointvec_minmax
    and can generate the following Oops if called concurrently with itself:

    | Unable to handle kernel NULL pointer dereference at virtual address 0000000000000010
    | Internal error: Oops: 96000006 [#1] SMP
    | Call trace:
    | update_insn_emulation_mode+0xc0/0x148
    | emulation_proc_handler+0x64/0xb8
    | proc_sys_call_handler+0x9c/0xf8
    | proc_sys_write+0x18/0x20
    | __vfs_write+0x20/0x48
    | vfs_write+0xe4/0x1d0
    | ksys_write+0x70/0xf8
    | __arm64_sys_write+0x20/0x28
    | el0_svc_common.constprop.0+0x7c/0x1c0
    | el0_svc_handler+0x2c/0xa0
    | el0_svc+0x8/0x200

    To fix this issue, keep the table->data as &insn->current_mode and
    use container_of() to retrieve the insn pointer. Another mutex is
    used to protect against the current_mode update but not for retrieving
    insn_emulation as table->data is no longer changing.

    Co-developed-by: hewenliang <hewenliang4@huawei.com>
    Signed-off-by: hewenliang <hewenliang4@huawei.com>
    Signed-off-by: Haibin Zhang <haibinzhang@tencent.com>
    Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
    Link: https://lore.kernel.org/r/20220128090324.2727688-1-hewenliang4@huawei.com
    Link: https://lore.kernel.org/r/9A004C03-250B-46C5-BF39-782D7551B00E@tencent.com
    Signed-off-by: Will Deacon <will@kernel.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    arch/arm64/kernel/armv8_deprecated.c | 9 +++++----
    1 file changed, 5 insertions(+), 4 deletions(-)

    diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
    index 181c29af5617..7c69a203cdf8 100644
    --- a/arch/arm64/kernel/armv8_deprecated.c
    +++ b/arch/arm64/kernel/armv8_deprecated.c
    @@ -62,6 +62,7 @@ struct insn_emulation {
    static LIST_HEAD(insn_emulation);
    static int nr_insn_emulated __initdata;
    static DEFINE_RAW_SPINLOCK(insn_emulation_lock);
    +static DEFINE_MUTEX(insn_emulation_mutex);

    static void register_emulation_hooks(struct insn_emulation_ops *ops)
    {
    @@ -210,10 +211,10 @@ static int emulation_proc_handler(struct ctl_table *table, int write,
    loff_t *ppos)
    {
    int ret = 0;
    - struct insn_emulation *insn = (struct insn_emulation *) table->data;
    + struct insn_emulation *insn = container_of(table->data, struct insn_emulation, current_mode);
    enum insn_emulation_mode prev_mode = insn->current_mode;

    - table->data = &insn->current_mode;
    + mutex_lock(&insn_emulation_mutex);
    ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);

    if (ret || !write || prev_mode == insn->current_mode)
    @@ -226,7 +227,7 @@ static int emulation_proc_handler(struct ctl_table *table, int write,
    update_insn_emulation_mode(insn, INSN_UNDEF);
    }
    ret:
    - table->data = insn;
    + mutex_unlock(&insn_emulation_mutex);
    return ret;
    }

    @@ -250,7 +251,7 @@ static void __init register_insn_emulation_sysctl(void)
    sysctl->maxlen = sizeof(int);

    sysctl->procname = insn->ops->name;
    - sysctl->data = insn;
    + sysctl->data = &insn->current_mode;
    sysctl->extra1 = &insn->min;
    sysctl->extra2 = &insn->max;
    sysctl->proc_handler = emulation_proc_handler;
    --
    2.35.1


    \
     
     \ /
      Last update: 2022-08-23 12:37    [W:4.132 / U:0.316 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site