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