Commit ad404010 authored by Jens Axboe's avatar Jens Axboe Committed by Jialin Zhang
Browse files

entry: Add support for TIF_NOTIFY_SIGNAL

stable inclusion
from stable-v5.10.162
commit 3c295bd2ddaecf3509458c86bf7ba610042f3609
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I6BTWC
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=v5.10.168&id=3c295bd2ddaecf3509458c86bf7ba610042f3609



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

[ Upstream commit 12db8b69 ]

Add TIF_NOTIFY_SIGNAL handling in the generic entry code, which if set,
will return true if signal_pending() is used in a wait loop. That causes an
exit of the loop so that notify_signal tracehooks can be run. If the wait
loop is currently inside a system call, the system call is restarted once
task_work has been processed.

In preparation for only having arch_do_signal() handle syscall restarts if
_TIF_SIGPENDING isn't set, rename it to arch_do_signal_or_restart().  Pass
in a boolean that tells the architecture specific signal handler if it
should attempt to get a signal, or just process a potential syscall
restart.

For !CONFIG_GENERIC_ENTRY archs, add the TIF_NOTIFY_SIGNAL handling to
get_signal(). This is done to minimize the needed architecture changes to
support this feature.

Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Reviewed-by: default avatarOleg Nesterov <oleg@redhat.com>
Link: https://lore.kernel.org/r/20201026203230.386348-3-axboe@kernel.dk


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>

Conflict:
	include/linux/tracehook.h

Signed-off-by: default avatarLi Lingfeng <lilingfeng3@huawei.com>
Reviewed-by: default avatartanghui <tanghui20@huawei.com>
Reviewed-by: default avatarWang Weiyang <wangweiyang2@huawei.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parent 25f86b0d
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -860,11 +860,11 @@ static inline unsigned long get_nr_restart_syscall(const struct pt_regs *regs)
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
 * mistake.
 */
void arch_do_signal(struct pt_regs *regs)
void arch_do_signal_or_restart(struct pt_regs *regs, bool has_signal)
{
	struct ksignal ksig;

	if (get_signal(&ksig)) {
	if (has_signal && get_signal(&ksig)) {
		/* Whee! Actually deliver the signal.  */
		handle_signal(&ksig, regs);
		return;
+8 −3
Original line number Diff line number Diff line
@@ -38,6 +38,10 @@
# define _TIF_UPROBE			(0)
#endif

#ifndef _TIF_NOTIFY_SIGNAL
# define _TIF_NOTIFY_SIGNAL		(0)
#endif

/*
 * TIF flags handled in syscall_enter_from_user_mode()
 */
@@ -70,7 +74,7 @@

#define EXIT_TO_USER_MODE_WORK						\
	(_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_UPROBE |		\
	 _TIF_NEED_RESCHED | _TIF_PATCH_PENDING |			\
	 _TIF_NEED_RESCHED | _TIF_PATCH_PENDING | _TIF_NOTIFY_SIGNAL |	\
	 ARCH_EXIT_TO_USER_MODE_WORK)

/**
@@ -260,12 +264,13 @@ static __always_inline void arch_exit_to_user_mode(void) { }
#endif

/**
 * arch_do_signal -  Architecture specific signal delivery function
 * arch_do_signal_or_restart -  Architecture specific signal delivery function
 * @regs:	Pointer to currents pt_regs
 * @has_signal:	actual signal to handle
 *
 * Invoked from exit_to_user_mode_loop().
 */
void arch_do_signal(struct pt_regs *regs);
void arch_do_signal_or_restart(struct pt_regs *regs, bool has_signal);

/**
 * arch_syscall_exit_tracehook - Wrapper around tracehook_report_syscall_exit()
+2 −2
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@
#endif

#define XFER_TO_GUEST_MODE_WORK						\
	(_TIF_NEED_RESCHED | _TIF_SIGPENDING |			\
	(_TIF_NEED_RESCHED | _TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL |	\
	 _TIF_NOTIFY_RESUME | ARCH_XFER_TO_GUEST_MODE_WORK)

struct kvm_vcpu;
+10 −1
Original line number Diff line number Diff line
@@ -367,6 +367,15 @@ static inline int task_sigpending(struct task_struct *p)

static inline int signal_pending(struct task_struct *p)
{
#if defined(TIF_NOTIFY_SIGNAL)
	/*
	 * TIF_NOTIFY_SIGNAL isn't really a signal, but it requires the same
	 * behavior in terms of ensuring that we break out of wait loops
	 * so that notify signal callbacks can be processed.
	 */
	if (unlikely(test_tsk_thread_flag(p, TIF_NOTIFY_SIGNAL)))
		return 1;
#endif
	return task_sigpending(p);
}

@@ -514,7 +523,7 @@ extern int set_user_sigmask(const sigset_t __user *umask, size_t sigsetsize);
static inline void restore_saved_sigmask_unless(bool interrupted)
{
	if (interrupted)
		WARN_ON(!test_thread_flag(TIF_SIGPENDING));
		WARN_ON(!signal_pending(current));
	else
		restore_saved_sigmask();
}
+27 −0
Original line number Diff line number Diff line
@@ -202,4 +202,31 @@ static inline void tracehook_notify_resume(struct pt_regs *regs)

}

/*
 * called by exit_to_user_mode_loop() if ti_work & _TIF_NOTIFY_SIGNAL. This
 * is currently used by TWA_SIGNAL based task_work, which requires breaking
 * wait loops to ensure that task_work is noticed and run.
 */
static inline void tracehook_notify_signal(void)
{
#if defined(TIF_NOTIFY_SIGNAL)
	clear_thread_flag(TIF_NOTIFY_SIGNAL);
	smp_mb__after_atomic();
	if (current->task_works)
		task_work_run();
#endif
}

/*
 * Called when we have work to process from exit_to_user_mode_loop()
 */
static inline void set_notify_signal(struct task_struct *task)
{
#if defined(TIF_NOTIFY_SIGNAL)
	if (!test_and_set_tsk_thread_flag(task, TIF_NOTIFY_SIGNAL) &&
	    !wake_up_state(task, TASK_INTERRUPTIBLE))
		kick_process(task);
#endif
}

#endif	/* <linux/tracehook.h> */
Loading