xref: /openbmc/linux/ipc/ipc_sysctl.c (revision 643d1f7f)
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