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