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