The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/sysv_ipc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: sysv_ipc.c,v 1.42 2022/03/27 16:23:08 christos Exp $   */
    2 
    3 /*-
    4  * Copyright (c) 1998, 2007 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Charles M. Hannum.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __KERNEL_RCSID(0, "$NetBSD: sysv_ipc.c,v 1.42 2022/03/27 16:23:08 christos Exp $");
   34 
   35 #ifdef _KERNEL_OPT
   36 #include "opt_sysv.h"
   37 #include "opt_sysvparam.h"
   38 #include "opt_compat_netbsd.h"
   39 #endif
   40 
   41 #include <sys/syscall.h>
   42 #include <sys/syscallargs.h>
   43 #include <sys/syscallvar.h>
   44 #include <sys/param.h>
   45 #include <sys/kernel.h>
   46 #include <sys/proc.h>
   47 #include <sys/ipc.h>
   48 #ifdef SYSVMSG
   49 #include <sys/msg.h>
   50 #endif
   51 #ifdef SYSVSEM
   52 #include <sys/sem.h>
   53 #endif
   54 #ifdef SYSVSHM
   55 #include <sys/shm.h>
   56 #endif
   57 #include <sys/systm.h>
   58 #include <sys/kmem.h>
   59 #include <sys/module.h>
   60 #include <sys/mount.h>
   61 #include <sys/vnode.h>
   62 #include <sys/stat.h>
   63 #include <sys/sysctl.h>
   64 #include <sys/kauth.h>
   65 #include <sys/compat_stub.h>
   66 
   67 #include <compat/common/compat_sysv_mod.h>      /* for sysctl routine vector */
   68 
   69 /*
   70  * Values in support of System V compatible shared memory.      XXX
   71  * (originally located in sys/conf/param.c)
   72  */
   73 #ifdef SYSVSHM
   74 #if !defined(SHMMAX) && defined(SHMMAXPGS)
   75 #define SHMMAX  SHMMAXPGS       /* shminit() performs a `*= PAGE_SIZE' */
   76 #elif !defined(SHMMAX)
   77 #define SHMMAX 0
   78 #endif
   79 #ifndef SHMMIN
   80 #define SHMMIN  1
   81 #endif
   82 #ifndef SHMMNI
   83 #define SHMMNI  128             /* <64k, see IPCID_TO_IX in ipc.h */
   84 #endif
   85 #ifndef SHMSEG
   86 #define SHMSEG  128
   87 #endif
   88 
   89 struct  shminfo shminfo = {
   90         SHMMAX,
   91         SHMMIN,
   92         SHMMNI,
   93         SHMSEG,
   94         0
   95 };
   96 #endif
   97 
   98 /*
   99  * Values in support of System V compatible semaphores.
  100  */
  101 #ifdef SYSVSEM
  102 struct  seminfo seminfo = {
  103         SEMMAP,         /* # of entries in semaphore map */
  104         SEMMNI,         /* # of semaphore identifiers */
  105         SEMMNS,         /* # of semaphores in system */
  106         SEMMNU,         /* # of undo structures in system */
  107         SEMMSL,         /* max # of semaphores per id */
  108         SEMOPM,         /* max # of operations per semop call */
  109         SEMUME,         /* max # of undo entries per process */
  110         SEMUSZ,         /* size in bytes of undo structure */
  111         SEMVMX,         /* semaphore maximum value */
  112         SEMAEM          /* adjust on exit max value */
  113 };
  114 #endif
  115 
  116 /*
  117  * Values in support of System V compatible messages.
  118  */
  119 #ifdef SYSVMSG
  120 struct  msginfo msginfo = {
  121         MSGMAX,         /* max chars in a message */
  122         MSGMNI,         /* # of message queue identifiers */
  123         MSGMNB,         /* max chars in a queue */
  124         MSGTQL,         /* max messages in system */
  125         MSGSSZ,         /* size of a message segment */
  126                         /* (must be small power of 2 greater than 4) */
  127         MSGSEG          /* number of message segments */
  128 };
  129 #endif
  130 
  131 MODULE(MODULE_CLASS_EXEC, sysv_ipc, NULL);
  132  
  133 SYSCTL_SETUP_PROTO(sysctl_ipc_setup);
  134 
  135 static const struct syscall_package sysvipc_syscalls[] = {
  136 #if defined(SYSVSHM)
  137         { SYS___shmctl50, 0, (sy_call_t *)sys___shmctl50 },
  138         { SYS_shmat, 0, (sy_call_t *)sys_shmat },
  139         { SYS_shmdt, 0, (sy_call_t *)sys_shmdt },
  140         { SYS_shmget, 0, (sy_call_t *)sys_shmget },
  141 #endif  /* SYSVSHM */
  142 
  143 #if defined(SYSVSEM)
  144         { SYS_____semctl50, 0, (sy_call_t *)sys_____semctl50 },
  145         { SYS_semget, 0, (sy_call_t *)sys_semget },
  146         { SYS_semop, 0, (sy_call_t *)sys_semop },
  147         { SYS_semconfig, 0, (sy_call_t *)sys_semconfig },
  148 #endif  /* SYSVSEM */
  149 
  150 #if defined(SYSVMSG)
  151         { SYS___msgctl50, 0, (sy_call_t *)sys___msgctl50 },
  152         { SYS_msgget, 0, (sy_call_t *)sys_msgget },
  153         { SYS_msgsnd, 0, (sy_call_t *)sys_msgsnd },
  154         { SYS_msgrcv, 0, (sy_call_t *)sys_msgrcv },
  155 #endif  /* SYSVMSG */
  156         { 0, 0, NULL }
  157 };
  158 
  159 static int
  160 sysv_ipc_modcmd(modcmd_t cmd, void *arg)
  161 {
  162         int error = 0;
  163 
  164         switch (cmd) {
  165         case MODULE_CMD_INIT:
  166                 /* Set up the kauth listener */
  167                 sysvipcinit();
  168 
  169                 /* Link the system calls */
  170                 error = syscall_establish(NULL, sysvipc_syscalls);
  171                 if (error) {
  172                         sysvipcfini();
  173                         return error;
  174                 }
  175 
  176                 /*
  177                  * Initialize each sub-component, including their
  178                  * sysctl data
  179                  */
  180 #ifdef SYSVSHM
  181                 error = shminit();
  182                 if (error != 0)
  183                         return error;
  184 #endif
  185 #ifdef SYSVSEM
  186                 error = seminit();
  187                 if (error != 0) {
  188 #ifdef SYSVSHM
  189                         shmfini();
  190 #endif
  191                         return error;
  192                 }
  193 #endif
  194 #ifdef SYSVMSG
  195                 error = msginit();
  196                 if (error != 0) {
  197 #ifdef SYSVSEM
  198                         semfini();
  199 #endif
  200 #ifdef SYSVSHM
  201                         shmfini();
  202 #endif
  203                         return error;
  204                 }
  205 #endif
  206                 break;
  207         case MODULE_CMD_FINI:
  208                 /*
  209                  * Make sure no subcomponents are active.  Each one
  210                  * tells us if it is busy, and if it was _not_ busy,
  211                  * we assume it has already done its own clean-up.
  212                  * So we might need to re-init any components that
  213                  * are successfully fini'd if we find one that is 
  214                  * still busy.
  215                  */
  216 #ifdef SYSVSHM
  217                 if (shmfini()) {
  218                         return EBUSY;
  219                 }
  220 #endif
  221 #ifdef SYSVSEM
  222                 if (semfini()) {
  223 #ifdef SYSVSHM
  224                         shminit();
  225 #endif
  226                         return EBUSY;
  227                 }
  228 #endif
  229 #ifdef SYSVMSG
  230                 if (msgfini()) {
  231 #ifdef SYSVSEM
  232                         seminit();
  233 #endif
  234 #ifdef SYSVSHM
  235                         shminit();
  236 #endif
  237                         return EBUSY;
  238                 }
  239 #endif
  240                 /* Unlink the system calls. */
  241                 error = syscall_disestablish(NULL, sysvipc_syscalls);
  242                 if (error)
  243                         return error;
  244 
  245                 /* Remove the kauth listener */
  246                 sysvipcfini();
  247                 break;
  248         default:
  249                 return ENOTTY;
  250         }
  251         return error;
  252 }
  253 
  254 static kauth_listener_t sysvipc_listener = NULL;
  255 
  256 static int
  257 sysvipc_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
  258     void *arg0, void *arg1, void *arg2, void *arg3)
  259 {
  260         mode_t mask;
  261         struct ipc_perm *perm;
  262         int mode;
  263         enum kauth_system_req req;
  264 
  265         req = (enum kauth_system_req)(uintptr_t)arg0;
  266 
  267         if (!(action == KAUTH_SYSTEM_SYSVIPC &&
  268               req == KAUTH_REQ_SYSTEM_SYSVIPC_BYPASS))
  269                 return KAUTH_RESULT_DEFER;
  270 
  271         perm = arg1;
  272         mode = (int)(uintptr_t)arg2;
  273 
  274         if (mode == IPC_M) {
  275                 if (kauth_cred_geteuid(cred) == perm->uid ||
  276                     kauth_cred_geteuid(cred) == perm->cuid)
  277                         return (KAUTH_RESULT_ALLOW);
  278                 return (KAUTH_RESULT_DEFER); /* EPERM */
  279         }
  280 
  281         mask = 0;
  282 
  283         if (kauth_cred_geteuid(cred) == perm->uid ||
  284             kauth_cred_geteuid(cred) == perm->cuid) {
  285                 if (mode & IPC_R)
  286                         mask |= S_IRUSR;
  287                 if (mode & IPC_W)
  288                         mask |= S_IWUSR;
  289                 return ((perm->mode & mask) == mask ? KAUTH_RESULT_ALLOW : KAUTH_RESULT_DEFER /* EACCES */);
  290         }
  291 
  292         if (kauth_cred_groupmember(cred, perm->gid) == 0 ||
  293             kauth_cred_groupmember(cred, perm->cgid) == 0) {
  294                 if (mode & IPC_R)
  295                         mask |= S_IRGRP;
  296                 if (mode & IPC_W)
  297                         mask |= S_IWGRP;
  298                 return ((perm->mode & mask) == mask ? KAUTH_RESULT_ALLOW : KAUTH_RESULT_DEFER /* EACCES */);
  299         }
  300 
  301         if (mode & IPC_R)
  302                 mask |= S_IROTH;
  303         if (mode & IPC_W)
  304                 mask |= S_IWOTH;
  305         return ((perm->mode & mask) == mask ? KAUTH_RESULT_ALLOW : KAUTH_RESULT_DEFER /* EACCES */);
  306 }
  307 
  308 /*
  309  * Check for ipc permission
  310  */
  311 
  312 int
  313 ipcperm(kauth_cred_t cred, struct ipc_perm *perm, int mode)
  314 {
  315         int error;
  316 
  317         error = kauth_authorize_system(cred, KAUTH_SYSTEM_SYSVIPC,
  318             KAUTH_REQ_SYSTEM_SYSVIPC_BYPASS, perm, KAUTH_ARG(mode), NULL);
  319         if (error == 0)
  320                 return (0);
  321 
  322         /* Adjust EPERM and EACCES errors until there's a better way to do this. */
  323         if (mode != IPC_M)
  324                 error = EACCES;
  325 
  326         return error;
  327 }
  328 
  329 void
  330 sysvipcfini(void)
  331 {
  332 
  333         KASSERT(sysvipc_listener != NULL);
  334         kauth_unlisten_scope(sysvipc_listener);
  335         sysvipc_listener = NULL;
  336 }
  337 
  338 void
  339 sysvipcinit(void)
  340 {
  341 
  342         KASSERT(sysvipc_listener == NULL);
  343 
  344         sysvipc_listener = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
  345             sysvipc_listener_cb, NULL);
  346 }
  347 
  348 static int
  349 stub_sysvipc50_sysctl(SYSCTLFN_ARGS)
  350 {
  351         return EPASSTHROUGH;
  352 }
  353 
  354 static int
  355 sysctl_kern_sysvipc(SYSCTLFN_ARGS)
  356 {
  357         void *where = oldp;
  358         size_t sz, *sizep = oldlenp;
  359 #ifdef SYSVMSG
  360         struct msg_sysctl_info *msgsi = NULL;
  361 #endif
  362 #ifdef SYSVSEM
  363         struct sem_sysctl_info *semsi = NULL;
  364 #endif
  365 #ifdef SYSVSHM
  366         struct shm_sysctl_info *shmsi = NULL;
  367 #endif
  368         size_t infosize, dssize, tsize, buflen;
  369         void *bf = NULL;
  370         char *start;
  371         int32_t nds;
  372         int i, error, ret;
  373 
  374 /*
  375  * If present, call the compat sysctl() code.  If it handles the request
  376  * completely (either success or error), return.  Otherwise fallthrough
  377  * to the non-compat sysctl code.
  378  */
  379 
  380         MODULE_HOOK_CALL(sysvipc_sysctl_50_hook, (SYSCTLFN_CALL(rnode)),
  381             stub_sysvipc50_sysctl(SYSCTLFN_CALL(rnode)), error);
  382         if (error != EPASSTHROUGH)
  383                 return error;
  384 
  385         if (namelen != 1)
  386                 return EINVAL;
  387 
  388         start = where;
  389         buflen = *sizep;
  390 
  391         switch (*name) {
  392         case KERN_SYSVIPC_MSG_INFO:
  393 #ifdef SYSVMSG
  394                 infosize = sizeof(msgsi->msginfo);
  395                 nds = msginfo.msgmni;
  396                 dssize = sizeof(msgsi->msgids[0]);
  397                 break;
  398 #else
  399                 return EINVAL;
  400 #endif
  401         case KERN_SYSVIPC_SEM_INFO:
  402 #ifdef SYSVSEM
  403                 infosize = sizeof(semsi->seminfo);
  404                 nds = seminfo.semmni;
  405                 dssize = sizeof(semsi->semids[0]);
  406                 break;
  407 #else
  408                 return EINVAL;
  409 #endif
  410         case KERN_SYSVIPC_SHM_INFO:
  411 #ifdef SYSVSHM
  412                 infosize = sizeof(shmsi->shminfo);
  413                 nds = shminfo.shmmni;
  414                 dssize = sizeof(shmsi->shmids[0]);
  415                 break;
  416 #else
  417                 return EINVAL;
  418 #endif
  419         default:
  420                 return EINVAL;
  421         }
  422         /*
  423          * Round infosize to 64 bit boundary if requesting more than just
  424          * the info structure or getting the total data size.
  425          */
  426         if (where == NULL || *sizep > infosize)
  427                 infosize = roundup(infosize, sizeof(quad_t));
  428         tsize = infosize + nds * dssize;
  429 
  430         /* Return just the total size required. */
  431         if (where == NULL) {
  432                 *sizep = tsize;
  433                 return 0;
  434         }
  435 
  436         /* Not enough room for even the info struct. */
  437         if (buflen < infosize) {
  438                 *sizep = 0;
  439                 return ENOMEM;
  440         }
  441         sz = uimin(tsize, buflen);
  442         bf = kmem_zalloc(sz, KM_SLEEP);
  443 
  444         switch (*name) {
  445 #ifdef SYSVMSG
  446         case KERN_SYSVIPC_MSG_INFO:
  447                 msgsi = (struct msg_sysctl_info *)bf;
  448                 msgsi->msginfo = msginfo;
  449                 break;
  450 #endif
  451 #ifdef SYSVSEM
  452         case KERN_SYSVIPC_SEM_INFO:
  453                 semsi = (struct sem_sysctl_info *)bf;
  454                 semsi->seminfo = seminfo;
  455                 break;
  456 #endif
  457 #ifdef SYSVSHM
  458         case KERN_SYSVIPC_SHM_INFO:
  459                 shmsi = (struct shm_sysctl_info *)bf;
  460                 shmsi->shminfo = shminfo;
  461                 break;
  462 #endif
  463         }
  464         buflen -= infosize;
  465 
  466         ret = 0;
  467         if (buflen > 0) {
  468                 /* Fill in the IPC data structures.  */
  469                 for (i = 0; i < nds; i++) {
  470                         if (buflen < dssize) {
  471                                 ret = ENOMEM;
  472                                 break;
  473                         }
  474                         switch (*name) {
  475 #ifdef SYSVMSG
  476                         case KERN_SYSVIPC_MSG_INFO:
  477                                 mutex_enter(&msgmutex);
  478                                 SYSCTL_FILL_MSG(msqs[i].msq_u, msgsi->msgids[i]);
  479                                 mutex_exit(&msgmutex);
  480                                 break;
  481 #endif
  482 #ifdef SYSVSEM
  483                         case KERN_SYSVIPC_SEM_INFO:
  484                                 SYSCTL_FILL_SEM(sema[i], semsi->semids[i]);
  485                                 break;
  486 #endif
  487 #ifdef SYSVSHM
  488                         case KERN_SYSVIPC_SHM_INFO:
  489                                 SYSCTL_FILL_SHM(shmsegs[i], shmsi->shmids[i]);
  490                                 break;
  491 #endif
  492                         }
  493                         buflen -= dssize;
  494                 }
  495         }
  496         *sizep -= buflen;
  497         error = copyout(bf, start, *sizep);
  498         /* If copyout succeeded, use return code set earlier. */
  499         if (error == 0)
  500                 error = ret;
  501         if (bf)
  502                 kmem_free(bf, sz);
  503         return error;
  504 }
  505 
  506 SYSCTL_SETUP(sysctl_ipc_setup, "sysctl kern.ipc subtree setup")
  507 {
  508 
  509         sysctl_createv(clog, 0, NULL, NULL,
  510                 CTLFLAG_PERMANENT,
  511                 CTLTYPE_NODE, "ipc",
  512                 SYSCTL_DESCR("SysV IPC options"),
  513                 NULL, 0, NULL, 0,
  514                 CTL_KERN, KERN_SYSVIPC, CTL_EOL);
  515 
  516         sysctl_createv(clog, 0, NULL, NULL,
  517                 CTLFLAG_PERMANENT,
  518                 CTLTYPE_STRUCT, "sysvipc_info",
  519                 SYSCTL_DESCR("System V style IPC information"),
  520                 sysctl_kern_sysvipc, 0, NULL, 0,
  521                 CTL_KERN, KERN_SYSVIPC, KERN_SYSVIPC_INFO, CTL_EOL);
  522 }

Cache object: 8bccf462fa71a0f5687d656611ae9281


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.