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> 175b825c3aSIngo Molnar #include <linux/cred.h> 1859607db3SSerge E. Hallyn #include <linux/user_namespace.h> 190bb80f24SDavid Howells #include <linux/proc_ns.h> 20f719ff9bSIngo Molnar #include <linux/sched/task.h> 214865ecf1SSerge E. Hallyn 22*3ea056c5SAlexey Dobriyan static struct kmem_cache *uts_ns_cache __ro_after_init; 23*3ea056c5SAlexey Dobriyan 24f7af3d1cSEric W. Biederman static struct ucounts *inc_uts_namespaces(struct user_namespace *ns) 25f7af3d1cSEric W. Biederman { 26f7af3d1cSEric W. Biederman return inc_ucount(ns, current_euid(), UCOUNT_UTS_NAMESPACES); 27f7af3d1cSEric W. Biederman } 28f7af3d1cSEric W. Biederman 29f7af3d1cSEric W. Biederman static void dec_uts_namespaces(struct ucounts *ucounts) 30f7af3d1cSEric W. Biederman { 31f7af3d1cSEric W. Biederman dec_ucount(ucounts, UCOUNT_UTS_NAMESPACES); 32f7af3d1cSEric W. Biederman } 33f7af3d1cSEric W. Biederman 344c2a7e72SAlexey Dobriyan static struct uts_namespace *create_uts_ns(void) 354c2a7e72SAlexey Dobriyan { 364c2a7e72SAlexey Dobriyan struct uts_namespace *uts_ns; 374c2a7e72SAlexey Dobriyan 38*3ea056c5SAlexey Dobriyan uts_ns = kmem_cache_alloc(uts_ns_cache, GFP_KERNEL); 394c2a7e72SAlexey Dobriyan if (uts_ns) 404c2a7e72SAlexey Dobriyan kref_init(&uts_ns->kref); 414c2a7e72SAlexey Dobriyan return uts_ns; 424c2a7e72SAlexey Dobriyan } 434c2a7e72SAlexey Dobriyan 444865ecf1SSerge E. Hallyn /* 45071df104SSerge E. Hallyn * Clone a new ns copying an original utsname, setting refcount to 1 46071df104SSerge E. Hallyn * @old_ns: namespace to clone 47*3ea056c5SAlexey Dobriyan * Return ERR_PTR(-ENOMEM) on error (failure to allocate), new ns otherwise 48071df104SSerge E. Hallyn */ 49bcf58e72SEric W. Biederman static struct uts_namespace *clone_uts_ns(struct user_namespace *user_ns, 50bb96a6f5SSerge E. Hallyn struct uts_namespace *old_ns) 51071df104SSerge E. Hallyn { 52071df104SSerge E. Hallyn struct uts_namespace *ns; 53f7af3d1cSEric W. Biederman struct ucounts *ucounts; 5498f842e6SEric W. Biederman int err; 55071df104SSerge E. Hallyn 56df75e774SEric W. Biederman err = -ENOSPC; 57f7af3d1cSEric W. Biederman ucounts = inc_uts_namespaces(user_ns); 58f7af3d1cSEric W. Biederman if (!ucounts) 59f7af3d1cSEric W. Biederman goto fail; 60f7af3d1cSEric W. Biederman 61f7af3d1cSEric W. Biederman err = -ENOMEM; 624c2a7e72SAlexey Dobriyan ns = create_uts_ns(); 63467e9f4bSCedric Le Goater if (!ns) 64f7af3d1cSEric W. Biederman goto fail_dec; 65467e9f4bSCedric Le Goater 666344c433SAl Viro err = ns_alloc_inum(&ns->ns); 67f7af3d1cSEric W. Biederman if (err) 68f7af3d1cSEric W. Biederman goto fail_free; 6998f842e6SEric W. Biederman 70f7af3d1cSEric W. Biederman ns->ucounts = ucounts; 7133c42940SAl Viro ns->ns.ops = &utsns_operations; 7233c42940SAl Viro 73efc63c4fSAlexey Dobriyan down_read(&uts_sem); 74071df104SSerge E. Hallyn memcpy(&ns->name, &old_ns->name, sizeof(ns->name)); 75bcf58e72SEric W. Biederman ns->user_ns = get_user_ns(user_ns); 76efc63c4fSAlexey Dobriyan up_read(&uts_sem); 77071df104SSerge E. Hallyn return ns; 78f7af3d1cSEric W. Biederman 79f7af3d1cSEric W. Biederman fail_free: 80*3ea056c5SAlexey Dobriyan kmem_cache_free(uts_ns_cache, ns); 81f7af3d1cSEric W. Biederman fail_dec: 82f7af3d1cSEric W. Biederman dec_uts_namespaces(ucounts); 83f7af3d1cSEric W. Biederman fail: 84f7af3d1cSEric W. Biederman return ERR_PTR(err); 85071df104SSerge E. Hallyn } 86071df104SSerge E. Hallyn 87071df104SSerge E. Hallyn /* 884865ecf1SSerge E. Hallyn * Copy task tsk's utsname namespace, or clone it if flags 894865ecf1SSerge E. Hallyn * specifies CLONE_NEWUTS. In latter case, changes to the 904865ecf1SSerge E. Hallyn * utsname of this process won't be seen by parent, and vice 914865ecf1SSerge E. Hallyn * versa. 924865ecf1SSerge E. Hallyn */ 93bb96a6f5SSerge E. Hallyn struct uts_namespace *copy_utsname(unsigned long flags, 94bcf58e72SEric W. Biederman struct user_namespace *user_ns, struct uts_namespace *old_ns) 954865ecf1SSerge E. Hallyn { 96071df104SSerge E. Hallyn struct uts_namespace *new_ns; 974865ecf1SSerge E. Hallyn 98e3222c4eSBadari Pulavarty BUG_ON(!old_ns); 994865ecf1SSerge E. Hallyn get_uts_ns(old_ns); 1004865ecf1SSerge E. Hallyn 101071df104SSerge E. Hallyn if (!(flags & CLONE_NEWUTS)) 102e3222c4eSBadari Pulavarty return old_ns; 103071df104SSerge E. Hallyn 104bcf58e72SEric W. Biederman new_ns = clone_uts_ns(user_ns, old_ns); 105071df104SSerge E. Hallyn 106071df104SSerge E. Hallyn put_uts_ns(old_ns); 107e3222c4eSBadari Pulavarty return new_ns; 1084865ecf1SSerge E. Hallyn } 1094865ecf1SSerge E. Hallyn 1104865ecf1SSerge E. Hallyn void free_uts_ns(struct kref *kref) 1114865ecf1SSerge E. Hallyn { 1124865ecf1SSerge E. Hallyn struct uts_namespace *ns; 1134865ecf1SSerge E. Hallyn 1144865ecf1SSerge E. Hallyn ns = container_of(kref, struct uts_namespace, kref); 115f7af3d1cSEric W. Biederman dec_uts_namespaces(ns->ucounts); 11659607db3SSerge E. Hallyn put_user_ns(ns->user_ns); 1176344c433SAl Viro ns_free_inum(&ns->ns); 118*3ea056c5SAlexey Dobriyan kmem_cache_free(uts_ns_cache, ns); 1194865ecf1SSerge E. Hallyn } 12034482e89SEric W. Biederman 1213c041184SAl Viro static inline struct uts_namespace *to_uts_ns(struct ns_common *ns) 1223c041184SAl Viro { 1233c041184SAl Viro return container_of(ns, struct uts_namespace, ns); 1243c041184SAl Viro } 1253c041184SAl Viro 12664964528SAl Viro static struct ns_common *utsns_get(struct task_struct *task) 12734482e89SEric W. Biederman { 12834482e89SEric W. Biederman struct uts_namespace *ns = NULL; 12934482e89SEric W. Biederman struct nsproxy *nsproxy; 13034482e89SEric W. Biederman 131728dba3aSEric W. Biederman task_lock(task); 132728dba3aSEric W. Biederman nsproxy = task->nsproxy; 13334482e89SEric W. Biederman if (nsproxy) { 13434482e89SEric W. Biederman ns = nsproxy->uts_ns; 13534482e89SEric W. Biederman get_uts_ns(ns); 13634482e89SEric W. Biederman } 137728dba3aSEric W. Biederman task_unlock(task); 13834482e89SEric W. Biederman 1393c041184SAl Viro return ns ? &ns->ns : NULL; 14034482e89SEric W. Biederman } 14134482e89SEric W. Biederman 14264964528SAl Viro static void utsns_put(struct ns_common *ns) 14334482e89SEric W. Biederman { 1443c041184SAl Viro put_uts_ns(to_uts_ns(ns)); 14534482e89SEric W. Biederman } 14634482e89SEric W. Biederman 14764964528SAl Viro static int utsns_install(struct nsproxy *nsproxy, struct ns_common *new) 14834482e89SEric W. Biederman { 1493c041184SAl Viro struct uts_namespace *ns = to_uts_ns(new); 150142e1d1dSEric W. Biederman 1515e4a0847SEric W. Biederman if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) || 152c7b96acfSEric W. Biederman !ns_capable(current_user_ns(), CAP_SYS_ADMIN)) 153142e1d1dSEric W. Biederman return -EPERM; 154142e1d1dSEric W. Biederman 15534482e89SEric W. Biederman get_uts_ns(ns); 15634482e89SEric W. Biederman put_uts_ns(nsproxy->uts_ns); 15734482e89SEric W. Biederman nsproxy->uts_ns = ns; 15834482e89SEric W. Biederman return 0; 15934482e89SEric W. Biederman } 16034482e89SEric W. Biederman 161bcac25a5SAndrey Vagin static struct user_namespace *utsns_owner(struct ns_common *ns) 162bcac25a5SAndrey Vagin { 163bcac25a5SAndrey Vagin return to_uts_ns(ns)->user_ns; 164bcac25a5SAndrey Vagin } 165bcac25a5SAndrey Vagin 16634482e89SEric W. Biederman const struct proc_ns_operations utsns_operations = { 16734482e89SEric W. Biederman .name = "uts", 16834482e89SEric W. Biederman .type = CLONE_NEWUTS, 16934482e89SEric W. Biederman .get = utsns_get, 17034482e89SEric W. Biederman .put = utsns_put, 17134482e89SEric W. Biederman .install = utsns_install, 172bcac25a5SAndrey Vagin .owner = utsns_owner, 17334482e89SEric W. Biederman }; 174*3ea056c5SAlexey Dobriyan 175*3ea056c5SAlexey Dobriyan void __init uts_ns_init(void) 176*3ea056c5SAlexey Dobriyan { 177*3ea056c5SAlexey Dobriyan uts_ns_cache = kmem_cache_create_usercopy( 178*3ea056c5SAlexey Dobriyan "uts_namespace", sizeof(struct uts_namespace), 0, 179*3ea056c5SAlexey Dobriyan SLAB_PANIC|SLAB_ACCOUNT, 180*3ea056c5SAlexey Dobriyan offsetof(struct uts_namespace, name), 181*3ea056c5SAlexey Dobriyan sizeof_field(struct uts_namespace, name), 182*3ea056c5SAlexey Dobriyan NULL); 183*3ea056c5SAlexey Dobriyan } 184