Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/ipc/util.h
26131 views
1
/* SPDX-License-Identifier: GPL-2.0 */
2
/*
3
* linux/ipc/util.h
4
* Copyright (C) 1999 Christoph Rohland
5
*
6
* ipc helper functions (c) 1999 Manfred Spraul <[email protected]>
7
* namespaces support. 2006 OpenVZ, SWsoft Inc.
8
* Pavel Emelianov <[email protected]>
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
#include <linux/pid.h>
18
19
/*
20
* The IPC ID contains 2 separate numbers - index and sequence number.
21
* By default,
22
* bits 0-14: index (32k, 15 bits)
23
* bits 15-30: sequence number (64k, 16 bits)
24
*
25
* When IPCMNI extension mode is turned on, the composition changes:
26
* bits 0-23: index (16M, 24 bits)
27
* bits 24-30: sequence number (128, 7 bits)
28
*/
29
#define IPCMNI_SHIFT 15
30
#define IPCMNI_EXTEND_SHIFT 24
31
#define IPCMNI_EXTEND_MIN_CYCLE (RADIX_TREE_MAP_SIZE * RADIX_TREE_MAP_SIZE)
32
#define IPCMNI (1 << IPCMNI_SHIFT)
33
#define IPCMNI_EXTEND (1 << IPCMNI_EXTEND_SHIFT)
34
35
#ifdef CONFIG_SYSVIPC_SYSCTL
36
extern int ipc_mni;
37
extern int ipc_mni_shift;
38
extern int ipc_min_cycle;
39
40
#define ipcmni_seq_shift() ipc_mni_shift
41
#define IPCMNI_IDX_MASK ((1 << ipc_mni_shift) - 1)
42
43
#else /* CONFIG_SYSVIPC_SYSCTL */
44
45
#define ipc_mni IPCMNI
46
#define ipc_min_cycle ((int)RADIX_TREE_MAP_SIZE)
47
#define ipcmni_seq_shift() IPCMNI_SHIFT
48
#define IPCMNI_IDX_MASK ((1 << IPCMNI_SHIFT) - 1)
49
#endif /* CONFIG_SYSVIPC_SYSCTL */
50
51
void sem_init(void);
52
void msg_init(void);
53
void shm_init(void);
54
55
struct ipc_namespace;
56
struct pid_namespace;
57
58
#ifdef CONFIG_POSIX_MQUEUE
59
extern void mq_clear_sbinfo(struct ipc_namespace *ns);
60
#else
61
static inline void mq_clear_sbinfo(struct ipc_namespace *ns) { }
62
#endif
63
64
#ifdef CONFIG_SYSVIPC
65
void sem_init_ns(struct ipc_namespace *ns);
66
int msg_init_ns(struct ipc_namespace *ns);
67
void shm_init_ns(struct ipc_namespace *ns);
68
69
void sem_exit_ns(struct ipc_namespace *ns);
70
void msg_exit_ns(struct ipc_namespace *ns);
71
void shm_exit_ns(struct ipc_namespace *ns);
72
#else
73
static inline void sem_init_ns(struct ipc_namespace *ns) { }
74
static inline int msg_init_ns(struct ipc_namespace *ns) { return 0; }
75
static inline void shm_init_ns(struct ipc_namespace *ns) { }
76
77
static inline void sem_exit_ns(struct ipc_namespace *ns) { }
78
static inline void msg_exit_ns(struct ipc_namespace *ns) { }
79
static inline void shm_exit_ns(struct ipc_namespace *ns) { }
80
#endif
81
82
/*
83
* Structure that holds the parameters needed by the ipc operations
84
* (see after)
85
*/
86
struct ipc_params {
87
key_t key;
88
int flg;
89
union {
90
size_t size; /* for shared memories */
91
int nsems; /* for semaphores */
92
} u; /* holds the getnew() specific param */
93
};
94
95
/*
96
* Structure that holds some ipc operations. This structure is used to unify
97
* the calls to sys_msgget(), sys_semget(), sys_shmget()
98
* . routine to call to create a new ipc object. Can be one of newque,
99
* newary, newseg
100
* . routine to call to check permissions for a new ipc object.
101
* Can be one of security_msg_associate, security_sem_associate,
102
* security_shm_associate
103
* . routine to call for an extra check if needed
104
*/
105
struct ipc_ops {
106
int (*getnew)(struct ipc_namespace *, struct ipc_params *);
107
int (*associate)(struct kern_ipc_perm *, int);
108
int (*more_checks)(struct kern_ipc_perm *, struct ipc_params *);
109
};
110
111
struct seq_file;
112
struct ipc_ids;
113
114
void ipc_init_ids(struct ipc_ids *ids);
115
#ifdef CONFIG_PROC_FS
116
void __init ipc_init_proc_interface(const char *path, const char *header,
117
int ids, int (*show)(struct seq_file *, void *));
118
struct pid_namespace *ipc_seq_pid_ns(struct seq_file *);
119
#else
120
#define ipc_init_proc_interface(path, header, ids, show) do {} while (0)
121
#endif
122
123
#define IPC_SEM_IDS 0
124
#define IPC_MSG_IDS 1
125
#define IPC_SHM_IDS 2
126
127
#define ipcid_to_idx(id) ((id) & IPCMNI_IDX_MASK)
128
#define ipcid_to_seqx(id) ((id) >> ipcmni_seq_shift())
129
#define ipcid_seq_max() (INT_MAX >> ipcmni_seq_shift())
130
131
/* must be called with ids->rwsem acquired for writing */
132
int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int);
133
134
/* must be called with both locks acquired. */
135
void ipc_rmid(struct ipc_ids *, struct kern_ipc_perm *);
136
137
/* must be called with both locks acquired. */
138
void ipc_set_key_private(struct ipc_ids *, struct kern_ipc_perm *);
139
140
/* must be called with ipcp locked */
141
int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flg);
142
143
/**
144
* ipc_get_maxidx - get the highest assigned index
145
* @ids: ipc identifier set
146
*
147
* The function returns the highest assigned index for @ids. The function
148
* doesn't scan the idr tree, it uses a cached value.
149
*
150
* Called with ipc_ids.rwsem held for reading.
151
*/
152
static inline int ipc_get_maxidx(struct ipc_ids *ids)
153
{
154
if (ids->in_use == 0)
155
return -1;
156
157
if (ids->in_use == ipc_mni)
158
return ipc_mni - 1;
159
160
return ids->max_idx;
161
}
162
163
/*
164
* For allocation that need to be freed by RCU.
165
* Objects are reference counted, they start with reference count 1.
166
* getref increases the refcount, the putref call that reduces the recount
167
* to 0 schedules the rcu destruction. Caller must guarantee locking.
168
*
169
* refcount is initialized by ipc_addid(), before that point call_rcu()
170
* must be used.
171
*/
172
bool ipc_rcu_getref(struct kern_ipc_perm *ptr);
173
void ipc_rcu_putref(struct kern_ipc_perm *ptr,
174
void (*func)(struct rcu_head *head));
175
176
struct kern_ipc_perm *ipc_obtain_object_idr(struct ipc_ids *ids, int id);
177
178
void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
179
void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
180
int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out);
181
struct kern_ipc_perm *ipcctl_obtain_check(struct ipc_namespace *ns,
182
struct ipc_ids *ids, int id, int cmd,
183
struct ipc64_perm *perm, int extra_perm);
184
185
static inline void ipc_update_pid(struct pid **pos, struct pid *pid)
186
{
187
struct pid *old = *pos;
188
if (old != pid) {
189
*pos = get_pid(pid);
190
put_pid(old);
191
}
192
}
193
194
#ifdef CONFIG_ARCH_WANT_IPC_PARSE_VERSION
195
int ipc_parse_version(int *cmd);
196
#endif
197
198
extern void free_msg(struct msg_msg *msg);
199
extern struct msg_msg *load_msg(const void __user *src, size_t len);
200
extern struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst);
201
extern int store_msg(void __user *dest, struct msg_msg *msg, size_t len);
202
203
static inline int ipc_checkid(struct kern_ipc_perm *ipcp, int id)
204
{
205
return ipcid_to_seqx(id) != ipcp->seq;
206
}
207
208
static inline void ipc_lock_object(struct kern_ipc_perm *perm)
209
{
210
spin_lock(&perm->lock);
211
}
212
213
static inline void ipc_unlock_object(struct kern_ipc_perm *perm)
214
{
215
spin_unlock(&perm->lock);
216
}
217
218
static inline void ipc_assert_locked_object(struct kern_ipc_perm *perm)
219
{
220
assert_spin_locked(&perm->lock);
221
}
222
223
static inline void ipc_unlock(struct kern_ipc_perm *perm)
224
{
225
ipc_unlock_object(perm);
226
rcu_read_unlock();
227
}
228
229
/*
230
* ipc_valid_object() - helper to sort out IPC_RMID races for codepaths
231
* where the respective ipc_ids.rwsem is not being held down.
232
* Checks whether the ipc object is still around or if it's gone already, as
233
* ipc_rmid() may have already freed the ID while the ipc lock was spinning.
234
* Needs to be called with kern_ipc_perm.lock held -- exception made for one
235
* checkpoint case at sys_semtimedop() as noted in code commentary.
236
*/
237
static inline bool ipc_valid_object(struct kern_ipc_perm *perm)
238
{
239
return !perm->deleted;
240
}
241
242
struct kern_ipc_perm *ipc_obtain_object_check(struct ipc_ids *ids, int id);
243
int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
244
const struct ipc_ops *ops, struct ipc_params *params);
245
void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
246
void (*free)(struct ipc_namespace *, struct kern_ipc_perm *));
247
248
static inline int sem_check_semmni(struct ipc_namespace *ns) {
249
/*
250
* Check semmni range [0, ipc_mni]
251
* semmni is the last element of sem_ctls[4] array
252
*/
253
return ((ns->sem_ctls[3] < 0) || (ns->sem_ctls[3] > ipc_mni))
254
? -ERANGE : 0;
255
}
256
257
#ifdef CONFIG_COMPAT
258
#include <linux/compat.h>
259
struct compat_ipc_perm {
260
key_t key;
261
__compat_uid_t uid;
262
__compat_gid_t gid;
263
__compat_uid_t cuid;
264
__compat_gid_t cgid;
265
compat_mode_t mode;
266
unsigned short seq;
267
};
268
269
void to_compat_ipc_perm(struct compat_ipc_perm *, struct ipc64_perm *);
270
void to_compat_ipc64_perm(struct compat_ipc64_perm *, struct ipc64_perm *);
271
int get_compat_ipc_perm(struct ipc64_perm *, struct compat_ipc_perm __user *);
272
int get_compat_ipc64_perm(struct ipc64_perm *,
273
struct compat_ipc64_perm __user *);
274
275
static inline int compat_ipc_parse_version(int *cmd)
276
{
277
int version = *cmd & IPC_64;
278
*cmd &= ~IPC_64;
279
return version;
280
}
281
282
long compat_ksys_old_semctl(int semid, int semnum, int cmd, int arg);
283
long compat_ksys_old_msgctl(int msqid, int cmd, void __user *uptr);
284
long compat_ksys_msgrcv(int msqid, compat_uptr_t msgp, compat_ssize_t msgsz,
285
compat_long_t msgtyp, int msgflg);
286
long compat_ksys_msgsnd(int msqid, compat_uptr_t msgp,
287
compat_ssize_t msgsz, int msgflg);
288
long compat_ksys_old_shmctl(int shmid, int cmd, void __user *uptr);
289
290
#endif
291
292
#endif
293
294