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