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 *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 *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 *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 *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 *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 *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
 116int ipc_mni = IPCMNI;
 117int ipc_mni_shift = IPCMNI_SHIFT;
 118int ipc_min_cycle = RADIX_TREE_MAP_SIZE;
 119
 120static struct ctl_table ipc_kern_table[] = {
 121        {
 122                .procname       = "shmmax",
 123                .data           = &init_ipc_ns.shm_ctlmax,
 124                .maxlen         = sizeof(init_ipc_ns.shm_ctlmax),
 125                .mode           = 0644,
 126                .proc_handler   = proc_ipc_doulongvec_minmax,
 127        },
 128        {
 129                .procname       = "shmall",
 130                .data           = &init_ipc_ns.shm_ctlall,
 131                .maxlen         = sizeof(init_ipc_ns.shm_ctlall),
 132                .mode           = 0644,
 133                .proc_handler   = proc_ipc_doulongvec_minmax,
 134        },
 135        {
 136                .procname       = "shmmni",
 137                .data           = &init_ipc_ns.shm_ctlmni,
 138                .maxlen         = sizeof(init_ipc_ns.shm_ctlmni),
 139                .mode           = 0644,
 140                .proc_handler   = proc_ipc_dointvec_minmax,
 141                .extra1         = SYSCTL_ZERO,
 142                .extra2         = &ipc_mni,
 143        },
 144        {
 145                .procname       = "shm_rmid_forced",
 146                .data           = &init_ipc_ns.shm_rmid_forced,
 147                .maxlen         = sizeof(init_ipc_ns.shm_rmid_forced),
 148                .mode           = 0644,
 149                .proc_handler   = proc_ipc_dointvec_minmax_orphans,
 150                .extra1         = SYSCTL_ZERO,
 151                .extra2         = SYSCTL_ONE,
 152        },
 153        {
 154                .procname       = "msgmax",
 155                .data           = &init_ipc_ns.msg_ctlmax,
 156                .maxlen         = sizeof(init_ipc_ns.msg_ctlmax),
 157                .mode           = 0644,
 158                .proc_handler   = proc_ipc_dointvec_minmax,
 159                .extra1         = SYSCTL_ZERO,
 160                .extra2         = SYSCTL_INT_MAX,
 161        },
 162        {
 163                .procname       = "msgmni",
 164                .data           = &init_ipc_ns.msg_ctlmni,
 165                .maxlen         = sizeof(init_ipc_ns.msg_ctlmni),
 166                .mode           = 0644,
 167                .proc_handler   = proc_ipc_dointvec_minmax,
 168                .extra1         = SYSCTL_ZERO,
 169                .extra2         = &ipc_mni,
 170        },
 171        {
 172                .procname       = "auto_msgmni",
 173                .data           = NULL,
 174                .maxlen         = sizeof(int),
 175                .mode           = 0644,
 176                .proc_handler   = proc_ipc_auto_msgmni,
 177                .extra1         = SYSCTL_ZERO,
 178                .extra2         = SYSCTL_ONE,
 179        },
 180        {
 181                .procname       =  "msgmnb",
 182                .data           = &init_ipc_ns.msg_ctlmnb,
 183                .maxlen         = sizeof(init_ipc_ns.msg_ctlmnb),
 184                .mode           = 0644,
 185                .proc_handler   = proc_ipc_dointvec_minmax,
 186                .extra1         = SYSCTL_ZERO,
 187                .extra2         = SYSCTL_INT_MAX,
 188        },
 189        {
 190                .procname       = "sem",
 191                .data           = &init_ipc_ns.sem_ctls,
 192                .maxlen         = 4*sizeof(int),
 193                .mode           = 0644,
 194                .proc_handler   = proc_ipc_sem_dointvec,
 195        },
 196#ifdef CONFIG_CHECKPOINT_RESTORE
 197        {
 198                .procname       = "sem_next_id",
 199                .data           = &init_ipc_ns.ids[IPC_SEM_IDS].next_id,
 200                .maxlen         = sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id),
 201                .mode           = 0644,
 202                .proc_handler   = proc_ipc_dointvec_minmax,
 203                .extra1         = SYSCTL_ZERO,
 204                .extra2         = SYSCTL_INT_MAX,
 205        },
 206        {
 207                .procname       = "msg_next_id",
 208                .data           = &init_ipc_ns.ids[IPC_MSG_IDS].next_id,
 209                .maxlen         = sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id),
 210                .mode           = 0644,
 211                .proc_handler   = proc_ipc_dointvec_minmax,
 212                .extra1         = SYSCTL_ZERO,
 213                .extra2         = SYSCTL_INT_MAX,
 214        },
 215        {
 216                .procname       = "shm_next_id",
 217                .data           = &init_ipc_ns.ids[IPC_SHM_IDS].next_id,
 218                .maxlen         = sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id),
 219                .mode           = 0644,
 220                .proc_handler   = proc_ipc_dointvec_minmax,
 221                .extra1         = SYSCTL_ZERO,
 222                .extra2         = SYSCTL_INT_MAX,
 223        },
 224#endif
 225        {}
 226};
 227
 228static struct ctl_table ipc_root_table[] = {
 229        {
 230                .procname       = "kernel",
 231                .mode           = 0555,
 232                .child          = ipc_kern_table,
 233        },
 234        {}
 235};
 236
 237static int __init ipc_sysctl_init(void)
 238{
 239        register_sysctl_table(ipc_root_table);
 240        return 0;
 241}
 242
 243device_initcall(ipc_sysctl_init);
 244
 245static int __init ipc_mni_extend(char *str)
 246{
 247        ipc_mni = IPCMNI_EXTEND;
 248        ipc_mni_shift = IPCMNI_EXTEND_SHIFT;
 249        ipc_min_cycle = IPCMNI_EXTEND_MIN_CYCLE;
 250        pr_info("IPCMNI extended to %d.\n", ipc_mni);
 251        return 0;
 252}
 253early_param("ipcmni_extend", ipc_mni_extend);
 254