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 12*9984de1aSPaul 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> 1834482e89SEric W. Biederman #include <linux/proc_fs.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 33071df104SSerge E. Hallyn * Return NULL on error (failure to kmalloc), new ns otherwise 34071df104SSerge E. Hallyn */ 35bb96a6f5SSerge E. Hallyn static struct uts_namespace *clone_uts_ns(struct task_struct *tsk, 36bb96a6f5SSerge E. Hallyn struct uts_namespace *old_ns) 37071df104SSerge E. Hallyn { 38071df104SSerge E. Hallyn struct uts_namespace *ns; 39071df104SSerge E. Hallyn 404c2a7e72SAlexey Dobriyan ns = create_uts_ns(); 41467e9f4bSCedric Le Goater if (!ns) 42467e9f4bSCedric Le Goater return ERR_PTR(-ENOMEM); 43467e9f4bSCedric Le Goater 44efc63c4fSAlexey Dobriyan down_read(&uts_sem); 45071df104SSerge E. Hallyn memcpy(&ns->name, &old_ns->name, sizeof(ns->name)); 46bb96a6f5SSerge E. Hallyn ns->user_ns = get_user_ns(task_cred_xxx(tsk, user)->user_ns); 47efc63c4fSAlexey Dobriyan up_read(&uts_sem); 48071df104SSerge E. Hallyn return ns; 49071df104SSerge E. Hallyn } 50071df104SSerge E. Hallyn 51071df104SSerge E. Hallyn /* 524865ecf1SSerge E. Hallyn * Copy task tsk's utsname namespace, or clone it if flags 534865ecf1SSerge E. Hallyn * specifies CLONE_NEWUTS. In latter case, changes to the 544865ecf1SSerge E. Hallyn * utsname of this process won't be seen by parent, and vice 554865ecf1SSerge E. Hallyn * versa. 564865ecf1SSerge E. Hallyn */ 57bb96a6f5SSerge E. Hallyn struct uts_namespace *copy_utsname(unsigned long flags, 58bb96a6f5SSerge E. Hallyn struct task_struct *tsk) 594865ecf1SSerge E. Hallyn { 60bb96a6f5SSerge E. Hallyn struct uts_namespace *old_ns = tsk->nsproxy->uts_ns; 61071df104SSerge E. Hallyn struct uts_namespace *new_ns; 624865ecf1SSerge E. Hallyn 63e3222c4eSBadari Pulavarty BUG_ON(!old_ns); 644865ecf1SSerge E. Hallyn get_uts_ns(old_ns); 654865ecf1SSerge E. Hallyn 66071df104SSerge E. Hallyn if (!(flags & CLONE_NEWUTS)) 67e3222c4eSBadari Pulavarty return old_ns; 68071df104SSerge E. Hallyn 69bb96a6f5SSerge E. Hallyn new_ns = clone_uts_ns(tsk, old_ns); 70071df104SSerge E. Hallyn 71071df104SSerge E. Hallyn put_uts_ns(old_ns); 72e3222c4eSBadari Pulavarty return new_ns; 734865ecf1SSerge E. Hallyn } 744865ecf1SSerge E. Hallyn 754865ecf1SSerge E. Hallyn void free_uts_ns(struct kref *kref) 764865ecf1SSerge E. Hallyn { 774865ecf1SSerge E. Hallyn struct uts_namespace *ns; 784865ecf1SSerge E. Hallyn 794865ecf1SSerge E. Hallyn ns = container_of(kref, struct uts_namespace, kref); 8059607db3SSerge E. Hallyn put_user_ns(ns->user_ns); 814865ecf1SSerge E. Hallyn kfree(ns); 824865ecf1SSerge E. Hallyn } 8334482e89SEric W. Biederman 8434482e89SEric W. Biederman static void *utsns_get(struct task_struct *task) 8534482e89SEric W. Biederman { 8634482e89SEric W. Biederman struct uts_namespace *ns = NULL; 8734482e89SEric W. Biederman struct nsproxy *nsproxy; 8834482e89SEric W. Biederman 8934482e89SEric W. Biederman rcu_read_lock(); 9034482e89SEric W. Biederman nsproxy = task_nsproxy(task); 9134482e89SEric W. Biederman if (nsproxy) { 9234482e89SEric W. Biederman ns = nsproxy->uts_ns; 9334482e89SEric W. Biederman get_uts_ns(ns); 9434482e89SEric W. Biederman } 9534482e89SEric W. Biederman rcu_read_unlock(); 9634482e89SEric W. Biederman 9734482e89SEric W. Biederman return ns; 9834482e89SEric W. Biederman } 9934482e89SEric W. Biederman 10034482e89SEric W. Biederman static void utsns_put(void *ns) 10134482e89SEric W. Biederman { 10234482e89SEric W. Biederman put_uts_ns(ns); 10334482e89SEric W. Biederman } 10434482e89SEric W. Biederman 10534482e89SEric W. Biederman static int utsns_install(struct nsproxy *nsproxy, void *ns) 10634482e89SEric W. Biederman { 10734482e89SEric W. Biederman get_uts_ns(ns); 10834482e89SEric W. Biederman put_uts_ns(nsproxy->uts_ns); 10934482e89SEric W. Biederman nsproxy->uts_ns = ns; 11034482e89SEric W. Biederman return 0; 11134482e89SEric W. Biederman } 11234482e89SEric W. Biederman 11334482e89SEric W. Biederman const struct proc_ns_operations utsns_operations = { 11434482e89SEric W. Biederman .name = "uts", 11534482e89SEric W. Biederman .type = CLONE_NEWUTS, 11634482e89SEric W. Biederman .get = utsns_get, 11734482e89SEric W. Biederman .put = utsns_put, 11834482e89SEric W. Biederman .install = utsns_install, 11934482e89SEric W. Biederman }; 12034482e89SEric W. Biederman 121