14865ecf1SSerge E. Hallyn /* 24865ecf1SSerge E. Hallyn * Copyright (C) 2004 IBM Corporation 34865ecf1SSerge E. Hallyn * 44865ecf1SSerge E. Hallyn * Author: Serge Hallyn <serue@us.ibm.com> 54865ecf1SSerge E. Hallyn * 64865ecf1SSerge E. Hallyn * This program is free software; you can redistribute it and/or 74865ecf1SSerge E. Hallyn * modify it under the terms of the GNU General Public License as 84865ecf1SSerge E. Hallyn * published by the Free Software Foundation, version 2 of the 94865ecf1SSerge E. Hallyn * License. 104865ecf1SSerge E. Hallyn */ 114865ecf1SSerge E. Hallyn 129984de1aSPaul Gortmaker #include <linux/export.h> 134865ecf1SSerge E. Hallyn #include <linux/uts.h> 144865ecf1SSerge E. Hallyn #include <linux/utsname.h> 15467e9f4bSCedric Le Goater #include <linux/err.h> 161aeb272cSRobert P. J. Day #include <linux/slab.h> 1759607db3SSerge E. Hallyn #include <linux/user_namespace.h> 180bb80f24SDavid Howells #include <linux/proc_ns.h> 194865ecf1SSerge E. Hallyn 204c2a7e72SAlexey Dobriyan static struct uts_namespace *create_uts_ns(void) 214c2a7e72SAlexey Dobriyan { 224c2a7e72SAlexey Dobriyan struct uts_namespace *uts_ns; 234c2a7e72SAlexey Dobriyan 244c2a7e72SAlexey Dobriyan uts_ns = kmalloc(sizeof(struct uts_namespace), GFP_KERNEL); 254c2a7e72SAlexey Dobriyan if (uts_ns) 264c2a7e72SAlexey Dobriyan kref_init(&uts_ns->kref); 274c2a7e72SAlexey Dobriyan return uts_ns; 284c2a7e72SAlexey Dobriyan } 294c2a7e72SAlexey Dobriyan 304865ecf1SSerge E. Hallyn /* 31071df104SSerge E. Hallyn * Clone a new ns copying an original utsname, setting refcount to 1 32071df104SSerge E. Hallyn * @old_ns: namespace to clone 33bf531536SYuanhan Liu * Return ERR_PTR(-ENOMEM) on error (failure to kmalloc), new ns otherwise 34071df104SSerge E. Hallyn */ 35bcf58e72SEric W. Biederman static struct uts_namespace *clone_uts_ns(struct user_namespace *user_ns, 36bb96a6f5SSerge E. Hallyn struct uts_namespace *old_ns) 37071df104SSerge E. Hallyn { 38071df104SSerge E. Hallyn struct uts_namespace *ns; 3998f842e6SEric W. Biederman int err; 40071df104SSerge E. Hallyn 414c2a7e72SAlexey Dobriyan ns = create_uts_ns(); 42467e9f4bSCedric Le Goater if (!ns) 43467e9f4bSCedric Le Goater return ERR_PTR(-ENOMEM); 44467e9f4bSCedric Le Goater 45*6344c433SAl Viro err = ns_alloc_inum(&ns->ns); 4698f842e6SEric W. Biederman if (err) { 4798f842e6SEric W. Biederman kfree(ns); 4898f842e6SEric W. Biederman return ERR_PTR(err); 4998f842e6SEric W. Biederman } 5098f842e6SEric W. Biederman 51efc63c4fSAlexey Dobriyan down_read(&uts_sem); 52071df104SSerge E. Hallyn memcpy(&ns->name, &old_ns->name, sizeof(ns->name)); 53bcf58e72SEric W. Biederman ns->user_ns = get_user_ns(user_ns); 54efc63c4fSAlexey Dobriyan up_read(&uts_sem); 55071df104SSerge E. Hallyn return ns; 56071df104SSerge E. Hallyn } 57071df104SSerge E. Hallyn 58071df104SSerge E. Hallyn /* 594865ecf1SSerge E. Hallyn * Copy task tsk's utsname namespace, or clone it if flags 604865ecf1SSerge E. Hallyn * specifies CLONE_NEWUTS. In latter case, changes to the 614865ecf1SSerge E. Hallyn * utsname of this process won't be seen by parent, and vice 624865ecf1SSerge E. Hallyn * versa. 634865ecf1SSerge E. Hallyn */ 64bb96a6f5SSerge E. Hallyn struct uts_namespace *copy_utsname(unsigned long flags, 65bcf58e72SEric W. Biederman struct user_namespace *user_ns, struct uts_namespace *old_ns) 664865ecf1SSerge E. Hallyn { 67071df104SSerge E. Hallyn struct uts_namespace *new_ns; 684865ecf1SSerge E. Hallyn 69e3222c4eSBadari Pulavarty BUG_ON(!old_ns); 704865ecf1SSerge E. Hallyn get_uts_ns(old_ns); 714865ecf1SSerge E. Hallyn 72071df104SSerge E. Hallyn if (!(flags & CLONE_NEWUTS)) 73e3222c4eSBadari Pulavarty return old_ns; 74071df104SSerge E. Hallyn 75bcf58e72SEric W. Biederman new_ns = clone_uts_ns(user_ns, old_ns); 76071df104SSerge E. Hallyn 77071df104SSerge E. Hallyn put_uts_ns(old_ns); 78e3222c4eSBadari Pulavarty return new_ns; 794865ecf1SSerge E. Hallyn } 804865ecf1SSerge E. Hallyn 814865ecf1SSerge E. Hallyn void free_uts_ns(struct kref *kref) 824865ecf1SSerge E. Hallyn { 834865ecf1SSerge E. Hallyn struct uts_namespace *ns; 844865ecf1SSerge E. Hallyn 854865ecf1SSerge E. Hallyn ns = container_of(kref, struct uts_namespace, kref); 8659607db3SSerge E. Hallyn put_user_ns(ns->user_ns); 87*6344c433SAl Viro ns_free_inum(&ns->ns); 884865ecf1SSerge E. Hallyn kfree(ns); 894865ecf1SSerge E. Hallyn } 9034482e89SEric W. Biederman 913c041184SAl Viro static inline struct uts_namespace *to_uts_ns(struct ns_common *ns) 923c041184SAl Viro { 933c041184SAl Viro return container_of(ns, struct uts_namespace, ns); 943c041184SAl Viro } 953c041184SAl Viro 9664964528SAl Viro static struct ns_common *utsns_get(struct task_struct *task) 9734482e89SEric W. Biederman { 9834482e89SEric W. Biederman struct uts_namespace *ns = NULL; 9934482e89SEric W. Biederman struct nsproxy *nsproxy; 10034482e89SEric W. Biederman 101728dba3aSEric W. Biederman task_lock(task); 102728dba3aSEric W. Biederman nsproxy = task->nsproxy; 10334482e89SEric W. Biederman if (nsproxy) { 10434482e89SEric W. Biederman ns = nsproxy->uts_ns; 10534482e89SEric W. Biederman get_uts_ns(ns); 10634482e89SEric W. Biederman } 107728dba3aSEric W. Biederman task_unlock(task); 10834482e89SEric W. Biederman 1093c041184SAl Viro return ns ? &ns->ns : NULL; 11034482e89SEric W. Biederman } 11134482e89SEric W. Biederman 11264964528SAl Viro static void utsns_put(struct ns_common *ns) 11334482e89SEric W. Biederman { 1143c041184SAl Viro put_uts_ns(to_uts_ns(ns)); 11534482e89SEric W. Biederman } 11634482e89SEric W. Biederman 11764964528SAl Viro static int utsns_install(struct nsproxy *nsproxy, struct ns_common *new) 11834482e89SEric W. Biederman { 1193c041184SAl Viro struct uts_namespace *ns = to_uts_ns(new); 120142e1d1dSEric W. Biederman 1215e4a0847SEric W. Biederman if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) || 122c7b96acfSEric W. Biederman !ns_capable(current_user_ns(), CAP_SYS_ADMIN)) 123142e1d1dSEric W. Biederman return -EPERM; 124142e1d1dSEric W. Biederman 12534482e89SEric W. Biederman get_uts_ns(ns); 12634482e89SEric W. Biederman put_uts_ns(nsproxy->uts_ns); 12734482e89SEric W. Biederman nsproxy->uts_ns = ns; 12834482e89SEric W. Biederman return 0; 12934482e89SEric W. Biederman } 13034482e89SEric W. Biederman 13134482e89SEric W. Biederman const struct proc_ns_operations utsns_operations = { 13234482e89SEric W. Biederman .name = "uts", 13334482e89SEric W. Biederman .type = CLONE_NEWUTS, 13434482e89SEric W. Biederman .get = utsns_get, 13534482e89SEric W. Biederman .put = utsns_put, 13634482e89SEric W. Biederman .install = utsns_install, 13734482e89SEric W. Biederman }; 138