提交 08f3f0b2 编写于 作者: H haibinzhang (张海斌) 提交者: Yongqiang Liu

arm64: fix oops in concurrently setting insn_emulation sysctls

stable inclusion
from stable-v4.19.256
commit b51881b1da57fe9877125dfdd0aac5172958fcfd
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I5U71M
CVE: CVE-2022-20422

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

[ Upstream commit af483947 ]

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: Nhewenliang <hewenliang4@huawei.com>
Signed-off-by: Nhewenliang <hewenliang4@huawei.com>
Signed-off-by: NHaibin Zhang <haibinzhang@tencent.com>
Reviewed-by: NCatalin 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.comSigned-off-by: NWill Deacon <will@kernel.org>
Signed-off-by: NSasha Levin <sashal@kernel.org>
Signed-off-by: Nruanjinjie <ruanjinjie@huawei.com>
Reviewed-by: NZhang Jianhua <chris.zjh@huawei.com>
Reviewed-by: NXiu Jianfeng <xiujianfeng@huawei.com>
Signed-off-by: NYongqiang Liu <liuyongqiang13@huawei.com>
上级 988dd3e9
...@@ -62,6 +62,7 @@ struct insn_emulation { ...@@ -62,6 +62,7 @@ struct insn_emulation {
static LIST_HEAD(insn_emulation); static LIST_HEAD(insn_emulation);
static int nr_insn_emulated __initdata; static int nr_insn_emulated __initdata;
static DEFINE_RAW_SPINLOCK(insn_emulation_lock); static DEFINE_RAW_SPINLOCK(insn_emulation_lock);
static DEFINE_MUTEX(insn_emulation_mutex);
static void register_emulation_hooks(struct insn_emulation_ops *ops) 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, ...@@ -210,10 +211,10 @@ static int emulation_proc_handler(struct ctl_table *table, int write,
loff_t *ppos) loff_t *ppos)
{ {
int ret = 0; 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; 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); ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
if (ret || !write || prev_mode == insn->current_mode) if (ret || !write || prev_mode == insn->current_mode)
...@@ -226,7 +227,7 @@ static int emulation_proc_handler(struct ctl_table *table, int write, ...@@ -226,7 +227,7 @@ static int emulation_proc_handler(struct ctl_table *table, int write,
update_insn_emulation_mode(insn, INSN_UNDEF); update_insn_emulation_mode(insn, INSN_UNDEF);
} }
ret: ret:
table->data = insn; mutex_unlock(&insn_emulation_mutex);
return ret; return ret;
} }
...@@ -250,7 +251,7 @@ static void __init register_insn_emulation_sysctl(void) ...@@ -250,7 +251,7 @@ static void __init register_insn_emulation_sysctl(void)
sysctl->maxlen = sizeof(int); sysctl->maxlen = sizeof(int);
sysctl->procname = insn->ops->name; sysctl->procname = insn->ops->name;
sysctl->data = insn; sysctl->data = &insn->current_mode;
sysctl->extra1 = &insn->min; sysctl->extra1 = &insn->min;
sysctl->extra2 = &insn->max; sysctl->extra2 = &insn->max;
sysctl->proc_handler = emulation_proc_handler; sysctl->proc_handler = emulation_proc_handler;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册