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