lkml.org 
[lkml]   [1999]   [Sep]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH] 2.3.18: siginfo data available for all signals
Date
Normally only real-time signals have siginfo data. However it is also
useful for other signals as well. Some of the other signals would like to
carry extra information, but that information is lost currently.

This patch handles all signals alike. Every signal is put into the signal
queue. Only real-time signals are queued multiple times. Other signals can
have only one siginfo in the queue.

The patch also fixes some unitialized data being passed to user space
under some circumstances. When sending a signal using kill, the siginfo
structure on the stack was not zeroed.

For some reason magic values for siginfo were passed to send_sig_info.
These magic values are transformed to normal pointers to a struct siginfo,
so that the rest of the code does not have to handle these special values.
This simplifies the rest of the code somewhat.

Any comments?
The last few times I have sent in this patch I have received zero reactions. On
the other hand the patch does not seem to make it into kernels. Something must
be wrong, however I don't know what it is.

Robert

--
Robert de Vries
rhdv@rhdv.cistron.nl
--- linux-2.3.18ac2-vanilla/kernel/signal.c Mon Aug 23 20:15:53 1999
+++ linux-2.3.18ac2-devt/kernel/signal.c Mon Sep 13 22:33:21 1999
@@ -129,64 +129,48 @@

if (sig) {
int reset = 1;
+ struct signal_queue *q, **pp;

/* Collect the siginfo appropriate to this signal. */
- if (sig < SIGRTMIN) {
- /* XXX: As an extension, support queueing exactly
- one non-rt signal if SA_SIGINFO is set, so that
- we can get more detailed information about the
- cause of the signal. */
- /* Deciding not to init these couple of fields is
- more expensive that just initializing them. */
+ pp = &current->sigqueue;
+ q = current->sigqueue;
+
+ /* Find the one we're interested in ... */
+ for ( ; q ; pp = &q->next, q = q->next)
+ if (q->info.si_signo == sig)
+ break;
+ if (q) {
+ if ((*pp = q->next) == NULL)
+ current->sigqueue_tail = pp;
+ *info = q->info;
+ kmem_cache_free(signal_queue_cachep,q);
+ atomic_dec(&nr_queued_signals);
+
+ /* then see if this signal is still pending. */
+ q = *pp;
+ while (q) {
+ if (q->info.si_signo == sig) {
+ reset = 0;
+ break;
+ }
+ q = q->next;
+ }
+ } else {
+ /* Ok, it wasn't in the queue. It must have
+ been sent either by a non-rt mechanism and
+ we ran out of queue space. So zero out the
+ info. */
info->si_signo = sig;
info->si_errno = 0;
info->si_code = 0;
info->si_pid = 0;
info->si_uid = 0;
- } else {
- struct signal_queue *q, **pp;
- pp = &current->sigqueue;
- q = current->sigqueue;
-
- /* Find the one we're interested in ... */
- for ( ; q ; pp = &q->next, q = q->next)
- if (q->info.si_signo == sig)
- break;
- if (q) {
- if ((*pp = q->next) == NULL)
- current->sigqueue_tail = pp;
- *info = q->info;
- kmem_cache_free(signal_queue_cachep,q);
- atomic_dec(&nr_queued_signals);
-
- /* then see if this signal is still pending. */
- q = *pp;
- while (q) {
- if (q->info.si_signo == sig) {
- reset = 0;
- break;
- }
- q = q->next;
- }
- } else {
- /* Ok, it wasn't in the queue. It must have
- been sent either by a non-rt mechanism and
- we ran out of queue space. So zero out the
- info. */
- info->si_signo = sig;
- info->si_errno = 0;
- info->si_code = 0;
- info->si_pid = 0;
- info->si_uid = 0;
- }
}

if (reset)
sigdelset(&current->signal, sig);
recalc_sigpending(current);

- /* XXX: Once POSIX.1b timers are in, if si_code == SI_TIMER,
- we need to xchg out the timer overrun values. */
} else {
/* XXX: Once CLONE_PID is in to join those "threads" that are
part of the same "process", look for signals sent to the
@@ -247,11 +231,33 @@
return 1;
}

+static void set_siginfo(siginfo_t *info, int sig, int kernel_signal)
+{
+ memset(info, 0, sizeof(*info));
+
+ if (kernel_signal) {
+ info->si_signo = sig;
+ info->si_errno = 0;
+ info->si_code = SI_KERNEL;
+ info->si_pid = 0;
+ info->si_uid = 0;
+ }
+ else {
+ info->si_signo = sig;
+ info->si_errno = 0;
+ info->si_code = SI_USER;
+ info->si_pid = current->pid;
+ info->si_uid = current->uid;
+ }
+}
+
int
send_sig_info(int sig, struct siginfo *info, struct task_struct *t)
{
unsigned long flags;
int ret;
+ struct signal_queue *q;
+ siginfo_t info_compat;

#if DEBUG_SIG
printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
@@ -260,9 +266,16 @@
ret = -EINVAL;
if (sig < 0 || sig > _NSIG)
goto out_nolock;
+
+ /* backward compatibility, convert magic info value to real info */
+ if ((info == NULL) || ((unsigned long)info == 1)) {
+ set_siginfo(&info_compat, sig, info != NULL);
+ info = &info_compat;
+ }
+
/* The somewhat baroque permissions check... */
ret = -EPERM;
- if ((!info || ((unsigned long)info != 1 && SI_FROMUSER(info)))
+ if (SI_FROMUSER(info)
&& ((sig != SIGCONT) || (current->session != t->session))
&& (current->euid ^ t->suid) && (current->euid ^ t->uid)
&& (current->uid ^ t->suid) && (current->uid ^ t->uid)
@@ -304,63 +317,42 @@
if (ignored_signal(sig, t))
goto out;

- if (sig < SIGRTMIN) {
- /* Non-real-time signals are not queued. */
- /* XXX: As an extension, support queueing exactly one
- non-rt signal if SA_SIGINFO is set, so that we can
- get more detailed information about the cause of
- the signal. */
+ /* If it is a NON RT signal, only one signal gets queued, the later
+ ones are discarded. */
+ else if (sig < SIGRTMIN) {
+ /* Non-real-time signals are not queued. */
if (sigismember(&t->signal, sig))
goto out;
+ }
+
+ /* Real-time signals must be queued if sent by sigqueue, or
+ some other real-time mechanism. It is implementation
+ defined whether kill() does so. We attempt to do so, on
+ the principle of least surprise, but since kill is not
+ allowed to fail with EAGAIN when low on memory we just
+ make sure at least one signal gets delivered and don't
+ pass on the info struct. */
+
+ q = 0;
+ if (atomic_read(&nr_queued_signals) < max_queued_signals) {
+ q = (struct signal_queue *)
+ kmem_cache_alloc(signal_queue_cachep, GFP_ATOMIC);
+ }
+
+ if (q) {
+ atomic_inc(&nr_queued_signals);
+ q->next = NULL;
+ *t->sigqueue_tail = q;
+ t->sigqueue_tail = &q->next;
+ q->info = *info;
} else {
- /* Real-time signals must be queued if sent by sigqueue, or
- some other real-time mechanism. It is implementation
- defined whether kill() does so. We attempt to do so, on
- the principle of least surprise, but since kill is not
- allowed to fail with EAGAIN when low on memory we just
- make sure at least one signal gets delivered and don't
- pass on the info struct. */
-
- struct signal_queue *q = 0;
-
- if (atomic_read(&nr_queued_signals) < max_queued_signals) {
- q = (struct signal_queue *)
- kmem_cache_alloc(signal_queue_cachep, GFP_ATOMIC);
- }
-
- if (q) {
- atomic_inc(&nr_queued_signals);
- q->next = NULL;
- *t->sigqueue_tail = q;
- t->sigqueue_tail = &q->next;
- switch ((unsigned long) info) {
- case 0:
- q->info.si_signo = sig;
- q->info.si_errno = 0;
- q->info.si_code = SI_USER;
- q->info.si_pid = current->pid;
- q->info.si_uid = current->uid;
- break;
- case 1:
- q->info.si_signo = sig;
- q->info.si_errno = 0;
- q->info.si_code = SI_KERNEL;
- q->info.si_pid = 0;
- q->info.si_uid = 0;
- break;
- default:
- q->info = *info;
- break;
- }
- } else {
- /* If this was sent by a rt mechanism, try again. */
- if (info->si_code < 0) {
- ret = -EAGAIN;
- goto out;
- }
- /* Otherwise, mention that the signal is pending,
- but don't queue the info. */
+ /* If this was sent by a rt mechanism, try again. */
+ if (info->si_code < 0) {
+ ret = -EAGAIN;
+ goto out;
}
+ /* Otherwise, mention that the signal is pending,
+ but don't queue the info. */
}

sigaddset(&t->signal, sig);
@@ -791,6 +783,8 @@
sys_kill(int pid, int sig)
{
struct siginfo info;
+
+ memset(&info, 0, sizeof(info));

info.si_signo = sig;
info.si_errno = 0;
\
 
 \ /
  Last update: 2005-03-22 13:53    [W:0.056 / U:0.256 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site