xref: /openbmc/linux/ipc/ipc_sysctl.c (revision d6344cc8)
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 <linux/slab.h>
17  #include <linux/cred.h>
18  #include "util.h"
19  
20  static int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write,
21  		void *buffer, size_t *lenp, loff_t *ppos)
22  {
23  	struct ipc_namespace *ns =
24  		container_of(table->data, struct ipc_namespace, shm_rmid_forced);
25  	int err;
26  
27  	err = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
28  
29  	if (err < 0)
30  		return err;
31  	if (ns->shm_rmid_forced)
32  		shm_destroy_orphaned(ns);
33  	return err;
34  }
35  
36  static int proc_ipc_auto_msgmni(struct ctl_table *table, int write,
37  		void *buffer, size_t *lenp, loff_t *ppos)
38  {
39  	struct ctl_table ipc_table;
40  	int dummy = 0;
41  
42  	memcpy(&ipc_table, table, sizeof(ipc_table));
43  	ipc_table.data = &dummy;
44  
45  	if (write)
46  		pr_info_once("writing to auto_msgmni has no effect");
47  
48  	return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
49  }
50  
51  static int proc_ipc_sem_dointvec(struct ctl_table *table, int write,
52  	void *buffer, size_t *lenp, loff_t *ppos)
53  {
54  	struct ipc_namespace *ns =
55  		container_of(table->data, struct ipc_namespace, sem_ctls);
56  	int ret, semmni;
57  
58  	semmni = ns->sem_ctls[3];
59  	ret = proc_dointvec(table, write, buffer, lenp, ppos);
60  
61  	if (!ret)
62  		ret = sem_check_semmni(ns);
63  
64  	/*
65  	 * Reset the semmni value if an error happens.
66  	 */
67  	if (ret)
68  		ns->sem_ctls[3] = semmni;
69  	return ret;
70  }
71  
72  int ipc_mni = IPCMNI;
73  int ipc_mni_shift = IPCMNI_SHIFT;
74  int ipc_min_cycle = RADIX_TREE_MAP_SIZE;
75  
76  static struct ctl_table ipc_sysctls[] = {
77  	{
78  		.procname	= "shmmax",
79  		.data		= &init_ipc_ns.shm_ctlmax,
80  		.maxlen		= sizeof(init_ipc_ns.shm_ctlmax),
81  		.mode		= 0644,
82  		.proc_handler	= proc_doulongvec_minmax,
83  	},
84  	{
85  		.procname	= "shmall",
86  		.data		= &init_ipc_ns.shm_ctlall,
87  		.maxlen		= sizeof(init_ipc_ns.shm_ctlall),
88  		.mode		= 0644,
89  		.proc_handler	= proc_doulongvec_minmax,
90  	},
91  	{
92  		.procname	= "shmmni",
93  		.data		= &init_ipc_ns.shm_ctlmni,
94  		.maxlen		= sizeof(init_ipc_ns.shm_ctlmni),
95  		.mode		= 0644,
96  		.proc_handler	= proc_dointvec_minmax,
97  		.extra1		= SYSCTL_ZERO,
98  		.extra2		= &ipc_mni,
99  	},
100  	{
101  		.procname	= "shm_rmid_forced",
102  		.data		= &init_ipc_ns.shm_rmid_forced,
103  		.maxlen		= sizeof(init_ipc_ns.shm_rmid_forced),
104  		.mode		= 0644,
105  		.proc_handler	= proc_ipc_dointvec_minmax_orphans,
106  		.extra1		= SYSCTL_ZERO,
107  		.extra2		= SYSCTL_ONE,
108  	},
109  	{
110  		.procname	= "msgmax",
111  		.data		= &init_ipc_ns.msg_ctlmax,
112  		.maxlen		= sizeof(init_ipc_ns.msg_ctlmax),
113  		.mode		= 0644,
114  		.proc_handler	= proc_dointvec_minmax,
115  		.extra1		= SYSCTL_ZERO,
116  		.extra2		= SYSCTL_INT_MAX,
117  	},
118  	{
119  		.procname	= "msgmni",
120  		.data		= &init_ipc_ns.msg_ctlmni,
121  		.maxlen		= sizeof(init_ipc_ns.msg_ctlmni),
122  		.mode		= 0644,
123  		.proc_handler	= proc_dointvec_minmax,
124  		.extra1		= SYSCTL_ZERO,
125  		.extra2		= &ipc_mni,
126  	},
127  	{
128  		.procname	= "auto_msgmni",
129  		.data		= NULL,
130  		.maxlen		= sizeof(int),
131  		.mode		= 0644,
132  		.proc_handler	= proc_ipc_auto_msgmni,
133  		.extra1		= SYSCTL_ZERO,
134  		.extra2		= SYSCTL_ONE,
135  	},
136  	{
137  		.procname	=  "msgmnb",
138  		.data		= &init_ipc_ns.msg_ctlmnb,
139  		.maxlen		= sizeof(init_ipc_ns.msg_ctlmnb),
140  		.mode		= 0644,
141  		.proc_handler	= proc_dointvec_minmax,
142  		.extra1		= SYSCTL_ZERO,
143  		.extra2		= SYSCTL_INT_MAX,
144  	},
145  	{
146  		.procname	= "sem",
147  		.data		= &init_ipc_ns.sem_ctls,
148  		.maxlen		= 4*sizeof(int),
149  		.mode		= 0644,
150  		.proc_handler	= proc_ipc_sem_dointvec,
151  	},
152  #ifdef CONFIG_CHECKPOINT_RESTORE
153  	{
154  		.procname	= "sem_next_id",
155  		.data		= &init_ipc_ns.ids[IPC_SEM_IDS].next_id,
156  		.maxlen		= sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id),
157  		.mode		= 0444,
158  		.proc_handler	= proc_dointvec_minmax,
159  		.extra1		= SYSCTL_ZERO,
160  		.extra2		= SYSCTL_INT_MAX,
161  	},
162  	{
163  		.procname	= "msg_next_id",
164  		.data		= &init_ipc_ns.ids[IPC_MSG_IDS].next_id,
165  		.maxlen		= sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id),
166  		.mode		= 0444,
167  		.proc_handler	= proc_dointvec_minmax,
168  		.extra1		= SYSCTL_ZERO,
169  		.extra2		= SYSCTL_INT_MAX,
170  	},
171  	{
172  		.procname	= "shm_next_id",
173  		.data		= &init_ipc_ns.ids[IPC_SHM_IDS].next_id,
174  		.maxlen		= sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id),
175  		.mode		= 0444,
176  		.proc_handler	= proc_dointvec_minmax,
177  		.extra1		= SYSCTL_ZERO,
178  		.extra2		= SYSCTL_INT_MAX,
179  	},
180  #endif
181  	{}
182  };
183  
184  static struct ctl_table_set *set_lookup(struct ctl_table_root *root)
185  {
186  	return &current->nsproxy->ipc_ns->ipc_set;
187  }
188  
189  static int set_is_seen(struct ctl_table_set *set)
190  {
191  	return &current->nsproxy->ipc_ns->ipc_set == set;
192  }
193  
194  static void ipc_set_ownership(struct ctl_table_header *head,
195  			      kuid_t *uid, kgid_t *gid)
196  {
197  	struct ipc_namespace *ns =
198  		container_of(head->set, struct ipc_namespace, ipc_set);
199  
200  	kuid_t ns_root_uid = make_kuid(ns->user_ns, 0);
201  	kgid_t ns_root_gid = make_kgid(ns->user_ns, 0);
202  
203  	*uid = uid_valid(ns_root_uid) ? ns_root_uid : GLOBAL_ROOT_UID;
204  	*gid = gid_valid(ns_root_gid) ? ns_root_gid : GLOBAL_ROOT_GID;
205  }
206  
207  static int ipc_permissions(struct ctl_table_header *head, struct ctl_table *table)
208  {
209  	int mode = table->mode;
210  
211  #ifdef CONFIG_CHECKPOINT_RESTORE
212  	struct ipc_namespace *ns =
213  		container_of(head->set, struct ipc_namespace, ipc_set);
214  
215  	if (((table->data == &ns->ids[IPC_SEM_IDS].next_id) ||
216  	     (table->data == &ns->ids[IPC_MSG_IDS].next_id) ||
217  	     (table->data == &ns->ids[IPC_SHM_IDS].next_id)) &&
218  	    checkpoint_restore_ns_capable(ns->user_ns))
219  		mode = 0666;
220  	else
221  #endif
222  	{
223  		kuid_t ns_root_uid;
224  		kgid_t ns_root_gid;
225  
226  		ipc_set_ownership(head, &ns_root_uid, &ns_root_gid);
227  
228  		if (uid_eq(current_euid(), ns_root_uid))
229  			mode >>= 6;
230  
231  		else if (in_egroup_p(ns_root_gid))
232  			mode >>= 3;
233  	}
234  
235  	mode &= 7;
236  
237  	return (mode << 6) | (mode << 3) | mode;
238  }
239  
240  static struct ctl_table_root set_root = {
241  	.lookup = set_lookup,
242  	.permissions = ipc_permissions,
243  	.set_ownership = ipc_set_ownership,
244  };
245  
246  bool setup_ipc_sysctls(struct ipc_namespace *ns)
247  {
248  	struct ctl_table *tbl;
249  
250  	setup_sysctl_set(&ns->ipc_set, &set_root, set_is_seen);
251  
252  	tbl = kmemdup(ipc_sysctls, sizeof(ipc_sysctls), GFP_KERNEL);
253  	if (tbl) {
254  		int i;
255  
256  		for (i = 0; i < ARRAY_SIZE(ipc_sysctls); i++) {
257  			if (tbl[i].data == &init_ipc_ns.shm_ctlmax)
258  				tbl[i].data = &ns->shm_ctlmax;
259  
260  			else if (tbl[i].data == &init_ipc_ns.shm_ctlall)
261  				tbl[i].data = &ns->shm_ctlall;
262  
263  			else if (tbl[i].data == &init_ipc_ns.shm_ctlmni)
264  				tbl[i].data = &ns->shm_ctlmni;
265  
266  			else if (tbl[i].data == &init_ipc_ns.shm_rmid_forced)
267  				tbl[i].data = &ns->shm_rmid_forced;
268  
269  			else if (tbl[i].data == &init_ipc_ns.msg_ctlmax)
270  				tbl[i].data = &ns->msg_ctlmax;
271  
272  			else if (tbl[i].data == &init_ipc_ns.msg_ctlmni)
273  				tbl[i].data = &ns->msg_ctlmni;
274  
275  			else if (tbl[i].data == &init_ipc_ns.msg_ctlmnb)
276  				tbl[i].data = &ns->msg_ctlmnb;
277  
278  			else if (tbl[i].data == &init_ipc_ns.sem_ctls)
279  				tbl[i].data = &ns->sem_ctls;
280  #ifdef CONFIG_CHECKPOINT_RESTORE
281  			else if (tbl[i].data == &init_ipc_ns.ids[IPC_SEM_IDS].next_id)
282  				tbl[i].data = &ns->ids[IPC_SEM_IDS].next_id;
283  
284  			else if (tbl[i].data == &init_ipc_ns.ids[IPC_MSG_IDS].next_id)
285  				tbl[i].data = &ns->ids[IPC_MSG_IDS].next_id;
286  
287  			else if (tbl[i].data == &init_ipc_ns.ids[IPC_SHM_IDS].next_id)
288  				tbl[i].data = &ns->ids[IPC_SHM_IDS].next_id;
289  #endif
290  			else
291  				tbl[i].data = NULL;
292  		}
293  
294  		ns->ipc_sysctls = __register_sysctl_table(&ns->ipc_set,
295  							  "kernel", tbl,
296  							  ARRAY_SIZE(ipc_sysctls));
297  	}
298  	if (!ns->ipc_sysctls) {
299  		kfree(tbl);
300  		retire_sysctl_set(&ns->ipc_set);
301  		return false;
302  	}
303  
304  	return true;
305  }
306  
307  void retire_ipc_sysctls(struct ipc_namespace *ns)
308  {
309  	struct ctl_table *tbl;
310  
311  	tbl = ns->ipc_sysctls->ctl_table_arg;
312  	unregister_sysctl_table(ns->ipc_sysctls);
313  	retire_sysctl_set(&ns->ipc_set);
314  	kfree(tbl);
315  }
316  
317  static int __init ipc_sysctl_init(void)
318  {
319  	if (!setup_ipc_sysctls(&init_ipc_ns)) {
320  		pr_warn("ipc sysctl registration failed\n");
321  		return -ENOMEM;
322  	}
323  	return 0;
324  }
325  
326  device_initcall(ipc_sysctl_init);
327  
328  static int __init ipc_mni_extend(char *str)
329  {
330  	ipc_mni = IPCMNI_EXTEND;
331  	ipc_mni_shift = IPCMNI_EXTEND_SHIFT;
332  	ipc_min_cycle = IPCMNI_EXTEND_MIN_CYCLE;
333  	pr_info("IPCMNI extended to %d.\n", ipc_mni);
334  	return 0;
335  }
336  early_param("ipcmni_extend", ipc_mni_extend);
337