X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;f=meta-starlingx%2Fmeta-stx-integ%2Frecipes-kernel%2Flinux%2Flinux%2FNotification-of-Death-of-arbitrary-processes.patch;fp=meta-starlingx%2Fmeta-stx-integ%2Frecipes-kernel%2Flinux%2Flinux%2FNotification-of-Death-of-arbitrary-processes.patch;h=0000000000000000000000000000000000000000;hb=48f4dcb359cde8be05e616cc6cbfc04a63b684be;hp=e1e4ecf5b65da91e7d23e5829f8f136bb8a511a2;hpb=683e49cccaff86dce0ecb80882cdf9b4fdec1e1b;p=pti%2Frtp.git diff --git a/meta-starlingx/meta-stx-integ/recipes-kernel/linux/linux/Notification-of-Death-of-arbitrary-processes.patch b/meta-starlingx/meta-stx-integ/recipes-kernel/linux/linux/Notification-of-Death-of-arbitrary-processes.patch deleted file mode 100644 index e1e4ecf..0000000 --- a/meta-starlingx/meta-stx-integ/recipes-kernel/linux/linux/Notification-of-Death-of-arbitrary-processes.patch +++ /dev/null @@ -1,546 +0,0 @@ -From 4cfbf1a112e17b071fcdae207e4f785c096a198c Mon Sep 17 00:00:00 2001 -From: Saul Wold -Date: Thu, 2 Jul 2020 09:46:12 -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 -Signed-off-by: Zhang Zhiguo -Signed-off-by: Shuicheng Lin -Signed-off-by: Saul Wold ---- - include/linux/init_task.h | 9 ++ - include/linux/sched.h | 6 + - include/uapi/linux/prctl.h | 18 +++ - 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, 353 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 a7083a45a26c..1ad2341b3036 100644 ---- a/include/linux/init_task.h -+++ b/include/linux/init_task.h -@@ -24,6 +24,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 9b35aff09f70..d6f5a2711b7d 100644 ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -1015,6 +1015,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 b4875a93363a..d50c435a04ea 100644 ---- a/include/uapi/linux/prctl.h -+++ b/include/uapi/linux/prctl.h -@@ -63,6 +63,24 @@ - # define PR_ENDIAN_LITTLE 1 /* True little endian mode */ - # define PR_ENDIAN_PPC_LITTLE 2 /* "PowerPC" pseudo little endian */ - -+#ifdef CONFIG_SIGEXIT -+#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 { -+ pid_t pid; -+ int sig; -+ unsigned int events; -+}; -+#endif -+ - /* Get/set process seccomp mode */ - #define PR_GET_SECCOMP 21 - #define PR_SET_SECCOMP 22 -diff --git a/init/Kconfig b/init/Kconfig -index bdf4f284509b..8102ef3d2adb 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1648,6 +1648,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 5aebe3be4d7c..d0891101ac7d 100644 ---- a/init/init_task.c -+++ b/init/init_task.c -@@ -116,6 +116,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 1ea0ba13a445..f839f425ca09 100644 ---- a/kernel/Makefile -+++ b/kernel/Makefile -@@ -99,6 +99,7 @@ obj-$(CONFIG_TRACEPOINTS) += trace/ - obj-$(CONFIG_IRQ_WORK) += irq_work.o - obj-$(CONFIG_CPU_PM) += cpu_pm.o - obj-$(CONFIG_BPF) += bpf/ -+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 -+#include -+#include -+#include -+#include -+#include -+#include -+#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, ¤t->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 2166c2d92ddc..f35f3a5870a8 100644 ---- a/kernel/exit.c -+++ b/kernel/exit.c -@@ -67,6 +67,9 @@ - #include - #include - #include -+#ifdef CONFIG_SIGEXIT -+#include "death_notify.h" -+#endif - - static void __unhash_process(struct task_struct *p, bool group_dead) - { -@@ -196,6 +199,9 @@ void release_task(struct task_struct *p) - proc_flush_task(p); - - write_lock_irq(&tasklist_lock); -+#ifdef CONFIG_SIGEXIT -+ release_notify_others(p); -+#endif - ptrace_release_task(p); - __exit_signal(p); - -diff --git a/kernel/fork.c b/kernel/fork.c -index 17389e9935c4..4d79f261c365 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -1907,6 +1907,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 57b7771e20d7..41126fa53102 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -51,6 +51,9 @@ - #include - #include - #include "audit.h" /* audit_signal_info() */ -+#ifdef CONFIG_SIGEXIT -+#include "death_notify.h" -+#endif - - /* - * SLAB caches for signal bits. -@@ -1893,6 +1896,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; - } - -@@ -1965,6 +1972,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 f7eb62eceb24..9fadbbe9565f 100644 ---- a/kernel/sys.c -+++ b/kernel/sys.c -@@ -72,6 +72,9 @@ - #include - - #include "uid16.h" -+#ifdef CONFIG_SIGEXIT -+#include "death_notify.h" -+#endif - - #ifndef SET_UNALIGN_CTL - # define SET_UNALIGN_CTL(a, b) (-EINVAL) -@@ -2405,6 +2408,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.17.1 -