kernel/kernel-rt/centos/patches/0001-Notification-of-death-of-arbitrary-processes.patch
Jiping Ma 2cb3d041cd Upgrade to 5.10 Linux kernel.
Move to kernel version 5.10 using source from the Yocto Project.
1. Add STX patches for kernel 5.10.
2. Support git source for linux-yocto.
3. Add build_srpm from build-tools/default_build_srpm
   and modified for git repo from yocto
4. Modify std and rt config files.
5. Build python-perf instead of python3-perf for std kernel.
   python-perf is needed by tuned-2.8.0-5.el7.noarch.
6. Modify rt spec to build out package kernel-rt-tools and kernel-rt-kvm.
7. Add kernel-5.10.30-x86_64-rt.config.tis_extra and
   kernel-5.10.30-x86_64.config.tis_extra
8. Add a dist field to avoid undesired rebuilds.
9. Ensure -unsigned package is populated

Story: 2008921
Partial-Task: 42519

Signed-off-by: Jackie Huang <jackie.huang@windriver.com>
Signed-off-by: Vefa Bicakci <vefa.bicakci@windriver.com>
Signed-off-by: Jiping Ma <jiping.ma2@windriver.com>
Change-Id: Id1f635302f265826f7ff2860a3bed4b7755b2888
2021-07-26 02:40:01 -04:00

546 lines
16 KiB
Diff

From 33efb73059c7e1f2facc7bb04f60d706c07f640d Mon Sep 17 00:00:00 2001
From: Chris Friesen <chris.friesen@windriver.com>
Date: Thu, 17 Jun 2021 01:28:11 -0700
Subject: [PATCH] Notification of death of arbitrary processes
Note: this commit was copied from Titanium Cloud Rel2
This exposes a new feature which may be called to request
notification when an arbitrary process changes state. The
caller specifies a pid, signal number, and event mask, and
when that pid dies, or is stopped, or anything else that
would normally cause a SIGCHLD, the kernel will send the
specified signal to the caller if the event is in the event
mask originally passed down. The siginfo_t struct will
contain the same information as would be included with SIGCHLD.
This is exposed to userspace via the prctl() call with the
PR_DO_NOTIFY_TASK_STATE option.
Signed-off-by: Jim Somerville <Jim.Somerville@windriver.com>
Signed-off-by: Zhang Zhiguo <zhangzhg@neusoft.com>
Signed-off-by: Shuicheng Lin <shuicheng.lin@intel.com>
[jm: Adapted the patch for context changes.]
Signed-off-by: Jiping Ma <jiping.ma2@windriver.com>
---
include/linux/init_task.h | 9 ++
include/linux/sched.h | 6 +
include/uapi/linux/prctl.h | 16 +++
init/Kconfig | 15 +++
init/init_task.c | 1 +
kernel/Makefile | 1 +
kernel/death_notify.c | 228 +++++++++++++++++++++++++++++++++++++
kernel/death_notify.h | 46 ++++++++
kernel/exit.c | 6 +
kernel/fork.c | 4 +
kernel/signal.c | 11 ++
kernel/sys.c | 8 ++
12 files changed, 351 insertions(+)
create mode 100644 kernel/death_notify.c
create mode 100644 kernel/death_notify.h
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index b2412b4d4c20..7a0828daf59c 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -25,6 +25,15 @@
extern struct files_struct init_files;
extern struct fs_struct init_fs;
extern struct nsproxy init_nsproxy;
+
+#ifdef CONFIG_SIGEXIT
+#define INIT_SIGEXIT(tsk) \
+ .notify = LIST_HEAD_INIT(tsk.notify), \
+ .monitor = LIST_HEAD_INIT(tsk.monitor),
+#else
+#define INIT_SIGEXIT(tsk)
+#endif
+
extern struct group_info init_groups;
extern struct cred init_cred;
diff --git a/include/linux/sched.h b/include/linux/sched.h
index e688e9307a21..c4b43b5d439f 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1145,6 +1145,12 @@ struct task_struct {
short il_prev;
short pref_node_fork;
#endif
+#ifdef CONFIG_SIGEXIT
+ /* list of processes to notify on death */
+ struct list_head notify;
+ /* list of outstanding monitor requests */
+ struct list_head monitor;
+#endif
#ifdef CONFIG_NUMA_BALANCING
int numa_scan_seq;
unsigned int numa_scan_period;
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index 7f0827705c9a..dbd5a8b6e002 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -63,6 +63,22 @@
# define PR_ENDIAN_LITTLE 1 /* True little endian mode */
# define PR_ENDIAN_PPC_LITTLE 2 /* "PowerPC" pseudo little endian */
+#define PR_DO_NOTIFY_TASK_STATE 17 /* Set/get notification for task
+ state changes */
+
+/* This is the data structure for requestion process death
+ * (and other state change) information. Sig of -1 means
+ * query, sig of 0 means deregistration, positive sig means
+ * that you want to set it. sig and events are value-result
+ * and will be updated with the previous values on every
+ * successful call.
+ */
+struct task_state_notify_info {
+ int pid;
+ int sig;
+ unsigned int events;
+};
+
/* Get/set process seccomp mode */
#define PR_GET_SECCOMP 21
#define PR_SET_SECCOMP 22
diff --git a/init/Kconfig b/init/Kconfig
index 7ba2b602b707..5a5f38706715 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1852,6 +1852,21 @@ config VM_EVENT_COUNTERS
on EXPERT systems. /proc/vmstat will only show page counts
if VM event counters are disabled.
+config SIGEXIT
+ bool "Notification of death of arbitrary processes"
+ default n
+ help
+ When enabled this exposes a new feature which may be called to request
+ notification when an arbitrary process changes state. The caller specifies
+ a pid, signal number, and event mask, and when that pid dies, or is
+ stopped, or anything else that would normally cause a SIGCHLD, the
+ kernel will send the specified signal to the caller if the event is in
+ the event mask originally passed down. The siginfo_t struct will
+ contain the same information as would be included with SIGCHLD.
+
+ This is exposed to userspace via the prctl()
+ call with the PR_DO_NOTIFY_TASK_STATE option
+
config SLUB_DEBUG
default y
bool "Enable SLUB debugging support" if EXPERT
diff --git a/init/init_task.c b/init/init_task.c
index 5fa18ed59d33..e1a245782828 100644
--- a/init/init_task.c
+++ b/init/init_task.c
@@ -128,6 +128,7 @@ struct task_struct init_task
.alloc_lock = __SPIN_LOCK_UNLOCKED(init_task.alloc_lock),
.journal_info = NULL,
INIT_CPU_TIMERS(init_task)
+ INIT_SIGEXIT(init_task)
.pi_lock = __RAW_SPIN_LOCK_UNLOCKED(init_task.pi_lock),
.timer_slack_ns = 50000, /* 50 usec default slack */
.thread_pid = &init_struct_pid,
diff --git a/kernel/Makefile b/kernel/Makefile
index e7905bdf6e97..ba9997c7a59c 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -108,6 +108,7 @@ obj-$(CONFIG_BPF) += bpf/
obj-$(CONFIG_KCSAN) += kcsan/
obj-$(CONFIG_SHADOW_CALL_STACK) += scs.o
obj-$(CONFIG_HAVE_STATIC_CALL_INLINE) += static_call.o
+obj-$(CONFIG_SIGEXIT) += death_notify.o
obj-$(CONFIG_PERF_EVENTS) += events/
diff --git a/kernel/death_notify.c b/kernel/death_notify.c
new file mode 100644
index 000000000000..5819d35a2564
--- /dev/null
+++ b/kernel/death_notify.c
@@ -0,0 +1,228 @@
+/*
+ * kernel/death_notify.c, Process death notification support
+ *
+ * Copyright (c) 2006-2014 Wind River Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/sched/task.h>
+#include <linux/slab.h>
+#include <linux/prctl.h>
+#include <linux/uaccess.h>
+#include "death_notify.h"
+
+static void unlink_status_notifier(struct signotifier *n)
+{
+ list_del(&n->monitor_list);
+ list_del(&n->notify_list);
+ kfree(n);
+}
+
+static void handle_already_monitoring(struct signotifier *node,
+ struct task_state_notify_info *args,
+ struct task_state_notify_info *oldargs)
+{
+ /* Store the old values */
+ oldargs->sig = node->sig;
+ oldargs->events = node->events;
+
+ /* We know that args->sig is 0 or a valid signal. */
+ if (args->sig > 0) {
+ /* Update the new values */
+ node->sig = args->sig;
+ node->events = args->events;
+ } else if (!args->sig) {
+ /* args->sig of 0 means to deregister */
+ unlink_status_notifier(node);
+ }
+}
+
+static void setup_new_node(struct task_struct *p,
+ struct signotifier *node,
+ struct task_state_notify_info *args)
+{
+ node->notify_tsk = current;
+ node->sig = args->sig;
+ node->events = args->events;
+
+ /* Add this node to the list of notification requests
+ * for the specified process.
+ */
+ list_add_tail(&node->notify_list, &p->notify);
+
+ /* Also add this node to the list of monitor requests
+ * for the current process.
+ */
+ list_add_tail(&node->monitor_list, &current->monitor);
+}
+
+/* Returns 0 if arguments are valid, 1 if they are not. */
+static int invalid_args(struct task_state_notify_info *args)
+{
+ int ret = 1;
+
+ if (args->pid <= 0)
+ goto out;
+
+ /* Sig of -1 implies query, sig of 0 implies deregistration.
+ * Otherwise sig must be positive and within range.
+ */
+ if ((args->sig < -1) || (args->sig > _NSIG))
+ goto out;
+
+ /* If positive sig, must have valid events. */
+ if (args->sig > 0) {
+ if (!args->events || (args->events >= (1 << (NSIGCHLD+1))))
+ goto out;
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+/* Notify those registered for process state updates via do_notify_task_state().
+ * If "del" is nonzero, the process is dying and we want to free
+ * the nodes in the list as we go.
+ *
+ * Note: we only notify processes for events in which they have registered
+ * interest.
+ *
+ * Must be called holding a lock on tasklist_lock.
+ */
+void do_notify_others(struct task_struct *tsk, struct kernel_siginfo *info)
+{
+ struct signotifier *node;
+ unsigned int events;
+
+ /* This method of generating the event bit must be
+ * matched in the userspace library.
+ */
+ events = 1 << (info->si_code & 0xFF);
+
+ list_for_each_entry(node, &tsk->notify, notify_list) {
+ if (events & node->events) {
+ info->si_signo = node->sig;
+ group_send_sig_info(node->sig, info, node->notify_tsk, PIDTYPE_TGID);
+ }
+ }
+}
+
+void release_notify_others(struct task_struct *p)
+{
+ struct signotifier *n, *t;
+
+ /* Need to clean up any outstanding requests where we
+ * wanted to be notified when others died.
+ */
+ list_for_each_entry_safe(n, t, &p->monitor, monitor_list) {
+ unlink_status_notifier(n);
+ }
+
+ /* Also need to clean up any outstanding requests where others
+ * wanted to be notified when we died.
+ */
+ list_for_each_entry_safe(n, t, &p->notify, notify_list) {
+ unlink_status_notifier(n);
+ }
+}
+
+/* If the config is defined, then processes can call this routine
+ * to request notification when the specified task's state changes.
+ * On the death (or other state change) of the specified process,
+ * we will send them the specified signal if the event is listed
+ * in their event bitfield.
+ *
+ * A sig of 0 means that we want to deregister.
+ *
+ * The sig/events fields are value/result. On success we update them
+ * to reflect what they were before the call.
+ *
+ * Returns error code on error, on success we return 0.
+ */
+int do_notify_task_state(unsigned long arg)
+{
+ int err;
+ struct task_struct *p;
+ struct signotifier *node, *tmp;
+ struct task_state_notify_info args, oldargs;
+
+ if (copy_from_user(&args, (struct task_state_notify_info __user *)arg,
+ sizeof(args)))
+ return -EFAULT;
+ oldargs.pid = args.pid;
+
+ /* Validate the arguments passed in. */
+ err = -EINVAL;
+ if (invalid_args(&args))
+ goto out;
+
+ /* We must hold a write lock on tasklist_lock to add the notification
+ * later on, and we need some lock on tasklist_lock for
+ * find_task_by_pid(), so may as well take the write lock now.
+ * Must use write_lock_irq().
+ */
+ write_lock_irq(&tasklist_lock);
+
+ err = -ESRCH;
+ p = find_task_by_vpid(args.pid);
+ if (!p)
+ goto unlock_out;
+
+ /* Now we know pid exists, unlikely to fail. */
+ err = 0;
+
+ /* Check if we're already monitoring the specified pid. If so, update
+ * the monitoring parameters and return the old ones.
+ */
+ list_for_each_entry(tmp, &p->notify, notify_list) {
+ if (tmp->notify_tsk == current) {
+ handle_already_monitoring(tmp, &args, &oldargs);
+ goto unlock_out;
+ }
+ }
+
+ /* If we get here, we're not currently monitoring the process. */
+ oldargs.sig = 0;
+ oldargs.events = 0;
+
+ /* If we wanted to set up a new monitor, do it now. If we didn't
+ * manage to allocate memory for the new node, then we return
+ * an appropriate error.
+ */
+ if (args.sig > 0) {
+ node = kmalloc(sizeof(*node), GFP_ATOMIC);
+ if (node)
+ setup_new_node(p, node, &args);
+ else
+ err = -ENOMEM;
+ }
+
+unlock_out:
+ write_unlock_irq(&tasklist_lock);
+
+ /* Copy the old values back to caller. */
+ if (copy_to_user((struct task_state_notify_info __user *)arg,
+ &oldargs, sizeof(oldargs)))
+ err = -EFAULT;
+
+out:
+ return err;
+}
+
diff --git a/kernel/death_notify.h b/kernel/death_notify.h
new file mode 100644
index 000000000000..14a0995b79af
--- /dev/null
+++ b/kernel/death_notify.h
@@ -0,0 +1,46 @@
+/*
+ * kernel/death_notify.h, Process death notification support
+ *
+ * Copyright (c) 2006-2014 Wind River Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef _KERNEL_DEATH_NOTIFY_H
+#define _KERNEL_DEATH_NOTIFY_H
+
+#ifdef CONFIG_SIGEXIT
+
+struct signotifier {
+ struct task_struct *notify_tsk;
+ struct list_head notify_list;
+ struct list_head monitor_list;
+ int sig;
+ unsigned int events;
+};
+
+extern int do_notify_task_state(unsigned long arg);
+extern void do_notify_others(struct task_struct *tsk,
+ struct kernel_siginfo *info);
+extern void release_notify_others(struct task_struct *p);
+
+#else /* !CONFIG_SIGEXIT */
+
+static inline void do_notify_others(struct task_struct *tsk,
+ struct kernel_siginfo *info) {}
+static inline void release_notify_others(struct task_struct *p) {}
+
+#endif /* CONFIG_SIGEXIT */
+#endif
+
diff --git a/kernel/exit.c b/kernel/exit.c
index f5933bd07932..3c328a630257 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -68,6 +68,9 @@
#include <linux/uaccess.h>
#include <asm/unistd.h>
#include <asm/mmu_context.h>
+#ifdef CONFIG_SIGEXIT
+#include "death_notify.h"
+#endif
static void __unhash_process(struct task_struct *p, bool group_dead)
{
@@ -194,6 +197,9 @@ void release_task(struct task_struct *p)
cgroup_release(p);
write_lock_irq(&tasklist_lock);
+#ifdef CONFIG_SIGEXIT
+ release_notify_others(p);
+#endif
ptrace_release_task(p);
thread_pid = get_pid(p->thread_pid);
__exit_signal(p);
diff --git a/kernel/fork.c b/kernel/fork.c
index fb3fbfd44b25..94769fcf71ac 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -2095,6 +2095,10 @@ static __latent_entropy struct task_struct *copy_process(
p->sequential_io = 0;
p->sequential_io_avg = 0;
#endif
+#ifdef CONFIG_SIGEXIT
+ INIT_LIST_HEAD(&p->notify);
+ INIT_LIST_HEAD(&p->monitor);
+#endif
/* Perform scheduler related setup. Assign this task to a CPU. */
retval = sched_fork(clone_flags, p);
diff --git a/kernel/signal.c b/kernel/signal.c
index 0be3c40c5662..1581b2a76823 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -56,6 +56,9 @@
#include <asm/unistd.h>
#include <asm/siginfo.h>
#include <asm/cacheflush.h>
+#ifdef CONFIG_SIGEXIT
+#include "death_notify.h"
+#endif
/*
* SLAB caches for signal bits.
@@ -2088,6 +2091,10 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
__wake_up_parent(tsk, tsk->parent);
spin_unlock_irqrestore(&psig->siglock, flags);
+#ifdef CONFIG_SIGEXIT
+ do_notify_others(tsk, &info);
+#endif
+
return autoreap;
}
@@ -2160,6 +2167,10 @@ static void do_notify_parent_cldstop(struct task_struct *tsk,
*/
__wake_up_parent(tsk, parent);
spin_unlock_irqrestore(&sighand->siglock, flags);
+
+#ifdef CONFIG_SIGEXIT
+ do_notify_others(tsk, &info);
+#endif
}
static inline bool may_ptrace_stop(void)
diff --git a/kernel/sys.c b/kernel/sys.c
index a730c03ee607..0f8decf763f1 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -73,6 +73,9 @@
#include <asm/unistd.h>
#include "uid16.h"
+#ifdef CONFIG_SIGEXIT
+#include "death_notify.h"
+#endif
#ifndef SET_UNALIGN_CTL
# define SET_UNALIGN_CTL(a, b) (-EINVAL)
@@ -2423,6 +2426,11 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
else
error = PR_MCE_KILL_DEFAULT;
break;
+#ifdef CONFIG_SIGEXIT
+ case PR_DO_NOTIFY_TASK_STATE:
+ error = do_notify_task_state(arg2);
+ break;
+#endif
case PR_SET_MM:
error = prctl_set_mm(arg2, arg3, arg4, arg5);
break;
--
2.31.1