1*a5494dcdSEric W. Biederman /* 2*a5494dcdSEric W. Biederman * Copyright (C) 2007 3*a5494dcdSEric W. Biederman * 4*a5494dcdSEric W. Biederman * Author: Eric Biederman <ebiederm@xmision.com> 5*a5494dcdSEric W. Biederman * 6*a5494dcdSEric W. Biederman * This program is free software; you can redistribute it and/or 7*a5494dcdSEric W. Biederman * modify it under the terms of the GNU General Public License as 8*a5494dcdSEric W. Biederman * published by the Free Software Foundation, version 2 of the 9*a5494dcdSEric W. Biederman * License. 10*a5494dcdSEric W. Biederman */ 11*a5494dcdSEric W. Biederman 12*a5494dcdSEric W. Biederman #include <linux/module.h> 13*a5494dcdSEric W. Biederman #include <linux/ipc.h> 14*a5494dcdSEric W. Biederman #include <linux/nsproxy.h> 15*a5494dcdSEric W. Biederman #include <linux/sysctl.h> 16*a5494dcdSEric W. Biederman #include <linux/uaccess.h> 17*a5494dcdSEric W. Biederman 18*a5494dcdSEric W. Biederman #ifdef CONFIG_IPC_NS 19*a5494dcdSEric W. Biederman static void *get_ipc(ctl_table *table) 20*a5494dcdSEric W. Biederman { 21*a5494dcdSEric W. Biederman char *which = table->data; 22*a5494dcdSEric W. Biederman struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; 23*a5494dcdSEric W. Biederman which = (which - (char *)&init_ipc_ns) + (char *)ipc_ns; 24*a5494dcdSEric W. Biederman return which; 25*a5494dcdSEric W. Biederman } 26*a5494dcdSEric W. Biederman #else 27*a5494dcdSEric W. Biederman #define get_ipc(T) ((T)->data) 28*a5494dcdSEric W. Biederman #endif 29*a5494dcdSEric W. Biederman 30*a5494dcdSEric W. Biederman #ifdef CONFIG_PROC_FS 31*a5494dcdSEric W. Biederman static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp, 32*a5494dcdSEric W. Biederman void __user *buffer, size_t *lenp, loff_t *ppos) 33*a5494dcdSEric W. Biederman { 34*a5494dcdSEric W. Biederman struct ctl_table ipc_table; 35*a5494dcdSEric W. Biederman memcpy(&ipc_table, table, sizeof(ipc_table)); 36*a5494dcdSEric W. Biederman ipc_table.data = get_ipc(table); 37*a5494dcdSEric W. Biederman 38*a5494dcdSEric W. Biederman return proc_dointvec(&ipc_table, write, filp, buffer, lenp, ppos); 39*a5494dcdSEric W. Biederman } 40*a5494dcdSEric W. Biederman 41*a5494dcdSEric W. Biederman static int proc_ipc_doulongvec_minmax(ctl_table *table, int write, 42*a5494dcdSEric W. Biederman struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) 43*a5494dcdSEric W. Biederman { 44*a5494dcdSEric W. Biederman struct ctl_table ipc_table; 45*a5494dcdSEric W. Biederman memcpy(&ipc_table, table, sizeof(ipc_table)); 46*a5494dcdSEric W. Biederman ipc_table.data = get_ipc(table); 47*a5494dcdSEric W. Biederman 48*a5494dcdSEric W. Biederman return proc_doulongvec_minmax(&ipc_table, write, filp, buffer, 49*a5494dcdSEric W. Biederman lenp, ppos); 50*a5494dcdSEric W. Biederman } 51*a5494dcdSEric W. Biederman 52*a5494dcdSEric W. Biederman #else 53*a5494dcdSEric W. Biederman #define proc_ipc_doulongvec_minmax NULL 54*a5494dcdSEric W. Biederman #define proc_ipc_dointvec NULL 55*a5494dcdSEric W. Biederman #endif 56*a5494dcdSEric W. Biederman 57*a5494dcdSEric W. Biederman #ifdef CONFIG_SYSCTL_SYSCALL 58*a5494dcdSEric W. Biederman /* The generic sysctl ipc data routine. */ 59*a5494dcdSEric W. Biederman static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen, 60*a5494dcdSEric W. Biederman void __user *oldval, size_t __user *oldlenp, 61*a5494dcdSEric W. Biederman void __user *newval, size_t newlen) 62*a5494dcdSEric W. Biederman { 63*a5494dcdSEric W. Biederman size_t len; 64*a5494dcdSEric W. Biederman void *data; 65*a5494dcdSEric W. Biederman 66*a5494dcdSEric W. Biederman /* Get out of I don't have a variable */ 67*a5494dcdSEric W. Biederman if (!table->data || !table->maxlen) 68*a5494dcdSEric W. Biederman return -ENOTDIR; 69*a5494dcdSEric W. Biederman 70*a5494dcdSEric W. Biederman data = get_ipc(table); 71*a5494dcdSEric W. Biederman if (!data) 72*a5494dcdSEric W. Biederman return -ENOTDIR; 73*a5494dcdSEric W. Biederman 74*a5494dcdSEric W. Biederman if (oldval && oldlenp) { 75*a5494dcdSEric W. Biederman if (get_user(len, oldlenp)) 76*a5494dcdSEric W. Biederman return -EFAULT; 77*a5494dcdSEric W. Biederman if (len) { 78*a5494dcdSEric W. Biederman if (len > table->maxlen) 79*a5494dcdSEric W. Biederman len = table->maxlen; 80*a5494dcdSEric W. Biederman if (copy_to_user(oldval, data, len)) 81*a5494dcdSEric W. Biederman return -EFAULT; 82*a5494dcdSEric W. Biederman if (put_user(len, oldlenp)) 83*a5494dcdSEric W. Biederman return -EFAULT; 84*a5494dcdSEric W. Biederman } 85*a5494dcdSEric W. Biederman } 86*a5494dcdSEric W. Biederman 87*a5494dcdSEric W. Biederman if (newval && newlen) { 88*a5494dcdSEric W. Biederman if (newlen > table->maxlen) 89*a5494dcdSEric W. Biederman newlen = table->maxlen; 90*a5494dcdSEric W. Biederman 91*a5494dcdSEric W. Biederman if (copy_from_user(data, newval, newlen)) 92*a5494dcdSEric W. Biederman return -EFAULT; 93*a5494dcdSEric W. Biederman } 94*a5494dcdSEric W. Biederman return 1; 95*a5494dcdSEric W. Biederman } 96*a5494dcdSEric W. Biederman #else 97*a5494dcdSEric W. Biederman #define sysctl_ipc_data NULL 98*a5494dcdSEric W. Biederman #endif 99*a5494dcdSEric W. Biederman 100*a5494dcdSEric W. Biederman static struct ctl_table ipc_kern_table[] = { 101*a5494dcdSEric W. Biederman { 102*a5494dcdSEric W. Biederman .ctl_name = KERN_SHMMAX, 103*a5494dcdSEric W. Biederman .procname = "shmmax", 104*a5494dcdSEric W. Biederman .data = &init_ipc_ns.shm_ctlmax, 105*a5494dcdSEric W. Biederman .maxlen = sizeof (init_ipc_ns.shm_ctlmax), 106*a5494dcdSEric W. Biederman .mode = 0644, 107*a5494dcdSEric W. Biederman .proc_handler = proc_ipc_doulongvec_minmax, 108*a5494dcdSEric W. Biederman .strategy = sysctl_ipc_data, 109*a5494dcdSEric W. Biederman }, 110*a5494dcdSEric W. Biederman { 111*a5494dcdSEric W. Biederman .ctl_name = KERN_SHMALL, 112*a5494dcdSEric W. Biederman .procname = "shmall", 113*a5494dcdSEric W. Biederman .data = &init_ipc_ns.shm_ctlall, 114*a5494dcdSEric W. Biederman .maxlen = sizeof (init_ipc_ns.shm_ctlall), 115*a5494dcdSEric W. Biederman .mode = 0644, 116*a5494dcdSEric W. Biederman .proc_handler = proc_ipc_doulongvec_minmax, 117*a5494dcdSEric W. Biederman .strategy = sysctl_ipc_data, 118*a5494dcdSEric W. Biederman }, 119*a5494dcdSEric W. Biederman { 120*a5494dcdSEric W. Biederman .ctl_name = KERN_SHMMNI, 121*a5494dcdSEric W. Biederman .procname = "shmmni", 122*a5494dcdSEric W. Biederman .data = &init_ipc_ns.shm_ctlmni, 123*a5494dcdSEric W. Biederman .maxlen = sizeof (init_ipc_ns.shm_ctlmni), 124*a5494dcdSEric W. Biederman .mode = 0644, 125*a5494dcdSEric W. Biederman .proc_handler = proc_ipc_dointvec, 126*a5494dcdSEric W. Biederman .strategy = sysctl_ipc_data, 127*a5494dcdSEric W. Biederman }, 128*a5494dcdSEric W. Biederman { 129*a5494dcdSEric W. Biederman .ctl_name = KERN_MSGMAX, 130*a5494dcdSEric W. Biederman .procname = "msgmax", 131*a5494dcdSEric W. Biederman .data = &init_ipc_ns.msg_ctlmax, 132*a5494dcdSEric W. Biederman .maxlen = sizeof (init_ipc_ns.msg_ctlmax), 133*a5494dcdSEric W. Biederman .mode = 0644, 134*a5494dcdSEric W. Biederman .proc_handler = proc_ipc_dointvec, 135*a5494dcdSEric W. Biederman .strategy = sysctl_ipc_data, 136*a5494dcdSEric W. Biederman }, 137*a5494dcdSEric W. Biederman { 138*a5494dcdSEric W. Biederman .ctl_name = KERN_MSGMNI, 139*a5494dcdSEric W. Biederman .procname = "msgmni", 140*a5494dcdSEric W. Biederman .data = &init_ipc_ns.msg_ctlmni, 141*a5494dcdSEric W. Biederman .maxlen = sizeof (init_ipc_ns.msg_ctlmni), 142*a5494dcdSEric W. Biederman .mode = 0644, 143*a5494dcdSEric W. Biederman .proc_handler = proc_ipc_dointvec, 144*a5494dcdSEric W. Biederman .strategy = sysctl_ipc_data, 145*a5494dcdSEric W. Biederman }, 146*a5494dcdSEric W. Biederman { 147*a5494dcdSEric W. Biederman .ctl_name = KERN_MSGMNB, 148*a5494dcdSEric W. Biederman .procname = "msgmnb", 149*a5494dcdSEric W. Biederman .data = &init_ipc_ns.msg_ctlmnb, 150*a5494dcdSEric W. Biederman .maxlen = sizeof (init_ipc_ns.msg_ctlmnb), 151*a5494dcdSEric W. Biederman .mode = 0644, 152*a5494dcdSEric W. Biederman .proc_handler = proc_ipc_dointvec, 153*a5494dcdSEric W. Biederman .strategy = sysctl_ipc_data, 154*a5494dcdSEric W. Biederman }, 155*a5494dcdSEric W. Biederman { 156*a5494dcdSEric W. Biederman .ctl_name = KERN_SEM, 157*a5494dcdSEric W. Biederman .procname = "sem", 158*a5494dcdSEric W. Biederman .data = &init_ipc_ns.sem_ctls, 159*a5494dcdSEric W. Biederman .maxlen = 4*sizeof (int), 160*a5494dcdSEric W. Biederman .mode = 0644, 161*a5494dcdSEric W. Biederman .proc_handler = proc_ipc_dointvec, 162*a5494dcdSEric W. Biederman .strategy = sysctl_ipc_data, 163*a5494dcdSEric W. Biederman }, 164*a5494dcdSEric W. Biederman {} 165*a5494dcdSEric W. Biederman }; 166*a5494dcdSEric W. Biederman 167*a5494dcdSEric W. Biederman static struct ctl_table ipc_root_table[] = { 168*a5494dcdSEric W. Biederman { 169*a5494dcdSEric W. Biederman .ctl_name = CTL_KERN, 170*a5494dcdSEric W. Biederman .procname = "kernel", 171*a5494dcdSEric W. Biederman .mode = 0555, 172*a5494dcdSEric W. Biederman .child = ipc_kern_table, 173*a5494dcdSEric W. Biederman }, 174*a5494dcdSEric W. Biederman {} 175*a5494dcdSEric W. Biederman }; 176*a5494dcdSEric W. Biederman 177*a5494dcdSEric W. Biederman static int __init ipc_sysctl_init(void) 178*a5494dcdSEric W. Biederman { 179*a5494dcdSEric W. Biederman register_sysctl_table(ipc_root_table, 0); 180*a5494dcdSEric W. Biederman return 0; 181*a5494dcdSEric W. Biederman } 182*a5494dcdSEric W. Biederman 183*a5494dcdSEric W. Biederman __initcall(ipc_sysctl_init); 184