1
2
3
4
5
6
7
8
9
10
11#ifndef _IPC_UTIL_H
12#define _IPC_UTIL_H
13
14#include <linux/unistd.h>
15#include <linux/err.h>
16#include <linux/ipc_namespace.h>
17
18
19
20
21
22
23
24
25
26
27
28#define IPCMNI_SHIFT 15
29#define IPCMNI_EXTEND_SHIFT 24
30#define IPCMNI_EXTEND_MIN_CYCLE (RADIX_TREE_MAP_SIZE * RADIX_TREE_MAP_SIZE)
31#define IPCMNI (1 << IPCMNI_SHIFT)
32#define IPCMNI_EXTEND (1 << IPCMNI_EXTEND_SHIFT)
33
34#ifdef CONFIG_SYSVIPC_SYSCTL
35extern int ipc_mni;
36extern int ipc_mni_shift;
37extern int ipc_min_cycle;
38
39#define ipcmni_seq_shift() ipc_mni_shift
40#define IPCMNI_IDX_MASK ((1 << ipc_mni_shift) - 1)
41
42#else
43
44#define ipc_mni IPCMNI
45#define ipc_min_cycle ((int)RADIX_TREE_MAP_SIZE)
46#define ipcmni_seq_shift() IPCMNI_SHIFT
47#define IPCMNI_IDX_MASK ((1 << IPCMNI_SHIFT) - 1)
48#endif
49
50void sem_init(void);
51void msg_init(void);
52void shm_init(void);
53
54struct ipc_namespace;
55struct pid_namespace;
56
57#ifdef CONFIG_POSIX_MQUEUE
58extern void mq_clear_sbinfo(struct ipc_namespace *ns);
59extern void mq_put_mnt(struct ipc_namespace *ns);
60#else
61static inline void mq_clear_sbinfo(struct ipc_namespace *ns) { }
62static inline void mq_put_mnt(struct ipc_namespace *ns) { }
63#endif
64
65#ifdef CONFIG_SYSVIPC
66void sem_init_ns(struct ipc_namespace *ns);
67void msg_init_ns(struct ipc_namespace *ns);
68void shm_init_ns(struct ipc_namespace *ns);
69
70void sem_exit_ns(struct ipc_namespace *ns);
71void msg_exit_ns(struct ipc_namespace *ns);
72void shm_exit_ns(struct ipc_namespace *ns);
73#else
74static inline void sem_init_ns(struct ipc_namespace *ns) { }
75static inline void msg_init_ns(struct ipc_namespace *ns) { }
76static inline void shm_init_ns(struct ipc_namespace *ns) { }
77
78static inline void sem_exit_ns(struct ipc_namespace *ns) { }
79static inline void msg_exit_ns(struct ipc_namespace *ns) { }
80static inline void shm_exit_ns(struct ipc_namespace *ns) { }
81#endif
82
83
84
85
86
87struct ipc_params {
88 key_t key;
89 int flg;
90 union {
91 size_t size;
92 int nsems;
93 } u;
94};
95
96
97
98
99
100
101
102
103
104
105
106struct ipc_ops {
107 int (*getnew)(struct ipc_namespace *, struct ipc_params *);
108 int (*associate)(struct kern_ipc_perm *, int);
109 int (*more_checks)(struct kern_ipc_perm *, struct ipc_params *);
110};
111
112struct seq_file;
113struct ipc_ids;
114
115void ipc_init_ids(struct ipc_ids *ids);
116#ifdef CONFIG_PROC_FS
117void __init ipc_init_proc_interface(const char *path, const char *header,
118 int ids, int (*show)(struct seq_file *, void *));
119struct pid_namespace *ipc_seq_pid_ns(struct seq_file *);
120#else
121#define ipc_init_proc_interface(path, header, ids, show) do {} while (0)
122#endif
123
124#define IPC_SEM_IDS 0
125#define IPC_MSG_IDS 1
126#define IPC_SHM_IDS 2
127
128#define ipcid_to_idx(id) ((id) & IPCMNI_IDX_MASK)
129#define ipcid_to_seqx(id) ((id) >> ipcmni_seq_shift())
130#define ipcid_seq_max() (INT_MAX >> ipcmni_seq_shift())
131
132
133int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int);
134
135
136void ipc_rmid(struct ipc_ids *, struct kern_ipc_perm *);
137
138
139void ipc_set_key_private(struct ipc_ids *, struct kern_ipc_perm *);
140
141
142int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flg);
143
144
145
146
147
148
149
150static inline int ipc_get_maxidx(struct ipc_ids *ids)
151{
152 if (ids->in_use == 0)
153 return -1;
154
155 if (ids->in_use == ipc_mni)
156 return ipc_mni - 1;
157
158 return ids->max_idx;
159}
160
161
162
163
164
165
166
167
168
169
170bool ipc_rcu_getref(struct kern_ipc_perm *ptr);
171void ipc_rcu_putref(struct kern_ipc_perm *ptr,
172 void (*func)(struct rcu_head *head));
173
174struct kern_ipc_perm *ipc_obtain_object_idr(struct ipc_ids *ids, int id);
175
176void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
177void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
178int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out);
179struct kern_ipc_perm *ipcctl_obtain_check(struct ipc_namespace *ns,
180 struct ipc_ids *ids, int id, int cmd,
181 struct ipc64_perm *perm, int extra_perm);
182
183static inline void ipc_update_pid(struct pid **pos, struct pid *pid)
184{
185 struct pid *old = *pos;
186 if (old != pid) {
187 *pos = get_pid(pid);
188 put_pid(old);
189 }
190}
191
192#ifndef CONFIG_ARCH_WANT_IPC_PARSE_VERSION
193
194# define ipc_parse_version(cmd) IPC_64
195#else
196int ipc_parse_version(int *cmd);
197#endif
198
199extern void free_msg(struct msg_msg *msg);
200extern struct msg_msg *load_msg(const void __user *src, size_t len);
201extern struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst);
202extern int store_msg(void __user *dest, struct msg_msg *msg, size_t len);
203
204static inline int ipc_checkid(struct kern_ipc_perm *ipcp, int id)
205{
206 return ipcid_to_seqx(id) != ipcp->seq;
207}
208
209static inline void ipc_lock_object(struct kern_ipc_perm *perm)
210{
211 spin_lock(&perm->lock);
212}
213
214static inline void ipc_unlock_object(struct kern_ipc_perm *perm)
215{
216 spin_unlock(&perm->lock);
217}
218
219static inline void ipc_assert_locked_object(struct kern_ipc_perm *perm)
220{
221 assert_spin_locked(&perm->lock);
222}
223
224static inline void ipc_unlock(struct kern_ipc_perm *perm)
225{
226 ipc_unlock_object(perm);
227 rcu_read_unlock();
228}
229
230
231
232
233
234
235
236
237
238static inline bool ipc_valid_object(struct kern_ipc_perm *perm)
239{
240 return !perm->deleted;
241}
242
243struct kern_ipc_perm *ipc_obtain_object_check(struct ipc_ids *ids, int id);
244int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
245 const struct ipc_ops *ops, struct ipc_params *params);
246void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
247 void (*free)(struct ipc_namespace *, struct kern_ipc_perm *));
248
249static inline int sem_check_semmni(struct ipc_namespace *ns) {
250
251
252
253
254 return ((ns->sem_ctls[3] < 0) || (ns->sem_ctls[3] > ipc_mni))
255 ? -ERANGE : 0;
256}
257
258#ifdef CONFIG_COMPAT
259#include <linux/compat.h>
260struct compat_ipc_perm {
261 key_t key;
262 __compat_uid_t uid;
263 __compat_gid_t gid;
264 __compat_uid_t cuid;
265 __compat_gid_t cgid;
266 compat_mode_t mode;
267 unsigned short seq;
268};
269
270void to_compat_ipc_perm(struct compat_ipc_perm *, struct ipc64_perm *);
271void to_compat_ipc64_perm(struct compat_ipc64_perm *, struct ipc64_perm *);
272int get_compat_ipc_perm(struct ipc64_perm *, struct compat_ipc_perm __user *);
273int get_compat_ipc64_perm(struct ipc64_perm *,
274 struct compat_ipc64_perm __user *);
275
276static inline int compat_ipc_parse_version(int *cmd)
277{
278#ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION
279 int version = *cmd & IPC_64;
280 *cmd &= ~IPC_64;
281 return version;
282#else
283 return IPC_64;
284#endif
285}
286#endif
287
288
289long ksys_semtimedop(int semid, struct sembuf __user *tsops,
290 unsigned int nsops,
291 const struct __kernel_timespec __user *timeout);
292long ksys_semget(key_t key, int nsems, int semflg);
293long ksys_semctl(int semid, int semnum, int cmd, unsigned long arg);
294long ksys_msgget(key_t key, int msgflg);
295long ksys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf);
296long ksys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz,
297 long msgtyp, int msgflg);
298long ksys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz,
299 int msgflg);
300long ksys_shmget(key_t key, size_t size, int shmflg);
301long ksys_shmdt(char __user *shmaddr);
302long ksys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf);
303
304
305long compat_ksys_semtimedop(int semid, struct sembuf __user *tsems,
306 unsigned int nsops,
307 const struct compat_timespec __user *timeout);
308#ifdef CONFIG_COMPAT
309long compat_ksys_semctl(int semid, int semnum, int cmd, int arg);
310long compat_ksys_msgctl(int msqid, int cmd, void __user *uptr);
311long compat_ksys_msgrcv(int msqid, compat_uptr_t msgp, compat_ssize_t msgsz,
312 compat_long_t msgtyp, int msgflg);
313long compat_ksys_msgsnd(int msqid, compat_uptr_t msgp,
314 compat_ssize_t msgsz, int msgflg);
315long compat_ksys_shmctl(int shmid, int cmd, void __user *uptr);
316#endif
317
318#endif
319