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 18 static void *get_ipc(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_FS 27 static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp, 28 void __user *buffer, size_t *lenp, loff_t *ppos) 29 { 30 struct ctl_table ipc_table; 31 memcpy(&ipc_table, table, sizeof(ipc_table)); 32 ipc_table.data = get_ipc(table); 33 34 return proc_dointvec(&ipc_table, write, filp, buffer, lenp, ppos); 35 } 36 37 static int proc_ipc_doulongvec_minmax(ctl_table *table, int write, 38 struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) 39 { 40 struct ctl_table ipc_table; 41 memcpy(&ipc_table, table, sizeof(ipc_table)); 42 ipc_table.data = get_ipc(table); 43 44 return proc_doulongvec_minmax(&ipc_table, write, filp, buffer, 45 lenp, ppos); 46 } 47 48 #else 49 #define proc_ipc_doulongvec_minmax NULL 50 #define proc_ipc_dointvec NULL 51 #endif 52 53 #ifdef CONFIG_SYSCTL_SYSCALL 54 /* The generic sysctl ipc data routine. */ 55 static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen, 56 void __user *oldval, size_t __user *oldlenp, 57 void __user *newval, size_t newlen) 58 { 59 size_t len; 60 void *data; 61 62 /* Get out of I don't have a variable */ 63 if (!table->data || !table->maxlen) 64 return -ENOTDIR; 65 66 data = get_ipc(table); 67 if (!data) 68 return -ENOTDIR; 69 70 if (oldval && oldlenp) { 71 if (get_user(len, oldlenp)) 72 return -EFAULT; 73 if (len) { 74 if (len > table->maxlen) 75 len = table->maxlen; 76 if (copy_to_user(oldval, data, len)) 77 return -EFAULT; 78 if (put_user(len, oldlenp)) 79 return -EFAULT; 80 } 81 } 82 83 if (newval && newlen) { 84 if (newlen > table->maxlen) 85 newlen = table->maxlen; 86 87 if (copy_from_user(data, newval, newlen)) 88 return -EFAULT; 89 } 90 return 1; 91 } 92 #else 93 #define sysctl_ipc_data NULL 94 #endif 95 96 static struct ctl_table ipc_kern_table[] = { 97 { 98 .ctl_name = KERN_SHMMAX, 99 .procname = "shmmax", 100 .data = &init_ipc_ns.shm_ctlmax, 101 .maxlen = sizeof (init_ipc_ns.shm_ctlmax), 102 .mode = 0644, 103 .proc_handler = proc_ipc_doulongvec_minmax, 104 .strategy = sysctl_ipc_data, 105 }, 106 { 107 .ctl_name = KERN_SHMALL, 108 .procname = "shmall", 109 .data = &init_ipc_ns.shm_ctlall, 110 .maxlen = sizeof (init_ipc_ns.shm_ctlall), 111 .mode = 0644, 112 .proc_handler = proc_ipc_doulongvec_minmax, 113 .strategy = sysctl_ipc_data, 114 }, 115 { 116 .ctl_name = KERN_SHMMNI, 117 .procname = "shmmni", 118 .data = &init_ipc_ns.shm_ctlmni, 119 .maxlen = sizeof (init_ipc_ns.shm_ctlmni), 120 .mode = 0644, 121 .proc_handler = proc_ipc_dointvec, 122 .strategy = sysctl_ipc_data, 123 }, 124 { 125 .ctl_name = KERN_MSGMAX, 126 .procname = "msgmax", 127 .data = &init_ipc_ns.msg_ctlmax, 128 .maxlen = sizeof (init_ipc_ns.msg_ctlmax), 129 .mode = 0644, 130 .proc_handler = proc_ipc_dointvec, 131 .strategy = sysctl_ipc_data, 132 }, 133 { 134 .ctl_name = KERN_MSGMNI, 135 .procname = "msgmni", 136 .data = &init_ipc_ns.msg_ctlmni, 137 .maxlen = sizeof (init_ipc_ns.msg_ctlmni), 138 .mode = 0644, 139 .proc_handler = proc_ipc_dointvec, 140 .strategy = sysctl_ipc_data, 141 }, 142 { 143 .ctl_name = KERN_MSGMNB, 144 .procname = "msgmnb", 145 .data = &init_ipc_ns.msg_ctlmnb, 146 .maxlen = sizeof (init_ipc_ns.msg_ctlmnb), 147 .mode = 0644, 148 .proc_handler = proc_ipc_dointvec, 149 .strategy = sysctl_ipc_data, 150 }, 151 { 152 .ctl_name = KERN_SEM, 153 .procname = "sem", 154 .data = &init_ipc_ns.sem_ctls, 155 .maxlen = 4*sizeof (int), 156 .mode = 0644, 157 .proc_handler = proc_ipc_dointvec, 158 .strategy = sysctl_ipc_data, 159 }, 160 {} 161 }; 162 163 static struct ctl_table ipc_root_table[] = { 164 { 165 .ctl_name = CTL_KERN, 166 .procname = "kernel", 167 .mode = 0555, 168 .child = ipc_kern_table, 169 }, 170 {} 171 }; 172 173 static int __init ipc_sysctl_init(void) 174 { 175 register_sysctl_table(ipc_root_table); 176 return 0; 177 } 178 179 __initcall(ipc_sysctl_init); 180