linux/ipc/ipc_sysctl.c
<<
>>
Prefs
   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/ipc_namespace.h>
  14#include <linux/msg.h>
  15#include "util.h"
  16
  17static void *get_ipc(struct ctl_table *table)
  18{
  19        char *which = table->data;
  20        struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
  21        which = (which - (char *)&init_ipc_ns) + (char *)ipc_ns;
  22        return which;
  23}
  24
  25#ifdef CONFIG_PROC_SYSCTL
  26static int proc_ipc_dointvec(struct ctl_table *table, int write,
  27        void __user *buffer, size_t *lenp, loff_t *ppos)
  28{
  29        struct ctl_table ipc_table;
  30
  31        memcpy(&ipc_table, table, sizeof(ipc_table));
  32        ipc_table.data = get_ipc(table);
  33
  34        return proc_dointvec(&ipc_table, write, buffer, lenp, ppos);
  35}
  36
  37static int proc_ipc_dointvec_minmax(struct ctl_table *table, int write,
  38        void __user *buffer, size_t *lenp, loff_t *ppos)
  39{
  40        struct ctl_table ipc_table;
  41
  42        memcpy(&ipc_table, table, sizeof(ipc_table));
  43        ipc_table.data = get_ipc(table);
  44
  45        return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
  46}
  47
  48static int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write,
  49        void __user *buffer, size_t *lenp, loff_t *ppos)
  50{
  51        struct ipc_namespace *ns = current->nsproxy->ipc_ns;
  52        int err = proc_ipc_dointvec_minmax(table, write, buffer, lenp, ppos);
  53
  54        if (err < 0)
  55                return err;
  56        if (ns->shm_rmid_forced)
  57                shm_destroy_orphaned(ns);
  58        return err;
  59}
  60
  61static int proc_ipc_doulongvec_minmax(struct ctl_table *table, int write,
  62        void __user *buffer, size_t *lenp, loff_t *ppos)
  63{
  64        struct ctl_table ipc_table;
  65        memcpy(&ipc_table, table, sizeof(ipc_table));
  66        ipc_table.data = get_ipc(table);
  67
  68        return proc_doulongvec_minmax(&ipc_table, write, buffer,
  69                                        lenp, ppos);
  70}
  71
  72static int proc_ipc_auto_msgmni(struct ctl_table *table, int write,
  73        void __user *buffer, size_t *lenp, loff_t *ppos)
  74{
  75        struct ctl_table ipc_table;
  76        int dummy = 0;
  77
  78        memcpy(&ipc_table, table, sizeof(ipc_table));
  79        ipc_table.data = &dummy;
  80
  81        if (write)
  82                pr_info_once("writing to auto_msgmni has no effect");
  83
  84        return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
  85}
  86
  87static int proc_ipc_sem_dointvec(struct ctl_table *table, int write,
  88        void __user *buffer, size_t *lenp, loff_t *ppos)
  89{
  90        int ret, semmni;
  91        struct ipc_namespace *ns = current->nsproxy->ipc_ns;
  92
  93        semmni = ns->sem_ctls[3];
  94        ret = proc_ipc_dointvec(table, write, buffer, lenp, ppos);
  95
  96        if (!ret)
  97                ret = sem_check_semmni(current->nsproxy->ipc_ns);
  98
  99        /*
 100         * Reset the semmni value if an error happens.
 101         */
 102        if (ret)
 103                ns->sem_ctls[3] = semmni;
 104        return ret;
 105}
 106
 107#else
 108#define proc_ipc_doulongvec_minmax NULL
 109#define proc_ipc_dointvec          NULL
 110#define proc_ipc_dointvec_minmax   NULL
 111#define proc_ipc_dointvec_minmax_orphans   NULL
 112#define proc_ipc_auto_msgmni       NULL
 113#define proc_ipc_sem_dointvec      NULL
 114#endif
 115
 116static int zero;
 117static int one = 1;
 118static int int_max = INT_MAX;
 119int ipc_mni = IPCMNI;
 120int ipc_mni_shift = IPCMNI_SHIFT;
 121int ipc_min_cycle = RADIX_TREE_MAP_SIZE;
 122
 123static struct ctl_table ipc_kern_table[] = {
 124        {
 125                .procname       = "shmmax",
 126                .data           = &init_ipc_ns.shm_ctlmax,
 127                .maxlen         = sizeof(init_ipc_ns.shm_ctlmax),
 128                .mode           = 0644,
 129                .proc_handler   = proc_ipc_doulongvec_minmax,
 130        },
 131        {
 132                .procname       = "shmall",
 133                .data           = &init_ipc_ns.shm_ctlall,
 134                .maxlen         = sizeof(init_ipc_ns.shm_ctlall),
 135                .mode           = 0644,
 136                .proc_handler   = proc_ipc_doulongvec_minmax,
 137        },
 138        {
 139                .procname       = "shmmni",
 140                .data           = &init_ipc_ns.shm_ctlmni,
 141                .maxlen         = sizeof(init_ipc_ns.shm_ctlmni),
 142                .mode           = 0644,
 143                .proc_handler   = proc_ipc_dointvec_minmax,
 144                .extra1         = &zero,
 145                .extra2         = &ipc_mni,
 146        },
 147        {
 148                .procname       = "shm_rmid_forced",
 149                .data           = &init_ipc_ns.shm_rmid_forced,
 150                .maxlen         = sizeof(init_ipc_ns.shm_rmid_forced),
 151                .mode           = 0644,
 152                .proc_handler   = proc_ipc_dointvec_minmax_orphans,
 153                .extra1         = &zero,
 154                .extra2         = &one,
 155        },
 156        {
 157                .procname       = "msgmax",
 158                .data           = &init_ipc_ns.msg_ctlmax,
 159                .maxlen         = sizeof(init_ipc_ns.msg_ctlmax),
 160                .mode           = 0644,
 161                .proc_handler   = proc_ipc_dointvec_minmax,
 162                .extra1         = &zero,
 163                .extra2         = &int_max,
 164        },
 165        {
 166                .procname       = "msgmni",
 167                .data           = &init_ipc_ns.msg_ctlmni,
 168                .maxlen         = sizeof(init_ipc_ns.msg_ctlmni),
 169                .mode           = 0644,
 170                .proc_handler   = proc_ipc_dointvec_minmax,
 171                .extra1         = &zero,
 172                .extra2         = &ipc_mni,
 173        },
 174        {
 175                .procname       = "auto_msgmni",
 176                .data           = NULL,
 177                .maxlen         = sizeof(int),
 178                .mode           = 0644,
 179                .proc_handler   = proc_ipc_auto_msgmni,
 180                .extra1         = &zero,
 181                .extra2         = &one,
 182        },
 183        {
 184                .procname       =  "msgmnb",
 185                .data           = &init_ipc_ns.msg_ctlmnb,
 186                .maxlen         = sizeof(init_ipc_ns.msg_ctlmnb),
 187                .mode           = 0644,
 188                .proc_handler   = proc_ipc_dointvec_minmax,
 189                .extra1         = &zero,
 190                .extra2         = &int_max,
 191        },
 192        {
 193                .procname       = "sem",
 194                .data           = &init_ipc_ns.sem_ctls,
 195                .maxlen         = 4*sizeof(int),
 196                .mode           = 0644,
 197                .proc_handler   = proc_ipc_sem_dointvec,
 198        },
 199#ifdef CONFIG_CHECKPOINT_RESTORE
 200        {
 201                .procname       = "sem_next_id",
 202                .data           = &init_ipc_ns.ids[IPC_SEM_IDS].next_id,
 203                .maxlen         = sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id),
 204                .mode           = 0644,
 205                .proc_handler   = proc_ipc_dointvec_minmax,
 206                .extra1         = &zero,
 207                .extra2         = &int_max,
 208        },
 209        {
 210                .procname       = "msg_next_id",
 211                .data           = &init_ipc_ns.ids[IPC_MSG_IDS].next_id,
 212                .maxlen         = sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id),
 213                .mode           = 0644,
 214                .proc_handler   = proc_ipc_dointvec_minmax,
 215                .extra1         = &zero,
 216                .extra2         = &int_max,
 217        },
 218        {
 219                .procname       = "shm_next_id",
 220                .data           = &init_ipc_ns.ids[IPC_SHM_IDS].next_id,
 221                .maxlen         = sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id),
 222                .mode           = 0644,
 223                .proc_handler   = proc_ipc_dointvec_minmax,
 224                .extra1         = &zero,
 225                .extra2         = &int_max,
 226        },
 227#endif
 228        {}
 229};
 230
 231static struct ctl_table ipc_root_table[] = {
 232        {
 233                .procname       = "kernel",
 234                .mode           = 0555,
 235                .child          = ipc_kern_table,
 236        },
 237        {}
 238};
 239
 240static int __init ipc_sysctl_init(void)
 241{
 242        register_sysctl_table(ipc_root_table);
 243        return 0;
 244}
 245
 246device_initcall(ipc_sysctl_init);
 247
 248static int __init ipc_mni_extend(char *str)
 249{
 250        ipc_mni = IPCMNI_EXTEND;
 251        ipc_mni_shift = IPCMNI_EXTEND_SHIFT;
 252        ipc_min_cycle = IPCMNI_EXTEND_MIN_CYCLE;
 253        pr_info("IPCMNI extended to %d.\n", ipc_mni);
 254        return 0;
 255}
 256early_param("ipcmni_extend", ipc_mni_extend);
 257