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

ipc_sysctl.c (7417B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *  Copyright (C) 2007
      4 *
      5 *  Author: Eric Biederman <ebiederm@xmision.com>
      6 */
      7
      8#include <linux/module.h>
      9#include <linux/ipc.h>
     10#include <linux/nsproxy.h>
     11#include <linux/sysctl.h>
     12#include <linux/uaccess.h>
     13#include <linux/capability.h>
     14#include <linux/ipc_namespace.h>
     15#include <linux/msg.h>
     16#include <linux/slab.h>
     17#include "util.h"
     18
     19static int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write,
     20		void *buffer, size_t *lenp, loff_t *ppos)
     21{
     22	struct ipc_namespace *ns =
     23		container_of(table->data, struct ipc_namespace, shm_rmid_forced);
     24	int err;
     25
     26	err = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
     27
     28	if (err < 0)
     29		return err;
     30	if (ns->shm_rmid_forced)
     31		shm_destroy_orphaned(ns);
     32	return err;
     33}
     34
     35static int proc_ipc_auto_msgmni(struct ctl_table *table, int write,
     36		void *buffer, size_t *lenp, loff_t *ppos)
     37{
     38	struct ctl_table ipc_table;
     39	int dummy = 0;
     40
     41	memcpy(&ipc_table, table, sizeof(ipc_table));
     42	ipc_table.data = &dummy;
     43
     44	if (write)
     45		pr_info_once("writing to auto_msgmni has no effect");
     46
     47	return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
     48}
     49
     50static int proc_ipc_sem_dointvec(struct ctl_table *table, int write,
     51	void *buffer, size_t *lenp, loff_t *ppos)
     52{
     53	struct ipc_namespace *ns =
     54		container_of(table->data, struct ipc_namespace, sem_ctls);
     55	int ret, semmni;
     56
     57	semmni = ns->sem_ctls[3];
     58	ret = proc_dointvec(table, write, buffer, lenp, ppos);
     59
     60	if (!ret)
     61		ret = sem_check_semmni(ns);
     62
     63	/*
     64	 * Reset the semmni value if an error happens.
     65	 */
     66	if (ret)
     67		ns->sem_ctls[3] = semmni;
     68	return ret;
     69}
     70
     71int ipc_mni = IPCMNI;
     72int ipc_mni_shift = IPCMNI_SHIFT;
     73int ipc_min_cycle = RADIX_TREE_MAP_SIZE;
     74
     75static struct ctl_table ipc_sysctls[] = {
     76	{
     77		.procname	= "shmmax",
     78		.data		= &init_ipc_ns.shm_ctlmax,
     79		.maxlen		= sizeof(init_ipc_ns.shm_ctlmax),
     80		.mode		= 0644,
     81		.proc_handler	= proc_doulongvec_minmax,
     82	},
     83	{
     84		.procname	= "shmall",
     85		.data		= &init_ipc_ns.shm_ctlall,
     86		.maxlen		= sizeof(init_ipc_ns.shm_ctlall),
     87		.mode		= 0644,
     88		.proc_handler	= proc_doulongvec_minmax,
     89	},
     90	{
     91		.procname	= "shmmni",
     92		.data		= &init_ipc_ns.shm_ctlmni,
     93		.maxlen		= sizeof(init_ipc_ns.shm_ctlmni),
     94		.mode		= 0644,
     95		.proc_handler	= proc_dointvec_minmax,
     96		.extra1		= SYSCTL_ZERO,
     97		.extra2		= &ipc_mni,
     98	},
     99	{
    100		.procname	= "shm_rmid_forced",
    101		.data		= &init_ipc_ns.shm_rmid_forced,
    102		.maxlen		= sizeof(init_ipc_ns.shm_rmid_forced),
    103		.mode		= 0644,
    104		.proc_handler	= proc_ipc_dointvec_minmax_orphans,
    105		.extra1		= SYSCTL_ZERO,
    106		.extra2		= SYSCTL_ONE,
    107	},
    108	{
    109		.procname	= "msgmax",
    110		.data		= &init_ipc_ns.msg_ctlmax,
    111		.maxlen		= sizeof(init_ipc_ns.msg_ctlmax),
    112		.mode		= 0644,
    113		.proc_handler	= proc_dointvec_minmax,
    114		.extra1		= SYSCTL_ZERO,
    115		.extra2		= SYSCTL_INT_MAX,
    116	},
    117	{
    118		.procname	= "msgmni",
    119		.data		= &init_ipc_ns.msg_ctlmni,
    120		.maxlen		= sizeof(init_ipc_ns.msg_ctlmni),
    121		.mode		= 0644,
    122		.proc_handler	= proc_dointvec_minmax,
    123		.extra1		= SYSCTL_ZERO,
    124		.extra2		= &ipc_mni,
    125	},
    126	{
    127		.procname	= "auto_msgmni",
    128		.data		= NULL,
    129		.maxlen		= sizeof(int),
    130		.mode		= 0644,
    131		.proc_handler	= proc_ipc_auto_msgmni,
    132		.extra1		= SYSCTL_ZERO,
    133		.extra2		= SYSCTL_ONE,
    134	},
    135	{
    136		.procname	=  "msgmnb",
    137		.data		= &init_ipc_ns.msg_ctlmnb,
    138		.maxlen		= sizeof(init_ipc_ns.msg_ctlmnb),
    139		.mode		= 0644,
    140		.proc_handler	= proc_dointvec_minmax,
    141		.extra1		= SYSCTL_ZERO,
    142		.extra2		= SYSCTL_INT_MAX,
    143	},
    144	{
    145		.procname	= "sem",
    146		.data		= &init_ipc_ns.sem_ctls,
    147		.maxlen		= 4*sizeof(int),
    148		.mode		= 0644,
    149		.proc_handler	= proc_ipc_sem_dointvec,
    150	},
    151#ifdef CONFIG_CHECKPOINT_RESTORE
    152	{
    153		.procname	= "sem_next_id",
    154		.data		= &init_ipc_ns.ids[IPC_SEM_IDS].next_id,
    155		.maxlen		= sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id),
    156		.mode		= 0444,
    157		.proc_handler	= proc_dointvec_minmax,
    158		.extra1		= SYSCTL_ZERO,
    159		.extra2		= SYSCTL_INT_MAX,
    160	},
    161	{
    162		.procname	= "msg_next_id",
    163		.data		= &init_ipc_ns.ids[IPC_MSG_IDS].next_id,
    164		.maxlen		= sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id),
    165		.mode		= 0444,
    166		.proc_handler	= proc_dointvec_minmax,
    167		.extra1		= SYSCTL_ZERO,
    168		.extra2		= SYSCTL_INT_MAX,
    169	},
    170	{
    171		.procname	= "shm_next_id",
    172		.data		= &init_ipc_ns.ids[IPC_SHM_IDS].next_id,
    173		.maxlen		= sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id),
    174		.mode		= 0444,
    175		.proc_handler	= proc_dointvec_minmax,
    176		.extra1		= SYSCTL_ZERO,
    177		.extra2		= SYSCTL_INT_MAX,
    178	},
    179#endif
    180	{}
    181};
    182
    183static struct ctl_table_set *set_lookup(struct ctl_table_root *root)
    184{
    185	return &current->nsproxy->ipc_ns->ipc_set;
    186}
    187
    188static int set_is_seen(struct ctl_table_set *set)
    189{
    190	return &current->nsproxy->ipc_ns->ipc_set == set;
    191}
    192
    193static int ipc_permissions(struct ctl_table_header *head, struct ctl_table *table)
    194{
    195	int mode = table->mode;
    196
    197#ifdef CONFIG_CHECKPOINT_RESTORE
    198	struct ipc_namespace *ns = current->nsproxy->ipc_ns;
    199
    200	if (((table->data == &ns->ids[IPC_SEM_IDS].next_id) ||
    201	     (table->data == &ns->ids[IPC_MSG_IDS].next_id) ||
    202	     (table->data == &ns->ids[IPC_SHM_IDS].next_id)) &&
    203	    checkpoint_restore_ns_capable(ns->user_ns))
    204		mode = 0666;
    205#endif
    206	return mode;
    207}
    208
    209static struct ctl_table_root set_root = {
    210	.lookup = set_lookup,
    211	.permissions = ipc_permissions,
    212};
    213
    214bool setup_ipc_sysctls(struct ipc_namespace *ns)
    215{
    216	struct ctl_table *tbl;
    217
    218	setup_sysctl_set(&ns->ipc_set, &set_root, set_is_seen);
    219
    220	tbl = kmemdup(ipc_sysctls, sizeof(ipc_sysctls), GFP_KERNEL);
    221	if (tbl) {
    222		int i;
    223
    224		for (i = 0; i < ARRAY_SIZE(ipc_sysctls); i++) {
    225			if (tbl[i].data == &init_ipc_ns.shm_ctlmax)
    226				tbl[i].data = &ns->shm_ctlmax;
    227
    228			else if (tbl[i].data == &init_ipc_ns.shm_ctlall)
    229				tbl[i].data = &ns->shm_ctlall;
    230
    231			else if (tbl[i].data == &init_ipc_ns.shm_ctlmni)
    232				tbl[i].data = &ns->shm_ctlmni;
    233
    234			else if (tbl[i].data == &init_ipc_ns.shm_rmid_forced)
    235				tbl[i].data = &ns->shm_rmid_forced;
    236
    237			else if (tbl[i].data == &init_ipc_ns.msg_ctlmax)
    238				tbl[i].data = &ns->msg_ctlmax;
    239
    240			else if (tbl[i].data == &init_ipc_ns.msg_ctlmni)
    241				tbl[i].data = &ns->msg_ctlmni;
    242
    243			else if (tbl[i].data == &init_ipc_ns.msg_ctlmnb)
    244				tbl[i].data = &ns->msg_ctlmnb;
    245
    246			else if (tbl[i].data == &init_ipc_ns.sem_ctls)
    247				tbl[i].data = &ns->sem_ctls;
    248#ifdef CONFIG_CHECKPOINT_RESTORE
    249			else if (tbl[i].data == &init_ipc_ns.ids[IPC_SEM_IDS].next_id)
    250				tbl[i].data = &ns->ids[IPC_SEM_IDS].next_id;
    251
    252			else if (tbl[i].data == &init_ipc_ns.ids[IPC_MSG_IDS].next_id)
    253				tbl[i].data = &ns->ids[IPC_MSG_IDS].next_id;
    254
    255			else if (tbl[i].data == &init_ipc_ns.ids[IPC_SHM_IDS].next_id)
    256				tbl[i].data = &ns->ids[IPC_SHM_IDS].next_id;
    257#endif
    258			else
    259				tbl[i].data = NULL;
    260		}
    261
    262		ns->ipc_sysctls = __register_sysctl_table(&ns->ipc_set, "kernel", tbl);
    263	}
    264	if (!ns->ipc_sysctls) {
    265		kfree(tbl);
    266		retire_sysctl_set(&ns->ipc_set);
    267		return false;
    268	}
    269
    270	return true;
    271}
    272
    273void retire_ipc_sysctls(struct ipc_namespace *ns)
    274{
    275	struct ctl_table *tbl;
    276
    277	tbl = ns->ipc_sysctls->ctl_table_arg;
    278	unregister_sysctl_table(ns->ipc_sysctls);
    279	retire_sysctl_set(&ns->ipc_set);
    280	kfree(tbl);
    281}
    282
    283static int __init ipc_sysctl_init(void)
    284{
    285	if (!setup_ipc_sysctls(&init_ipc_ns)) {
    286		pr_warn("ipc sysctl registration failed\n");
    287		return -ENOMEM;
    288	}
    289	return 0;
    290}
    291
    292device_initcall(ipc_sysctl_init);
    293
    294static int __init ipc_mni_extend(char *str)
    295{
    296	ipc_mni = IPCMNI_EXTEND;
    297	ipc_mni_shift = IPCMNI_EXTEND_SHIFT;
    298	ipc_min_cycle = IPCMNI_EXTEND_MIN_CYCLE;
    299	pr_info("IPCMNI extended to %d.\n", ipc_mni);
    300	return 0;
    301}
    302early_param("ipcmni_extend", ipc_mni_extend);