xref: /openbmc/linux/ipc/ipc_sysctl.c (revision fbb6b31a)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  *  Copyright (C) 2007
4  *
5  *  Author: Eric Biederman <ebiederm@xmision.com>
6  */
7 
8 #include <linux/module.h>
9 #include <linux/ipc.h>
10 #include <linux/nsproxy.h>
11 #include <linux/sysctl.h>
12 #include <linux/uaccess.h>
13 #include <linux/capability.h>
14 #include <linux/ipc_namespace.h>
15 #include <linux/msg.h>
16 #include "util.h"
17 
18 static void *get_ipc(struct 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 static int proc_ipc_dointvec(struct ctl_table *table, int write,
27 		void *buffer, size_t *lenp, loff_t *ppos)
28 {
29 	struct ctl_table ipc_table;
30 
31 	memcpy(&ipc_table, table, sizeof(ipc_table));
32 	ipc_table.data = get_ipc(table);
33 
34 	return proc_dointvec(&ipc_table, write, buffer, lenp, ppos);
35 }
36 
37 static int proc_ipc_dointvec_minmax(struct ctl_table *table, int write,
38 		void *buffer, size_t *lenp, loff_t *ppos)
39 {
40 	struct ctl_table ipc_table;
41 
42 	memcpy(&ipc_table, table, sizeof(ipc_table));
43 	ipc_table.data = get_ipc(table);
44 
45 	return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
46 }
47 
48 static int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write,
49 		void *buffer, size_t *lenp, loff_t *ppos)
50 {
51 	struct ipc_namespace *ns = current->nsproxy->ipc_ns;
52 	int err = proc_ipc_dointvec_minmax(table, write, buffer, lenp, ppos);
53 
54 	if (err < 0)
55 		return err;
56 	if (ns->shm_rmid_forced)
57 		shm_destroy_orphaned(ns);
58 	return err;
59 }
60 
61 static int proc_ipc_doulongvec_minmax(struct ctl_table *table, int write,
62 		void *buffer, size_t *lenp, loff_t *ppos)
63 {
64 	struct ctl_table ipc_table;
65 	memcpy(&ipc_table, table, sizeof(ipc_table));
66 	ipc_table.data = get_ipc(table);
67 
68 	return proc_doulongvec_minmax(&ipc_table, write, buffer,
69 					lenp, ppos);
70 }
71 
72 static int proc_ipc_auto_msgmni(struct ctl_table *table, int write,
73 		void *buffer, size_t *lenp, loff_t *ppos)
74 {
75 	struct ctl_table ipc_table;
76 	int dummy = 0;
77 
78 	memcpy(&ipc_table, table, sizeof(ipc_table));
79 	ipc_table.data = &dummy;
80 
81 	if (write)
82 		pr_info_once("writing to auto_msgmni has no effect");
83 
84 	return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
85 }
86 
87 static int proc_ipc_sem_dointvec(struct ctl_table *table, int write,
88 	void *buffer, size_t *lenp, loff_t *ppos)
89 {
90 	int ret, semmni;
91 	struct ipc_namespace *ns = current->nsproxy->ipc_ns;
92 
93 	semmni = ns->sem_ctls[3];
94 	ret = proc_ipc_dointvec(table, write, buffer, lenp, ppos);
95 
96 	if (!ret)
97 		ret = sem_check_semmni(current->nsproxy->ipc_ns);
98 
99 	/*
100 	 * Reset the semmni value if an error happens.
101 	 */
102 	if (ret)
103 		ns->sem_ctls[3] = semmni;
104 	return ret;
105 }
106 
107 #ifdef CONFIG_CHECKPOINT_RESTORE
108 static int proc_ipc_dointvec_minmax_checkpoint_restore(struct ctl_table *table,
109 		int write, void *buffer, size_t *lenp, loff_t *ppos)
110 {
111 	struct user_namespace *user_ns = current->nsproxy->ipc_ns->user_ns;
112 
113 	if (write && !checkpoint_restore_ns_capable(user_ns))
114 		return -EPERM;
115 
116 	return proc_ipc_dointvec_minmax(table, write, buffer, lenp, ppos);
117 }
118 #endif
119 
120 int ipc_mni = IPCMNI;
121 int ipc_mni_shift = IPCMNI_SHIFT;
122 int ipc_min_cycle = RADIX_TREE_MAP_SIZE;
123 
124 static struct ctl_table ipc_kern_table[] = {
125 	{
126 		.procname	= "shmmax",
127 		.data		= &init_ipc_ns.shm_ctlmax,
128 		.maxlen		= sizeof(init_ipc_ns.shm_ctlmax),
129 		.mode		= 0644,
130 		.proc_handler	= proc_ipc_doulongvec_minmax,
131 	},
132 	{
133 		.procname	= "shmall",
134 		.data		= &init_ipc_ns.shm_ctlall,
135 		.maxlen		= sizeof(init_ipc_ns.shm_ctlall),
136 		.mode		= 0644,
137 		.proc_handler	= proc_ipc_doulongvec_minmax,
138 	},
139 	{
140 		.procname	= "shmmni",
141 		.data		= &init_ipc_ns.shm_ctlmni,
142 		.maxlen		= sizeof(init_ipc_ns.shm_ctlmni),
143 		.mode		= 0644,
144 		.proc_handler	= proc_ipc_dointvec_minmax,
145 		.extra1		= SYSCTL_ZERO,
146 		.extra2		= &ipc_mni,
147 	},
148 	{
149 		.procname	= "shm_rmid_forced",
150 		.data		= &init_ipc_ns.shm_rmid_forced,
151 		.maxlen		= sizeof(init_ipc_ns.shm_rmid_forced),
152 		.mode		= 0644,
153 		.proc_handler	= proc_ipc_dointvec_minmax_orphans,
154 		.extra1		= SYSCTL_ZERO,
155 		.extra2		= SYSCTL_ONE,
156 	},
157 	{
158 		.procname	= "msgmax",
159 		.data		= &init_ipc_ns.msg_ctlmax,
160 		.maxlen		= sizeof(init_ipc_ns.msg_ctlmax),
161 		.mode		= 0644,
162 		.proc_handler	= proc_ipc_dointvec_minmax,
163 		.extra1		= SYSCTL_ZERO,
164 		.extra2		= SYSCTL_INT_MAX,
165 	},
166 	{
167 		.procname	= "msgmni",
168 		.data		= &init_ipc_ns.msg_ctlmni,
169 		.maxlen		= sizeof(init_ipc_ns.msg_ctlmni),
170 		.mode		= 0644,
171 		.proc_handler	= proc_ipc_dointvec_minmax,
172 		.extra1		= SYSCTL_ZERO,
173 		.extra2		= &ipc_mni,
174 	},
175 	{
176 		.procname	= "auto_msgmni",
177 		.data		= NULL,
178 		.maxlen		= sizeof(int),
179 		.mode		= 0644,
180 		.proc_handler	= proc_ipc_auto_msgmni,
181 		.extra1		= SYSCTL_ZERO,
182 		.extra2		= SYSCTL_ONE,
183 	},
184 	{
185 		.procname	=  "msgmnb",
186 		.data		= &init_ipc_ns.msg_ctlmnb,
187 		.maxlen		= sizeof(init_ipc_ns.msg_ctlmnb),
188 		.mode		= 0644,
189 		.proc_handler	= proc_ipc_dointvec_minmax,
190 		.extra1		= SYSCTL_ZERO,
191 		.extra2		= SYSCTL_INT_MAX,
192 	},
193 	{
194 		.procname	= "sem",
195 		.data		= &init_ipc_ns.sem_ctls,
196 		.maxlen		= 4*sizeof(int),
197 		.mode		= 0644,
198 		.proc_handler	= proc_ipc_sem_dointvec,
199 	},
200 #ifdef CONFIG_CHECKPOINT_RESTORE
201 	{
202 		.procname	= "sem_next_id",
203 		.data		= &init_ipc_ns.ids[IPC_SEM_IDS].next_id,
204 		.maxlen		= sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id),
205 		.mode		= 0666,
206 		.proc_handler	= proc_ipc_dointvec_minmax_checkpoint_restore,
207 		.extra1		= SYSCTL_ZERO,
208 		.extra2		= SYSCTL_INT_MAX,
209 	},
210 	{
211 		.procname	= "msg_next_id",
212 		.data		= &init_ipc_ns.ids[IPC_MSG_IDS].next_id,
213 		.maxlen		= sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id),
214 		.mode		= 0666,
215 		.proc_handler	= proc_ipc_dointvec_minmax_checkpoint_restore,
216 		.extra1		= SYSCTL_ZERO,
217 		.extra2		= SYSCTL_INT_MAX,
218 	},
219 	{
220 		.procname	= "shm_next_id",
221 		.data		= &init_ipc_ns.ids[IPC_SHM_IDS].next_id,
222 		.maxlen		= sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id),
223 		.mode		= 0666,
224 		.proc_handler	= proc_ipc_dointvec_minmax_checkpoint_restore,
225 		.extra1		= SYSCTL_ZERO,
226 		.extra2		= SYSCTL_INT_MAX,
227 	},
228 #endif
229 	{}
230 };
231 
232 static struct ctl_table ipc_root_table[] = {
233 	{
234 		.procname	= "kernel",
235 		.mode		= 0555,
236 		.child		= ipc_kern_table,
237 	},
238 	{}
239 };
240 
241 static int __init ipc_sysctl_init(void)
242 {
243 	register_sysctl_table(ipc_root_table);
244 	return 0;
245 }
246 
247 device_initcall(ipc_sysctl_init);
248 
249 static int __init ipc_mni_extend(char *str)
250 {
251 	ipc_mni = IPCMNI_EXTEND;
252 	ipc_mni_shift = IPCMNI_EXTEND_SHIFT;
253 	ipc_min_cycle = IPCMNI_EXTEND_MIN_CYCLE;
254 	pr_info("IPCMNI extended to %d.\n", ipc_mni);
255 	return 0;
256 }
257 early_param("ipcmni_extend", ipc_mni_extend);
258