diff options
Diffstat (limited to 'kernel/signal.c')
| -rw-r--r-- | kernel/signal.c | 73 |
1 files changed, 47 insertions, 26 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index 1814e68e4de3..dbd7fe073c55 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
| @@ -159,6 +159,10 @@ void recalc_sigpending(void) | |||
| 159 | 159 | ||
| 160 | /* Given the mask, find the first available signal that should be serviced. */ | 160 | /* Given the mask, find the first available signal that should be serviced. */ |
| 161 | 161 | ||
| 162 | #define SYNCHRONOUS_MASK \ | ||
| 163 | (sigmask(SIGSEGV) | sigmask(SIGBUS) | sigmask(SIGILL) | \ | ||
| 164 | sigmask(SIGTRAP) | sigmask(SIGFPE)) | ||
| 165 | |||
| 162 | int next_signal(struct sigpending *pending, sigset_t *mask) | 166 | int next_signal(struct sigpending *pending, sigset_t *mask) |
| 163 | { | 167 | { |
| 164 | unsigned long i, *s, *m, x; | 168 | unsigned long i, *s, *m, x; |
| @@ -166,26 +170,39 @@ int next_signal(struct sigpending *pending, sigset_t *mask) | |||
| 166 | 170 | ||
| 167 | s = pending->signal.sig; | 171 | s = pending->signal.sig; |
| 168 | m = mask->sig; | 172 | m = mask->sig; |
| 173 | |||
| 174 | /* | ||
| 175 | * Handle the first word specially: it contains the | ||
| 176 | * synchronous signals that need to be dequeued first. | ||
| 177 | */ | ||
| 178 | x = *s &~ *m; | ||
| 179 | if (x) { | ||
| 180 | if (x & SYNCHRONOUS_MASK) | ||
| 181 | x &= SYNCHRONOUS_MASK; | ||
| 182 | sig = ffz(~x) + 1; | ||
| 183 | return sig; | ||
| 184 | } | ||
| 185 | |||
| 169 | switch (_NSIG_WORDS) { | 186 | switch (_NSIG_WORDS) { |
| 170 | default: | 187 | default: |
| 171 | for (i = 0; i < _NSIG_WORDS; ++i, ++s, ++m) | 188 | for (i = 1; i < _NSIG_WORDS; ++i) { |
| 172 | if ((x = *s &~ *m) != 0) { | 189 | x = *++s &~ *++m; |
| 173 | sig = ffz(~x) + i*_NSIG_BPW + 1; | 190 | if (!x) |
| 174 | break; | 191 | continue; |
| 175 | } | 192 | sig = ffz(~x) + i*_NSIG_BPW + 1; |
| 193 | break; | ||
| 194 | } | ||
| 176 | break; | 195 | break; |
| 177 | 196 | ||
| 178 | case 2: if ((x = s[0] &~ m[0]) != 0) | 197 | case 2: |
| 179 | sig = 1; | 198 | x = s[1] &~ m[1]; |
| 180 | else if ((x = s[1] &~ m[1]) != 0) | 199 | if (!x) |
| 181 | sig = _NSIG_BPW + 1; | ||
| 182 | else | ||
| 183 | break; | 200 | break; |
| 184 | sig += ffz(~x); | 201 | sig = ffz(~x) + _NSIG_BPW + 1; |
| 185 | break; | 202 | break; |
| 186 | 203 | ||
| 187 | case 1: if ((x = *s &~ *m) != 0) | 204 | case 1: |
| 188 | sig = ffz(~x) + 1; | 205 | /* Nothing to do */ |
| 189 | break; | 206 | break; |
| 190 | } | 207 | } |
| 191 | 208 | ||
| @@ -218,17 +235,17 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimi | |||
| 218 | struct user_struct *user; | 235 | struct user_struct *user; |
| 219 | 236 | ||
| 220 | /* | 237 | /* |
| 221 | * We won't get problems with the target's UID changing under us | 238 | * Protect access to @t credentials. This can go away when all |
| 222 | * because changing it requires RCU be used, and if t != current, the | 239 | * callers hold rcu read lock. |
| 223 | * caller must be holding the RCU readlock (by way of a spinlock) and | ||
| 224 | * we use RCU protection here | ||
| 225 | */ | 240 | */ |
| 241 | rcu_read_lock(); | ||
| 226 | user = get_uid(__task_cred(t)->user); | 242 | user = get_uid(__task_cred(t)->user); |
| 227 | atomic_inc(&user->sigpending); | 243 | atomic_inc(&user->sigpending); |
| 244 | rcu_read_unlock(); | ||
| 228 | 245 | ||
| 229 | if (override_rlimit || | 246 | if (override_rlimit || |
| 230 | atomic_read(&user->sigpending) <= | 247 | atomic_read(&user->sigpending) <= |
| 231 | t->signal->rlim[RLIMIT_SIGPENDING].rlim_cur) { | 248 | task_rlimit(t, RLIMIT_SIGPENDING)) { |
| 232 | q = kmem_cache_alloc(sigqueue_cachep, flags); | 249 | q = kmem_cache_alloc(sigqueue_cachep, flags); |
| 233 | } else { | 250 | } else { |
| 234 | print_dropped_signal(sig); | 251 | print_dropped_signal(sig); |
| @@ -979,7 +996,8 @@ static void print_fatal_signal(struct pt_regs *regs, int signr) | |||
| 979 | for (i = 0; i < 16; i++) { | 996 | for (i = 0; i < 16; i++) { |
| 980 | unsigned char insn; | 997 | unsigned char insn; |
| 981 | 998 | ||
| 982 | __get_user(insn, (unsigned char *)(regs->ip + i)); | 999 | if (get_user(insn, (unsigned char *)(regs->ip + i))) |
| 1000 | break; | ||
| 983 | printk("%02x ", insn); | 1001 | printk("%02x ", insn); |
| 984 | } | 1002 | } |
| 985 | } | 1003 | } |
| @@ -1179,11 +1197,12 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid, | |||
| 1179 | int ret = -EINVAL; | 1197 | int ret = -EINVAL; |
| 1180 | struct task_struct *p; | 1198 | struct task_struct *p; |
| 1181 | const struct cred *pcred; | 1199 | const struct cred *pcred; |
| 1200 | unsigned long flags; | ||
| 1182 | 1201 | ||
| 1183 | if (!valid_signal(sig)) | 1202 | if (!valid_signal(sig)) |
| 1184 | return ret; | 1203 | return ret; |
| 1185 | 1204 | ||
| 1186 | read_lock(&tasklist_lock); | 1205 | rcu_read_lock(); |
| 1187 | p = pid_task(pid, PIDTYPE_PID); | 1206 | p = pid_task(pid, PIDTYPE_PID); |
| 1188 | if (!p) { | 1207 | if (!p) { |
| 1189 | ret = -ESRCH; | 1208 | ret = -ESRCH; |
| @@ -1199,14 +1218,16 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid, | |||
| 1199 | ret = security_task_kill(p, info, sig, secid); | 1218 | ret = security_task_kill(p, info, sig, secid); |
| 1200 | if (ret) | 1219 | if (ret) |
| 1201 | goto out_unlock; | 1220 | goto out_unlock; |
| 1202 | if (sig && p->sighand) { | 1221 | |
| 1203 | unsigned long flags; | 1222 | if (sig) { |
| 1204 | spin_lock_irqsave(&p->sighand->siglock, flags); | 1223 | if (lock_task_sighand(p, &flags)) { |
| 1205 | ret = __send_signal(sig, info, p, 1, 0); | 1224 | ret = __send_signal(sig, info, p, 1, 0); |
| 1206 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | 1225 | unlock_task_sighand(p, &flags); |
| 1226 | } else | ||
| 1227 | ret = -ESRCH; | ||
| 1207 | } | 1228 | } |
| 1208 | out_unlock: | 1229 | out_unlock: |
| 1209 | read_unlock(&tasklist_lock); | 1230 | rcu_read_unlock(); |
| 1210 | return ret; | 1231 | return ret; |
| 1211 | } | 1232 | } |
| 1212 | EXPORT_SYMBOL_GPL(kill_pid_info_as_uid); | 1233 | EXPORT_SYMBOL_GPL(kill_pid_info_as_uid); |
