Ядро Linux в комментариях

       

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


Содержание раздела