1 /* 2 * Copyright (C) 2007 3 * 4 * Author: Eric Biederman <[email protected]> 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 #else 92 #define proc_ipc_doulongvec_minmax NULL 93 #define proc_ipc_dointvec NULL 94 #define proc_ipc_dointvec_minmax NULL 95 #define proc_ipc_dointvec_minmax_orphans NULL 96 #define proc_ipc_auto_msgmni NULL 97 #endif 98 99 static int zero; 100 static int one = 1; 101 static int int_max = INT_MAX; 102 static int ipc_mni = IPCMNI; 103 104 static struct ctl_table ipc_kern_table[] = { 105 { 106 .procname = "shmmax", 107 .data = &init_ipc_ns.shm_ctlmax, 108 .maxlen = sizeof(init_ipc_ns.shm_ctlmax), 109 .mode = 0644, 110 .proc_handler = proc_ipc_doulongvec_minmax, 111 }, 112 { 113 .procname = "shmall", 114 .data = &init_ipc_ns.shm_ctlall, 115 .maxlen = sizeof(init_ipc_ns.shm_ctlall), 116 .mode = 0644, 117 .proc_handler = proc_ipc_doulongvec_minmax, 118 }, 119 { 120 .procname = "shmmni", 121 .data = &init_ipc_ns.shm_ctlmni, 122 .maxlen = sizeof(init_ipc_ns.shm_ctlmni), 123 .mode = 0644, 124 .proc_handler = proc_ipc_dointvec_minmax, 125 .extra1 = &zero, 126 .extra2 = &ipc_mni, 127 }, 128 { 129 .procname = "shm_rmid_forced", 130 .data = &init_ipc_ns.shm_rmid_forced, 131 .maxlen = sizeof(init_ipc_ns.shm_rmid_forced), 132 .mode = 0644, 133 .proc_handler = proc_ipc_dointvec_minmax_orphans, 134 .extra1 = &zero, 135 .extra2 = &one, 136 }, 137 { 138 .procname = "msgmax", 139 .data = &init_ipc_ns.msg_ctlmax, 140 .maxlen = sizeof(init_ipc_ns.msg_ctlmax), 141 .mode = 0644, 142 .proc_handler = proc_ipc_dointvec_minmax, 143 .extra1 = &zero, 144 .extra2 = &int_max, 145 }, 146 { 147 .procname = "msgmni", 148 .data = &init_ipc_ns.msg_ctlmni, 149 .maxlen = sizeof(init_ipc_ns.msg_ctlmni), 150 .mode = 0644, 151 .proc_handler = proc_ipc_dointvec_minmax, 152 .extra1 = &zero, 153 .extra2 = &ipc_mni, 154 }, 155 { 156 .procname = "auto_msgmni", 157 .data = NULL, 158 .maxlen = sizeof(int), 159 .mode = 0644, 160 .proc_handler = proc_ipc_auto_msgmni, 161 .extra1 = &zero, 162 .extra2 = &one, 163 }, 164 { 165 .procname = "msgmnb", 166 .data = &init_ipc_ns.msg_ctlmnb, 167 .maxlen = sizeof(init_ipc_ns.msg_ctlmnb), 168 .mode = 0644, 169 .proc_handler = proc_ipc_dointvec_minmax, 170 .extra1 = &zero, 171 .extra2 = &int_max, 172 }, 173 { 174 .procname = "sem", 175 .data = &init_ipc_ns.sem_ctls, 176 .maxlen = 4*sizeof(int), 177 .mode = 0644, 178 .proc_handler = proc_ipc_dointvec, 179 }, 180 #ifdef CONFIG_CHECKPOINT_RESTORE 181 { 182 .procname = "sem_next_id", 183 .data = &init_ipc_ns.ids[IPC_SEM_IDS].next_id, 184 .maxlen = sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id), 185 .mode = 0644, 186 .proc_handler = proc_ipc_dointvec_minmax, 187 .extra1 = &zero, 188 .extra2 = &int_max, 189 }, 190 { 191 .procname = "msg_next_id", 192 .data = &init_ipc_ns.ids[IPC_MSG_IDS].next_id, 193 .maxlen = sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id), 194 .mode = 0644, 195 .proc_handler = proc_ipc_dointvec_minmax, 196 .extra1 = &zero, 197 .extra2 = &int_max, 198 }, 199 { 200 .procname = "shm_next_id", 201 .data = &init_ipc_ns.ids[IPC_SHM_IDS].next_id, 202 .maxlen = sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id), 203 .mode = 0644, 204 .proc_handler = proc_ipc_dointvec_minmax, 205 .extra1 = &zero, 206 .extra2 = &int_max, 207 }, 208 #endif 209 {} 210 }; 211 212 static struct ctl_table ipc_root_table[] = { 213 { 214 .procname = "kernel", 215 .mode = 0555, 216 .child = ipc_kern_table, 217 }, 218 {} 219 }; 220 221 static int __init ipc_sysctl_init(void) 222 { 223 register_sysctl_table(ipc_root_table); 224 return 0; 225 } 226 227 device_initcall(ipc_sysctl_init); 228