Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  Copyright (C) 2007
0004  *
0005  *  Author: Eric Biederman <ebiederm@xmision.com>
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/ipc.h>
0010 #include <linux/nsproxy.h>
0011 #include <linux/sysctl.h>
0012 #include <linux/uaccess.h>
0013 #include <linux/capability.h>
0014 #include <linux/ipc_namespace.h>
0015 #include <linux/msg.h>
0016 #include <linux/slab.h>
0017 #include "util.h"
0018 
0019 static int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write,
0020         void *buffer, size_t *lenp, loff_t *ppos)
0021 {
0022     struct ipc_namespace *ns =
0023         container_of(table->data, struct ipc_namespace, shm_rmid_forced);
0024     int err;
0025 
0026     err = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
0027 
0028     if (err < 0)
0029         return err;
0030     if (ns->shm_rmid_forced)
0031         shm_destroy_orphaned(ns);
0032     return err;
0033 }
0034 
0035 static int proc_ipc_auto_msgmni(struct ctl_table *table, int write,
0036         void *buffer, size_t *lenp, loff_t *ppos)
0037 {
0038     struct ctl_table ipc_table;
0039     int dummy = 0;
0040 
0041     memcpy(&ipc_table, table, sizeof(ipc_table));
0042     ipc_table.data = &dummy;
0043 
0044     if (write)
0045         pr_info_once("writing to auto_msgmni has no effect");
0046 
0047     return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
0048 }
0049 
0050 static int proc_ipc_sem_dointvec(struct ctl_table *table, int write,
0051     void *buffer, size_t *lenp, loff_t *ppos)
0052 {
0053     struct ipc_namespace *ns =
0054         container_of(table->data, struct ipc_namespace, sem_ctls);
0055     int ret, semmni;
0056 
0057     semmni = ns->sem_ctls[3];
0058     ret = proc_dointvec(table, write, buffer, lenp, ppos);
0059 
0060     if (!ret)
0061         ret = sem_check_semmni(ns);
0062 
0063     /*
0064      * Reset the semmni value if an error happens.
0065      */
0066     if (ret)
0067         ns->sem_ctls[3] = semmni;
0068     return ret;
0069 }
0070 
0071 int ipc_mni = IPCMNI;
0072 int ipc_mni_shift = IPCMNI_SHIFT;
0073 int ipc_min_cycle = RADIX_TREE_MAP_SIZE;
0074 
0075 static struct ctl_table ipc_sysctls[] = {
0076     {
0077         .procname   = "shmmax",
0078         .data       = &init_ipc_ns.shm_ctlmax,
0079         .maxlen     = sizeof(init_ipc_ns.shm_ctlmax),
0080         .mode       = 0644,
0081         .proc_handler   = proc_doulongvec_minmax,
0082     },
0083     {
0084         .procname   = "shmall",
0085         .data       = &init_ipc_ns.shm_ctlall,
0086         .maxlen     = sizeof(init_ipc_ns.shm_ctlall),
0087         .mode       = 0644,
0088         .proc_handler   = proc_doulongvec_minmax,
0089     },
0090     {
0091         .procname   = "shmmni",
0092         .data       = &init_ipc_ns.shm_ctlmni,
0093         .maxlen     = sizeof(init_ipc_ns.shm_ctlmni),
0094         .mode       = 0644,
0095         .proc_handler   = proc_dointvec_minmax,
0096         .extra1     = SYSCTL_ZERO,
0097         .extra2     = &ipc_mni,
0098     },
0099     {
0100         .procname   = "shm_rmid_forced",
0101         .data       = &init_ipc_ns.shm_rmid_forced,
0102         .maxlen     = sizeof(init_ipc_ns.shm_rmid_forced),
0103         .mode       = 0644,
0104         .proc_handler   = proc_ipc_dointvec_minmax_orphans,
0105         .extra1     = SYSCTL_ZERO,
0106         .extra2     = SYSCTL_ONE,
0107     },
0108     {
0109         .procname   = "msgmax",
0110         .data       = &init_ipc_ns.msg_ctlmax,
0111         .maxlen     = sizeof(init_ipc_ns.msg_ctlmax),
0112         .mode       = 0644,
0113         .proc_handler   = proc_dointvec_minmax,
0114         .extra1     = SYSCTL_ZERO,
0115         .extra2     = SYSCTL_INT_MAX,
0116     },
0117     {
0118         .procname   = "msgmni",
0119         .data       = &init_ipc_ns.msg_ctlmni,
0120         .maxlen     = sizeof(init_ipc_ns.msg_ctlmni),
0121         .mode       = 0644,
0122         .proc_handler   = proc_dointvec_minmax,
0123         .extra1     = SYSCTL_ZERO,
0124         .extra2     = &ipc_mni,
0125     },
0126     {
0127         .procname   = "auto_msgmni",
0128         .data       = NULL,
0129         .maxlen     = sizeof(int),
0130         .mode       = 0644,
0131         .proc_handler   = proc_ipc_auto_msgmni,
0132         .extra1     = SYSCTL_ZERO,
0133         .extra2     = SYSCTL_ONE,
0134     },
0135     {
0136         .procname   =  "msgmnb",
0137         .data       = &init_ipc_ns.msg_ctlmnb,
0138         .maxlen     = sizeof(init_ipc_ns.msg_ctlmnb),
0139         .mode       = 0644,
0140         .proc_handler   = proc_dointvec_minmax,
0141         .extra1     = SYSCTL_ZERO,
0142         .extra2     = SYSCTL_INT_MAX,
0143     },
0144     {
0145         .procname   = "sem",
0146         .data       = &init_ipc_ns.sem_ctls,
0147         .maxlen     = 4*sizeof(int),
0148         .mode       = 0644,
0149         .proc_handler   = proc_ipc_sem_dointvec,
0150     },
0151 #ifdef CONFIG_CHECKPOINT_RESTORE
0152     {
0153         .procname   = "sem_next_id",
0154         .data       = &init_ipc_ns.ids[IPC_SEM_IDS].next_id,
0155         .maxlen     = sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id),
0156         .mode       = 0444,
0157         .proc_handler   = proc_dointvec_minmax,
0158         .extra1     = SYSCTL_ZERO,
0159         .extra2     = SYSCTL_INT_MAX,
0160     },
0161     {
0162         .procname   = "msg_next_id",
0163         .data       = &init_ipc_ns.ids[IPC_MSG_IDS].next_id,
0164         .maxlen     = sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id),
0165         .mode       = 0444,
0166         .proc_handler   = proc_dointvec_minmax,
0167         .extra1     = SYSCTL_ZERO,
0168         .extra2     = SYSCTL_INT_MAX,
0169     },
0170     {
0171         .procname   = "shm_next_id",
0172         .data       = &init_ipc_ns.ids[IPC_SHM_IDS].next_id,
0173         .maxlen     = sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id),
0174         .mode       = 0444,
0175         .proc_handler   = proc_dointvec_minmax,
0176         .extra1     = SYSCTL_ZERO,
0177         .extra2     = SYSCTL_INT_MAX,
0178     },
0179 #endif
0180     {}
0181 };
0182 
0183 static struct ctl_table_set *set_lookup(struct ctl_table_root *root)
0184 {
0185     return &current->nsproxy->ipc_ns->ipc_set;
0186 }
0187 
0188 static int set_is_seen(struct ctl_table_set *set)
0189 {
0190     return &current->nsproxy->ipc_ns->ipc_set == set;
0191 }
0192 
0193 static int ipc_permissions(struct ctl_table_header *head, struct ctl_table *table)
0194 {
0195     int mode = table->mode;
0196 
0197 #ifdef CONFIG_CHECKPOINT_RESTORE
0198     struct ipc_namespace *ns = current->nsproxy->ipc_ns;
0199 
0200     if (((table->data == &ns->ids[IPC_SEM_IDS].next_id) ||
0201          (table->data == &ns->ids[IPC_MSG_IDS].next_id) ||
0202          (table->data == &ns->ids[IPC_SHM_IDS].next_id)) &&
0203         checkpoint_restore_ns_capable(ns->user_ns))
0204         mode = 0666;
0205 #endif
0206     return mode;
0207 }
0208 
0209 static struct ctl_table_root set_root = {
0210     .lookup = set_lookup,
0211     .permissions = ipc_permissions,
0212 };
0213 
0214 bool setup_ipc_sysctls(struct ipc_namespace *ns)
0215 {
0216     struct ctl_table *tbl;
0217 
0218     setup_sysctl_set(&ns->ipc_set, &set_root, set_is_seen);
0219 
0220     tbl = kmemdup(ipc_sysctls, sizeof(ipc_sysctls), GFP_KERNEL);
0221     if (tbl) {
0222         int i;
0223 
0224         for (i = 0; i < ARRAY_SIZE(ipc_sysctls); i++) {
0225             if (tbl[i].data == &init_ipc_ns.shm_ctlmax)
0226                 tbl[i].data = &ns->shm_ctlmax;
0227 
0228             else if (tbl[i].data == &init_ipc_ns.shm_ctlall)
0229                 tbl[i].data = &ns->shm_ctlall;
0230 
0231             else if (tbl[i].data == &init_ipc_ns.shm_ctlmni)
0232                 tbl[i].data = &ns->shm_ctlmni;
0233 
0234             else if (tbl[i].data == &init_ipc_ns.shm_rmid_forced)
0235                 tbl[i].data = &ns->shm_rmid_forced;
0236 
0237             else if (tbl[i].data == &init_ipc_ns.msg_ctlmax)
0238                 tbl[i].data = &ns->msg_ctlmax;
0239 
0240             else if (tbl[i].data == &init_ipc_ns.msg_ctlmni)
0241                 tbl[i].data = &ns->msg_ctlmni;
0242 
0243             else if (tbl[i].data == &init_ipc_ns.msg_ctlmnb)
0244                 tbl[i].data = &ns->msg_ctlmnb;
0245 
0246             else if (tbl[i].data == &init_ipc_ns.sem_ctls)
0247                 tbl[i].data = &ns->sem_ctls;
0248 #ifdef CONFIG_CHECKPOINT_RESTORE
0249             else if (tbl[i].data == &init_ipc_ns.ids[IPC_SEM_IDS].next_id)
0250                 tbl[i].data = &ns->ids[IPC_SEM_IDS].next_id;
0251 
0252             else if (tbl[i].data == &init_ipc_ns.ids[IPC_MSG_IDS].next_id)
0253                 tbl[i].data = &ns->ids[IPC_MSG_IDS].next_id;
0254 
0255             else if (tbl[i].data == &init_ipc_ns.ids[IPC_SHM_IDS].next_id)
0256                 tbl[i].data = &ns->ids[IPC_SHM_IDS].next_id;
0257 #endif
0258             else
0259                 tbl[i].data = NULL;
0260         }
0261 
0262         ns->ipc_sysctls = __register_sysctl_table(&ns->ipc_set, "kernel", tbl);
0263     }
0264     if (!ns->ipc_sysctls) {
0265         kfree(tbl);
0266         retire_sysctl_set(&ns->ipc_set);
0267         return false;
0268     }
0269 
0270     return true;
0271 }
0272 
0273 void retire_ipc_sysctls(struct ipc_namespace *ns)
0274 {
0275     struct ctl_table *tbl;
0276 
0277     tbl = ns->ipc_sysctls->ctl_table_arg;
0278     unregister_sysctl_table(ns->ipc_sysctls);
0279     retire_sysctl_set(&ns->ipc_set);
0280     kfree(tbl);
0281 }
0282 
0283 static int __init ipc_sysctl_init(void)
0284 {
0285     if (!setup_ipc_sysctls(&init_ipc_ns)) {
0286         pr_warn("ipc sysctl registration failed\n");
0287         return -ENOMEM;
0288     }
0289     return 0;
0290 }
0291 
0292 device_initcall(ipc_sysctl_init);
0293 
0294 static int __init ipc_mni_extend(char *str)
0295 {
0296     ipc_mni = IPCMNI_EXTEND;
0297     ipc_mni_shift = IPCMNI_EXTEND_SHIFT;
0298     ipc_min_cycle = IPCMNI_EXTEND_MIN_CYCLE;
0299     pr_info("IPCMNI extended to %d.\n", ipc_mni);
0300     return 0;
0301 }
0302 early_param("ipcmni_extend", ipc_mni_extend);