cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

utsname.c (3855B)


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