linux/kernel/utsname.c
<<
>>
Prefs
   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/cred.h>
  18#include <linux/user_namespace.h>
  19#include <linux/proc_ns.h>
  20#include <linux/sched/task.h>
  21
  22static struct kmem_cache *uts_ns_cache __ro_after_init;
  23
  24static struct ucounts *inc_uts_namespaces(struct user_namespace *ns)
  25{
  26        return inc_ucount(ns, current_euid(), UCOUNT_UTS_NAMESPACES);
  27}
  28
  29static void dec_uts_namespaces(struct ucounts *ucounts)
  30{
  31        dec_ucount(ucounts, UCOUNT_UTS_NAMESPACES);
  32}
  33
  34static struct uts_namespace *create_uts_ns(void)
  35{
  36        struct uts_namespace *uts_ns;
  37
  38        uts_ns = kmem_cache_alloc(uts_ns_cache, GFP_KERNEL);
  39        if (uts_ns)
  40                kref_init(&uts_ns->kref);
  41        return uts_ns;
  42}
  43
  44/*
  45 * Clone a new ns copying an original utsname, setting refcount to 1
  46 * @old_ns: namespace to clone
  47 * Return ERR_PTR(-ENOMEM) on error (failure to allocate), new ns otherwise
  48 */
  49static struct uts_namespace *clone_uts_ns(struct user_namespace *user_ns,
  50                                          struct uts_namespace *old_ns)
  51{
  52        struct uts_namespace *ns;
  53        struct ucounts *ucounts;
  54        int err;
  55
  56        err = -ENOSPC;
  57        ucounts = inc_uts_namespaces(user_ns);
  58        if (!ucounts)
  59                goto fail;
  60
  61        err = -ENOMEM;
  62        ns = create_uts_ns();
  63        if (!ns)
  64                goto fail_dec;
  65
  66        err = ns_alloc_inum(&ns->ns);
  67        if (err)
  68                goto fail_free;
  69
  70        ns->ucounts = ucounts;
  71        ns->ns.ops = &utsns_operations;
  72
  73        down_read(&uts_sem);
  74        memcpy(&ns->name, &old_ns->name, sizeof(ns->name));
  75        ns->user_ns = get_user_ns(user_ns);
  76        up_read(&uts_sem);
  77        return ns;
  78
  79fail_free:
  80        kmem_cache_free(uts_ns_cache, ns);
  81fail_dec:
  82        dec_uts_namespaces(ucounts);
  83fail:
  84        return ERR_PTR(err);
  85}
  86
  87/*
  88 * Copy task tsk's utsname namespace, or clone it if flags
  89 * specifies CLONE_NEWUTS.  In latter case, changes to the
  90 * utsname of this process won't be seen by parent, and vice
  91 * versa.
  92 */
  93struct uts_namespace *copy_utsname(unsigned long flags,
  94        struct user_namespace *user_ns, struct uts_namespace *old_ns)
  95{
  96        struct uts_namespace *new_ns;
  97
  98        BUG_ON(!old_ns);
  99        get_uts_ns(old_ns);
 100
 101        if (!(flags & CLONE_NEWUTS))
 102                return old_ns;
 103
 104        new_ns = clone_uts_ns(user_ns, old_ns);
 105
 106        put_uts_ns(old_ns);
 107        return new_ns;
 108}
 109
 110void free_uts_ns(struct kref *kref)
 111{
 112        struct uts_namespace *ns;
 113
 114        ns = container_of(kref, struct uts_namespace, kref);
 115        dec_uts_namespaces(ns->ucounts);
 116        put_user_ns(ns->user_ns);
 117        ns_free_inum(&ns->ns);
 118        kmem_cache_free(uts_ns_cache, ns);
 119}
 120
 121static inline struct uts_namespace *to_uts_ns(struct ns_common *ns)
 122{
 123        return container_of(ns, struct uts_namespace, ns);
 124}
 125
 126static struct ns_common *utsns_get(struct task_struct *task)
 127{
 128        struct uts_namespace *ns = NULL;
 129        struct nsproxy *nsproxy;
 130
 131        task_lock(task);
 132        nsproxy = task->nsproxy;
 133        if (nsproxy) {
 134                ns = nsproxy->uts_ns;
 135                get_uts_ns(ns);
 136        }
 137        task_unlock(task);
 138
 139        return ns ? &ns->ns : NULL;
 140}
 141
 142static void utsns_put(struct ns_common *ns)
 143{
 144        put_uts_ns(to_uts_ns(ns));
 145}
 146
 147static int utsns_install(struct nsproxy *nsproxy, struct ns_common *new)
 148{
 149        struct uts_namespace *ns = to_uts_ns(new);
 150
 151        if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) ||
 152            !ns_capable(current_user_ns(), CAP_SYS_ADMIN))
 153                return -EPERM;
 154
 155        get_uts_ns(ns);
 156        put_uts_ns(nsproxy->uts_ns);
 157        nsproxy->uts_ns = ns;
 158        return 0;
 159}
 160
 161static struct user_namespace *utsns_owner(struct ns_common *ns)
 162{
 163        return to_uts_ns(ns)->user_ns;
 164}
 165
 166const struct proc_ns_operations utsns_operations = {
 167        .name           = "uts",
 168        .type           = CLONE_NEWUTS,
 169        .get            = utsns_get,
 170        .put            = utsns_put,
 171        .install        = utsns_install,
 172        .owner          = utsns_owner,
 173};
 174
 175void __init uts_ns_init(void)
 176{
 177        uts_ns_cache = kmem_cache_create_usercopy(
 178                        "uts_namespace", sizeof(struct uts_namespace), 0,
 179                        SLAB_PANIC|SLAB_ACCOUNT,
 180                        offsetof(struct uts_namespace, name),
 181                        sizeof_field(struct uts_namespace, name),
 182                        NULL);
 183}
 184