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(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(ctl_table *table, int write, 31 void __user *buffer, size_t *lenp, loff_t *ppos) 32 { 33 struct ctl_table ipc_table; 34 memcpy(&ipc_table, table, sizeof(ipc_table)); 35 ipc_table.data = get_ipc(table); 36 37 return proc_dointvec(&ipc_table, write, buffer, lenp, ppos); 38 } 39 40 static int proc_ipc_callback_dointvec(ctl_table *table, int write, 41 void __user *buffer, size_t *lenp, loff_t *ppos) 42 { 43 struct ctl_table ipc_table; 44 size_t lenp_bef = *lenp; 45 int rc; 46 47 memcpy(&ipc_table, table, sizeof(ipc_table)); 48 ipc_table.data = get_ipc(table); 49 50 rc = proc_dointvec(&ipc_table, write, buffer, lenp, ppos); 51 52 if (write && !rc && lenp_bef == *lenp) 53 /* 54 * Tunable has successfully been changed by hand. Disable its 55 * automatic adjustment. This simply requires unregistering 56 * the notifiers that trigger recalculation. 57 */ 58 unregister_ipcns_notifier(current->nsproxy->ipc_ns); 59 60 return rc; 61 } 62 63 static int proc_ipc_doulongvec_minmax(ctl_table *table, int write, 64 void __user *buffer, size_t *lenp, loff_t *ppos) 65 { 66 struct ctl_table ipc_table; 67 memcpy(&ipc_table, table, sizeof(ipc_table)); 68 ipc_table.data = get_ipc(table); 69 70 return proc_doulongvec_minmax(&ipc_table, write, buffer, 71 lenp, ppos); 72 } 73 74 /* 75 * Routine that is called when the file "auto_msgmni" has successfully been 76 * written. 77 * Two values are allowed: 78 * 0: unregister msgmni's callback routine from the ipc namespace notifier 79 * chain. This means that msgmni won't be recomputed anymore upon memory 80 * add/remove or ipc namespace creation/removal. 81 * 1: register back the callback routine. 82 */ 83 static void ipc_auto_callback(int val) 84 { 85 if (!val) 86 unregister_ipcns_notifier(current->nsproxy->ipc_ns); 87 else { 88 /* 89 * Re-enable automatic recomputing only if not already 90 * enabled. 91 */ 92 recompute_msgmni(current->nsproxy->ipc_ns); 93 cond_register_ipcns_notifier(current->nsproxy->ipc_ns); 94 } 95 } 96 97 static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write, 98 void __user *buffer, size_t *lenp, loff_t *ppos) 99 { 100 struct ctl_table ipc_table; 101 size_t lenp_bef = *lenp; 102 int oldval; 103 int rc; 104 105 memcpy(&ipc_table, table, sizeof(ipc_table)); 106 ipc_table.data = get_ipc(table); 107 oldval = *((int *)(ipc_table.data)); 108 109 rc = proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos); 110 111 if (write && !rc && lenp_bef == *lenp) { 112 int newval = *((int *)(ipc_table.data)); 113 /* 114 * The file "auto_msgmni" has correctly been set. 115 * React by (un)registering the corresponding tunable, if the 116 * value has changed. 117 */ 118 if (newval != oldval) 119 ipc_auto_callback(newval); 120 } 121 122 return rc; 123 } 124 125 #else 126 #define proc_ipc_doulongvec_minmax NULL 127 #define proc_ipc_dointvec NULL 128 #define proc_ipc_callback_dointvec NULL 129 #define proc_ipcauto_dointvec_minmax NULL 130 #endif 131 132 static int zero; 133 static int one = 1; 134 135 static struct ctl_table ipc_kern_table[] = { 136 { 137 .procname = "shmmax", 138 .data = &init_ipc_ns.shm_ctlmax, 139 .maxlen = sizeof (init_ipc_ns.shm_ctlmax), 140 .mode = 0644, 141 .proc_handler = proc_ipc_doulongvec_minmax, 142 }, 143 { 144 .procname = "shmall", 145 .data = &init_ipc_ns.shm_ctlall, 146 .maxlen = sizeof (init_ipc_ns.shm_ctlall), 147 .mode = 0644, 148 .proc_handler = proc_ipc_doulongvec_minmax, 149 }, 150 { 151 .procname = "shmmni", 152 .data = &init_ipc_ns.shm_ctlmni, 153 .maxlen = sizeof (init_ipc_ns.shm_ctlmni), 154 .mode = 0644, 155 .proc_handler = proc_ipc_dointvec, 156 }, 157 { 158 .procname = "msgmax", 159 .data = &init_ipc_ns.msg_ctlmax, 160 .maxlen = sizeof (init_ipc_ns.msg_ctlmax), 161 .mode = 0644, 162 .proc_handler = proc_ipc_dointvec, 163 }, 164 { 165 .procname = "msgmni", 166 .data = &init_ipc_ns.msg_ctlmni, 167 .maxlen = sizeof (init_ipc_ns.msg_ctlmni), 168 .mode = 0644, 169 .proc_handler = proc_ipc_callback_dointvec, 170 }, 171 { 172 .procname = "msgmnb", 173 .data = &init_ipc_ns.msg_ctlmnb, 174 .maxlen = sizeof (init_ipc_ns.msg_ctlmnb), 175 .mode = 0644, 176 .proc_handler = proc_ipc_dointvec, 177 }, 178 { 179 .procname = "sem", 180 .data = &init_ipc_ns.sem_ctls, 181 .maxlen = 4*sizeof (int), 182 .mode = 0644, 183 .proc_handler = proc_ipc_dointvec, 184 }, 185 { 186 .procname = "auto_msgmni", 187 .data = &init_ipc_ns.auto_msgmni, 188 .maxlen = sizeof(int), 189 .mode = 0644, 190 .proc_handler = proc_ipcauto_dointvec_minmax, 191 .extra1 = &zero, 192 .extra2 = &one, 193 }, 194 {} 195 }; 196 197 static struct ctl_table ipc_root_table[] = { 198 { 199 .procname = "kernel", 200 .mode = 0555, 201 .child = ipc_kern_table, 202 }, 203 {} 204 }; 205 206 static int __init ipc_sysctl_init(void) 207 { 208 register_sysctl_table(ipc_root_table); 209 return 0; 210 } 211 212 __initcall(ipc_sysctl_init); 213