Unverified Commit dac6bbe8 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!2632 arm64: fix a concurrency issue in emulation_proc_handler()

Merge Pull Request from: @ci-robot 
 
PR sync from: Jinjie Ruan <ruanjinjie@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/U5NMENU3HKU43Z6ZQPMDWERAWKW6MV5L/

 
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

In linux-6.1, the related code is refactored in commit 124c49b1
("arm64: armv8_deprecated: rework deprected instruction handling") and this
issue was incidentally fixed. This patch set try to adapt the refactoring
stable 5.10 patches to solve the problem of repeated addition of linked
lists described below.

How to reproduce:
CONFIG_ARMV8_DEPRECATED=y, CONFIG_SWP_EMULATION=y, and CONFIG_DEBUG_LIST=y,
then launch two shell executions:
       #!/bin/bash
       while [ 1 ];
       do
           echo 1 > /proc/sys/abi/swp
       done

or "echo 1 > /proc/sys/abi/swp" and then launch two shell executions:
       #!/bin/bash
       while [ 1 ];
       do
           echo 0 > /proc/sys/abi/swp
       done

In emulation_proc_handler(), read and write operations are performed on
resulting in a list_add double problem.

commit 124c49b1 ("arm64: armv8_deprecated: rework deprected instruction
handling") remove the dynamic registration and unregistration so remove the
register_undef_hook() function, so the below problem was incidentally
fixed.

Call trace:
 __list_add_valid+0xd8/0xe4
 register_undef_hook+0x94/0x13c
 emulation_proc_handler+0xd8/0xf4
 proc_sys_call_handler+0x140/0x250
 proc_sys_write+0x1c/0x2c
 new_sync_write+0xec/0x18c
 vfs_write+0x214/0x2ac
 ksys_write+0x70/0xfc
 __arm64_sys_write+0x24/0x30
 el0_svc_common.constprop.0+0x7c/0x1bc
 do_el0_svc+0x2c/0x94
 el0_svc+0x20/0x30
 el0_sync_handler+0xb0/0xb4
 el0_sync+0x160/0x180

Call trace:
 __list_del_entry_valid+0xac/0x110
 unregister_undef_hook+0x34/0x80
 emulation_proc_handler+0x8c/0xd8
 proc_sys_call_handler+0x1d8/0x208
 proc_sys_write+0x14/0x20
 new_sync_write+0xf0/0x190
 vfs_write+0x304/0x388
 ksys_write+0x6c/0x100
 __arm64_sys_write+0x1c/0x28
 el0_svc_common.constprop.4+0x68/0x188
 do_el0_svc+0x24/0xa0
 el0_svc+0x14/0x20
 el0_sync_handler+0x90/0xb8
 el0_sync+0x160/0x180

The first patch is the self-developed patch, so revert it.

The next 4 patches is a patch set which provides context for subsequent
refactoring 9 patches, especially commit 0f2cb928 ("arm64:
consistently pass ESR_ELx to die()") which modify do_undefinstr() to add a
ESR_ELx value arg, and then commit 61d64a37 ("arm64: split EL0/EL1
UNDEF handlers") splits do_undefinstr() handler into separate
do_el0_undef() and do_el1_undef() handlers.

The 9 patches after that is another refactoring patch set, which is in
preparation for the main rework commit 124c49b1 ("arm64:
armv8_deprecated: rework deprected instruction handling"). To remove struct
undef_hook, commit bff8f413 ("arm64: factor out EL1 SSBS emulation
hook") factor out EL1 SSBS emulation hook, which also avoid call
call_undef_hook() in do_el1_undef(), commit f5962add ("arm64: rework
EL0 MRS emulation") factor out EL0 MRS emulation hook, which also prepare
for replacing call_undef_hook() in do_el0_undef(). To replace
call_undef_hook() function, commit 61d64a37 ("arm64: split EL0/EL1
UNDEF handlers") split the do_undefinstr() into do_el0_undef() and
do_el1_undef() functions, and commit dbfbd87e ("arm64: factor insn
read out of call_undef_hook()") factor user_insn_read() from
call_undef_hook() so the main rework patch can replace the
call_undef_hook() in do_el0_undef().

The last patch is a bugfix for the main rework patch.

I've tested this with userspace programs which use each of the
deprecated instructions on Raspberry Pi 4B KVM/Qemu, and I've concurrently
modified the support level for each of the features back-and-forth between
HW and emulated to check that there are no oops or above repeated addition
or deletion call trace.

Fixes: af483947 ("arm64: fix oops in concurrently setting insn_emulation sysctls")
Signed-off-by: default avatarJinjie Ruan <ruanjinjie@huawei.com>


Jinjie Ruan (1):
  Revert "arm64: fix a concurrency issue in emulation_proc_handler()"

Mark Rutland (13):
  arm64: die(): pass 'err' as long
  arm64: consistently pass ESR_ELx to die()
  arm64: rework FPAC exception handling
  arm64: rework BTI exception handling
  arm64: allow kprobes on EL0 handlers
  arm64: split EL0/EL1 UNDEF handlers
  arm64: factor out EL1 SSBS emulation hook
  arm64: factor insn read out of call_undef_hook()
  arm64: rework EL0 MRS emulation
  arm64: armv8_deprecated: fold ops into insn_emulation
  arm64: armv8_deprecated move emulation functions
  arm64: armv8_deprecated: move aarch32 helper earlier
  arm64: armv8_deprecated: rework deprected instruction handling

Ren Zhijie (1):
  arm64: armv8_deprecated: fix unused-function error


-- 
2.34.1
 
https://gitee.com/src-openeuler/kernel/issues/I65RG3?from=project-issue 
 
Link:https://gitee.com/openeuler/kernel/pulls/2632

 

Reviewed-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parents a8adb1a9 d3cb6492
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -782,7 +782,8 @@ static inline bool system_supports_pbha(void)
}
#endif

extern int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt);
int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt);
bool try_emulate_mrs(struct pt_regs *regs, u32 isn);

static inline u32 id_aa64mmfr0_parange_to_phys_shift(int parange)
{
+8 −5
Original line number Diff line number Diff line
@@ -38,19 +38,22 @@ asmlinkage void exit_to_user_mode(void);
void arm64_enter_nmi(struct pt_regs *regs);
void arm64_exit_nmi(struct pt_regs *regs);
void do_mem_abort(unsigned long addr, unsigned int esr, struct pt_regs *regs);
void do_undefinstr(struct pt_regs *regs);
void do_bti(struct pt_regs *regs);
void do_el0_undef(struct pt_regs *regs, unsigned long esr);
void do_el1_undef(struct pt_regs *regs, unsigned long esr);
void do_el0_bti(struct pt_regs *regs);
void do_el1_bti(struct pt_regs *regs, unsigned long esr);
asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr);
void do_debug_exception(unsigned long addr_if_watchpoint, unsigned int esr,
			struct pt_regs *regs);
void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs);
void do_sve_acc(unsigned int esr, struct pt_regs *regs);
void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs);
void do_sysinstr(unsigned int esr, struct pt_regs *regs);
void do_el0_sys(unsigned long esr, struct pt_regs *regs);
void do_sp_pc_abort(unsigned long addr, unsigned int esr, struct pt_regs *regs);
void bad_el0_sync(struct pt_regs *regs, int reason, unsigned int esr);
void do_cp15instr(unsigned int esr, struct pt_regs *regs);
void do_el0_cp15(unsigned long esr, struct pt_regs *regs);
void do_el0_svc(struct pt_regs *regs);
void do_el0_svc_compat(struct pt_regs *regs);
void do_ptrauth_fault(struct pt_regs *regs, unsigned int esr);
void do_el0_fpac(struct pt_regs *regs, unsigned long esr);
void do_el1_fpac(struct pt_regs *regs, unsigned long esr);
#endif	/* __ASM_EXCEPTION_H */
+2 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ enum mitigation_state {
	SPECTRE_VULNERABLE,
};

struct pt_regs;
struct task_struct;

enum mitigation_state arm64_get_spectre_v2_state(void);
@@ -33,4 +34,5 @@ enum mitigation_state arm64_get_spectre_bhb_state(void);
bool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry, int scope);
u8 spectre_bhb_loop_affected(int scope);
void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *__unused);
bool try_emulate_el1_ssbs(struct pt_regs *regs, u32 instr);
#endif	/* __ASM_SPECTRE_H */
+1 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@

struct pt_regs;

void die(const char *msg, struct pt_regs *regs, int err);
void die(const char *msg, struct pt_regs *regs, long err);

struct siginfo;
void arm64_notify_die(const char *str, struct pt_regs *regs,
+9 −10
Original line number Diff line number Diff line
@@ -13,17 +13,16 @@

struct pt_regs;

struct undef_hook {
	struct list_head node;
	u32 instr_mask;
	u32 instr_val;
	u64 pstate_mask;
	u64 pstate_val;
	int (*fn)(struct pt_regs *regs, u32 instr);
};
#ifdef CONFIG_ARMV8_DEPRECATED
bool try_emulate_armv8_deprecated(struct pt_regs *regs, u32 insn);
#else
static inline bool
try_emulate_armv8_deprecated(struct pt_regs *regs, u32 insn)
{
	return false;
}
#endif /* CONFIG_ARMV8_DEPRECATED */

void register_undef_hook(struct undef_hook *hook);
void unregister_undef_hook(struct undef_hook *hook);
void force_signal_inject(int signal, int code, unsigned long address, unsigned int err);
void arm64_notify_segfault(unsigned long addr);
void arm64_force_sig_fault(int signo, int code, void __user *addr, const char *str);
Loading