1b2441318SGreg Kroah-Hartman/* SPDX-License-Identifier: GPL-2.0 */
21da177e4SLinus Torvalds/*
31da177e4SLinus Torvalds * linux/ipc/util.h
41da177e4SLinus Torvalds * Copyright (C) 1999 Christoph Rohland
51da177e4SLinus Torvalds *
6624dffcbSChristian Kujau * ipc helper functions (c) 1999 Manfred Spraul <manfred@colorfullife.com>
773ea4130SKirill Korotaev * namespaces support.      2006 OpenVZ, SWsoft Inc.
873ea4130SKirill Korotaev *                               Pavel Emelianov <xemul@openvz.org>
91da177e4SLinus Torvalds */
101da177e4SLinus Torvalds
111da177e4SLinus Torvalds#ifndef _IPC_UTIL_H
121da177e4SLinus Torvalds#define _IPC_UTIL_H
131da177e4SLinus Torvalds
14232086b1SJohannes Weiner#include <linux/unistd.h>
15023a5355SNadia Derbey#include <linux/err.h>
1615df03c8SDavidlohr Bueso#include <linux/ipc_namespace.h>
177ca7e564SNadia Derbey
185ac893b8SWaiman Long/*
195ac893b8SWaiman Long * The IPC ID contains 2 separate numbers - index and sequence number.
205ac893b8SWaiman Long * By default,
215ac893b8SWaiman Long *   bits  0-14: index (32k, 15 bits)
225ac893b8SWaiman Long *   bits 15-30: sequence number (64k, 16 bits)
235ac893b8SWaiman Long *
245ac893b8SWaiman Long * When IPCMNI extension mode is turned on, the composition changes:
255ac893b8SWaiman Long *   bits  0-23: index (16M, 24 bits)
265ac893b8SWaiman Long *   bits 24-30: sequence number (128, 7 bits)
275ac893b8SWaiman Long */
285ac893b8SWaiman Long#define IPCMNI_SHIFT		15
295ac893b8SWaiman Long#define IPCMNI_EXTEND_SHIFT	24
3099db46eaSManfred Spraul#define IPCMNI_EXTEND_MIN_CYCLE	(RADIX_TREE_MAP_SIZE * RADIX_TREE_MAP_SIZE)
315ac893b8SWaiman Long#define IPCMNI			(1 << IPCMNI_SHIFT)
325ac893b8SWaiman Long#define IPCMNI_EXTEND		(1 << IPCMNI_EXTEND_SHIFT)
335ac893b8SWaiman Long
345ac893b8SWaiman Long#ifdef CONFIG_SYSVIPC_SYSCTL
355ac893b8SWaiman Longextern int ipc_mni;
365ac893b8SWaiman Longextern int ipc_mni_shift;
3799db46eaSManfred Spraulextern int ipc_min_cycle;
385ac893b8SWaiman Long
393278a2c2SManfred Spraul#define ipcmni_seq_shift()	ipc_mni_shift
405ac893b8SWaiman Long#define IPCMNI_IDX_MASK		((1 << ipc_mni_shift) - 1)
415ac893b8SWaiman Long
425ac893b8SWaiman Long#else /* CONFIG_SYSVIPC_SYSCTL */
435ac893b8SWaiman Long
445ac893b8SWaiman Long#define ipc_mni			IPCMNI
4599db46eaSManfred Spraul#define ipc_min_cycle		((int)RADIX_TREE_MAP_SIZE)
463278a2c2SManfred Spraul#define ipcmni_seq_shift()	IPCMNI_SHIFT
475ac893b8SWaiman Long#define IPCMNI_IDX_MASK		((1 << IPCMNI_SHIFT) - 1)
485ac893b8SWaiman Long#endif /* CONFIG_SYSVIPC_SYSCTL */
491da177e4SLinus Torvalds
50eae04d25SDavidlohr Buesovoid sem_init(void);
51eae04d25SDavidlohr Buesovoid msg_init(void);
52239521f3SManfred Spraulvoid shm_init(void);
531da177e4SLinus Torvalds
54ae5e1b22SPavel Emelyanovstruct ipc_namespace;
5503f1fc09SEric W. Biedermanstruct pid_namespace;
56ae5e1b22SPavel Emelyanov
57614b84cfSSerge E. Hallyn#ifdef CONFIG_POSIX_MQUEUE
587eafd7c7SSerge E. Hallynextern void mq_clear_sbinfo(struct ipc_namespace *ns);
597eafd7c7SSerge E. Hallynextern void mq_put_mnt(struct ipc_namespace *ns);
60614b84cfSSerge E. Hallyn#else
617eafd7c7SSerge E. Hallynstatic inline void mq_clear_sbinfo(struct ipc_namespace *ns) { }
627eafd7c7SSerge E. Hallynstatic inline void mq_put_mnt(struct ipc_namespace *ns) { }
63614b84cfSSerge E. Hallyn#endif
64614b84cfSSerge E. Hallyn
65614b84cfSSerge E. Hallyn#ifdef CONFIG_SYSVIPC
66eae04d25SDavidlohr Buesovoid sem_init_ns(struct ipc_namespace *ns);
67eae04d25SDavidlohr Buesovoid msg_init_ns(struct ipc_namespace *ns);
68eae04d25SDavidlohr Buesovoid shm_init_ns(struct ipc_namespace *ns);
6973ea4130SKirill Korotaev
7073ea4130SKirill Korotaevvoid sem_exit_ns(struct ipc_namespace *ns);
7173ea4130SKirill Korotaevvoid msg_exit_ns(struct ipc_namespace *ns);
7273ea4130SKirill Korotaevvoid shm_exit_ns(struct ipc_namespace *ns);
73614b84cfSSerge E. Hallyn#else
74eae04d25SDavidlohr Buesostatic inline void sem_init_ns(struct ipc_namespace *ns) { }
75eae04d25SDavidlohr Buesostatic inline void msg_init_ns(struct ipc_namespace *ns) { }
76eae04d25SDavidlohr Buesostatic inline void shm_init_ns(struct ipc_namespace *ns) { }
77614b84cfSSerge E. Hallyn
78614b84cfSSerge E. Hallynstatic inline void sem_exit_ns(struct ipc_namespace *ns) { }
79614b84cfSSerge E. Hallynstatic inline void msg_exit_ns(struct ipc_namespace *ns) { }
80614b84cfSSerge E. Hallynstatic inline void shm_exit_ns(struct ipc_namespace *ns) { }
81614b84cfSSerge E. Hallyn#endif
8273ea4130SKirill Korotaev
837748dbfaSNadia Derbey/*
847748dbfaSNadia Derbey * Structure that holds the parameters needed by the ipc operations
857748dbfaSNadia Derbey * (see after)
867748dbfaSNadia Derbey */
877748dbfaSNadia Derbeystruct ipc_params {
887748dbfaSNadia Derbey	key_t key;
897748dbfaSNadia Derbey	int flg;
907748dbfaSNadia Derbey	union {
917748dbfaSNadia Derbey		size_t size;	/* for shared memories */
927748dbfaSNadia Derbey		int nsems;	/* for semaphores */
937748dbfaSNadia Derbey	} u;			/* holds the getnew() specific param */
947748dbfaSNadia Derbey};
957748dbfaSNadia Derbey
967748dbfaSNadia Derbey/*
977748dbfaSNadia Derbey * Structure that holds some ipc operations. This structure is used to unify
987748dbfaSNadia Derbey * the calls to sys_msgget(), sys_semget(), sys_shmget()
997748dbfaSNadia Derbey *      . routine to call to create a new ipc object. Can be one of newque,
1007748dbfaSNadia Derbey *        newary, newseg
101f4566f04SNadia Derbey *      . routine to call to check permissions for a new ipc object.
1027748dbfaSNadia Derbey *        Can be one of security_msg_associate, security_sem_associate,
1037748dbfaSNadia Derbey *        security_shm_associate
1047748dbfaSNadia Derbey *      . routine to call for an extra check if needed
1057748dbfaSNadia Derbey */
1067748dbfaSNadia Derbeystruct ipc_ops {
10746c0a8caSPaul McQuade	int (*getnew)(struct ipc_namespace *, struct ipc_params *);
10846c0a8caSPaul McQuade	int (*associate)(struct kern_ipc_perm *, int);
10946c0a8caSPaul McQuade	int (*more_checks)(struct kern_ipc_perm *, struct ipc_params *);
1107748dbfaSNadia Derbey};
1117748dbfaSNadia Derbey
112ae781774SMike Waychisonstruct seq_file;
113ed2ddbf8SPierre Peifferstruct ipc_ids;
1147d69a1f4SCedric Le Goater
115eae04d25SDavidlohr Buesovoid ipc_init_ids(struct ipc_ids *ids);
116ae781774SMike Waychison#ifdef CONFIG_PROC_FS
117ae781774SMike Waychisonvoid __init ipc_init_proc_interface(const char *path, const char *header,
11873ea4130SKirill Korotaev		int ids, int (*show)(struct seq_file *, void *));
11903f1fc09SEric W. Biedermanstruct pid_namespace *ipc_seq_pid_ns(struct seq_file *);
120ae781774SMike Waychison#else
121ae781774SMike Waychison#define ipc_init_proc_interface(path, header, ids, show) do {} while (0)
122ae781774SMike Waychison#endif
1231da177e4SLinus Torvalds
12473ea4130SKirill Korotaev#define IPC_SEM_IDS	0
12573ea4130SKirill Korotaev#define IPC_MSG_IDS	1
12673ea4130SKirill Korotaev#define IPC_SHM_IDS	2
12773ea4130SKirill Korotaev
1285ac893b8SWaiman Long#define ipcid_to_idx(id)  ((id) & IPCMNI_IDX_MASK)
1293278a2c2SManfred Spraul#define ipcid_to_seqx(id) ((id) >> ipcmni_seq_shift())
1303278a2c2SManfred Spraul#define ipcid_seq_max()	  (INT_MAX >> ipcmni_seq_shift())
131ce621f5bSNadia Derbey
132d9a605e4SDavidlohr Bueso/* must be called with ids->rwsem acquired for writing */
1337ca7e564SNadia Derbeyint ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int);
1343e148c79SNadia Derbey
1351da177e4SLinus Torvalds/* must be called with both locks acquired. */
1367ca7e564SNadia Derbeyvoid ipc_rmid(struct ipc_ids *, struct kern_ipc_perm *);
1371da177e4SLinus Torvalds
1380cfb6aeeSGuillaume Knispel/* must be called with both locks acquired. */
1390cfb6aeeSGuillaume Knispelvoid ipc_set_key_private(struct ipc_ids *, struct kern_ipc_perm *);
1400cfb6aeeSGuillaume Knispel
141f4566f04SNadia Derbey/* must be called with ipcp locked */
142b0e77598SSerge E. Hallynint ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flg);
1431da177e4SLinus Torvalds
14415df03c8SDavidlohr Bueso/**
14527c331a1SManfred Spraul * ipc_get_maxidx - get the highest assigned index
14615df03c8SDavidlohr Bueso * @ids: ipc identifier set
14715df03c8SDavidlohr Bueso *
148b869d5beSManfred Spraul * The function returns the highest assigned index for @ids. The function
149b869d5beSManfred Spraul * doesn't scan the idr tree, it uses a cached value.
150b869d5beSManfred Spraul *
15115df03c8SDavidlohr Bueso * Called with ipc_ids.rwsem held for reading.
15215df03c8SDavidlohr Bueso */
15327c331a1SManfred Spraulstatic inline int ipc_get_maxidx(struct ipc_ids *ids)
15415df03c8SDavidlohr Bueso{
15515df03c8SDavidlohr Bueso	if (ids->in_use == 0)
15615df03c8SDavidlohr Bueso		return -1;
15715df03c8SDavidlohr Bueso
1585ac893b8SWaiman Long	if (ids->in_use == ipc_mni)
1595ac893b8SWaiman Long		return ipc_mni - 1;
16015df03c8SDavidlohr Bueso
16127c331a1SManfred Spraul	return ids->max_idx;
16215df03c8SDavidlohr Bueso}
16315df03c8SDavidlohr Bueso
1641da177e4SLinus Torvalds/*
1651da177e4SLinus Torvalds * For allocation that need to be freed by RCU.
1661da177e4SLinus Torvalds * Objects are reference counted, they start with reference count 1.
1671da177e4SLinus Torvalds * getref increases the refcount, the putref call that reduces the recount
1681da177e4SLinus Torvalds * to 0 schedules the rcu destruction. Caller must guarantee locking.
16962b49c99SManfred Spraul *
17062b49c99SManfred Spraul * refcount is initialized by ipc_addid(), before that point call_rcu()
17162b49c99SManfred Spraul * must be used.
1721da177e4SLinus Torvalds */
1732a9d6481SManfred Spraulbool ipc_rcu_getref(struct kern_ipc_perm *ptr);
174dba4cdd3SManfred Spraulvoid ipc_rcu_putref(struct kern_ipc_perm *ptr,
175dba4cdd3SManfred Spraul			void (*func)(struct rcu_head *head));
1761da177e4SLinus Torvalds
17755b7ae50SDavidlohr Buesostruct kern_ipc_perm *ipc_obtain_object_idr(struct ipc_ids *ids, int id);
1781da177e4SLinus Torvalds
1791da177e4SLinus Torvaldsvoid kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
1801da177e4SLinus Torvaldsvoid ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
1811efdb69bSEric W. Biedermanint ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out);
1824241c1a3SManfred Spraulstruct kern_ipc_perm *ipcctl_obtain_check(struct ipc_namespace *ns,
183444d0f62SDavidlohr Bueso					     struct ipc_ids *ids, int id, int cmd,
184444d0f62SDavidlohr Bueso					     struct ipc64_perm *perm, int extra_perm);
1851da177e4SLinus Torvalds
18603f1fc09SEric W. Biedermanstatic inline void ipc_update_pid(struct pid **pos, struct pid *pid)
18703f1fc09SEric W. Biederman{
18803f1fc09SEric W. Biederman	struct pid *old = *pos;
18903f1fc09SEric W. Biederman	if (old != pid) {
19003f1fc09SEric W. Biederman		*pos = get_pid(pid);
19103f1fc09SEric W. Biederman		put_pid(old);
19203f1fc09SEric W. Biederman	}
19303f1fc09SEric W. Biederman}
19403f1fc09SEric W. Biederman
195275f2214SArnd Bergmann#ifdef CONFIG_ARCH_WANT_IPC_PARSE_VERSION
196239521f3SManfred Spraulint ipc_parse_version(int *cmd);
1971da177e4SLinus Torvalds#endif
1981da177e4SLinus Torvalds
1991da177e4SLinus Torvaldsextern void free_msg(struct msg_msg *msg);
2004e9b45a1SMathias Krauseextern struct msg_msg *load_msg(const void __user *src, size_t len);
2014a674f34SStanislav Kinsburskyextern struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst);
2024e9b45a1SMathias Krauseextern int store_msg(void __user *dest, struct msg_msg *msg, size_t len);
2037748dbfaSNadia Derbey
20427c331a1SManfred Spraulstatic inline int ipc_checkid(struct kern_ipc_perm *ipcp, int id)
205023a5355SNadia Derbey{
20627c331a1SManfred Spraul	return ipcid_to_seqx(id) != ipcp->seq;
207023a5355SNadia Derbey}
208023a5355SNadia Derbey
2091ca7003aSDavidlohr Buesostatic inline void ipc_lock_object(struct kern_ipc_perm *perm)
210023a5355SNadia Derbey{
211023a5355SNadia Derbey	spin_lock(&perm->lock);
212023a5355SNadia Derbey}
213023a5355SNadia Derbey
2141ca7003aSDavidlohr Buesostatic inline void ipc_unlock_object(struct kern_ipc_perm *perm)
215023a5355SNadia Derbey{
216023a5355SNadia Derbey	spin_unlock(&perm->lock);
217023a5355SNadia Derbey}
218023a5355SNadia Derbey
2191ca7003aSDavidlohr Buesostatic inline void ipc_assert_locked_object(struct kern_ipc_perm *perm)
22016df3674SDavidlohr Bueso{
2211ca7003aSDavidlohr Bueso	assert_spin_locked(&perm->lock);
2221ca7003aSDavidlohr Bueso}
2231ca7003aSDavidlohr Bueso
2241ca7003aSDavidlohr Buesostatic inline void ipc_unlock(struct kern_ipc_perm *perm)
2251ca7003aSDavidlohr Bueso{
226cf9d5d78SDavidlohr Bueso	ipc_unlock_object(perm);
2271ca7003aSDavidlohr Bueso	rcu_read_unlock();
2281ca7003aSDavidlohr Bueso}
2291ca7003aSDavidlohr Bueso
2300f3d2b01SRafael Aquini/*
2310f3d2b01SRafael Aquini * ipc_valid_object() - helper to sort out IPC_RMID races for codepaths
2320f3d2b01SRafael Aquini * where the respective ipc_ids.rwsem is not being held down.
2330f3d2b01SRafael Aquini * Checks whether the ipc object is still around or if it's gone already, as
2340f3d2b01SRafael Aquini * ipc_rmid() may have already freed the ID while the ipc lock was spinning.
2350f3d2b01SRafael Aquini * Needs to be called with kern_ipc_perm.lock held -- exception made for one
2360f3d2b01SRafael Aquini * checkpoint case at sys_semtimedop() as noted in code commentary.
2370f3d2b01SRafael Aquini */
2380f3d2b01SRafael Aquinistatic inline bool ipc_valid_object(struct kern_ipc_perm *perm)
2390f3d2b01SRafael Aquini{
24072a8ff2fSRafael Aquini	return !perm->deleted;
2410f3d2b01SRafael Aquini}
2420f3d2b01SRafael Aquini
2434d2bff5eSDavidlohr Buesostruct kern_ipc_perm *ipc_obtain_object_check(struct ipc_ids *ids, int id);
244b2d75cddSPavel Emelyanovint ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
245eb66ec44SMathias Krause			const struct ipc_ops *ops, struct ipc_params *params);
246665c7741SAlexey Dobriyanvoid free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
247665c7741SAlexey Dobriyan		void (*free)(struct ipc_namespace *, struct kern_ipc_perm *));
248553f770eSAl Viro
2498c81ddd2SWaiman Longstatic inline int sem_check_semmni(struct ipc_namespace *ns) {
2508c81ddd2SWaiman Long	/*
2515ac893b8SWaiman Long	 * Check semmni range [0, ipc_mni]
2528c81ddd2SWaiman Long	 * semmni is the last element of sem_ctls[4] array
2538c81ddd2SWaiman Long	 */
2545ac893b8SWaiman Long	return ((ns->sem_ctls[3] < 0) || (ns->sem_ctls[3] > ipc_mni))
2558c81ddd2SWaiman Long		? -ERANGE : 0;
2568c81ddd2SWaiman Long}
2578c81ddd2SWaiman Long
258553f770eSAl Viro#ifdef CONFIG_COMPAT
259553f770eSAl Viro#include <linux/compat.h>
260553f770eSAl Virostruct compat_ipc_perm {
261553f770eSAl Viro	key_t key;
262553f770eSAl Viro	__compat_uid_t uid;
263553f770eSAl Viro	__compat_gid_t gid;
264553f770eSAl Viro	__compat_uid_t cuid;
265553f770eSAl Viro	__compat_gid_t cgid;
266553f770eSAl Viro	compat_mode_t mode;
267553f770eSAl Viro	unsigned short seq;
268553f770eSAl Viro};
269553f770eSAl Viro
270c0ebccb6SAl Virovoid to_compat_ipc_perm(struct compat_ipc_perm *, struct ipc64_perm *);
271c0ebccb6SAl Virovoid to_compat_ipc64_perm(struct compat_ipc64_perm *, struct ipc64_perm *);
272c0ebccb6SAl Viroint get_compat_ipc_perm(struct ipc64_perm *, struct compat_ipc_perm __user *);
273c0ebccb6SAl Viroint get_compat_ipc64_perm(struct ipc64_perm *,
274c0ebccb6SAl Viro			  struct compat_ipc64_perm __user *);
275c0ebccb6SAl Viro
276553f770eSAl Virostatic inline int compat_ipc_parse_version(int *cmd)
277553f770eSAl Viro{
278553f770eSAl Viro	int version = *cmd & IPC_64;
279553f770eSAl Viro	*cmd &= ~IPC_64;
280553f770eSAl Viro	return version;
281553f770eSAl Viro}
28241f4f0e2SDominik Brodowski
283275f2214SArnd Bergmannlong compat_ksys_old_semctl(int semid, int semnum, int cmd, int arg);
284275f2214SArnd Bergmannlong compat_ksys_old_msgctl(int msqid, int cmd, void __user *uptr);
285078faac9SDominik Brodowskilong compat_ksys_msgrcv(int msqid, compat_uptr_t msgp, compat_ssize_t msgsz,
286078faac9SDominik Brodowski			compat_long_t msgtyp, int msgflg);
28731c213f2SDominik Brodowskilong compat_ksys_msgsnd(int msqid, compat_uptr_t msgp,
28831c213f2SDominik Brodowski		       compat_ssize_t msgsz, int msgflg);
289275f2214SArnd Bergmannlong compat_ksys_old_shmctl(int shmid, int cmd, void __user *uptr);
290fb377eb8SArnd Bergmann
291fb377eb8SArnd Bergmann#endif
29241f4f0e2SDominik Brodowski
2931da177e4SLinus Torvalds#endif
294