aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/signal.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-05-23 20:42:39 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-23 20:42:39 -0400
commit644473e9c60c1ff4f6351fed637a6e5551e3dce7 (patch)
tree10316518bedc735a2c6552886658d69dfd9f1eb0 /kernel/signal.c
parentfb827ec68446c83e9e8754fa9b55aed27ecc4661 (diff)
parent4b06a81f1daee668fbd6de85557bfb36dd36078f (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace
Pull user namespace enhancements from Eric Biederman: "This is a course correction for the user namespace, so that we can reach an inexpensive, maintainable, and reasonably complete implementation. Highlights: - Config guards make it impossible to enable the user namespace and code that has not been converted to be user namespace safe. - Use of the new kuid_t type ensures the if you somehow get past the config guards the kernel will encounter type errors if you enable user namespaces and attempt to compile in code whose permission checks have not been updated to be user namespace safe. - All uids from child user namespaces are mapped into the initial user namespace before they are processed. Removing the need to add an additional check to see if the user namespace of the compared uids remains the same. - With the user namespaces compiled out the performance is as good or better than it is today. - For most operations absolutely nothing changes performance or operationally with the user namespace enabled. - The worst case performance I could come up with was timing 1 billion cache cold stat operations with the user namespace code enabled. This went from 156s to 164s on my laptop (or 156ns to 164ns per stat operation). - (uid_t)-1 and (gid_t)-1 are reserved as an internal error value. Most uid/gid setting system calls treat these value specially anyway so attempting to use -1 as a uid would likely cause entertaining failures in userspace. - If setuid is called with a uid that can not be mapped setuid fails. I have looked at sendmail, login, ssh and every other program I could think of that would call setuid and they all check for and handle the case where setuid fails. - If stat or a similar system call is called from a context in which we can not map a uid we lie and return overflowuid. The LFS experience suggests not lying and returning an error code might be better, but the historical precedent with uids is different and I can not think of anything that would break by lying about a uid we can't map. - Capabilities are localized to the current user namespace making it safe to give the initial user in a user namespace all capabilities. My git tree covers all of the modifications needed to convert the core kernel and enough changes to make a system bootable to runlevel 1." Fix up trivial conflicts due to nearby independent changes in fs/stat.c * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: (46 commits) userns: Silence silly gcc warning. cred: use correct cred accessor with regards to rcu read lock userns: Convert the move_pages, and migrate_pages permission checks to use uid_eq userns: Convert cgroup permission checks to use uid_eq userns: Convert tmpfs to use kuid and kgid where appropriate userns: Convert sysfs to use kgid/kuid where appropriate userns: Convert sysctl permission checks to use kuid and kgids. userns: Convert proc to use kuid/kgid where appropriate userns: Convert ext4 to user kuid/kgid where appropriate userns: Convert ext3 to use kuid/kgid where appropriate userns: Convert ext2 to use kuid/kgid where appropriate. userns: Convert devpts to use kuid/kgid where appropriate userns: Convert binary formats to use kuid/kgid where appropriate userns: Add negative depends on entries to avoid building code that is userns unsafe userns: signal remove unnecessary map_cred_ns userns: Teach inode_capable to understand inodes whose uids map to other namespaces. userns: Fail exec for suid and sgid binaries with ids outside our user namespace. userns: Convert stat to return values mapped from kuids and kgids userns: Convert user specfied uids and gids in chown into kuids and kgid userns: Use uid_eq gid_eq helpers when comparing kuids and kgids in the vfs ...
Diffstat (limited to 'kernel/signal.c')
-rw-r--r--kernel/signal.c51
1 files changed, 20 insertions, 31 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index 1a006b5d9d9d..21ebe75ff85f 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -767,14 +767,13 @@ static int kill_ok_by_cred(struct task_struct *t)
767 const struct cred *cred = current_cred(); 767 const struct cred *cred = current_cred();
768 const struct cred *tcred = __task_cred(t); 768 const struct cred *tcred = __task_cred(t);
769 769
770 if (cred->user->user_ns == tcred->user->user_ns && 770 if (uid_eq(cred->euid, tcred->suid) ||
771 (cred->euid == tcred->suid || 771 uid_eq(cred->euid, tcred->uid) ||
772 cred->euid == tcred->uid || 772 uid_eq(cred->uid, tcred->suid) ||
773 cred->uid == tcred->suid || 773 uid_eq(cred->uid, tcred->uid))
774 cred->uid == tcred->uid))
775 return 1; 774 return 1;
776 775
777 if (ns_capable(tcred->user->user_ns, CAP_KILL)) 776 if (ns_capable(tcred->user_ns, CAP_KILL))
778 return 1; 777 return 1;
779 778
780 return 0; 779 return 0;
@@ -1020,15 +1019,6 @@ static inline int legacy_queue(struct sigpending *signals, int sig)
1020 return (sig < SIGRTMIN) && sigismember(&signals->signal, sig); 1019 return (sig < SIGRTMIN) && sigismember(&signals->signal, sig);
1021} 1020}
1022 1021
1023/*
1024 * map the uid in struct cred into user namespace *ns
1025 */
1026static inline uid_t map_cred_ns(const struct cred *cred,
1027 struct user_namespace *ns)
1028{
1029 return user_ns_map_uid(ns, cred, cred->uid);
1030}
1031
1032#ifdef CONFIG_USER_NS 1022#ifdef CONFIG_USER_NS
1033static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t) 1023static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t)
1034{ 1024{
@@ -1038,8 +1028,10 @@ static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_str
1038 if (SI_FROMKERNEL(info)) 1028 if (SI_FROMKERNEL(info))
1039 return; 1029 return;
1040 1030
1041 info->si_uid = user_ns_map_uid(task_cred_xxx(t, user_ns), 1031 rcu_read_lock();
1042 current_cred(), info->si_uid); 1032 info->si_uid = from_kuid_munged(task_cred_xxx(t, user_ns),
1033 make_kuid(current_user_ns(), info->si_uid));
1034 rcu_read_unlock();
1043} 1035}
1044#else 1036#else
1045static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t) 1037static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t)
@@ -1106,7 +1098,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
1106 q->info.si_code = SI_USER; 1098 q->info.si_code = SI_USER;
1107 q->info.si_pid = task_tgid_nr_ns(current, 1099 q->info.si_pid = task_tgid_nr_ns(current,
1108 task_active_pid_ns(t)); 1100 task_active_pid_ns(t));
1109 q->info.si_uid = current_uid(); 1101 q->info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
1110 break; 1102 break;
1111 case (unsigned long) SEND_SIG_PRIV: 1103 case (unsigned long) SEND_SIG_PRIV:
1112 q->info.si_signo = sig; 1104 q->info.si_signo = sig;
@@ -1387,10 +1379,8 @@ static int kill_as_cred_perm(const struct cred *cred,
1387 struct task_struct *target) 1379 struct task_struct *target)
1388{ 1380{
1389 const struct cred *pcred = __task_cred(target); 1381 const struct cred *pcred = __task_cred(target);
1390 if (cred->user_ns != pcred->user_ns) 1382 if (!uid_eq(cred->euid, pcred->suid) && !uid_eq(cred->euid, pcred->uid) &&
1391 return 0; 1383 !uid_eq(cred->uid, pcred->suid) && !uid_eq(cred->uid, pcred->uid))
1392 if (cred->euid != pcred->suid && cred->euid != pcred->uid &&
1393 cred->uid != pcred->suid && cred->uid != pcred->uid)
1394 return 0; 1384 return 0;
1395 return 1; 1385 return 1;
1396} 1386}
@@ -1678,8 +1668,8 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
1678 */ 1668 */
1679 rcu_read_lock(); 1669 rcu_read_lock();
1680 info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns); 1670 info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns);
1681 info.si_uid = map_cred_ns(__task_cred(tsk), 1671 info.si_uid = from_kuid_munged(task_cred_xxx(tsk->parent, user_ns),
1682 task_cred_xxx(tsk->parent, user_ns)); 1672 task_uid(tsk));
1683 rcu_read_unlock(); 1673 rcu_read_unlock();
1684 1674
1685 info.si_utime = cputime_to_clock_t(tsk->utime + tsk->signal->utime); 1675 info.si_utime = cputime_to_clock_t(tsk->utime + tsk->signal->utime);
@@ -1762,8 +1752,7 @@ static void do_notify_parent_cldstop(struct task_struct *tsk,
1762 */ 1752 */
1763 rcu_read_lock(); 1753 rcu_read_lock();
1764 info.si_pid = task_pid_nr_ns(tsk, parent->nsproxy->pid_ns); 1754 info.si_pid = task_pid_nr_ns(tsk, parent->nsproxy->pid_ns);
1765 info.si_uid = map_cred_ns(__task_cred(tsk), 1755 info.si_uid = from_kuid_munged(task_cred_xxx(parent, user_ns), task_uid(tsk));
1766 task_cred_xxx(parent, user_ns));
1767 rcu_read_unlock(); 1756 rcu_read_unlock();
1768 1757
1769 info.si_utime = cputime_to_clock_t(tsk->utime); 1758 info.si_utime = cputime_to_clock_t(tsk->utime);
@@ -1973,7 +1962,7 @@ static void ptrace_do_notify(int signr, int exit_code, int why)
1973 info.si_signo = signr; 1962 info.si_signo = signr;
1974 info.si_code = exit_code; 1963 info.si_code = exit_code;
1975 info.si_pid = task_pid_vnr(current); 1964 info.si_pid = task_pid_vnr(current);
1976 info.si_uid = current_uid(); 1965 info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
1977 1966
1978 /* Let the debugger run. */ 1967 /* Let the debugger run. */
1979 ptrace_stop(exit_code, why, 1, &info); 1968 ptrace_stop(exit_code, why, 1, &info);
@@ -2181,8 +2170,8 @@ static int ptrace_signal(int signr, siginfo_t *info,
2181 info->si_code = SI_USER; 2170 info->si_code = SI_USER;
2182 rcu_read_lock(); 2171 rcu_read_lock();
2183 info->si_pid = task_pid_vnr(current->parent); 2172 info->si_pid = task_pid_vnr(current->parent);
2184 info->si_uid = map_cred_ns(__task_cred(current->parent), 2173 info->si_uid = from_kuid_munged(current_user_ns(),
2185 current_user_ns()); 2174 task_uid(current->parent));
2186 rcu_read_unlock(); 2175 rcu_read_unlock();
2187 } 2176 }
2188 2177
@@ -2835,7 +2824,7 @@ SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)
2835 info.si_errno = 0; 2824 info.si_errno = 0;
2836 info.si_code = SI_USER; 2825 info.si_code = SI_USER;
2837 info.si_pid = task_tgid_vnr(current); 2826 info.si_pid = task_tgid_vnr(current);
2838 info.si_uid = current_uid(); 2827 info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
2839 2828
2840 return kill_something_info(sig, &info, pid); 2829 return kill_something_info(sig, &info, pid);
2841} 2830}
@@ -2878,7 +2867,7 @@ static int do_tkill(pid_t tgid, pid_t pid, int sig)
2878 info.si_errno = 0; 2867 info.si_errno = 0;
2879 info.si_code = SI_TKILL; 2868 info.si_code = SI_TKILL;
2880 info.si_pid = task_tgid_vnr(current); 2869 info.si_pid = task_tgid_vnr(current);
2881 info.si_uid = current_uid(); 2870 info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
2882 2871
2883 return do_send_specific(tgid, pid, sig, &info); 2872 return do_send_specific(tgid, pid, sig, &info);
2884} 2873}