Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

userns: allow sethostname in a container

Changelog:
Feb 23: let clone_uts_ns() handle setting uts->user_ns
To do so we need to pass in the task_struct who'll
get the utsname, so we can get its user_ns.
Feb 23: As per Oleg's coment, just pass in tsk, instead of two
of its members.

Signed-off-by: Serge E. Hallyn <serge.hallyn@canonical.com>
Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
Acked-by: Daniel Lezcano <daniel.lezcano@free.fr>
Acked-by: David Howells <dhowells@redhat.com>
Cc: James Morris <jmorris@namei.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Serge E. Hallyn and committed by
Linus Torvalds
bb96a6f5 3486740a

+12 -15
+3 -3
include/linux/utsname.h
··· 54 54 } 55 55 56 56 extern struct uts_namespace *copy_utsname(unsigned long flags, 57 - struct uts_namespace *ns); 57 + struct task_struct *tsk); 58 58 extern void free_uts_ns(struct kref *kref); 59 59 60 60 static inline void put_uts_ns(struct uts_namespace *ns) ··· 71 71 } 72 72 73 73 static inline struct uts_namespace *copy_utsname(unsigned long flags, 74 - struct uts_namespace *ns) 74 + struct task_struct *tsk) 75 75 { 76 76 if (flags & CLONE_NEWUTS) 77 77 return ERR_PTR(-EINVAL); 78 78 79 - return ns; 79 + return tsk->nsproxy->uts_ns; 80 80 } 81 81 #endif 82 82
+1 -6
kernel/nsproxy.c
··· 69 69 goto out_ns; 70 70 } 71 71 72 - new_nsp->uts_ns = copy_utsname(flags, tsk->nsproxy->uts_ns); 72 + new_nsp->uts_ns = copy_utsname(flags, tsk); 73 73 if (IS_ERR(new_nsp->uts_ns)) { 74 74 err = PTR_ERR(new_nsp->uts_ns); 75 75 goto out_uts; 76 - } 77 - if (new_nsp->uts_ns != tsk->nsproxy->uts_ns) { 78 - put_user_ns(new_nsp->uts_ns->user_ns); 79 - new_nsp->uts_ns->user_ns = task_cred_xxx(tsk, user)->user_ns; 80 - get_user_ns(new_nsp->uts_ns->user_ns); 81 76 } 82 77 83 78 new_nsp->ipc_ns = copy_ipcs(flags, tsk->nsproxy->ipc_ns);
+1 -1
kernel/sys.c
··· 1181 1181 int errno; 1182 1182 char tmp[__NEW_UTS_LEN]; 1183 1183 1184 - if (!capable(CAP_SYS_ADMIN)) 1184 + if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN)) 1185 1185 return -EPERM; 1186 1186 if (len < 0 || len > __NEW_UTS_LEN) 1187 1187 return -EINVAL;
+7 -5
kernel/utsname.c
··· 31 31 * @old_ns: namespace to clone 32 32 * Return NULL on error (failure to kmalloc), new ns otherwise 33 33 */ 34 - static struct uts_namespace *clone_uts_ns(struct uts_namespace *old_ns) 34 + static struct uts_namespace *clone_uts_ns(struct task_struct *tsk, 35 + struct uts_namespace *old_ns) 35 36 { 36 37 struct uts_namespace *ns; 37 38 ··· 42 41 43 42 down_read(&uts_sem); 44 43 memcpy(&ns->name, &old_ns->name, sizeof(ns->name)); 45 - ns->user_ns = old_ns->user_ns; 46 - get_user_ns(ns->user_ns); 44 + ns->user_ns = get_user_ns(task_cred_xxx(tsk, user)->user_ns); 47 45 up_read(&uts_sem); 48 46 return ns; 49 47 } ··· 53 53 * utsname of this process won't be seen by parent, and vice 54 54 * versa. 55 55 */ 56 - struct uts_namespace *copy_utsname(unsigned long flags, struct uts_namespace *old_ns) 56 + struct uts_namespace *copy_utsname(unsigned long flags, 57 + struct task_struct *tsk) 57 58 { 59 + struct uts_namespace *old_ns = tsk->nsproxy->uts_ns; 58 60 struct uts_namespace *new_ns; 59 61 60 62 BUG_ON(!old_ns); ··· 65 63 if (!(flags & CLONE_NEWUTS)) 66 64 return old_ns; 67 65 68 - new_ns = clone_uts_ns(old_ns); 66 + new_ns = clone_uts_ns(tsk, old_ns); 69 67 70 68 put_uts_ns(old_ns); 71 69 return new_ns;