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/cred.h> 18 #include <linux/user_namespace.h> 19 #include <linux/proc_ns.h> 20 21 static struct ucounts *inc_uts_namespaces(struct user_namespace *ns) 22 { 23 return inc_ucount(ns, current_euid(), UCOUNT_UTS_NAMESPACES); 24 } 25 26 static void dec_uts_namespaces(struct ucounts *ucounts) 27 { 28 dec_ucount(ucounts, UCOUNT_UTS_NAMESPACES); 29 } 30 31 static struct uts_namespace *create_uts_ns(void) 32 { 33 struct uts_namespace *uts_ns; 34 35 uts_ns = kmalloc(sizeof(struct uts_namespace), GFP_KERNEL); 36 if (uts_ns) 37 kref_init(&uts_ns->kref); 38 return uts_ns; 39 } 40 41 /* 42 * Clone a new ns copying an original utsname, setting refcount to 1 43 * @old_ns: namespace to clone 44 * Return ERR_PTR(-ENOMEM) on error (failure to kmalloc), new ns otherwise 45 */ 46 static struct uts_namespace *clone_uts_ns(struct user_namespace *user_ns, 47 struct uts_namespace *old_ns) 48 { 49 struct uts_namespace *ns; 50 struct ucounts *ucounts; 51 int err; 52 53 err = -ENOSPC; 54 ucounts = inc_uts_namespaces(user_ns); 55 if (!ucounts) 56 goto fail; 57 58 err = -ENOMEM; 59 ns = create_uts_ns(); 60 if (!ns) 61 goto fail_dec; 62 63 err = ns_alloc_inum(&ns->ns); 64 if (err) 65 goto fail_free; 66 67 ns->ucounts = ucounts; 68 ns->ns.ops = &utsns_operations; 69 70 down_read(&uts_sem); 71 memcpy(&ns->name, &old_ns->name, sizeof(ns->name)); 72 ns->user_ns = get_user_ns(user_ns); 73 up_read(&uts_sem); 74 return ns; 75 76 fail_free: 77 kfree(ns); 78 fail_dec: 79 dec_uts_namespaces(ucounts); 80 fail: 81 return ERR_PTR(err); 82 } 83 84 /* 85 * Copy task tsk's utsname namespace, or clone it if flags 86 * specifies CLONE_NEWUTS. In latter case, changes to the 87 * utsname of this process won't be seen by parent, and vice 88 * versa. 89 */ 90 struct uts_namespace *copy_utsname(unsigned long flags, 91 struct user_namespace *user_ns, struct uts_namespace *old_ns) 92 { 93 struct uts_namespace *new_ns; 94 95 BUG_ON(!old_ns); 96 get_uts_ns(old_ns); 97 98 if (!(flags & CLONE_NEWUTS)) 99 return old_ns; 100 101 new_ns = clone_uts_ns(user_ns, old_ns); 102 103 put_uts_ns(old_ns); 104 return new_ns; 105 } 106 107 void free_uts_ns(struct kref *kref) 108 { 109 struct uts_namespace *ns; 110 111 ns = container_of(kref, struct uts_namespace, kref); 112 dec_uts_namespaces(ns->ucounts); 113 put_user_ns(ns->user_ns); 114 ns_free_inum(&ns->ns); 115 kfree(ns); 116 } 117 118 static inline struct uts_namespace *to_uts_ns(struct ns_common *ns) 119 { 120 return container_of(ns, struct uts_namespace, ns); 121 } 122 123 static struct ns_common *utsns_get(struct task_struct *task) 124 { 125 struct uts_namespace *ns = NULL; 126 struct nsproxy *nsproxy; 127 128 task_lock(task); 129 nsproxy = task->nsproxy; 130 if (nsproxy) { 131 ns = nsproxy->uts_ns; 132 get_uts_ns(ns); 133 } 134 task_unlock(task); 135 136 return ns ? &ns->ns : NULL; 137 } 138 139 static void utsns_put(struct ns_common *ns) 140 { 141 put_uts_ns(to_uts_ns(ns)); 142 } 143 144 static int utsns_install(struct nsproxy *nsproxy, struct ns_common *new) 145 { 146 struct uts_namespace *ns = to_uts_ns(new); 147 148 if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) || 149 !ns_capable(current_user_ns(), CAP_SYS_ADMIN)) 150 return -EPERM; 151 152 get_uts_ns(ns); 153 put_uts_ns(nsproxy->uts_ns); 154 nsproxy->uts_ns = ns; 155 return 0; 156 } 157 158 static struct user_namespace *utsns_owner(struct ns_common *ns) 159 { 160 return to_uts_ns(ns)->user_ns; 161 } 162 163 const struct proc_ns_operations utsns_operations = { 164 .name = "uts", 165 .type = CLONE_NEWUTS, 166 .get = utsns_get, 167 .put = utsns_put, 168 .install = utsns_install, 169 .owner = utsns_owner, 170 }; 171