LCOV - code coverage report
Current view: top level - kern - sysv_msg.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 307 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 19 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: sysv_msg.c,v 1.33 2016/09/15 02:00:16 dlg Exp $       */
       2             : /*      $NetBSD: sysv_msg.c,v 1.19 1996/02/09 19:00:18 christos Exp $   */
       3             : /*
       4             :  * Copyright (c) 2009 Bret S. Lambert <blambert@openbsd.org>
       5             :  *
       6             :  * Permission to use, copy, modify, and distribute this software for any
       7             :  * purpose with or without fee is hereby granted, provided that the above
       8             :  * copyright notice and this permission notice appear in all copies.
       9             :  *
      10             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      11             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      12             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      13             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      14             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      15             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      16             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      17             :  */
      18             : /*
      19             :  * Implementation of SVID messages
      20             :  *
      21             :  * Author:  Daniel Boulet
      22             :  *
      23             :  * Copyright 1993 Daniel Boulet and RTMX Inc.
      24             :  *
      25             :  * This system call was implemented by Daniel Boulet under contract from RTMX.
      26             :  *
      27             :  * Redistribution and use in source forms, with and without modification,
      28             :  * are permitted provided that this entire comment appears intact.
      29             :  *
      30             :  * Redistribution in binary form may occur without any restrictions.
      31             :  * Obviously, it would be nice if you gave credit where credit is due
      32             :  * but requiring it would be too onerous.
      33             :  *
      34             :  * This software is provided ``AS IS'' without any warranties of any kind.
      35             :  */
      36             : 
      37             : #include <sys/param.h>
      38             : #include <sys/malloc.h>
      39             : #include <sys/mbuf.h>
      40             : #include <sys/mount.h>
      41             : #include <sys/msg.h>
      42             : #include <sys/pool.h>
      43             : #include <sys/proc.h>
      44             : #include <sys/queue.h>
      45             : #include <sys/syscallargs.h>
      46             : #include <sys/sysctl.h>
      47             : #include <sys/systm.h>
      48             : #include <sys/uio.h>
      49             : 
      50             : struct que *que_create(key_t, struct ucred *, int);
      51             : struct que *que_lookup(int);
      52             : struct que *que_key_lookup(key_t);
      53             : void que_wakewriters(void);
      54             : void que_free(struct que *);
      55             : struct msg *msg_create(struct que *);
      56             : void msg_free(struct msg *);
      57             : void msg_enqueue(struct que *, struct msg *, struct proc *);
      58             : void msg_dequeue(struct que *, struct msg *, struct proc *);
      59             : struct msg *msg_lookup(struct que *, int);
      60             : int msg_copyin(struct msg *, const char *, size_t, struct proc *);
      61             : int msg_copyout(struct msg *, char *, size_t *, struct proc *);
      62             : 
      63             : struct  pool sysvmsgpl;
      64             : struct  msginfo msginfo;
      65             : 
      66             : TAILQ_HEAD(, que) msg_queues;
      67             : 
      68             : int num_ques;
      69             : int num_msgs;
      70             : int sequence;
      71             : int maxmsgs;
      72             : 
      73             : void
      74           0 : msginit(void)
      75             : {
      76           0 :         msginfo.msgmax = MSGMAX;
      77           0 :         msginfo.msgmni = MSGMNI;
      78           0 :         msginfo.msgmnb = MSGMNB;
      79           0 :         msginfo.msgtql = MSGTQL;
      80           0 :         msginfo.msgssz = MSGSSZ;
      81           0 :         msginfo.msgseg = MSGSEG;
      82             : 
      83           0 :         pool_init(&sysvmsgpl, sizeof(struct msg), 0, IPL_NONE, PR_WAITOK,
      84             :             "sysvmsgpl", NULL);
      85             : 
      86           0 :         TAILQ_INIT(&msg_queues);
      87             : 
      88           0 :         num_ques = 0;
      89           0 :         num_msgs = 0;
      90           0 :         sequence = 1;
      91           0 :         maxmsgs = 0;
      92           0 : }
      93             : 
      94             : int
      95           0 : sys_msgctl(struct proc *p, void *v, register_t *retval)
      96             : {
      97             :         struct sys_msgctl_args /* {
      98             :                 syscallarg(int) msqid;
      99             :                 syscallarg(int) cmd;
     100             :                 syscallarg(struct msqid_ds *) buf;
     101           0 :         } */ *uap = v;
     102             : 
     103           0 :         return (msgctl1(p, SCARG(uap, msqid), SCARG(uap, cmd),
     104           0 :             (caddr_t)SCARG(uap, buf), copyin, copyout));
     105             : }
     106             : 
     107             : int
     108           0 : msgctl1(struct proc *p, int msqid, int cmd, caddr_t buf,
     109             :     int (*ds_copyin)(const void *, void *, size_t),
     110             :     int (*ds_copyout)(const void *, void *, size_t))
     111             : {
     112           0 :         struct msqid_ds tmp;
     113           0 :         struct ucred *cred = p->p_ucred;
     114             :         struct que *que;
     115             :         int error = 0;
     116             : 
     117           0 :         if ((que = que_lookup(msqid)) == NULL)
     118           0 :                 return (EINVAL);
     119             : 
     120           0 :         QREF(que);
     121             : 
     122           0 :         switch (cmd) {
     123             : 
     124             :         case IPC_RMID:
     125           0 :                 if ((error = ipcperm(cred, &que->msqid_ds.msg_perm, IPC_M)))
     126             :                         goto out;
     127             : 
     128           0 :                 TAILQ_REMOVE(&msg_queues, que, que_next);
     129           0 :                 que->que_flags |= MSGQ_DYING;
     130             : 
     131             :                 /* lose interest in the queue and wait for others to too */
     132           0 :                 if (--que->que_references > 0) {
     133           0 :                         wakeup(que);
     134           0 :                         tsleep(&que->que_references, PZERO, "msgqrm", 0);
     135           0 :                 }
     136             : 
     137           0 :                 que_free(que);
     138             : 
     139           0 :                 return (0);
     140             : 
     141             :         case IPC_SET:
     142           0 :                 if ((error = ipcperm(cred, &que->msqid_ds.msg_perm, IPC_M)))
     143             :                         goto out;
     144           0 :                 if ((error = ds_copyin(buf, &tmp, sizeof(struct msqid_ds))))
     145             :                         goto out;
     146             : 
     147             :                 /* only superuser can bump max bytes in queue */
     148           0 :                 if (tmp.msg_qbytes > que->msqid_ds.msg_qbytes &&
     149           0 :                     cred->cr_uid != 0) {
     150             :                         error = EPERM;
     151           0 :                         goto out;
     152             :                 }
     153             : 
     154             :                 /* restrict max bytes in queue to system limit */
     155           0 :                 if (tmp.msg_qbytes > msginfo.msgmnb)
     156           0 :                         tmp.msg_qbytes = msginfo.msgmnb;
     157             : 
     158             :                 /* can't reduce msg_bytes to 0 */
     159           0 :                 if (tmp.msg_qbytes == 0) {
     160             :                         error = EINVAL;         /* non-standard errno! */
     161           0 :                         goto out;
     162             :                 }
     163             : 
     164           0 :                 que->msqid_ds.msg_perm.uid = tmp.msg_perm.uid;
     165           0 :                 que->msqid_ds.msg_perm.gid = tmp.msg_perm.gid;
     166           0 :                 que->msqid_ds.msg_perm.mode =
     167           0 :                     (que->msqid_ds.msg_perm.mode & ~0777) |
     168           0 :                     (tmp.msg_perm.mode & 0777);
     169           0 :                 que->msqid_ds.msg_qbytes = tmp.msg_qbytes;
     170           0 :                 que->msqid_ds.msg_ctime = time_second;
     171           0 :                 break;
     172             : 
     173             :         case IPC_STAT:
     174           0 :                 if ((error = ipcperm(cred, &que->msqid_ds.msg_perm, IPC_R)))
     175             :                         goto out;
     176           0 :                 error = ds_copyout(&que->msqid_ds, buf,
     177             :                     sizeof(struct msqid_ds));
     178           0 :                 break;
     179             : 
     180             :         default:
     181             :                 error = EINVAL;
     182           0 :                 break;
     183             :         }
     184             : out:
     185           0 :         QRELE(que);
     186             : 
     187           0 :         return (error);
     188           0 : }
     189             : 
     190             : int
     191           0 : sys_msgget(struct proc *p, void *v, register_t *retval)
     192             : {
     193             :         struct sys_msgget_args /* {
     194             :                 syscallarg(key_t) key;
     195             :                 syscallarg(int) msgflg;
     196           0 :         } */ *uap = v;
     197           0 :         struct ucred *cred = p->p_ucred;
     198             :         struct que *que;
     199           0 :         key_t key = SCARG(uap, key);
     200           0 :         int msgflg = SCARG(uap, msgflg);
     201           0 :         int error = 0;
     202             : 
     203             : again:
     204           0 :         if (key != IPC_PRIVATE) {
     205           0 :                 que = que_key_lookup(key);
     206           0 :                 if (que) {
     207           0 :                         if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL))
     208           0 :                                 return (EEXIST);
     209           0 :                         if ((error = ipcperm(cred, &que->msqid_ds.msg_perm,
     210           0 :                             msgflg & 0700)))
     211           0 :                                 return (error);
     212             :                         goto found;
     213             :                 }
     214             :         }
     215             : 
     216             :         /* don't create a new message queue if the caller doesn't want to */
     217           0 :         if (key != IPC_PRIVATE && !(msgflg & IPC_CREAT))
     218           0 :                 return (ENOENT);
     219             : 
     220             :         /* enforce limits on the maximum number of message queues */
     221           0 :         if (num_ques >= msginfo.msgmni)
     222           0 :                 return (ENOSPC);
     223             : 
     224             :         /*
     225             :          * if que_create returns NULL, it means that a que with an identical
     226             :          * key was created while this process was sleeping, so start over
     227             :          */
     228           0 :         if ((que = que_create(key, cred, msgflg & 0777)) == NULL)
     229           0 :                 goto again;
     230             : 
     231             : found:
     232           0 :         *retval = IXSEQ_TO_IPCID(que->que_ix, que->msqid_ds.msg_perm);
     233           0 :         return (error);
     234           0 : }
     235             : 
     236             : #define MSGQ_SPACE(q)   ((q)->msqid_ds.msg_qbytes - (q)->msqid_ds.msg_cbytes)
     237             : 
     238             : int
     239           0 : sys_msgsnd(struct proc *p, void *v, register_t *retval)
     240             : {
     241             :         struct sys_msgsnd_args /* {
     242             :                 syscallarg(int) msqid;
     243             :                 syscallarg(const void *) msgp;
     244             :                 syscallarg(size_t) msgsz;
     245             :                 syscallarg(int) msgflg;
     246           0 :         } */ *uap = v;
     247           0 :         struct ucred *cred = p->p_ucred;
     248             :         struct que *que;
     249             :         struct msg *msg;
     250           0 :         size_t msgsz = SCARG(uap, msgsz);
     251             :         int error;
     252             : 
     253           0 :         if ((que = que_lookup(SCARG(uap, msqid))) == NULL)
     254           0 :                 return (EINVAL);
     255             : 
     256           0 :         if (msgsz > que->msqid_ds.msg_qbytes || msgsz > msginfo.msgmax)
     257           0 :                 return (EINVAL);
     258             : 
     259           0 :         if ((error = ipcperm(cred, &que->msqid_ds.msg_perm, IPC_W)))
     260           0 :                 return (error);
     261             : 
     262           0 :         QREF(que);
     263             : 
     264           0 :         while (MSGQ_SPACE(que) < msgsz || num_msgs >= msginfo.msgtql) {
     265             : 
     266           0 :                 if (SCARG(uap, msgflg) & IPC_NOWAIT) {
     267             :                         error = EAGAIN;
     268           0 :                         goto out;
     269             :                 }
     270             : 
     271             :                 /* notify world that process may wedge here */
     272           0 :                 if (num_msgs >= msginfo.msgtql)
     273           0 :                         maxmsgs = 1;
     274             : 
     275           0 :                 que->que_flags |= MSGQ_WRITERS;
     276           0 :                 if ((error = tsleep(que, PZERO|PCATCH, "msgwait", 0)))
     277             :                         goto out;
     278             : 
     279           0 :                 if (que->que_flags & MSGQ_DYING) {
     280             :                         error = EIDRM;
     281           0 :                         goto out;
     282             :                 }
     283             :         }
     284             : 
     285             :         /* if msg_create returns NULL, the queue is being removed */
     286           0 :         if ((msg = msg_create(que)) == NULL) {
     287             :                 error = EIDRM;
     288           0 :                 goto out;
     289             :         }
     290             : 
     291             :         /* msg_copyin frees msg on error */
     292           0 :         if ((error = msg_copyin(msg, (const char *)SCARG(uap, msgp), msgsz, p)))
     293             :                 goto out;
     294             : 
     295           0 :         msg_enqueue(que, msg, p);
     296             : 
     297           0 :         if (que->que_flags & MSGQ_READERS) {
     298           0 :                 que->que_flags &= ~MSGQ_READERS;
     299           0 :                 wakeup(que);
     300           0 :         }
     301             : 
     302           0 :         if (que->que_flags & MSGQ_DYING) {
     303             :                 error = EIDRM;
     304           0 :                 wakeup(que);
     305           0 :         }
     306             : out:
     307           0 :         QRELE(que);
     308             : 
     309           0 :         return (error);
     310           0 : }
     311             : 
     312             : int
     313           0 : sys_msgrcv(struct proc *p, void *v, register_t *retval)
     314             : {
     315             :         struct sys_msgrcv_args /* {
     316             :                 syscallarg(int) msqid;
     317             :                 syscallarg(void *) msgp;
     318             :                 syscallarg(size_t) msgsz;
     319             :                 syscallarg(long) msgtyp;
     320             :                 syscallarg(int) msgflg;
     321           0 :         } */ *uap = v;
     322           0 :         struct ucred *cred = p->p_ucred;
     323           0 :         char *msgp = SCARG(uap, msgp);
     324             :         struct que *que;
     325             :         struct msg *msg;
     326           0 :         size_t msgsz = SCARG(uap, msgsz);
     327           0 :         long msgtyp = SCARG(uap, msgtyp);
     328             :         int error;
     329             : 
     330           0 :         if ((que = que_lookup(SCARG(uap, msqid))) == NULL)
     331           0 :                 return (EINVAL);
     332             : 
     333           0 :         if ((error = ipcperm(cred, &que->msqid_ds.msg_perm, IPC_R)))
     334           0 :                 return (error);
     335             : 
     336           0 :         QREF(que);
     337             : 
     338             :         /* msg_lookup handles matching; sleeping gets handled here */
     339           0 :         while ((msg = msg_lookup(que, msgtyp)) == NULL) {
     340             : 
     341           0 :                 if (SCARG(uap, msgflg) & IPC_NOWAIT) {
     342             :                         error = ENOMSG;
     343           0 :                         goto out;
     344             :                 }
     345             : 
     346           0 :                 que->que_flags |= MSGQ_READERS;
     347           0 :                 if ((error = tsleep(que, PZERO|PCATCH, "msgwait", 0)))
     348             :                         goto out;
     349             : 
     350             :                 /* make sure the queue still alive */
     351           0 :                 if (que->que_flags & MSGQ_DYING) {
     352             :                         error = EIDRM;
     353           0 :                         goto out;
     354             :                 }
     355             :         }
     356             : 
     357             :         /* if msg_copyout fails, keep the message around so it isn't lost */
     358           0 :         if ((error = msg_copyout(msg, msgp, &msgsz, p)))
     359             :                 goto out;
     360             : 
     361           0 :         msg_dequeue(que, msg, p);
     362           0 :         msg_free(msg);
     363             : 
     364           0 :         if (que->que_flags & MSGQ_WRITERS) {
     365           0 :                 que->que_flags &= ~MSGQ_WRITERS;
     366           0 :                 wakeup(que);
     367           0 :         }
     368             : 
     369             :         /* ensure processes waiting on the global limit don't wedge */
     370           0 :         if (maxmsgs) {
     371           0 :                 maxmsgs = 0;
     372           0 :                 que_wakewriters();
     373           0 :         }
     374             : 
     375           0 :         *retval = msgsz;
     376             : out:
     377           0 :         QRELE(que);
     378             : 
     379           0 :         return (error);
     380           0 : }
     381             : 
     382             : /*
     383             :  * que management functions
     384             :  */
     385             : 
     386             : struct que *
     387           0 : que_create(key_t key, struct ucred *cred, int mode)
     388             : {
     389             :         struct que *que, *que2;
     390             :         int nextix = 1;
     391             : 
     392           0 :         que = malloc(sizeof(*que), M_TEMP, M_WAIT|M_ZERO);
     393             : 
     394             :         /* if malloc slept, a queue with the same key may have been created */
     395           0 :         if (que_key_lookup(key)) {
     396           0 :                 free(que, M_TEMP, sizeof *que);
     397           0 :                 return (NULL);
     398             :         }
     399             : 
     400             :         /* find next available "index" */
     401           0 :         TAILQ_FOREACH(que2, &msg_queues, que_next) {
     402           0 :                 if (nextix < que2->que_ix)
     403             :                         break;
     404           0 :                 nextix = que2->que_ix + 1;
     405             :         }
     406           0 :         que->que_ix = nextix;
     407             : 
     408           0 :         que->msqid_ds.msg_perm.key = key;
     409           0 :         que->msqid_ds.msg_perm.cuid = cred->cr_uid;
     410           0 :         que->msqid_ds.msg_perm.uid = cred->cr_uid;
     411           0 :         que->msqid_ds.msg_perm.cgid = cred->cr_gid;
     412           0 :         que->msqid_ds.msg_perm.gid = cred->cr_gid;
     413           0 :         que->msqid_ds.msg_perm.mode = mode & 0777;
     414           0 :         que->msqid_ds.msg_perm.seq = ++sequence & 0x7fff;
     415           0 :         que->msqid_ds.msg_qbytes = msginfo.msgmnb;
     416           0 :         que->msqid_ds.msg_ctime = time_second;
     417             : 
     418           0 :         TAILQ_INIT(&que->que_msgs);
     419             : 
     420             :         /* keep queues in "index" order */
     421           0 :         if (que2)
     422           0 :                 TAILQ_INSERT_BEFORE(que2, que, que_next);
     423             :         else
     424           0 :                 TAILQ_INSERT_TAIL(&msg_queues, que, que_next);
     425           0 :         num_ques++;
     426             : 
     427           0 :         return (que);
     428           0 : }
     429             : 
     430             : struct que *
     431           0 : que_lookup(int id)
     432             : {
     433             :         struct que *que;
     434             : 
     435           0 :         TAILQ_FOREACH(que, &msg_queues, que_next)
     436           0 :                 if (que->que_ix == IPCID_TO_IX(id))
     437             :                         break;
     438             : 
     439             :         /* don't return queues marked for removal */
     440           0 :         if (que && que->que_flags & MSGQ_DYING)
     441           0 :                 return (NULL);
     442             : 
     443           0 :         return (que);
     444           0 : }
     445             : 
     446             : struct que *
     447           0 : que_key_lookup(key_t key)
     448             : {
     449             :         struct que *que;
     450             : 
     451           0 :         if (key == IPC_PRIVATE)
     452           0 :                 return (NULL);
     453             : 
     454           0 :         TAILQ_FOREACH(que, &msg_queues, que_next)
     455           0 :                 if (que->msqid_ds.msg_perm.key == key)
     456             :                         break;
     457             : 
     458             :         /* don't return queues marked for removal */
     459           0 :         if (que && que->que_flags & MSGQ_DYING)
     460           0 :                 return (NULL);
     461             : 
     462           0 :         return (que);
     463           0 : }
     464             : 
     465             : void
     466           0 : que_wakewriters(void)
     467             : {
     468             :         struct que *que;
     469             : 
     470           0 :         TAILQ_FOREACH(que, &msg_queues, que_next) {
     471           0 :                 if (que->que_flags & MSGQ_WRITERS) {
     472           0 :                         que->que_flags &= ~MSGQ_WRITERS;
     473           0 :                         wakeup(que);
     474           0 :                 }
     475             :         }
     476           0 : }
     477             : 
     478             : void
     479           0 : que_free(struct que *que)
     480             : {
     481             :         struct msg *msg;
     482             : #ifdef DIAGNOSTIC
     483           0 :         if (que->que_references > 0)
     484           0 :                 panic("freeing message queue with active references");
     485             : #endif
     486             : 
     487           0 :         while ((msg = TAILQ_FIRST(&que->que_msgs))) {
     488           0 :                 TAILQ_REMOVE(&que->que_msgs, msg, msg_next);
     489           0 :                 msg_free(msg);
     490             :         }
     491           0 :         free(que, M_TEMP, sizeof *que);
     492           0 :         num_ques--;
     493           0 : }
     494             : 
     495             : /*
     496             :  * msg management functions
     497             :  */
     498             : 
     499             : struct msg *
     500           0 : msg_create(struct que *que)
     501             : {
     502             :         struct msg *msg;
     503             : 
     504           0 :         msg = pool_get(&sysvmsgpl, PR_WAITOK|PR_ZERO);
     505             : 
     506             :         /* if the queue has died during allocation, return NULL */
     507           0 :         if (que->que_flags & MSGQ_DYING) {
     508           0 :                 pool_put(&sysvmsgpl, msg);
     509           0 :                 wakeup(que);
     510           0 :                 return(NULL);
     511             :         }
     512             : 
     513           0 :         num_msgs++;
     514             : 
     515           0 :         return (msg);
     516           0 : }
     517             : 
     518             : struct msg *
     519           0 : msg_lookup(struct que *que, int msgtyp)
     520             : {
     521             :         struct msg *msg;
     522             : 
     523             :         /*
     524             :          * Three different matches are performed based on the value of msgtyp:
     525             :          * 1) msgtyp > 0 => match exactly
     526             :          * 2) msgtyp = 0 => match any
     527             :          * 3) msgtyp < 0 => match any up to absolute value of msgtyp
     528             :          */
     529           0 :         TAILQ_FOREACH(msg, &que->que_msgs, msg_next)
     530           0 :                 if (msgtyp == 0 || msgtyp == msg->msg_type ||
     531           0 :                     (msgtyp < 0 && -msgtyp <= msg->msg_type))
     532             :                         break;
     533             : 
     534           0 :         return (msg);
     535             : }
     536             : 
     537             : void
     538           0 : msg_free(struct msg *msg)
     539             : {
     540           0 :         m_freem(msg->msg_data);
     541           0 :         pool_put(&sysvmsgpl, msg);
     542           0 :         num_msgs--;
     543           0 : }
     544             : 
     545             : void
     546           0 : msg_enqueue(struct que *que, struct msg *msg, struct proc *p)
     547             : {
     548           0 :         que->msqid_ds.msg_cbytes += msg->msg_len;
     549           0 :         que->msqid_ds.msg_qnum++;
     550           0 :         que->msqid_ds.msg_lspid = p->p_p->ps_pid;
     551           0 :         que->msqid_ds.msg_stime = time_second;
     552             : 
     553           0 :         TAILQ_INSERT_TAIL(&que->que_msgs, msg, msg_next);
     554           0 : }
     555             : 
     556             : void
     557           0 : msg_dequeue(struct que *que, struct msg *msg, struct proc *p)
     558             : {
     559           0 :         que->msqid_ds.msg_cbytes -= msg->msg_len;
     560           0 :         que->msqid_ds.msg_qnum--;
     561           0 :         que->msqid_ds.msg_lrpid = p->p_p->ps_pid;
     562           0 :         que->msqid_ds.msg_rtime = time_second;
     563             : 
     564           0 :         TAILQ_REMOVE(&que->que_msgs, msg, msg_next);
     565           0 : }
     566             : 
     567             : /*
     568             :  * The actual I/O routines. A note concerning the layout of SysV msg buffers:
     569             :  *
     570             :  * The data to be copied is laid out as a single userspace buffer, with a
     571             :  * long preceding an opaque buffer of len bytes. The long value ends
     572             :  * up being the message type, which needs to be copied separately from
     573             :  * the buffer data, which is stored in in mbufs.
     574             :  */
     575             : 
     576             : int
     577           0 : msg_copyin(struct msg *msg, const char *ubuf, size_t len, struct proc *p)
     578             : {
     579             :         struct mbuf **mm, *m;
     580             :         size_t xfer;
     581             :         int error;
     582             : 
     583           0 :         if (msg == NULL)
     584           0 :                 panic ("msg NULL");
     585             : 
     586           0 :         if ((error = copyin(ubuf, &msg->msg_type, sizeof(long)))) {
     587           0 :                 msg_free(msg);
     588           0 :                 return (error);
     589             :         }
     590             : 
     591           0 :         if (msg->msg_type < 0) {
     592           0 :                 msg_free(msg);
     593           0 :                 return (EINVAL);
     594             :         }
     595             : 
     596           0 :         ubuf += sizeof(long);
     597             : 
     598           0 :         msg->msg_len = 0;
     599           0 :         mm = &msg->msg_data;
     600             : 
     601           0 :         while (msg->msg_len < len) {
     602           0 :                 m = m_get(M_WAIT, MT_DATA);
     603           0 :                 if (len >= MINCLSIZE) {
     604           0 :                         MCLGET(m, M_WAIT);
     605           0 :                         xfer = min(len, MCLBYTES);
     606           0 :                 } else {
     607           0 :                         xfer = min(len, MLEN);
     608             :                 }
     609           0 :                 m->m_len = xfer;
     610           0 :                 msg->msg_len += xfer;
     611           0 :                 *mm = m;
     612           0 :                 mm = &m->m_next;
     613             :         }
     614             : 
     615           0 :         for (m = msg->msg_data; m; m = m->m_next) {
     616           0 :                 if ((error = copyin(ubuf, mtod(m, void *), m->m_len))) {
     617           0 :                         msg_free(msg);
     618           0 :                         return (error);
     619             :                 }
     620           0 :                 ubuf += m->m_len;
     621             :         }
     622             : 
     623           0 :         return (0);
     624           0 : }
     625             : 
     626             : int
     627           0 : msg_copyout(struct msg *msg, char *ubuf, size_t *len, struct proc *p)
     628             : {
     629             :         struct mbuf *m;
     630             :         size_t xfer;
     631             :         int error;
     632             : 
     633             : #ifdef DIAGNOSTIC
     634           0 :         if (msg->msg_len > MSGMAX)
     635           0 :                 panic("SysV message longer than MSGMAX");
     636             : #endif
     637             : 
     638             :         /* silently truncate messages too large for user buffer */
     639           0 :         xfer = min(*len, msg->msg_len);
     640             : 
     641           0 :         if ((error = copyout(&msg->msg_type, ubuf, sizeof(long))))
     642           0 :                 return (error);
     643             : 
     644           0 :         ubuf += sizeof(long);
     645           0 :         *len = xfer;
     646             : 
     647           0 :         for (m = msg->msg_data; m; m = m->m_next) {
     648           0 :                 if ((error = copyout(mtod(m, void *), ubuf, m->m_len)))
     649           0 :                         return (error);
     650           0 :                 ubuf += m->m_len;
     651             :         }
     652             : 
     653           0 :         return (0);
     654           0 : }
     655             : 
     656             : int
     657           0 : sysctl_sysvmsg(int *name, u_int namelen, void *where, size_t *sizep)
     658             : {
     659             :         struct msg_sysctl_info *info;
     660             :         struct que *que;
     661             :         size_t infolen;
     662             :         int error;
     663             : 
     664           0 :         switch (*name) {
     665             :         case KERN_SYSVIPC_MSG_INFO:
     666             : 
     667           0 :                 if (namelen != 1)
     668           0 :                         return (ENOTDIR);
     669             : 
     670             :                 /*
     671             :                  * The userland ipcs(1) utility expects to be able
     672             :                  * to iterate over at least msginfo.msgmni queues,
     673             :                  * even if those queues don't exist. This is an
     674             :                  * artifact of the previous implementation of
     675             :                  * message queues; for now, emulate this behavior
     676             :                  * until a more thorough fix can be made.
     677             :                  */
     678           0 :                 infolen = sizeof(msginfo) +
     679           0 :                     msginfo.msgmni * sizeof(struct msqid_ds);
     680           0 :                 if (where == NULL) {
     681           0 :                         *sizep = infolen;
     682           0 :                         return (0);
     683             :                 }
     684             : 
     685             :                 /*
     686             :                  * More special-casing due to previous implementation:
     687             :                  * if the caller just wants the msginfo struct, then
     688             :                  * sizep will point to the value sizeof(struct msginfo).
     689             :                  * In that case, only copy out the msginfo struct to
     690             :                  * the caller.
     691             :                  */
     692           0 :                 if (*sizep == sizeof(struct msginfo))
     693           0 :                         return (copyout(&msginfo, where, sizeof(msginfo)));
     694             : 
     695           0 :                 info = malloc(infolen, M_TEMP, M_WAIT|M_ZERO);
     696             : 
     697             :                 /* if the malloc slept, this may have changed */
     698           0 :                 infolen = sizeof(msginfo) +
     699           0 :                     msginfo.msgmni * sizeof(struct msqid_ds);
     700             : 
     701           0 :                 if (*sizep < infolen) {
     702           0 :                         free(info, M_TEMP, 0);
     703           0 :                         return (ENOMEM);
     704             :                 }
     705             : 
     706           0 :                 memcpy(&info->msginfo, &msginfo, sizeof(struct msginfo));
     707             : 
     708             :                 /*
     709             :                  * Special case #3: the previous array-based implementation
     710             :                  * exported the array indices and userland has come to rely
     711             :                  * upon these indices, so keep behavior consisitent.
     712             :                  */
     713           0 :                 TAILQ_FOREACH(que, &msg_queues, que_next)
     714           0 :                         memcpy(&info->msgids[que->que_ix], &que->msqid_ds,
     715             :                             sizeof(struct msqid_ds));
     716             : 
     717           0 :                 error = copyout(info, where, infolen);
     718             : 
     719           0 :                 free(info, M_TEMP, 0);
     720             : 
     721           0 :                 return (error);
     722             : 
     723             :         default:
     724           0 :                 return (EINVAL);
     725             :         }
     726           0 : }

Generated by: LCOV version 1.13