|
@@ -635,6 +635,27 @@ static inline bool si_fromuser(const struct siginfo *info)
|
|
|
(!is_si_special(info) && SI_FROMUSER(info));
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * called with RCU read lock from check_kill_permission()
|
|
|
+ */
|
|
|
+static int kill_ok_by_cred(struct task_struct *t)
|
|
|
+{
|
|
|
+ const struct cred *cred = current_cred();
|
|
|
+ const struct cred *tcred = __task_cred(t);
|
|
|
+
|
|
|
+ if (cred->user->user_ns == tcred->user->user_ns &&
|
|
|
+ (cred->euid == tcred->suid ||
|
|
|
+ cred->euid == tcred->uid ||
|
|
|
+ cred->uid == tcred->suid ||
|
|
|
+ cred->uid == tcred->uid))
|
|
|
+ return 1;
|
|
|
+
|
|
|
+ if (ns_capable(tcred->user->user_ns, CAP_KILL))
|
|
|
+ return 1;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Bad permissions for sending the signal
|
|
|
* - the caller must hold the RCU read lock
|
|
@@ -642,7 +663,6 @@ static inline bool si_fromuser(const struct siginfo *info)
|
|
|
static int check_kill_permission(int sig, struct siginfo *info,
|
|
|
struct task_struct *t)
|
|
|
{
|
|
|
- const struct cred *cred, *tcred;
|
|
|
struct pid *sid;
|
|
|
int error;
|
|
|
|
|
@@ -656,14 +676,8 @@ static int check_kill_permission(int sig, struct siginfo *info,
|
|
|
if (error)
|
|
|
return error;
|
|
|
|
|
|
- cred = current_cred();
|
|
|
- tcred = __task_cred(t);
|
|
|
if (!same_thread_group(current, t) &&
|
|
|
- (cred->euid ^ tcred->suid) &&
|
|
|
- (cred->euid ^ tcred->uid) &&
|
|
|
- (cred->uid ^ tcred->suid) &&
|
|
|
- (cred->uid ^ tcred->uid) &&
|
|
|
- !capable(CAP_KILL)) {
|
|
|
+ !kill_ok_by_cred(t)) {
|
|
|
switch (sig) {
|
|
|
case SIGCONT:
|
|
|
sid = task_session(t);
|