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