1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/config.h>
14#include <linux/mm.h>
15#include <linux/shm.h>
16#include <linux/init.h>
17#include <linux/msg.h>
18#include <linux/smp_lock.h>
19#include <linux/vmalloc.h>
20#include <linux/slab.h>
21#include <linux/highuid.h>
22
23#if defined(CONFIG_SYSVIPC)
24
25#include "util.h"
26
27
28
29
30
31
32
33
34void __init ipc_init (void)
35{
36 sem_init();
37 msg_init();
38 shm_init();
39 return;
40}
41
42
43
44
45
46
47
48
49
50
51
52void __init ipc_init_ids(struct ipc_ids* ids, int size)
53{
54 int i;
55 sema_init(&ids->sem,1);
56
57 if(size > IPCMNI)
58 size = IPCMNI;
59 ids->size = size;
60 ids->in_use = 0;
61 ids->max_id = -1;
62 ids->seq = 0;
63 {
64 int seq_limit = INT_MAX/SEQ_MULTIPLIER;
65 if(seq_limit > USHRT_MAX)
66 ids->seq_max = USHRT_MAX;
67 else
68 ids->seq_max = seq_limit;
69 }
70
71 ids->entries = ipc_alloc(sizeof(struct ipc_id)*size);
72
73 if(ids->entries == NULL) {
74 printk(KERN_ERR "ipc_init_ids() failed, ipc service disabled.\n");
75 ids->size = 0;
76 }
77 ids->ary = SPIN_LOCK_UNLOCKED;
78 for(i=0;i<ids->size;i++)
79 ids->entries[i].p = NULL;
80}
81
82
83
84
85
86
87
88
89
90int ipc_findkey(struct ipc_ids* ids, key_t key)
91{
92 int id;
93 struct kern_ipc_perm* p;
94
95 for (id = 0; id <= ids->max_id; id++) {
96 p = ids->entries[id].p;
97 if(p==NULL)
98 continue;
99 if (key == p->key)
100 return id;
101 }
102 return -1;
103}
104
105static int grow_ary(struct ipc_ids* ids, int newsize)
106{
107 struct ipc_id* new;
108 struct ipc_id* old;
109 int i;
110
111 if(newsize > IPCMNI)
112 newsize = IPCMNI;
113 if(newsize <= ids->size)
114 return newsize;
115
116 new = ipc_alloc(sizeof(struct ipc_id)*newsize);
117 if(new == NULL)
118 return ids->size;
119 memcpy(new, ids->entries, sizeof(struct ipc_id)*ids->size);
120 for(i=ids->size;i<newsize;i++) {
121 new[i].p = NULL;
122 }
123 spin_lock(&ids->ary);
124
125 old = ids->entries;
126 ids->entries = new;
127 i = ids->size;
128 ids->size = newsize;
129 spin_unlock(&ids->ary);
130 ipc_free(old, sizeof(struct ipc_id)*i);
131 return ids->size;
132}
133
134
135
136
137
138
139
140
141
142
143
144
145
146int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
147{
148 int id;
149
150 size = grow_ary(ids,size);
151 for (id = 0; id < size; id++) {
152 if(ids->entries[id].p == NULL)
153 goto found;
154 }
155 return -1;
156found:
157 ids->in_use++;
158 if (id > ids->max_id)
159 ids->max_id = id;
160
161 new->cuid = new->uid = current->euid;
162 new->gid = new->cgid = current->egid;
163
164 new->seq = ids->seq++;
165 if(ids->seq > ids->seq_max)
166 ids->seq = 0;
167
168 spin_lock(&ids->ary);
169 ids->entries[id].p = new;
170 return id;
171}
172
173
174
175
176
177
178
179
180
181
182
183
184struct kern_ipc_perm* ipc_rmid(struct ipc_ids* ids, int id)
185{
186 struct kern_ipc_perm* p;
187 int lid = id % SEQ_MULTIPLIER;
188 if(lid >= ids->size)
189 BUG();
190 p = ids->entries[lid].p;
191 ids->entries[lid].p = NULL;
192 if(p==NULL)
193 BUG();
194 ids->in_use--;
195
196 if (lid == ids->max_id) {
197 do {
198 lid--;
199 if(lid == -1)
200 break;
201 } while (ids->entries[lid].p == NULL);
202 ids->max_id = lid;
203 }
204 return p;
205}
206
207
208
209
210
211
212
213
214
215void* ipc_alloc(int size)
216{
217 void* out;
218 if(size > PAGE_SIZE)
219 out = vmalloc(size);
220 else
221 out = kmalloc(size, GFP_KERNEL);
222 return out;
223}
224
225
226
227
228
229
230
231
232
233
234void ipc_free(void* ptr, int size)
235{
236 if(size > PAGE_SIZE)
237 vfree(ptr);
238 else
239 kfree(ptr);
240}
241
242
243
244
245
246
247
248
249
250
251int ipcperms (struct kern_ipc_perm *ipcp, short flag)
252{
253 int requested_mode, granted_mode;
254
255 requested_mode = (flag >> 6) | (flag >> 3) | flag;
256 granted_mode = ipcp->mode;
257 if (current->euid == ipcp->cuid || current->euid == ipcp->uid)
258 granted_mode >>= 6;
259 else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))
260 granted_mode >>= 3;
261
262 if ((requested_mode & ~granted_mode & 0007) &&
263 !capable(CAP_IPC_OWNER))
264 return -1;
265
266 return 0;
267}
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out)
285{
286 out->key = in->key;
287 out->uid = in->uid;
288 out->gid = in->gid;
289 out->cuid = in->cuid;
290 out->cgid = in->cgid;
291 out->mode = in->mode;
292 out->seq = in->seq;
293}
294
295
296
297
298
299
300
301
302
303
304void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out)
305{
306 out->key = in->key;
307 out->uid = NEW_TO_OLD_UID(in->uid);
308 out->gid = NEW_TO_OLD_GID(in->gid);
309 out->cuid = NEW_TO_OLD_UID(in->cuid);
310 out->cgid = NEW_TO_OLD_GID(in->cgid);
311 out->mode = in->mode;
312 out->seq = in->seq;
313}
314
315#if !defined(__ia64__) && !defined(__hppa__)
316
317
318
319
320
321
322
323
324
325
326int ipc_parse_version (int *cmd)
327{
328#ifdef __x86_64__
329 if (!(current->thread.flags & THREAD_IA32))
330 return IPC_64;
331#endif
332 if (*cmd & IPC_64) {
333 *cmd ^= IPC_64;
334 return IPC_64;
335 } else {
336 return IPC_OLD;
337 }
338}
339
340#endif
341
342#else
343
344
345
346
347void sem_exit (void)
348{
349 return;
350}
351
352asmlinkage long sys_semget (key_t key, int nsems, int semflg)
353{
354 return -ENOSYS;
355}
356
357asmlinkage long sys_semop (int semid, struct sembuf *sops, unsigned nsops)
358{
359 return -ENOSYS;
360}
361
362asmlinkage long sys_semtimedop(int semid, struct sembuf *sops, unsigned nsops,
363 const struct timespec *timeout)
364{
365 return -ENOSYS;
366}
367
368asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
369{
370 return -ENOSYS;
371}
372
373asmlinkage long sys_msgget (key_t key, int msgflg)
374{
375 return -ENOSYS;
376}
377
378asmlinkage long sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
379{
380 return -ENOSYS;
381}
382
383asmlinkage long sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp,
384 int msgflg)
385{
386 return -ENOSYS;
387}
388
389asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
390{
391 return -ENOSYS;
392}
393
394asmlinkage long sys_shmget (key_t key, size_t size, int shmflag)
395{
396 return -ENOSYS;
397}
398
399asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *addr)
400{
401 return -ENOSYS;
402}
403
404asmlinkage long sys_shmdt (char *shmaddr)
405{
406 return -ENOSYS;
407}
408
409asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
410{
411 return -ENOSYS;
412}
413
414#endif
415