patch for 2.1.81 kernel/signal.c

Bill Hawes (whawes@star.net)
Sat, 24 Jan 1998 10:45:42 -0500


This is a multi-part message in MIME format.
--------------5007E57361BACB0252E338F6
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

The attached patch fixes two incorrect tests of the copy_xx_user return value,
and also corrects a couple of error exits that would leave the task's spinlock
held. I've also streamlined the code a bit to substitute untaken jumps for
multiple returns.

Regards,
Bill
--------------5007E57361BACB0252E338F6
Content-Type: text/plain; charset=us-ascii; name="signal_81-patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="signal_81-patch"

--- kernel/signal.c.old Fri Dec 19 00:22:36 1997
+++ kernel/signal.c Sat Jan 24 11:29:17 1998
@@ -583,23 +583,27 @@
asmlinkage int
sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, size_t sigsetsize)
{
+ int error = -EINVAL;
sigset_t old_set, new_set;

/* XXX: Don't preclude handling different sized sigset_t's. */
if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
+ goto out;

if (set) {
+ error = -EFAULT;
if (copy_from_user(&new_set, set, sizeof(*set)))
- return -EFAULT;
+ goto out;
sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP));

spin_lock_irq(&current->sigmask_lock);
old_set = current->blocked;

+ error = 0;
switch (how) {
default:
- return -EINVAL;
+ error = -EINVAL;
+ break;
case SIG_BLOCK:
sigorsets(&new_set, &old_set, &new_set);
break;
@@ -613,47 +617,54 @@
current->blocked = new_set;
recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);
-
- if (oset) {
- if (copy_to_user(oset, &old_set, sizeof(*oset)))
- return -EFAULT;
- }
+ if (error)
+ goto out;
+ if (oset)
+ goto set_old;
} else if (oset) {
spin_lock_irq(&current->sigmask_lock);
old_set = current->blocked;
spin_unlock_irq(&current->sigmask_lock);

+ set_old:
+ error = -EFAULT;
if (copy_to_user(oset, &old_set, sizeof(*oset)))
- return -EFAULT;
+ goto out;
}
-
- return 0;
+ error = 0;
+out:
+ return error;
}

asmlinkage int
sys_rt_sigpending(sigset_t *set, size_t sigsetsize)
{
+ int error = -EINVAL;
sigset_t pending;

/* XXX: Don't preclude handling different sized sigset_t's. */
if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
+ goto out;

spin_lock_irq(&current->sigmask_lock);
sigandsets(&pending, &current->blocked, &current->signal);
spin_unlock_irq(&current->sigmask_lock);

- return copy_to_user(set, &pending, sizeof(*set));
+ error = -EFAULT;
+ if (!copy_to_user(set, &pending, sizeof(*set)))
+ error = 0;
+out:
+ return error;
}

asmlinkage int
sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo,
const struct timespec *uts, size_t sigsetsize)
{
+ int ret, sig;
sigset_t these;
struct timespec ts;
siginfo_t info;
- int ret, sig;

/* XXX: Don't preclude handling different sized sigset_t's. */
if (sigsetsize != sizeof(sigset_t))
@@ -825,19 +836,23 @@
asmlinkage int
sys_sigprocmask(int how, old_sigset_t *set, old_sigset_t *oset)
{
+ int error;
old_sigset_t old_set, new_set;

if (set) {
+ error = -EFAULT;
if (copy_from_user(&new_set, set, sizeof(*set)))
- return -EFAULT;
+ goto out;
new_set &= ~(sigmask(SIGKILL)|sigmask(SIGSTOP));

spin_lock_irq(&current->sigmask_lock);
old_set = current->blocked.sig[0];

+ error = 0;
switch (how) {
default:
- return -EINVAL;
+ error = -EINVAL;
+ break;
case SIG_BLOCK:
sigaddsetmask(&current->blocked, new_set);
break;
@@ -851,30 +866,36 @@

recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);
-
- if (oset) {
- if (copy_to_user(oset, &old_set, sizeof(*oset)))
- return -EFAULT;
- }
+ if (error)
+ goto out;
+ if (oset)
+ goto set_old;
} else if (oset) {
old_set = current->blocked.sig[0];
+ set_old:
+ error = -EFAULT;
if (copy_to_user(oset, &old_set, sizeof(*oset)))
- return -EFAULT;
+ goto out;
}
-
- return 0;
+ error = 0;
+out:
+ return error;
}

asmlinkage int
sys_sigpending(old_sigset_t *set)
{
+ int error;
old_sigset_t pending;

spin_lock_irq(&current->sigmask_lock);
pending = current->blocked.sig[0] & current->signal.sig[0];
spin_unlock_irq(&current->sigmask_lock);

- return copy_to_user(set, &pending, sizeof(*set));
+ error = -EFAULT;
+ if (!copy_to_user(set, &pending, sizeof(*set)))
+ error = 0;
+ return error;
}

asmlinkage int
@@ -882,11 +903,11 @@
size_t sigsetsize)
{
struct k_sigaction new_sa, old_sa;
- int ret;
+ int ret = -EINVAL;

/* XXX: Don't preclude handling different sized sigset_t's. */
if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
+ goto out;

if (act) {
if (copy_from_user(&new_sa.sa, act, sizeof(new_sa.sa)))
@@ -899,7 +920,7 @@
if (copy_to_user(oact, &old_sa.sa, sizeof(old_sa.sa)))
return -EFAULT;
}
-
+out:
return ret;
}
#endif

--------------5007E57361BACB0252E338F6--