summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2003-07-07 01:31:32 -0700
committerSteve French <cifs.adm@hostme.bitkeeper.com>2003-07-07 01:31:32 -0700
commit62133cb1109242fde586f965cff48c85eaa7f52b (patch)
tree07656df61505697ba63078a7b1b0bf76890c1288
parentf597d1debdd1f5314a0177cb68d1d0ced960929b (diff)
[PATCH] tgkill patch for safe inter-thread signals
This is the updated versions of the patch Ingo sent some time ago to implement a new tgkill() syscall which specifies the target thread without any possibility of ambiguity or thread ID wrap races, by passing in both the thread group _and_ the thread ID as the arguments. This is really needed since many/most people still run with limited PID ranges (maybe due to legacy apps breaking) and the PID reuse can cause problems.
-rw-r--r--arch/i386/kernel/entry.S1
-rw-r--r--include/asm-i386/unistd.h3
-rw-r--r--kernel/signal.c50
3 files changed, 51 insertions, 3 deletions
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index 5aef7a47a383..dafcae8663c8 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -876,5 +876,6 @@ ENTRY(sys_call_table)
.long sys_clock_nanosleep
.long sys_statfs64
.long sys_fstatfs64
+ .long sys_tgkill
nr_syscalls=(.-sys_call_table)/4
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
index b1bdc016eed5..f39e505e3eb4 100644
--- a/include/asm-i386/unistd.h
+++ b/include/asm-i386/unistd.h
@@ -275,8 +275,9 @@
#define __NR_clock_nanosleep (__NR_timer_create+8)
#define __NR_statfs64 268
#define __NR_fstatfs64 269
+#define __NR_tgkill 270
-#define NR_syscalls 270
+#define NR_syscalls 271
/* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
diff --git a/kernel/signal.c b/kernel/signal.c
index dbefbea7623e..7ac72191b30b 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -579,8 +579,8 @@ static int rm_from_queue(unsigned long mask, struct sigpending *s)
/*
* Bad permissions for sending the signal
*/
-static inline int check_kill_permission(int sig, struct siginfo *info,
- struct task_struct *t)
+static int check_kill_permission(int sig, struct siginfo *info,
+ struct task_struct *t)
{
int error = -EINVAL;
if (sig < 0 || sig > _NSIG)
@@ -2088,6 +2088,52 @@ sys_kill(int pid, int sig)
return kill_something_info(sig, &info, pid);
}
+/**
+ * sys_tkill - send signal to one specific thread
+ * @tgid: the thread group ID of the thread
+ * @pid: the PID of the thread
+ * @sig: signal to be sent
+ *
+ * This syscall also checks the tgid and returns -ESRCH even if the PID
+ * exists but it's not belonging to the target process anymore. This
+ * method solves the problem of threads exiting and PIDs getting reused.
+ */
+asmlinkage long sys_tgkill(int tgid, int pid, int sig)
+{
+ struct siginfo info;
+ int error;
+ struct task_struct *p;
+
+ /* This is only valid for single tasks */
+ if (pid <= 0 || tgid <= 0)
+ return -EINVAL;
+
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = SI_TKILL;
+ info.si_pid = current->tgid;
+ info.si_uid = current->uid;
+
+ read_lock(&tasklist_lock);
+ p = find_task_by_pid(pid);
+ error = -ESRCH;
+ if (p && (p->tgid == tgid)) {
+ error = check_kill_permission(sig, &info, p);
+ /*
+ * The null signal is a permissions and process existence
+ * probe. No signal is actually delivered.
+ */
+ if (!error && sig && p->sighand) {
+ spin_lock_irq(&p->sighand->siglock);
+ handle_stop_signal(sig, p);
+ error = specific_send_sig_info(sig, &info, p);
+ spin_unlock_irq(&p->sighand->siglock);
+ }
+ }
+ read_unlock(&tasklist_lock);
+ return error;
+}
+
/*
* Send a signal to only one task, even if it's a CLONE_THREAD task.
*/