xref: /openbmc/linux/kernel/utsname.c (revision 9984de1a5a8a96275fcab818f7419af5a3c86e71)
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