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 20static 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 */ 35static 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 = ns_alloc_inum(&ns->ns); 46 if (err) { 47 kfree(ns); 48 return ERR_PTR(err); 49 } 50 51 ns->ns.ops = &utsns_operations; 52 53 down_read(&uts_sem); 54 memcpy(&ns->name, &old_ns->name, sizeof(ns->name)); 55 ns->user_ns = get_user_ns(user_ns); 56 up_read(&uts_sem); 57 return ns; 58} 59 60/* 61 * Copy task tsk's utsname namespace, or clone it if flags 62 * specifies CLONE_NEWUTS. In latter case, changes to the 63 * utsname of this process won't be seen by parent, and vice 64 * versa. 65 */ 66struct uts_namespace *copy_utsname(unsigned long flags, 67 struct user_namespace *user_ns, struct uts_namespace *old_ns) 68{ 69 struct uts_namespace *new_ns; 70 71 BUG_ON(!old_ns); 72 get_uts_ns(old_ns); 73 74 if (!(flags & CLONE_NEWUTS)) 75 return old_ns; 76 77 new_ns = clone_uts_ns(user_ns, old_ns); 78 79 put_uts_ns(old_ns); 80 return new_ns; 81} 82 83void free_uts_ns(struct kref *kref) 84{ 85 struct uts_namespace *ns; 86 87 ns = container_of(kref, struct uts_namespace, kref); 88 put_user_ns(ns->user_ns); 89 ns_free_inum(&ns->ns); 90 kfree(ns); 91} 92 93static inline struct uts_namespace *to_uts_ns(struct ns_common *ns) 94{ 95 return container_of(ns, struct uts_namespace, ns); 96} 97 98static struct ns_common *utsns_get(struct task_struct *task) 99{ 100 struct uts_namespace *ns = NULL; 101 struct nsproxy *nsproxy; 102 103 task_lock(task); 104 nsproxy = task->nsproxy; 105 if (nsproxy) { 106 ns = nsproxy->uts_ns; 107 get_uts_ns(ns); 108 } 109 task_unlock(task); 110 111 return ns ? &ns->ns : NULL; 112} 113 114static void utsns_put(struct ns_common *ns) 115{ 116 put_uts_ns(to_uts_ns(ns)); 117} 118 119static int utsns_install(struct nsproxy *nsproxy, struct ns_common *new) 120{ 121 struct uts_namespace *ns = to_uts_ns(new); 122 123 if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) || 124 !ns_capable(current_user_ns(), CAP_SYS_ADMIN)) 125 return -EPERM; 126 127 get_uts_ns(ns); 128 put_uts_ns(nsproxy->uts_ns); 129 nsproxy->uts_ns = ns; 130 return 0; 131} 132 133const struct proc_ns_operations utsns_operations = { 134 .name = "uts", 135 .type = CLONE_NEWUTS, 136 .get = utsns_get, 137 .put = utsns_put, 138 .install = utsns_install, 139}; 140