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