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/capability.h> 14 #include <linux/ipc_namespace.h> 15 #include <linux/msg.h> 16 #include <linux/slab.h> 17 #include "util.h" 18 19 static int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write, 20 void *buffer, size_t *lenp, loff_t *ppos) 21 { 22 struct ipc_namespace *ns = 23 container_of(table->data, struct ipc_namespace, shm_rmid_forced); 24 int err; 25 26 err = proc_dointvec_minmax(table, write, buffer, lenp, ppos); 27 28 if (err < 0) 29 return err; 30 if (ns->shm_rmid_forced) 31 shm_destroy_orphaned(ns); 32 return err; 33 } 34 35 static int proc_ipc_auto_msgmni(struct ctl_table *table, int write, 36 void *buffer, size_t *lenp, loff_t *ppos) 37 { 38 struct ctl_table ipc_table; 39 int dummy = 0; 40 41 memcpy(&ipc_table, table, sizeof(ipc_table)); 42 ipc_table.data = &dummy; 43 44 if (write) 45 pr_info_once("writing to auto_msgmni has no effect"); 46 47 return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos); 48 } 49 50 static int proc_ipc_sem_dointvec(struct ctl_table *table, int write, 51 void *buffer, size_t *lenp, loff_t *ppos) 52 { 53 struct ipc_namespace *ns = 54 container_of(table->data, struct ipc_namespace, sem_ctls); 55 int ret, semmni; 56 57 semmni = ns->sem_ctls[3]; 58 ret = proc_dointvec(table, write, buffer, lenp, ppos); 59 60 if (!ret) 61 ret = sem_check_semmni(ns); 62 63 /* 64 * Reset the semmni value if an error happens. 65 */ 66 if (ret) 67 ns->sem_ctls[3] = semmni; 68 return ret; 69 } 70 71 int ipc_mni = IPCMNI; 72 int ipc_mni_shift = IPCMNI_SHIFT; 73 int ipc_min_cycle = RADIX_TREE_MAP_SIZE; 74 75 static struct ctl_table ipc_sysctls[] = { 76 { 77 .procname = "shmmax", 78 .data = &init_ipc_ns.shm_ctlmax, 79 .maxlen = sizeof(init_ipc_ns.shm_ctlmax), 80 .mode = 0644, 81 .proc_handler = proc_doulongvec_minmax, 82 }, 83 { 84 .procname = "shmall", 85 .data = &init_ipc_ns.shm_ctlall, 86 .maxlen = sizeof(init_ipc_ns.shm_ctlall), 87 .mode = 0644, 88 .proc_handler = proc_doulongvec_minmax, 89 }, 90 { 91 .procname = "shmmni", 92 .data = &init_ipc_ns.shm_ctlmni, 93 .maxlen = sizeof(init_ipc_ns.shm_ctlmni), 94 .mode = 0644, 95 .proc_handler = proc_dointvec_minmax, 96 .extra1 = SYSCTL_ZERO, 97 .extra2 = &ipc_mni, 98 }, 99 { 100 .procname = "shm_rmid_forced", 101 .data = &init_ipc_ns.shm_rmid_forced, 102 .maxlen = sizeof(init_ipc_ns.shm_rmid_forced), 103 .mode = 0644, 104 .proc_handler = proc_ipc_dointvec_minmax_orphans, 105 .extra1 = SYSCTL_ZERO, 106 .extra2 = SYSCTL_ONE, 107 }, 108 { 109 .procname = "msgmax", 110 .data = &init_ipc_ns.msg_ctlmax, 111 .maxlen = sizeof(init_ipc_ns.msg_ctlmax), 112 .mode = 0644, 113 .proc_handler = proc_dointvec_minmax, 114 .extra1 = SYSCTL_ZERO, 115 .extra2 = SYSCTL_INT_MAX, 116 }, 117 { 118 .procname = "msgmni", 119 .data = &init_ipc_ns.msg_ctlmni, 120 .maxlen = sizeof(init_ipc_ns.msg_ctlmni), 121 .mode = 0644, 122 .proc_handler = proc_dointvec_minmax, 123 .extra1 = SYSCTL_ZERO, 124 .extra2 = &ipc_mni, 125 }, 126 { 127 .procname = "auto_msgmni", 128 .data = NULL, 129 .maxlen = sizeof(int), 130 .mode = 0644, 131 .proc_handler = proc_ipc_auto_msgmni, 132 .extra1 = SYSCTL_ZERO, 133 .extra2 = SYSCTL_ONE, 134 }, 135 { 136 .procname = "msgmnb", 137 .data = &init_ipc_ns.msg_ctlmnb, 138 .maxlen = sizeof(init_ipc_ns.msg_ctlmnb), 139 .mode = 0644, 140 .proc_handler = proc_dointvec_minmax, 141 .extra1 = SYSCTL_ZERO, 142 .extra2 = SYSCTL_INT_MAX, 143 }, 144 { 145 .procname = "sem", 146 .data = &init_ipc_ns.sem_ctls, 147 .maxlen = 4*sizeof(int), 148 .mode = 0644, 149 .proc_handler = proc_ipc_sem_dointvec, 150 }, 151 #ifdef CONFIG_CHECKPOINT_RESTORE 152 { 153 .procname = "sem_next_id", 154 .data = &init_ipc_ns.ids[IPC_SEM_IDS].next_id, 155 .maxlen = sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id), 156 .mode = 0444, 157 .proc_handler = proc_dointvec_minmax, 158 .extra1 = SYSCTL_ZERO, 159 .extra2 = SYSCTL_INT_MAX, 160 }, 161 { 162 .procname = "msg_next_id", 163 .data = &init_ipc_ns.ids[IPC_MSG_IDS].next_id, 164 .maxlen = sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id), 165 .mode = 0444, 166 .proc_handler = proc_dointvec_minmax, 167 .extra1 = SYSCTL_ZERO, 168 .extra2 = SYSCTL_INT_MAX, 169 }, 170 { 171 .procname = "shm_next_id", 172 .data = &init_ipc_ns.ids[IPC_SHM_IDS].next_id, 173 .maxlen = sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id), 174 .mode = 0444, 175 .proc_handler = proc_dointvec_minmax, 176 .extra1 = SYSCTL_ZERO, 177 .extra2 = SYSCTL_INT_MAX, 178 }, 179 #endif 180 {} 181 }; 182 183 static struct ctl_table_set *set_lookup(struct ctl_table_root *root) 184 { 185 return ¤t->nsproxy->ipc_ns->ipc_set; 186 } 187 188 static int set_is_seen(struct ctl_table_set *set) 189 { 190 return ¤t->nsproxy->ipc_ns->ipc_set == set; 191 } 192 193 static int ipc_permissions(struct ctl_table_header *head, struct ctl_table *table) 194 { 195 int mode = table->mode; 196 197 #ifdef CONFIG_CHECKPOINT_RESTORE 198 struct ipc_namespace *ns = current->nsproxy->ipc_ns; 199 200 if (((table->data == &ns->ids[IPC_SEM_IDS].next_id) || 201 (table->data == &ns->ids[IPC_MSG_IDS].next_id) || 202 (table->data == &ns->ids[IPC_SHM_IDS].next_id)) && 203 checkpoint_restore_ns_capable(ns->user_ns)) 204 mode = 0666; 205 #endif 206 return mode; 207 } 208 209 static struct ctl_table_root set_root = { 210 .lookup = set_lookup, 211 .permissions = ipc_permissions, 212 }; 213 214 bool setup_ipc_sysctls(struct ipc_namespace *ns) 215 { 216 struct ctl_table *tbl; 217 218 setup_sysctl_set(&ns->ipc_set, &set_root, set_is_seen); 219 220 tbl = kmemdup(ipc_sysctls, sizeof(ipc_sysctls), GFP_KERNEL); 221 if (tbl) { 222 int i; 223 224 for (i = 0; i < ARRAY_SIZE(ipc_sysctls); i++) { 225 if (tbl[i].data == &init_ipc_ns.shm_ctlmax) 226 tbl[i].data = &ns->shm_ctlmax; 227 228 else if (tbl[i].data == &init_ipc_ns.shm_ctlall) 229 tbl[i].data = &ns->shm_ctlall; 230 231 else if (tbl[i].data == &init_ipc_ns.shm_ctlmni) 232 tbl[i].data = &ns->shm_ctlmni; 233 234 else if (tbl[i].data == &init_ipc_ns.shm_rmid_forced) 235 tbl[i].data = &ns->shm_rmid_forced; 236 237 else if (tbl[i].data == &init_ipc_ns.msg_ctlmax) 238 tbl[i].data = &ns->msg_ctlmax; 239 240 else if (tbl[i].data == &init_ipc_ns.msg_ctlmni) 241 tbl[i].data = &ns->msg_ctlmni; 242 243 else if (tbl[i].data == &init_ipc_ns.msg_ctlmnb) 244 tbl[i].data = &ns->msg_ctlmnb; 245 246 else if (tbl[i].data == &init_ipc_ns.sem_ctls) 247 tbl[i].data = &ns->sem_ctls; 248 #ifdef CONFIG_CHECKPOINT_RESTORE 249 else if (tbl[i].data == &init_ipc_ns.ids[IPC_SEM_IDS].next_id) 250 tbl[i].data = &ns->ids[IPC_SEM_IDS].next_id; 251 252 else if (tbl[i].data == &init_ipc_ns.ids[IPC_MSG_IDS].next_id) 253 tbl[i].data = &ns->ids[IPC_MSG_IDS].next_id; 254 255 else if (tbl[i].data == &init_ipc_ns.ids[IPC_SHM_IDS].next_id) 256 tbl[i].data = &ns->ids[IPC_SHM_IDS].next_id; 257 #endif 258 else 259 tbl[i].data = NULL; 260 } 261 262 ns->ipc_sysctls = __register_sysctl_table(&ns->ipc_set, 263 "kernel", tbl, 264 ARRAY_SIZE(ipc_sysctls)); 265 } 266 if (!ns->ipc_sysctls) { 267 kfree(tbl); 268 retire_sysctl_set(&ns->ipc_set); 269 return false; 270 } 271 272 return true; 273 } 274 275 void retire_ipc_sysctls(struct ipc_namespace *ns) 276 { 277 struct ctl_table *tbl; 278 279 tbl = ns->ipc_sysctls->ctl_table_arg; 280 unregister_sysctl_table(ns->ipc_sysctls); 281 retire_sysctl_set(&ns->ipc_set); 282 kfree(tbl); 283 } 284 285 static int __init ipc_sysctl_init(void) 286 { 287 if (!setup_ipc_sysctls(&init_ipc_ns)) { 288 pr_warn("ipc sysctl registration failed\n"); 289 return -ENOMEM; 290 } 291 return 0; 292 } 293 294 device_initcall(ipc_sysctl_init); 295 296 static int __init ipc_mni_extend(char *str) 297 { 298 ipc_mni = IPCMNI_EXTEND; 299 ipc_mni_shift = IPCMNI_EXTEND_SHIFT; 300 ipc_min_cycle = IPCMNI_EXTEND_MIN_CYCLE; 301 pr_info("IPCMNI extended to %d.\n", ipc_mni); 302 return 0; 303 } 304 early_param("ipcmni_extend", ipc_mni_extend); 305