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