ipc/msg.c
20103 /*
20104 * linux/ipc/msg.c
20105 * Copyright (C) 1992 Krishna Balasubramanian
20106 *
20107 * Removed all the remaining kerneld mess
20108 * Catch the -EFAULT stuff properly
20109 * Use GFP_KERNEL for messages as in 1.2
20110 * Fixed up the unchecked user space derefs
20111 * Copyright (C) 1998 Alan Cox & Andi Kleen
20112 *
20113 */
20114
20115 #include <linux/malloc.h>
20116 #include <linux/msg.h>
20117 #include <linux/interrupt.h>
20118 #include <linux/smp_lock.h>
20119 #include <linux/init.h>
20120
20121 #include <asm/uaccess.h>
20122
20123 extern int ipcperms(struct ipc_perm *ipcp, short msgflg);
20124
20125 static void freeque (int id);
20126 static int newque (key_t key, int msgflg);
20127 static int findkey (key_t key);
20128
20129 static struct msqid_ds *msgque[MSGMNI];
20130 static int msgbytes = 0;
20131 static int msghdrs = 0;
20132 static unsigned short msg_seq = 0;
20133 static int used_queues = 0;
20134 static int max_msqid = 0;
20135 static struct wait_queue *msg_lock = NULL;
20136
20137 void __init msg_init (void)
20138 {
20139 int id;
20140
20141 for (id = 0; id < MSGMNI; id++)
20142 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
20143 msgbytes = msghdrs = msg_seq = max_msqid =
20144 used_queues = 0;
20145 msg_lock = NULL;
20146 return;
20147 }
20148
20149 static int real_msgsnd(int msqid, struct msgbuf *msgp,
20150 size_t msgsz, int msgflg)
20151 {
20152 int id;
20153 struct msqid_ds *msq;
20154 struct ipc_perm *ipcp;
20155 struct msg *msgh;
20156 long mtype;
20157
20158 if (msgsz > MSGMAX || (long) msgsz < 0 || msqid < 0)
20159 return -EINVAL;
20160 if (get_user(mtype, &msgp->mtype))
20161 return -EFAULT;
20162 if (mtype < 1)
20163 return -EINVAL;
20164 id = (unsigned int) msqid % MSGMNI;
20165 msq = msgque [id];
20166 if (msq == IPC_UNUSED || msq == IPC_NOID)
20167 return -EINVAL;
20168 ipcp = &msq->msg_perm;
20169
20170 slept:
20171 if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
20172 return -EIDRM;
20173
20174 if (ipcperms(ipcp, S_IWUGO))
20175 return -EACCES;
20176
20177 if (msgsz + msq->msg_cbytes > msq->msg_qbytes) {
20178 if (msgsz + msq->msg_cbytes > msq->msg_qbytes) {
20179 /* still no space in queue */
20180 if (msgflg & IPC_NOWAIT)
20181 return -EAGAIN;
20182 if (signal_pending(current))
20183 return -EINTR;
20184 interruptible_sleep_on (&msq->wwait);
20185 goto slept;
20186 }
20187 }
20188
20189 /* allocate message header and text space*/
20190 msgh = (struct msg *) kmalloc(sizeof(*msgh) + msgsz,
20191 GFP_KERNEL);
20192 if (!msgh)
20193 return -ENOMEM;
20194 msgh->msg_spot = (char *) (msgh + 1);
20195
20196 if (copy_from_user(msgh->msg_spot, msgp->mtext, msgsz))
20197 {
20198 kfree(msgh);
20199 return -EFAULT;
20200 }
20201
20202 if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID
20203 || msq->msg_perm.seq !=
20204 (unsigned int) msqid / MSGMNI) {
20205 kfree(msgh);
20206 return -EIDRM;
20207 }
20208
20209 msgh->msg_next = NULL;
20210 msgh->msg_ts = msgsz;
20211 msgh->msg_type = mtype;
20212 msgh->msg_stime = CURRENT_TIME;
20213
20214 if (!msq->msg_first)
20215 msq->msg_first = msq->msg_last = msgh;
20216 else {
20217 msq->msg_last->msg_next = msgh;
20218 msq->msg_last = msgh;
20219 }
20220 msq->msg_cbytes += msgsz;
20221 msgbytes += msgsz;
20222 msghdrs++;
20223 msq->msg_qnum++;
20224 msq->msg_lspid = current->pid;
20225 msq->msg_stime = CURRENT_TIME;
20226 wake_up (&msq->rwait);
20227 return 0;
20228 }
20229
20230 static int real_msgrcv(int msqid, struct msgbuf *msgp,
20231 size_t msgsz, long msgtyp, int msgflg)
20232 {
20233 struct msqid_ds *msq;
20234 struct ipc_perm *ipcp;
20235 struct msg *tmsg, *leastp = NULL;
20236 struct msg *nmsg = NULL;
20237 int id;
20238
20239 if (msqid < 0 || (long) msgsz < 0)
20240 return -EINVAL;
20241
20242 id = (unsigned int) msqid % MSGMNI;
20243 msq = msgque [id];
20244 if (msq == IPC_NOID || msq == IPC_UNUSED)
20245 return -EINVAL;
20246 ipcp = &msq->msg_perm;
20247
20248 /* find message of correct type.
20249 * msgtyp = 0 => get first.
20250 * msgtyp > 0 => get first message of matching type.
20251 * msgtyp < 0 => get message with least type
20252 * must be < abs(msgtype). */
20253 while (!nmsg) {
20254 if (msq->msg_perm.seq !=
20255 (unsigned int) msqid / MSGMNI) {
20256 return -EIDRM;
20257 }
20258 if (ipcperms (ipcp, S_IRUGO)) {
20259 return -EACCES;
20260 }
20261
20262 if (msgtyp == 0)
20263 nmsg = msq->msg_first;
20264 else if (msgtyp > 0) {
20265 if (msgflg & MSG_EXCEPT) {
20266 for (tmsg = msq->msg_first; tmsg;
20267 tmsg = tmsg->msg_next)
20268 if (tmsg->msg_type != msgtyp)
20269 break;
20270 nmsg = tmsg;
20271 } else {
20272 for (tmsg = msq->msg_first; tmsg;
20273 tmsg = tmsg->msg_next)
20274 if (tmsg->msg_type == msgtyp)
20275 break;
20276 nmsg = tmsg;
20277 }
20278 } else {
20279 for (leastp = tmsg = msq->msg_first; tmsg;
20280 tmsg = tmsg->msg_next)
20281 if (tmsg->msg_type < leastp->msg_type)
20282 leastp = tmsg;
20283 if (leastp && leastp->msg_type <= - msgtyp)
20284 nmsg = leastp;
20285 }
20286
20287 if (nmsg) { /* done finding a message */
20288 if ((msgsz < nmsg->msg_ts) &&
20289 !(msgflg & MSG_NOERROR)) {
20290 return -E2BIG;
20291 }
20292 msgsz = (msgsz > nmsg->msg_ts)
20293 ? nmsg->msg_ts : msgsz;
20294 if (nmsg == msq->msg_first)
20295 msq->msg_first = nmsg->msg_next;
20296 else {
20297 for (tmsg = msq->msg_first; tmsg;
20298 tmsg = tmsg->msg_next)
20299 if (tmsg->msg_next == nmsg)
20300 break;
20301 tmsg->msg_next = nmsg->msg_next;
20302 if (nmsg == msq->msg_last)
20303 msq->msg_last = tmsg;
20304 }
20305 if (!(--msq->msg_qnum))
20306 msq->msg_last = msq->msg_first = NULL;
20307
20308 msq->msg_rtime = CURRENT_TIME;
20309 msq->msg_lrpid = current->pid;
20310 msgbytes -= nmsg->msg_ts;
20311 msghdrs--;
20312 msq->msg_cbytes -= nmsg->msg_ts;
20313 wake_up (&msq->wwait);
20314 if (put_user (nmsg->msg_type, &msgp->mtype) ||
20315 copy_to_user(msgp->mtext,nmsg->msg_spot,msgsz))
20316 msgsz = -EFAULT;
20317 kfree(nmsg);
20318 return msgsz;
20319 } else { /* did not find a message */
20320 if (msgflg & IPC_NOWAIT) {
20321 return -ENOMSG;
20322 }
20323 if (signal_pending(current)) {
20324 return -EINTR;
20325 }
20326 interruptible_sleep_on (&msq->rwait);
20327 }
20328 } /* end while */
20329 return -1;
20330 }
20331
20332 asmlinkage int sys_msgsnd(int msqid, struct msgbuf *msgp
20333 , size_t msgsz, int msgflg)
20334 {
20335 int ret;
20336
20337 lock_kernel();
20338 ret = real_msgsnd(msqid, msgp, msgsz, msgflg);
20339 unlock_kernel();
20340 return ret;
20341 }
20342
20343 asmlinkage int sys_msgrcv(int msqid, struct msgbuf *msgp
20344 , size_t msgsz, long msgtyp, int msgflg)
20345 {
20346 int ret;
20347
20348 lock_kernel();
20349 ret = real_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg);
20350 unlock_kernel();
20351 return ret;
20352 }
20353
20354 static int findkey (key_t key)
20355 {
20356 int id;
20357 struct msqid_ds *msq;
20358
20359 for (id = 0; id <= max_msqid; id++) {
20360 while ((msq = msgque[id]) == IPC_NOID)
20361 interruptible_sleep_on (&msg_lock);
20362 if (msq == IPC_UNUSED)
20363 continue;
20364 if (key == msq->msg_perm.key)
20365 return id;
20366 }
20367 return -1;
20368 }
20369
20370 static int newque (key_t key, int msgflg)
20371 {
20372 int id;
20373 struct msqid_ds *msq;
20374 struct ipc_perm *ipcp;
20375
20376 for (id = 0; id < MSGMNI; id++)
20377 if (msgque[id] == IPC_UNUSED) {
20378 msgque[id] = (struct msqid_ds *) IPC_NOID;
20379 goto found;
20380 }
20381 return -ENOSPC;
20382
20383 found:
20384 msq =
20385 (struct msqid_ds *)kmalloc(sizeof(*msq), GFP_KERNEL);
20386 if (!msq) {
20387 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
20388 wake_up (&msg_lock);
20389 return -ENOMEM;
20390 }
20391 ipcp = &msq->msg_perm;
20392 ipcp->mode = (msgflg & S_IRWXUGO);
20393 ipcp->key = key;
20394 ipcp->cuid = ipcp->uid = current->euid;
20395 ipcp->gid = ipcp->cgid = current->egid;
20396 msq->msg_perm.seq = msg_seq;
20397 msq->msg_first = msq->msg_last = NULL;
20398 msq->rwait = msq->wwait = NULL;
20399 msq->msg_cbytes = msq->msg_qnum = 0;
20400 msq->msg_lspid = msq->msg_lrpid = 0;
20401 msq->msg_stime = msq->msg_rtime = 0;
20402 msq->msg_qbytes = MSGMNB;
20403 msq->msg_ctime = CURRENT_TIME;
20404 if (id > max_msqid)
20405 max_msqid = id;
20406 msgque[id] = msq;
20407 used_queues++;
20408 wake_up (&msg_lock);
20409 return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
20410 }
20411
20412 asmlinkage int sys_msgget (key_t key, int msgflg)
20413 {
20414 int id, ret = -EPERM;
20415 struct msqid_ds *msq;
20416
20417 lock_kernel();
20418 if (key == IPC_PRIVATE)
20419 ret = newque(key, msgflg);
20420 else if ((id = findkey (key)) == -1) { /*key not used*/
20421 if (!(msgflg & IPC_CREAT))
20422 ret = -ENOENT;
20423 else
20424 ret = newque(key, msgflg);
20425 } else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) {
20426 ret = -EEXIST;
20427 } else {
20428 msq = msgque[id];
20429 if (msq == IPC_UNUSED || msq == IPC_NOID)
20430 ret = -EIDRM;
20431 else if (ipcperms(&msq->msg_perm, msgflg))
20432 ret = -EACCES;
20433 else
20434 ret = (unsigned int) msq->msg_perm.seq*MSGMNI + id;
20435 }
20436 unlock_kernel();
20437 return ret;
20438 }
20439
20440 static void freeque (int id)
20441 {
20442 struct msqid_ds *msq = msgque[id];
20443 struct msg *msgp, *msgh;
20444
20445 msq->msg_perm.seq++;
20446 /* increment, but avoid overflow */
20447 msg_seq = (msg_seq+1) % ((unsigned)(1<<31)/MSGMNI);
20448 msgbytes -= msq->msg_cbytes;
20449 if (id == max_msqid)
20450 while (max_msqid &&
20451 (msgque[--max_msqid] == IPC_UNUSED));
20452 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
20453 used_queues--;
20454 while (waitqueue_active(&msq->rwait) ||
20455 waitqueue_active(&msq->wwait)) {
20456 wake_up (&msq->rwait);
20457 wake_up (&msq->wwait);
20458 schedule();
20459 }
20460 for (msgp = msq->msg_first; msgp; msgp = msgh ) {
20461 msgh = msgp->msg_next;
20462 msghdrs--;
20463 kfree(msgp);
20464 }
20465 kfree(msq);
20466 }
20467
20468 asmlinkage int sys_msgctl(int msqid, int cmd,
20469 struct msqid_ds *buf)
20470 {
20471 int id, err = -EINVAL;
20472 struct msqid_ds *msq;
20473 struct msqid_ds tbuf;
20474 struct ipc_perm *ipcp;
20475
20476 lock_kernel();
20477 if (msqid < 0 || cmd < 0)
20478 goto out;
20479 err = -EFAULT;
20480 switch (cmd) {
20481 case IPC_INFO:
20482 case MSG_INFO:
20483 if (!buf)
20484 goto out;
20485 {
20486 struct msginfo msginfo;
20487 msginfo.msgmni = MSGMNI;
20488 msginfo.msgmax = MSGMAX;
20489 msginfo.msgmnb = MSGMNB;
20490 msginfo.msgmap = MSGMAP;
20491 msginfo.msgpool = MSGPOOL;
20492 msginfo.msgtql = MSGTQL;
20493 msginfo.msgssz = MSGSSZ;
20494 msginfo.msgseg = MSGSEG;
20495 if (cmd == MSG_INFO) {
20496 msginfo.msgpool = used_queues;
20497 msginfo.msgmap = msghdrs;
20498 msginfo.msgtql = msgbytes;
20499 }
20500
20501 err = -EFAULT;
20502 if (copy_to_user(buf, &msginfo,
20503 sizeof(struct msginfo)))
20504 goto out;
20505 err = max_msqid;
20506 goto out;
20507 }
20508 case MSG_STAT:
20509 if (!buf)
20510 goto out;
20511 err = -EINVAL;
20512 if (msqid > max_msqid)
20513 goto out;
20514 msq = msgque[msqid];
20515 if (msq == IPC_UNUSED || msq == IPC_NOID)
20516 goto out;
20517 err = -EACCES;
20518 if (ipcperms (&msq->msg_perm, S_IRUGO))
20519 goto out;
20520 id = (unsigned int) msq->msg_perm.seq*MSGMNI + msqid;
20521 tbuf.msg_perm = msq->msg_perm;
20522 tbuf.msg_stime = msq->msg_stime;
20523 tbuf.msg_rtime = msq->msg_rtime;
20524 tbuf.msg_ctime = msq->msg_ctime;
20525 tbuf.msg_cbytes = msq->msg_cbytes;
20526 tbuf.msg_qnum = msq->msg_qnum;
20527 tbuf.msg_qbytes = msq->msg_qbytes;
20528 tbuf.msg_lspid = msq->msg_lspid;
20529 tbuf.msg_lrpid = msq->msg_lrpid;
20530 err = -EFAULT;
20531 if (copy_to_user (buf, &tbuf, sizeof(*buf)))
20532 goto out;
20533 err = id;
20534 goto out;
20535 case IPC_SET:
20536 if (!buf)
20537 goto out;
20538 err = -EFAULT;
20539 if (!copy_from_user (&tbuf, buf, sizeof (*buf)))
20540 err = 0;
20541 break;
20542 case IPC_STAT:
20543 if (!buf)
20544 goto out;
20545 break;
20546 }
20547
20548 id = (unsigned int) msqid % MSGMNI;
20549 msq = msgque [id];
20550 err = -EINVAL;
20551 if (msq == IPC_UNUSED || msq == IPC_NOID)
20552 goto out;
20553 err = -EIDRM;
20554 if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
20555 goto out;
20556 ipcp = &msq->msg_perm;
20557
20558 switch (cmd) {
20559 case IPC_STAT:
20560 err = -EACCES;
20561 if (ipcperms (ipcp, S_IRUGO))
20562 goto out;
20563 tbuf.msg_perm = msq->msg_perm;
20564 tbuf.msg_stime = msq->msg_stime;
20565 tbuf.msg_rtime = msq->msg_rtime;
20566 tbuf.msg_ctime = msq->msg_ctime;
20567 tbuf.msg_cbytes = msq->msg_cbytes;
20568 tbuf.msg_qnum = msq->msg_qnum;
20569 tbuf.msg_qbytes = msq->msg_qbytes;
20570 tbuf.msg_lspid = msq->msg_lspid;
20571 tbuf.msg_lrpid = msq->msg_lrpid;
20572 err = -EFAULT;
20573 if (!copy_to_user (buf, &tbuf, sizeof (*buf)))
20574 err = 0;
20575 goto out;
20576 case IPC_SET:
20577 err = -EPERM;
20578 if (current->euid != ipcp->cuid &&
20579 current->euid != ipcp->uid &&
20580 !capable(CAP_SYS_ADMIN))
20581 /* We _could_ check for CAP_CHOWN above, but we
20582 don't */
20583 goto out;
20584 if (tbuf.msg_qbytes > MSGMNB &&
20585 !capable(CAP_SYS_RESOURCE))
20586 goto out;
20587 msq->msg_qbytes = tbuf.msg_qbytes;
20588 ipcp->uid = tbuf.msg_perm.uid;
20589 ipcp->gid = tbuf.msg_perm.gid;
20590 ipcp->mode = (ipcp->mode & ~S_IRWXUGO) |
20591 (S_IRWXUGO & tbuf.msg_perm.mode);
20592 msq->msg_ctime = CURRENT_TIME;
20593 err = 0;
20594 goto out;
20595 case IPC_RMID:
20596 err = -EPERM;
20597 if (current->euid != ipcp->cuid &&
20598 current->euid != ipcp->uid &&
20599 !capable(CAP_SYS_ADMIN))
20600 goto out;
20601
20602 freeque (id);
20603 err = 0;
20604 goto out;
20605 default:
20606 err = -EINVAL;
20607 goto out;
20608 }
20609 out:
20610 unlock_kernel();
20611 return err;
20612 }
20613
Сайт управляется системой
uCoz