1 /* 2 * Copyright (C) 2004 IBM Corporation 3 * 4 * Author: Serge Hallyn <serue@us.ibm.com> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation, version 2 of the 9 * License. 10 */ 11 12 #include <linux/export.h> 13 #include <linux/uts.h> 14 #include <linux/utsname.h> 15 #include <linux/err.h> 16 #include <linux/slab.h> 17 #include <linux/user_namespace.h> 18 #include <linux/proc_ns.h> 19 20 static struct uts_namespace *create_uts_ns(void) 21 { 22 struct uts_namespace *uts_ns; 23 24 uts_ns = kmalloc(sizeof(struct uts_namespace), GFP_KERNEL); 25 if (uts_ns) 26 kref_init(&uts_ns->kref); 27 return uts_ns; 28 } 29 30 /* 31 * Clone a new ns copying an original utsname, setting refcount to 1 32 * @old_ns: namespace to clone 33 * Return ERR_PTR(-ENOMEM) on error (failure to kmalloc), new ns otherwise 34 */ 35 static struct uts_namespace *clone_uts_ns(struct user_namespace *user_ns, 36 struct uts_namespace *old_ns) 37 { 38 struct uts_namespace *ns; 39 int err; 40 41 ns = create_uts_ns(); 42 if (!ns) 43 return ERR_PTR(-ENOMEM); 44 45 err = proc_alloc_inum(&ns->ns.inum); 46 if (err) { 47 kfree(ns); 48 return ERR_PTR(err); 49 } 50 51 down_read(&uts_sem); 52 memcpy(&ns->name, &old_ns->name, sizeof(ns->name)); 53 ns->user_ns = get_user_ns(user_ns); 54 up_read(&uts_sem); 55 return ns; 56 } 57 58 /* 59 * Copy task tsk's utsname namespace, or clone it if flags 60 * specifies CLONE_NEWUTS. In latter case, changes to the 61 * utsname of this process won't be seen by parent, and vice 62 * versa. 63 */ 64 struct uts_namespace *copy_utsname(unsigned long flags, 65 struct user_namespace *user_ns, struct uts_namespace *old_ns) 66 { 67 struct uts_namespace *new_ns; 68 69 BUG_ON(!old_ns); 70 get_uts_ns(old_ns); 71 72 if (!(flags & CLONE_NEWUTS)) 73 return old_ns; 74 75 new_ns = clone_uts_ns(user_ns, old_ns); 76 77 put_uts_ns(old_ns); 78 return new_ns; 79 } 80 81 void free_uts_ns(struct kref *kref) 82 { 83 struct uts_namespace *ns; 84 85 ns = container_of(kref, struct uts_namespace, kref); 86 put_user_ns(ns->user_ns); 87 proc_free_inum(ns->ns.inum); 88 kfree(ns); 89 } 90 91 static inline struct uts_namespace *to_uts_ns(struct ns_common *ns) 92 { 93 return container_of(ns, struct uts_namespace, ns); 94 } 95 96 static struct ns_common *utsns_get(struct task_struct *task) 97 { 98 struct uts_namespace *ns = NULL; 99 struct nsproxy *nsproxy; 100 101 task_lock(task); 102 nsproxy = task->nsproxy; 103 if (nsproxy) { 104 ns = nsproxy->uts_ns; 105 get_uts_ns(ns); 106 } 107 task_unlock(task); 108 109 return ns ? &ns->ns : NULL; 110 } 111 112 static void utsns_put(struct ns_common *ns) 113 { 114 put_uts_ns(to_uts_ns(ns)); 115 } 116 117 static int utsns_install(struct nsproxy *nsproxy, struct ns_common *new) 118 { 119 struct uts_namespace *ns = to_uts_ns(new); 120 121 if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) || 122 !ns_capable(current_user_ns(), CAP_SYS_ADMIN)) 123 return -EPERM; 124 125 get_uts_ns(ns); 126 put_uts_ns(nsproxy->uts_ns); 127 nsproxy->uts_ns = ns; 128 return 0; 129 } 130 131 const struct proc_ns_operations utsns_operations = { 132 .name = "uts", 133 .type = CLONE_NEWUTS, 134 .get = utsns_get, 135 .put = utsns_put, 136 .install = utsns_install, 137 }; 138