This source file includes following definitions.
- msg_init
- real_msgsnd
- real_msgrcv
- sys_msgsnd
- sys_msgrcv
- findkey
- newque
- sys_msgget
- freeque
- sys_msgctl
- kerneld_exit
- kerneld_send
1
2
3
4
5
6
7
8
9 #include <linux/config.h>
10 #include <linux/errno.h>
11 #include <linux/sched.h>
12 #include <linux/msg.h>
13 #include <linux/stat.h>
14 #include <linux/malloc.h>
15 #include <linux/kerneld.h>
16
17 #include <asm/segment.h>
18
19 extern int ipcperms (struct ipc_perm *ipcp, short msgflg);
20
21 static void freeque (int id);
22 static int newque (key_t key, int msgflg);
23 static int findkey (key_t key);
24
25 static struct msqid_ds *msgque[MSGMNI];
26 static int msgbytes = 0;
27 static int msghdrs = 0;
28 static unsigned short msg_seq = 0;
29 static int used_queues = 0;
30 static int max_msqid = 0;
31 static struct wait_queue *msg_lock = NULL;
32 static int kerneld_msqid = -1;
33 static int kerneld_pid;
34
35 void msg_init (void)
36 {
37 int id;
38
39 for (id = 0; id < MSGMNI; id++)
40 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
41 msgbytes = msghdrs = msg_seq = max_msqid = used_queues = 0;
42 msg_lock = NULL;
43 return;
44 }
45
46 static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
47 {
48 int id, err;
49 struct msqid_ds *msq;
50 struct ipc_perm *ipcp;
51 struct msg *msgh;
52 long mtype;
53
54 if (msgsz > MSGMAX || (long) msgsz < 0 || msqid < 0)
55 return -EINVAL;
56 if (!msgp)
57 return -EFAULT;
58
59
60
61
62 if ((msgflg & IPC_KERNELD))
63 mtype = msgp->mtype;
64 else {
65 err = verify_area (VERIFY_READ, msgp->mtext, msgsz);
66 if (err)
67 return err;
68 if ((mtype = get_user (&msgp->mtype)) < 1)
69 return -EINVAL;
70 }
71 id = (unsigned int) msqid % MSGMNI;
72 msq = msgque [id];
73 if (msq == IPC_UNUSED || msq == IPC_NOID)
74 return -EINVAL;
75 ipcp = &msq->msg_perm;
76
77 slept:
78 if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
79 return -EIDRM;
80
81
82
83
84
85 if ((msgflg & IPC_KERNELD) == 0)
86 if (ipcperms(ipcp, S_IWUGO))
87 return -EACCES;
88
89 if (msgsz + msq->msg_cbytes > msq->msg_qbytes) {
90
91 if (msgflg & IPC_NOWAIT)
92 return -EAGAIN;
93 if (current->signal & ~current->blocked)
94 return -EINTR;
95 if (intr_count) {
96
97 printk("Ouch, kerneld:msgsnd wants to sleep at interrupt!\n");
98 return -EINTR;
99 }
100 interruptible_sleep_on (&msq->wwait);
101 goto slept;
102 }
103
104
105 msgh = (struct msg *) kmalloc (sizeof(*msgh) + msgsz,
106 (intr_count ? GFP_ATOMIC : GFP_USER));
107 if (!msgh)
108 return -ENOMEM;
109 msgh->msg_spot = (char *) (msgh + 1);
110
111
112
113
114
115 if (msgflg & IPC_KERNELD) {
116 struct kerneld_msg *kdmp = (struct kerneld_msg *)msgp;
117
118
119
120
121
122 memcpy(msgh->msg_spot, (char *)(&(kdmp->id)), sizeof(long));
123 memcpy(msgh->msg_spot + sizeof(long), kdmp->text,
124 msgsz - sizeof(long));
125 }
126 else
127 memcpy_fromfs (msgh->msg_spot, msgp->mtext, msgsz);
128
129 if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID
130 || msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
131 kfree(msgh);
132 return -EIDRM;
133 }
134
135 msgh->msg_next = NULL;
136 if (!msq->msg_first)
137 msq->msg_first = msq->msg_last = msgh;
138 else {
139 msq->msg_last->msg_next = msgh;
140 msq->msg_last = msgh;
141 }
142 msgh->msg_ts = msgsz;
143 msgh->msg_type = mtype;
144 msq->msg_cbytes += msgsz;
145 msgbytes += msgsz;
146 msghdrs++;
147 msq->msg_qnum++;
148 msq->msg_lspid = current->pid;
149 msq->msg_stime = CURRENT_TIME;
150 if (msq->rwait)
151 wake_up (&msq->rwait);
152 return 0;
153 }
154
155 static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg)
156 {
157 struct msqid_ds *msq;
158 struct ipc_perm *ipcp;
159 struct msg *tmsg, *leastp = NULL;
160 struct msg *nmsg = NULL;
161 int id, err;
162
163 if (msqid < 0 || (long) msgsz < 0)
164 return -EINVAL;
165 if (!msgp || !msgp->mtext)
166 return -EFAULT;
167
168
169
170
171 if ((msgflg & IPC_KERNELD) == 0) {
172 err = verify_area (VERIFY_WRITE, msgp->mtext, msgsz);
173 if (err)
174 return err;
175 }
176
177 id = (unsigned int) msqid % MSGMNI;
178 msq = msgque [id];
179 if (msq == IPC_NOID || msq == IPC_UNUSED)
180 return -EINVAL;
181 ipcp = &msq->msg_perm;
182
183
184
185
186
187
188
189 while (!nmsg) {
190 if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
191 return -EIDRM;
192 if ((msgflg & IPC_KERNELD) == 0)
193
194
195
196
197
198 if (ipcperms (ipcp, S_IRUGO))
199 return -EACCES;
200 if (msgtyp == 0)
201 nmsg = msq->msg_first;
202 else if (msgtyp > 0) {
203 if (msgflg & MSG_EXCEPT) {
204 for (tmsg = msq->msg_first; tmsg;
205 tmsg = tmsg->msg_next)
206 if (tmsg->msg_type != msgtyp)
207 break;
208 nmsg = tmsg;
209 } else {
210 for (tmsg = msq->msg_first; tmsg;
211 tmsg = tmsg->msg_next)
212 if (tmsg->msg_type == msgtyp)
213 break;
214 nmsg = tmsg;
215 }
216 } else {
217 for (leastp = tmsg = msq->msg_first; tmsg;
218 tmsg = tmsg->msg_next)
219 if (tmsg->msg_type < leastp->msg_type)
220 leastp = tmsg;
221 if (leastp && leastp->msg_type <= - msgtyp)
222 nmsg = leastp;
223 }
224
225 if (nmsg) {
226 if ((msgsz < nmsg->msg_ts) && !(msgflg & MSG_NOERROR))
227 return -E2BIG;
228 msgsz = (msgsz > nmsg->msg_ts)? nmsg->msg_ts : msgsz;
229 if (nmsg == msq->msg_first)
230 msq->msg_first = nmsg->msg_next;
231 else {
232 for (tmsg = msq->msg_first; tmsg;
233 tmsg = tmsg->msg_next)
234 if (tmsg->msg_next == nmsg)
235 break;
236 tmsg->msg_next = nmsg->msg_next;
237 if (nmsg == msq->msg_last)
238 msq->msg_last = tmsg;
239 }
240 if (!(--msq->msg_qnum))
241 msq->msg_last = msq->msg_first = NULL;
242
243 msq->msg_rtime = CURRENT_TIME;
244 msq->msg_lrpid = current->pid;
245 msgbytes -= nmsg->msg_ts;
246 msghdrs--;
247 msq->msg_cbytes -= nmsg->msg_ts;
248 if (msq->wwait)
249 wake_up (&msq->wwait);
250
251
252
253
254 if (msgflg & IPC_KERNELD) {
255 struct kerneld_msg *kdmp = (struct kerneld_msg *) msgp;
256
257 memcpy((char *)(&(kdmp->id)),
258 nmsg->msg_spot,
259 sizeof(long));
260
261
262
263
264 if ((msgsz > sizeof(long)) && kdmp->text)
265 memcpy(kdmp->text,
266 nmsg->msg_spot + sizeof(long),
267 msgsz - sizeof(long));
268 }
269 else {
270 put_user (nmsg->msg_type, &msgp->mtype);
271 memcpy_tofs (msgp->mtext, nmsg->msg_spot, msgsz);
272 }
273 kfree(nmsg);
274 return msgsz;
275 } else {
276 if (msgflg & IPC_NOWAIT)
277 return -ENOMSG;
278 if (current->signal & ~current->blocked)
279 return -EINTR;
280 if (intr_count) {
281
282 printk("Ouch, kerneld:msgrcv wants to sleep at interrupt!\n");
283 return -EINTR;
284 }
285 interruptible_sleep_on (&msq->rwait);
286 }
287 }
288 return -1;
289 }
290
291 asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
292 {
293
294 return real_msgsnd(msqid, msgp, msgsz, msgflg & ~IPC_KERNELD);
295 }
296
297 asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,
298 long msgtyp, int msgflg)
299 {
300
301 return real_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg & ~IPC_KERNELD);
302 }
303
304 static int findkey (key_t key)
305 {
306 int id;
307 struct msqid_ds *msq;
308
309 for (id = 0; id <= max_msqid; id++) {
310 while ((msq = msgque[id]) == IPC_NOID)
311 interruptible_sleep_on (&msg_lock);
312 if (msq == IPC_UNUSED)
313 continue;
314 if (key == msq->msg_perm.key)
315 return id;
316 }
317 return -1;
318 }
319
320 static int newque (key_t key, int msgflg)
321 {
322 int id;
323 struct msqid_ds *msq;
324 struct ipc_perm *ipcp;
325
326 for (id = 0; id < MSGMNI; id++)
327 if (msgque[id] == IPC_UNUSED) {
328 msgque[id] = (struct msqid_ds *) IPC_NOID;
329 goto found;
330 }
331 return -ENOSPC;
332
333 found:
334 msq = (struct msqid_ds *) kmalloc (sizeof (*msq), GFP_KERNEL);
335 if (!msq) {
336 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
337 if (msg_lock)
338 wake_up (&msg_lock);
339 return -ENOMEM;
340 }
341 ipcp = &msq->msg_perm;
342 ipcp->mode = (msgflg & S_IRWXUGO);
343 ipcp->key = key;
344 ipcp->cuid = ipcp->uid = current->euid;
345 ipcp->gid = ipcp->cgid = current->egid;
346 msq->msg_perm.seq = msg_seq;
347 msq->msg_first = msq->msg_last = NULL;
348 msq->rwait = msq->wwait = NULL;
349 msq->msg_cbytes = msq->msg_qnum = 0;
350 msq->msg_lspid = msq->msg_lrpid = 0;
351 msq->msg_stime = msq->msg_rtime = 0;
352 msq->msg_qbytes = MSGMNB;
353 msq->msg_ctime = CURRENT_TIME;
354 if (id > max_msqid)
355 max_msqid = id;
356 msgque[id] = msq;
357 used_queues++;
358 if (msg_lock)
359 wake_up (&msg_lock);
360 return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
361 }
362
363 asmlinkage int sys_msgget (key_t key, int msgflg)
364 {
365 int id;
366 struct msqid_ds *msq;
367
368
369
370
371
372 if ((msgflg & IPC_KERNELD)) {
373 if (!suser())
374 return -EPERM;
375 if ((kerneld_msqid == -1) && (kerneld_msqid =
376 newque(IPC_PRIVATE, msgflg & S_IRWXU)) >= 0)
377 kerneld_pid = current->pid;
378 return kerneld_msqid;
379 }
380
381 if (key == IPC_PRIVATE)
382 return newque(key, msgflg);
383 if ((id = findkey (key)) == -1) {
384 if (!(msgflg & IPC_CREAT))
385 return -ENOENT;
386 return newque(key, msgflg);
387 }
388 if (msgflg & IPC_CREAT && msgflg & IPC_EXCL)
389 return -EEXIST;
390 msq = msgque[id];
391 if (msq == IPC_UNUSED || msq == IPC_NOID)
392 return -EIDRM;
393 if (ipcperms(&msq->msg_perm, msgflg))
394 return -EACCES;
395 return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
396 }
397
398 static void freeque (int id)
399 {
400 struct msqid_ds *msq = msgque[id];
401 struct msg *msgp, *msgh;
402
403 msq->msg_perm.seq++;
404 msg_seq = (msg_seq+1) % ((unsigned)(1<<31)/MSGMNI);
405 msgbytes -= msq->msg_cbytes;
406 if (id == max_msqid)
407 while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED));
408 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
409 used_queues--;
410 while (msq->rwait || msq->wwait) {
411 if (msq->rwait)
412 wake_up (&msq->rwait);
413 if (msq->wwait)
414 wake_up (&msq->wwait);
415 schedule();
416 }
417 for (msgp = msq->msg_first; msgp; msgp = msgh ) {
418 msgh = msgp->msg_next;
419 msghdrs--;
420 kfree(msgp);
421 }
422 kfree(msq);
423 }
424
425 asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
426 {
427 int id, err;
428 struct msqid_ds *msq;
429 struct msqid_ds tbuf;
430 struct ipc_perm *ipcp;
431
432 if (msqid < 0 || cmd < 0)
433 return -EINVAL;
434 switch (cmd) {
435 case IPC_INFO:
436 case MSG_INFO:
437 if (!buf)
438 return -EFAULT;
439 {
440 struct msginfo msginfo;
441 msginfo.msgmni = MSGMNI;
442 msginfo.msgmax = MSGMAX;
443 msginfo.msgmnb = MSGMNB;
444 msginfo.msgmap = MSGMAP;
445 msginfo.msgpool = MSGPOOL;
446 msginfo.msgtql = MSGTQL;
447 msginfo.msgssz = MSGSSZ;
448 msginfo.msgseg = MSGSEG;
449 if (cmd == MSG_INFO) {
450 msginfo.msgpool = used_queues;
451 msginfo.msgmap = msghdrs;
452 msginfo.msgtql = msgbytes;
453 }
454 err = verify_area (VERIFY_WRITE, buf, sizeof (struct msginfo));
455 if (err)
456 return err;
457 memcpy_tofs (buf, &msginfo, sizeof(struct msginfo));
458 return max_msqid;
459 }
460 case MSG_STAT:
461 if (!buf)
462 return -EFAULT;
463 err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
464 if (err)
465 return err;
466 if (msqid > max_msqid)
467 return -EINVAL;
468 msq = msgque[msqid];
469 if (msq == IPC_UNUSED || msq == IPC_NOID)
470 return -EINVAL;
471 if (ipcperms (&msq->msg_perm, S_IRUGO))
472 return -EACCES;
473 id = (unsigned int) msq->msg_perm.seq * MSGMNI + msqid;
474 tbuf.msg_perm = msq->msg_perm;
475 tbuf.msg_stime = msq->msg_stime;
476 tbuf.msg_rtime = msq->msg_rtime;
477 tbuf.msg_ctime = msq->msg_ctime;
478 tbuf.msg_cbytes = msq->msg_cbytes;
479 tbuf.msg_qnum = msq->msg_qnum;
480 tbuf.msg_qbytes = msq->msg_qbytes;
481 tbuf.msg_lspid = msq->msg_lspid;
482 tbuf.msg_lrpid = msq->msg_lrpid;
483 memcpy_tofs (buf, &tbuf, sizeof(*buf));
484 return id;
485 case IPC_SET:
486 if (!buf)
487 return -EFAULT;
488 err = verify_area (VERIFY_READ, buf, sizeof (*buf));
489 if (err)
490 return err;
491 memcpy_fromfs (&tbuf, buf, sizeof (*buf));
492 break;
493 case IPC_STAT:
494 if (!buf)
495 return -EFAULT;
496 err = verify_area (VERIFY_WRITE, buf, sizeof(*buf));
497 if (err)
498 return err;
499 break;
500 }
501
502 id = (unsigned int) msqid % MSGMNI;
503 msq = msgque [id];
504 if (msq == IPC_UNUSED || msq == IPC_NOID)
505 return -EINVAL;
506 if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
507 return -EIDRM;
508 ipcp = &msq->msg_perm;
509
510 switch (cmd) {
511 case IPC_STAT:
512 if (ipcperms (ipcp, S_IRUGO))
513 return -EACCES;
514 tbuf.msg_perm = msq->msg_perm;
515 tbuf.msg_stime = msq->msg_stime;
516 tbuf.msg_rtime = msq->msg_rtime;
517 tbuf.msg_ctime = msq->msg_ctime;
518 tbuf.msg_cbytes = msq->msg_cbytes;
519 tbuf.msg_qnum = msq->msg_qnum;
520 tbuf.msg_qbytes = msq->msg_qbytes;
521 tbuf.msg_lspid = msq->msg_lspid;
522 tbuf.msg_lrpid = msq->msg_lrpid;
523 memcpy_tofs (buf, &tbuf, sizeof (*buf));
524 return 0;
525 case IPC_SET:
526 if (!suser() && current->euid != ipcp->cuid &&
527 current->euid != ipcp->uid)
528 return -EPERM;
529 if (tbuf.msg_qbytes > MSGMNB && !suser())
530 return -EPERM;
531 msq->msg_qbytes = tbuf.msg_qbytes;
532 ipcp->uid = tbuf.msg_perm.uid;
533 ipcp->gid = tbuf.msg_perm.gid;
534 ipcp->mode = (ipcp->mode & ~S_IRWXUGO) |
535 (S_IRWXUGO & tbuf.msg_perm.mode);
536 msq->msg_ctime = CURRENT_TIME;
537 return 0;
538 case IPC_RMID:
539 if (!suser() && current->euid != ipcp->cuid &&
540 current->euid != ipcp->uid)
541 return -EPERM;
542
543
544
545
546 if ((kerneld_msqid >= 0) && (msqid == kerneld_msqid))
547 kerneld_pid = kerneld_msqid = -1;
548 freeque (id);
549 return 0;
550 default:
551 return -EINVAL;
552 }
553 }
554
555
556
557
558
559
560
561
562 void kerneld_exit(void)
563 {
564 if ((current->pid == kerneld_pid) && (kerneld_msqid != -1))
565 sys_msgctl(kerneld_msqid, IPC_RMID, NULL);
566 }
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600 int kerneld_send(int msgtype, int ret_size, int msgsz,
601 const char *text, const char *ret_val)
602 {
603 int status = -ENOSYS;
604 #ifdef CONFIG_KERNELD
605 static int id = KERNELD_MINSEQ;
606 struct kerneld_msg kmsp = { msgtype, 0, (char *)text };
607 int msgflg = S_IRUSR | S_IWUSR | IPC_KERNELD | MSG_NOERROR;
608
609 if (kerneld_msqid == -1)
610 return -ENODEV;
611
612
613 if (intr_count)
614 ret_size &= ~KERNELD_WAIT;
615
616 msgsz += sizeof(long);
617 if (ret_size & KERNELD_WAIT) {
618 if (++id <= 0)
619 id = KERNELD_MINSEQ;
620 kmsp.id = id;
621 }
622
623 status = real_msgsnd(kerneld_msqid, (struct msgbuf *)&kmsp, msgsz, msgflg);
624 if ((status >= 0) && (ret_size & KERNELD_WAIT)) {
625 ret_size &= ~KERNELD_WAIT;
626 kmsp.text = (char *)ret_val;
627 status = real_msgrcv(kerneld_msqid, (struct msgbuf *)&kmsp,
628 sizeof(long) + ((ret_val)?ret_size:0),
629 kmsp.id, msgflg);
630 if (status > 0)
631 status = kmsp.id;
632 }
633
634 #endif
635 return status;
636 }