diff options
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 28 |
1 files changed, 16 insertions, 12 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index 1814e68e4de3..934ae5e687b9 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -218,13 +218,13 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimi | |||
218 | struct user_struct *user; | 218 | struct user_struct *user; |
219 | 219 | ||
220 | /* | 220 | /* |
221 | * We won't get problems with the target's UID changing under us | 221 | * Protect access to @t credentials. This can go away when all |
222 | * because changing it requires RCU be used, and if t != current, the | 222 | * 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 | */ | 223 | */ |
224 | rcu_read_lock(); | ||
226 | user = get_uid(__task_cred(t)->user); | 225 | user = get_uid(__task_cred(t)->user); |
227 | atomic_inc(&user->sigpending); | 226 | atomic_inc(&user->sigpending); |
227 | rcu_read_unlock(); | ||
228 | 228 | ||
229 | if (override_rlimit || | 229 | if (override_rlimit || |
230 | atomic_read(&user->sigpending) <= | 230 | atomic_read(&user->sigpending) <= |
@@ -979,7 +979,8 @@ static void print_fatal_signal(struct pt_regs *regs, int signr) | |||
979 | for (i = 0; i < 16; i++) { | 979 | for (i = 0; i < 16; i++) { |
980 | unsigned char insn; | 980 | unsigned char insn; |
981 | 981 | ||
982 | __get_user(insn, (unsigned char *)(regs->ip + i)); | 982 | if (get_user(insn, (unsigned char *)(regs->ip + i))) |
983 | break; | ||
983 | printk("%02x ", insn); | 984 | printk("%02x ", insn); |
984 | } | 985 | } |
985 | } | 986 | } |
@@ -1179,11 +1180,12 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid, | |||
1179 | int ret = -EINVAL; | 1180 | int ret = -EINVAL; |
1180 | struct task_struct *p; | 1181 | struct task_struct *p; |
1181 | const struct cred *pcred; | 1182 | const struct cred *pcred; |
1183 | unsigned long flags; | ||
1182 | 1184 | ||
1183 | if (!valid_signal(sig)) | 1185 | if (!valid_signal(sig)) |
1184 | return ret; | 1186 | return ret; |
1185 | 1187 | ||
1186 | read_lock(&tasklist_lock); | 1188 | rcu_read_lock(); |
1187 | p = pid_task(pid, PIDTYPE_PID); | 1189 | p = pid_task(pid, PIDTYPE_PID); |
1188 | if (!p) { | 1190 | if (!p) { |
1189 | ret = -ESRCH; | 1191 | ret = -ESRCH; |
@@ -1199,14 +1201,16 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid, | |||
1199 | ret = security_task_kill(p, info, sig, secid); | 1201 | ret = security_task_kill(p, info, sig, secid); |
1200 | if (ret) | 1202 | if (ret) |
1201 | goto out_unlock; | 1203 | goto out_unlock; |
1202 | if (sig && p->sighand) { | 1204 | |
1203 | unsigned long flags; | 1205 | if (sig) { |
1204 | spin_lock_irqsave(&p->sighand->siglock, flags); | 1206 | if (lock_task_sighand(p, &flags)) { |
1205 | ret = __send_signal(sig, info, p, 1, 0); | 1207 | ret = __send_signal(sig, info, p, 1, 0); |
1206 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | 1208 | unlock_task_sighand(p, &flags); |
1209 | } else | ||
1210 | ret = -ESRCH; | ||
1207 | } | 1211 | } |
1208 | out_unlock: | 1212 | out_unlock: |
1209 | read_unlock(&tasklist_lock); | 1213 | rcu_read_unlock(); |
1210 | return ret; | 1214 | return ret; |
1211 | } | 1215 | } |
1212 | EXPORT_SYMBOL_GPL(kill_pid_info_as_uid); | 1216 | EXPORT_SYMBOL_GPL(kill_pid_info_as_uid); |