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 17 static 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 26 static 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 37 static 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 48 static 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 61 static 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 72 static 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 87 static 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 116 int ipc_mni = IPCMNI; 117 int ipc_mni_shift = IPCMNI_SHIFT; 118 int ipc_min_cycle = RADIX_TREE_MAP_SIZE; 119 120 static 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 228 static struct ctl_table ipc_root_table[] = { 229 { 230 .procname = "kernel", 231 .mode = 0555, 232 .child = ipc_kern_table, 233 }, 234 {} 235 }; 236 237 static int __init ipc_sysctl_init(void) 238 { 239 register_sysctl_table(ipc_root_table); 240 return 0; 241 } 242 243 device_initcall(ipc_sysctl_init); 244 245 static 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 } 253 early_param("ipcmni_extend", ipc_mni_extend); 254