1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2a5494dcdSEric W. Biederman /* 3a5494dcdSEric W. Biederman * Copyright (C) 2007 4a5494dcdSEric W. Biederman * 5a5494dcdSEric W. Biederman * Author: Eric Biederman <ebiederm@xmision.com> 6a5494dcdSEric W. Biederman */ 7a5494dcdSEric W. Biederman 8a5494dcdSEric W. Biederman #include <linux/module.h> 9a5494dcdSEric W. Biederman #include <linux/ipc.h> 10a5494dcdSEric W. Biederman #include <linux/nsproxy.h> 11a5494dcdSEric W. Biederman #include <linux/sysctl.h> 12a5494dcdSEric W. Biederman #include <linux/uaccess.h> 135563cabdSMichal Clapinski #include <linux/capability.h> 14ae5e1b22SPavel Emelyanov #include <linux/ipc_namespace.h> 156546bc42SNadia Derbey #include <linux/msg.h> 161f5c135eSAlexey Gladkov #include <linux/slab.h> 176546bc42SNadia Derbey #include "util.h" 18a5494dcdSEric W. Biederman 19a5c5928bSJoe Perches static int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write, 2032927393SChristoph Hellwig void *buffer, size_t *lenp, loff_t *ppos) 21b34a6b1dSVasiliy Kulikov { 22*dd141a49SAlexey Gladkov struct ipc_namespace *ns = 23*dd141a49SAlexey Gladkov container_of(table->data, struct ipc_namespace, shm_rmid_forced); 241f5c135eSAlexey Gladkov int err; 251f5c135eSAlexey Gladkov 26*dd141a49SAlexey Gladkov err = proc_dointvec_minmax(table, write, buffer, lenp, ppos); 27b34a6b1dSVasiliy Kulikov 28b34a6b1dSVasiliy Kulikov if (err < 0) 29b34a6b1dSVasiliy Kulikov return err; 30b34a6b1dSVasiliy Kulikov if (ns->shm_rmid_forced) 31b34a6b1dSVasiliy Kulikov shm_destroy_orphaned(ns); 32b34a6b1dSVasiliy Kulikov return err; 33b34a6b1dSVasiliy Kulikov } 34b34a6b1dSVasiliy Kulikov 350050ee05SManfred Spraul static int proc_ipc_auto_msgmni(struct ctl_table *table, int write, 3632927393SChristoph Hellwig void *buffer, size_t *lenp, loff_t *ppos) 379eefe520SNadia Derbey { 389eefe520SNadia Derbey struct ctl_table ipc_table; 390050ee05SManfred Spraul int dummy = 0; 409eefe520SNadia Derbey 419eefe520SNadia Derbey memcpy(&ipc_table, table, sizeof(ipc_table)); 420050ee05SManfred Spraul ipc_table.data = &dummy; 439eefe520SNadia Derbey 440050ee05SManfred Spraul if (write) 450050ee05SManfred Spraul pr_info_once("writing to auto_msgmni has no effect"); 469eefe520SNadia Derbey 470050ee05SManfred Spraul return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos); 489eefe520SNadia Derbey } 499eefe520SNadia Derbey 508c81ddd2SWaiman Long static int proc_ipc_sem_dointvec(struct ctl_table *table, int write, 51fff1662cSTobias Klauser void *buffer, size_t *lenp, loff_t *ppos) 528c81ddd2SWaiman Long { 53*dd141a49SAlexey Gladkov struct ipc_namespace *ns = 54*dd141a49SAlexey Gladkov container_of(table->data, struct ipc_namespace, sem_ctls); 558c81ddd2SWaiman Long int ret, semmni; 561f5c135eSAlexey Gladkov 578c81ddd2SWaiman Long semmni = ns->sem_ctls[3]; 581f5c135eSAlexey Gladkov ret = proc_dointvec(table, write, buffer, lenp, ppos); 598c81ddd2SWaiman Long 608c81ddd2SWaiman Long if (!ret) 61def7343fSAlexey Gladkov ret = sem_check_semmni(ns); 628c81ddd2SWaiman Long 638c81ddd2SWaiman Long /* 648c81ddd2SWaiman Long * Reset the semmni value if an error happens. 658c81ddd2SWaiman Long */ 668c81ddd2SWaiman Long if (ret) 678c81ddd2SWaiman Long ns->sem_ctls[3] = semmni; 688c81ddd2SWaiman Long return ret; 698c81ddd2SWaiman Long } 708c81ddd2SWaiman Long 715563cabdSMichal Clapinski #ifdef CONFIG_CHECKPOINT_RESTORE 725563cabdSMichal Clapinski static int proc_ipc_dointvec_minmax_checkpoint_restore(struct ctl_table *table, 735563cabdSMichal Clapinski int write, void *buffer, size_t *lenp, loff_t *ppos) 745563cabdSMichal Clapinski { 751f5c135eSAlexey Gladkov struct ipc_namespace *ns = table->extra1; 761f5c135eSAlexey Gladkov struct ctl_table ipc_table; 775563cabdSMichal Clapinski 781f5c135eSAlexey Gladkov if (write && !checkpoint_restore_ns_capable(ns->user_ns)) 795563cabdSMichal Clapinski return -EPERM; 805563cabdSMichal Clapinski 811f5c135eSAlexey Gladkov memcpy(&ipc_table, table, sizeof(ipc_table)); 821f5c135eSAlexey Gladkov 831f5c135eSAlexey Gladkov ipc_table.extra1 = SYSCTL_ZERO; 841f5c135eSAlexey Gladkov ipc_table.extra2 = SYSCTL_INT_MAX; 851f5c135eSAlexey Gladkov 861f5c135eSAlexey Gladkov return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos); 875563cabdSMichal Clapinski } 885563cabdSMichal Clapinski #endif 895563cabdSMichal Clapinski 905ac893b8SWaiman Long int ipc_mni = IPCMNI; 915ac893b8SWaiman Long int ipc_mni_shift = IPCMNI_SHIFT; 9299db46eaSManfred Spraul int ipc_min_cycle = RADIX_TREE_MAP_SIZE; 939eefe520SNadia Derbey 941f5c135eSAlexey Gladkov static struct ctl_table ipc_sysctls[] = { 95a5494dcdSEric W. Biederman { 96a5494dcdSEric W. Biederman .procname = "shmmax", 97a5494dcdSEric W. Biederman .data = &init_ipc_ns.shm_ctlmax, 98a5494dcdSEric W. Biederman .maxlen = sizeof(init_ipc_ns.shm_ctlmax), 99a5494dcdSEric W. Biederman .mode = 0644, 1001f5c135eSAlexey Gladkov .proc_handler = proc_doulongvec_minmax, 101a5494dcdSEric W. Biederman }, 102a5494dcdSEric W. Biederman { 103a5494dcdSEric W. Biederman .procname = "shmall", 104a5494dcdSEric W. Biederman .data = &init_ipc_ns.shm_ctlall, 105a5494dcdSEric W. Biederman .maxlen = sizeof(init_ipc_ns.shm_ctlall), 106a5494dcdSEric W. Biederman .mode = 0644, 1071f5c135eSAlexey Gladkov .proc_handler = proc_doulongvec_minmax, 108a5494dcdSEric W. Biederman }, 109a5494dcdSEric W. Biederman { 110a5494dcdSEric W. Biederman .procname = "shmmni", 111a5494dcdSEric W. Biederman .data = &init_ipc_ns.shm_ctlmni, 112a5494dcdSEric W. Biederman .maxlen = sizeof(init_ipc_ns.shm_ctlmni), 113a5494dcdSEric W. Biederman .mode = 0644, 1141f5c135eSAlexey Gladkov .proc_handler = proc_dointvec_minmax, 115eec4844fSMatteo Croce .extra1 = SYSCTL_ZERO, 1166730e658SWaiman Long .extra2 = &ipc_mni, 117a5494dcdSEric W. Biederman }, 118a5494dcdSEric W. Biederman { 119b34a6b1dSVasiliy Kulikov .procname = "shm_rmid_forced", 120b34a6b1dSVasiliy Kulikov .data = &init_ipc_ns.shm_rmid_forced, 121b34a6b1dSVasiliy Kulikov .maxlen = sizeof(init_ipc_ns.shm_rmid_forced), 122b34a6b1dSVasiliy Kulikov .mode = 0644, 123b34a6b1dSVasiliy Kulikov .proc_handler = proc_ipc_dointvec_minmax_orphans, 124*dd141a49SAlexey Gladkov .extra1 = SYSCTL_ZERO, 125*dd141a49SAlexey Gladkov .extra2 = SYSCTL_ONE, 126b34a6b1dSVasiliy Kulikov }, 127b34a6b1dSVasiliy Kulikov { 128a5494dcdSEric W. Biederman .procname = "msgmax", 129a5494dcdSEric W. Biederman .data = &init_ipc_ns.msg_ctlmax, 130a5494dcdSEric W. Biederman .maxlen = sizeof(init_ipc_ns.msg_ctlmax), 131a5494dcdSEric W. Biederman .mode = 0644, 1321f5c135eSAlexey Gladkov .proc_handler = proc_dointvec_minmax, 133eec4844fSMatteo Croce .extra1 = SYSCTL_ZERO, 134eec4844fSMatteo Croce .extra2 = SYSCTL_INT_MAX, 135a5494dcdSEric W. Biederman }, 136a5494dcdSEric W. Biederman { 137a5494dcdSEric W. Biederman .procname = "msgmni", 138a5494dcdSEric W. Biederman .data = &init_ipc_ns.msg_ctlmni, 139a5494dcdSEric W. Biederman .maxlen = sizeof(init_ipc_ns.msg_ctlmni), 140a5494dcdSEric W. Biederman .mode = 0644, 1411f5c135eSAlexey Gladkov .proc_handler = proc_dointvec_minmax, 142eec4844fSMatteo Croce .extra1 = SYSCTL_ZERO, 1436730e658SWaiman Long .extra2 = &ipc_mni, 144a5494dcdSEric W. Biederman }, 145a5494dcdSEric W. Biederman { 1460050ee05SManfred Spraul .procname = "auto_msgmni", 1470050ee05SManfred Spraul .data = NULL, 1480050ee05SManfred Spraul .maxlen = sizeof(int), 1490050ee05SManfred Spraul .mode = 0644, 1500050ee05SManfred Spraul .proc_handler = proc_ipc_auto_msgmni, 151eec4844fSMatteo Croce .extra1 = SYSCTL_ZERO, 152eec4844fSMatteo Croce .extra2 = SYSCTL_ONE, 1530050ee05SManfred Spraul }, 1540050ee05SManfred Spraul { 155a5494dcdSEric W. Biederman .procname = "msgmnb", 156a5494dcdSEric W. Biederman .data = &init_ipc_ns.msg_ctlmnb, 157a5494dcdSEric W. Biederman .maxlen = sizeof(init_ipc_ns.msg_ctlmnb), 158a5494dcdSEric W. Biederman .mode = 0644, 1591f5c135eSAlexey Gladkov .proc_handler = proc_dointvec_minmax, 160eec4844fSMatteo Croce .extra1 = SYSCTL_ZERO, 161eec4844fSMatteo Croce .extra2 = SYSCTL_INT_MAX, 162a5494dcdSEric W. Biederman }, 163a5494dcdSEric W. Biederman { 164a5494dcdSEric W. Biederman .procname = "sem", 165a5494dcdSEric W. Biederman .data = &init_ipc_ns.sem_ctls, 166a5494dcdSEric W. Biederman .maxlen = 4*sizeof(int), 167a5494dcdSEric W. Biederman .mode = 0644, 1688c81ddd2SWaiman Long .proc_handler = proc_ipc_sem_dointvec, 169a5494dcdSEric W. Biederman }, 17003f59566SStanislav Kinsbursky #ifdef CONFIG_CHECKPOINT_RESTORE 17103f59566SStanislav Kinsbursky { 17203f59566SStanislav Kinsbursky .procname = "sem_next_id", 17303f59566SStanislav Kinsbursky .data = &init_ipc_ns.ids[IPC_SEM_IDS].next_id, 17403f59566SStanislav Kinsbursky .maxlen = sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id), 1755563cabdSMichal Clapinski .mode = 0666, 1765563cabdSMichal Clapinski .proc_handler = proc_ipc_dointvec_minmax_checkpoint_restore, 17703f59566SStanislav Kinsbursky }, 17803f59566SStanislav Kinsbursky { 17903f59566SStanislav Kinsbursky .procname = "msg_next_id", 18003f59566SStanislav Kinsbursky .data = &init_ipc_ns.ids[IPC_MSG_IDS].next_id, 18103f59566SStanislav Kinsbursky .maxlen = sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id), 1825563cabdSMichal Clapinski .mode = 0666, 1835563cabdSMichal Clapinski .proc_handler = proc_ipc_dointvec_minmax_checkpoint_restore, 18403f59566SStanislav Kinsbursky }, 18503f59566SStanislav Kinsbursky { 18603f59566SStanislav Kinsbursky .procname = "shm_next_id", 18703f59566SStanislav Kinsbursky .data = &init_ipc_ns.ids[IPC_SHM_IDS].next_id, 18803f59566SStanislav Kinsbursky .maxlen = sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id), 1895563cabdSMichal Clapinski .mode = 0666, 1905563cabdSMichal Clapinski .proc_handler = proc_ipc_dointvec_minmax_checkpoint_restore, 19103f59566SStanislav Kinsbursky }, 19203f59566SStanislav Kinsbursky #endif 193a5494dcdSEric W. Biederman {} 194a5494dcdSEric W. Biederman }; 195a5494dcdSEric W. Biederman 1961f5c135eSAlexey Gladkov static struct ctl_table_set *set_lookup(struct ctl_table_root *root) 197a5494dcdSEric W. Biederman { 1981f5c135eSAlexey Gladkov return ¤t->nsproxy->ipc_ns->ipc_set; 1991f5c135eSAlexey Gladkov } 2001f5c135eSAlexey Gladkov 2011f5c135eSAlexey Gladkov static int set_is_seen(struct ctl_table_set *set) 2021f5c135eSAlexey Gladkov { 2031f5c135eSAlexey Gladkov return ¤t->nsproxy->ipc_ns->ipc_set == set; 2041f5c135eSAlexey Gladkov } 2051f5c135eSAlexey Gladkov 2061f5c135eSAlexey Gladkov static struct ctl_table_root set_root = { 2071f5c135eSAlexey Gladkov .lookup = set_lookup, 208a5494dcdSEric W. Biederman }; 209a5494dcdSEric W. Biederman 2101f5c135eSAlexey Gladkov bool setup_ipc_sysctls(struct ipc_namespace *ns) 2111f5c135eSAlexey Gladkov { 2121f5c135eSAlexey Gladkov struct ctl_table *tbl; 2131f5c135eSAlexey Gladkov 2141f5c135eSAlexey Gladkov setup_sysctl_set(&ns->ipc_set, &set_root, set_is_seen); 2151f5c135eSAlexey Gladkov 2161f5c135eSAlexey Gladkov tbl = kmemdup(ipc_sysctls, sizeof(ipc_sysctls), GFP_KERNEL); 2171f5c135eSAlexey Gladkov if (tbl) { 2181f5c135eSAlexey Gladkov int i; 2191f5c135eSAlexey Gladkov 2201f5c135eSAlexey Gladkov for (i = 0; i < ARRAY_SIZE(ipc_sysctls); i++) { 2211f5c135eSAlexey Gladkov if (tbl[i].data == &init_ipc_ns.shm_ctlmax) { 2221f5c135eSAlexey Gladkov tbl[i].data = &ns->shm_ctlmax; 2231f5c135eSAlexey Gladkov 2241f5c135eSAlexey Gladkov } else if (tbl[i].data == &init_ipc_ns.shm_ctlall) { 2251f5c135eSAlexey Gladkov tbl[i].data = &ns->shm_ctlall; 2261f5c135eSAlexey Gladkov 2271f5c135eSAlexey Gladkov } else if (tbl[i].data == &init_ipc_ns.shm_ctlmni) { 2281f5c135eSAlexey Gladkov tbl[i].data = &ns->shm_ctlmni; 2291f5c135eSAlexey Gladkov 2301f5c135eSAlexey Gladkov } else if (tbl[i].data == &init_ipc_ns.shm_rmid_forced) { 2311f5c135eSAlexey Gladkov tbl[i].data = &ns->shm_rmid_forced; 2321f5c135eSAlexey Gladkov 2331f5c135eSAlexey Gladkov } else if (tbl[i].data == &init_ipc_ns.msg_ctlmax) { 2341f5c135eSAlexey Gladkov tbl[i].data = &ns->msg_ctlmax; 2351f5c135eSAlexey Gladkov 2361f5c135eSAlexey Gladkov } else if (tbl[i].data == &init_ipc_ns.msg_ctlmni) { 2371f5c135eSAlexey Gladkov tbl[i].data = &ns->msg_ctlmni; 2381f5c135eSAlexey Gladkov 2391f5c135eSAlexey Gladkov } else if (tbl[i].data == &init_ipc_ns.msg_ctlmnb) { 2401f5c135eSAlexey Gladkov tbl[i].data = &ns->msg_ctlmnb; 2411f5c135eSAlexey Gladkov 2421f5c135eSAlexey Gladkov } else if (tbl[i].data == &init_ipc_ns.sem_ctls) { 2431f5c135eSAlexey Gladkov tbl[i].data = &ns->sem_ctls; 2441f5c135eSAlexey Gladkov #ifdef CONFIG_CHECKPOINT_RESTORE 2451f5c135eSAlexey Gladkov } else if (tbl[i].data == &init_ipc_ns.ids[IPC_SEM_IDS].next_id) { 2461f5c135eSAlexey Gladkov tbl[i].data = &ns->ids[IPC_SEM_IDS].next_id; 2471f5c135eSAlexey Gladkov tbl[i].extra1 = ns; 2481f5c135eSAlexey Gladkov 2491f5c135eSAlexey Gladkov } else if (tbl[i].data == &init_ipc_ns.ids[IPC_MSG_IDS].next_id) { 2501f5c135eSAlexey Gladkov tbl[i].data = &ns->ids[IPC_MSG_IDS].next_id; 2511f5c135eSAlexey Gladkov tbl[i].extra1 = ns; 2521f5c135eSAlexey Gladkov 2531f5c135eSAlexey Gladkov } else if (tbl[i].data == &init_ipc_ns.ids[IPC_SHM_IDS].next_id) { 2541f5c135eSAlexey Gladkov tbl[i].data = &ns->ids[IPC_SHM_IDS].next_id; 2551f5c135eSAlexey Gladkov tbl[i].extra1 = ns; 2561f5c135eSAlexey Gladkov #endif 2571f5c135eSAlexey Gladkov } else { 2581f5c135eSAlexey Gladkov tbl[i].data = NULL; 2591f5c135eSAlexey Gladkov } 2601f5c135eSAlexey Gladkov } 2611f5c135eSAlexey Gladkov 2621f5c135eSAlexey Gladkov ns->ipc_sysctls = __register_sysctl_table(&ns->ipc_set, "kernel", tbl); 2631f5c135eSAlexey Gladkov } 2641f5c135eSAlexey Gladkov if (!ns->ipc_sysctls) { 2651f5c135eSAlexey Gladkov kfree(tbl); 2661f5c135eSAlexey Gladkov retire_sysctl_set(&ns->ipc_set); 2671f5c135eSAlexey Gladkov return false; 2681f5c135eSAlexey Gladkov } 2691f5c135eSAlexey Gladkov 2701f5c135eSAlexey Gladkov return true; 2711f5c135eSAlexey Gladkov } 2721f5c135eSAlexey Gladkov 2731f5c135eSAlexey Gladkov void retire_ipc_sysctls(struct ipc_namespace *ns) 2741f5c135eSAlexey Gladkov { 2751f5c135eSAlexey Gladkov struct ctl_table *tbl; 2761f5c135eSAlexey Gladkov 2771f5c135eSAlexey Gladkov tbl = ns->ipc_sysctls->ctl_table_arg; 2781f5c135eSAlexey Gladkov unregister_sysctl_table(ns->ipc_sysctls); 2791f5c135eSAlexey Gladkov retire_sysctl_set(&ns->ipc_set); 2801f5c135eSAlexey Gladkov kfree(tbl); 2811f5c135eSAlexey Gladkov } 2821f5c135eSAlexey Gladkov 283a5494dcdSEric W. Biederman static int __init ipc_sysctl_init(void) 284a5494dcdSEric W. Biederman { 2851f5c135eSAlexey Gladkov if (!setup_ipc_sysctls(&init_ipc_ns)) { 2861f5c135eSAlexey Gladkov pr_warn("ipc sysctl registration failed\n"); 2871f5c135eSAlexey Gladkov return -ENOMEM; 2881f5c135eSAlexey Gladkov } 289a5494dcdSEric W. Biederman return 0; 290a5494dcdSEric W. Biederman } 291a5494dcdSEric W. Biederman 2926d08a256SDavidlohr Bueso device_initcall(ipc_sysctl_init); 2935ac893b8SWaiman Long 2945ac893b8SWaiman Long static int __init ipc_mni_extend(char *str) 2955ac893b8SWaiman Long { 2965ac893b8SWaiman Long ipc_mni = IPCMNI_EXTEND; 2975ac893b8SWaiman Long ipc_mni_shift = IPCMNI_EXTEND_SHIFT; 29899db46eaSManfred Spraul ipc_min_cycle = IPCMNI_EXTEND_MIN_CYCLE; 2995ac893b8SWaiman Long pr_info("IPCMNI extended to %d.\n", ipc_mni); 3005ac893b8SWaiman Long return 0; 3015ac893b8SWaiman Long } 3025ac893b8SWaiman Long early_param("ipcmni_extend", ipc_mni_extend); 303