diff options
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index cba193ceda0d..50c992643771 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -1193,6 +1193,40 @@ kill_proc_info(int sig, struct siginfo *info, pid_t pid) | |||
1193 | return error; | 1193 | return error; |
1194 | } | 1194 | } |
1195 | 1195 | ||
1196 | /* like kill_proc_info(), but doesn't use uid/euid of "current" */ | ||
1197 | int kill_proc_info_as_uid(int sig, struct siginfo *info, pid_t pid, | ||
1198 | uid_t uid, uid_t euid) | ||
1199 | { | ||
1200 | int ret = -EINVAL; | ||
1201 | struct task_struct *p; | ||
1202 | |||
1203 | if (!valid_signal(sig)) | ||
1204 | return ret; | ||
1205 | |||
1206 | read_lock(&tasklist_lock); | ||
1207 | p = find_task_by_pid(pid); | ||
1208 | if (!p) { | ||
1209 | ret = -ESRCH; | ||
1210 | goto out_unlock; | ||
1211 | } | ||
1212 | if ((!info || ((unsigned long)info != 1 && | ||
1213 | (unsigned long)info != 2 && SI_FROMUSER(info))) | ||
1214 | && (euid != p->suid) && (euid != p->uid) | ||
1215 | && (uid != p->suid) && (uid != p->uid)) { | ||
1216 | ret = -EPERM; | ||
1217 | goto out_unlock; | ||
1218 | } | ||
1219 | if (sig && p->sighand) { | ||
1220 | unsigned long flags; | ||
1221 | spin_lock_irqsave(&p->sighand->siglock, flags); | ||
1222 | ret = __group_send_sig_info(sig, info, p); | ||
1223 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | ||
1224 | } | ||
1225 | out_unlock: | ||
1226 | read_unlock(&tasklist_lock); | ||
1227 | return ret; | ||
1228 | } | ||
1229 | EXPORT_SYMBOL_GPL(kill_proc_info_as_uid); | ||
1196 | 1230 | ||
1197 | /* | 1231 | /* |
1198 | * kill_something_info() interprets pid in interesting ways just like kill(2). | 1232 | * kill_something_info() interprets pid in interesting ways just like kill(2). |