1 /* $NetBSD: sysv_ipc_50.c,v 1.6 2019/01/27 02:08:39 pgoyette 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_50.c,v 1.6 2019/01/27 02:08:39 pgoyette Exp $"); 34 35 #ifdef _KERNEL_OPT 36 #include "opt_sysv.h" 37 #include "opt_compat_netbsd.h" 38 #endif 39 40 #include <sys/param.h> 41 #include <sys/kernel.h> 42 #include <sys/proc.h> 43 #include <sys/ipc.h> 44 #ifdef SYSVMSG 45 #include <sys/msg.h> 46 #endif 47 #ifdef SYSVSEM 48 #include <sys/sem.h> 49 #endif 50 #ifdef SYSVSHM 51 #include <sys/shm.h> 52 #endif 53 #include <sys/systm.h> 54 #include <sys/malloc.h> 55 #include <sys/mount.h> 56 #include <sys/vnode.h> 57 #include <sys/stat.h> 58 #include <sys/sysctl.h> 59 #include <sys/kauth.h> 60 61 #include <compat/sys/ipc.h> 62 #ifdef SYSVMSG 63 #include <compat/sys/msg.h> 64 #endif 65 #ifdef SYSVSEM 66 #include <compat/sys/sem.h> 67 #endif 68 #ifdef SYSVSHM 69 #include <compat/sys/shm.h> 70 #endif 71 72 /* 73 * Check for ipc permission 74 */ 75 76 int 77 sysctl_kern_sysvipc50(SYSCTLFN_ARGS) 78 { 79 void *where = oldp; 80 size_t *sizep = oldlenp; 81 #ifdef SYSVMSG 82 struct msg_sysctl_info50 *msgsi = NULL; 83 #endif 84 #ifdef SYSVSEM 85 struct sem_sysctl_info50 *semsi = NULL; 86 #endif 87 #ifdef SYSVSHM 88 struct shm_sysctl_info50 *shmsi = NULL; 89 #endif 90 size_t infosize, dssize, tsize, buflen; 91 void *bf = NULL; 92 char *start; 93 int32_t nds; 94 int i, error, ret; 95 96 if (namelen != 1) 97 return EINVAL; 98 99 start = where; 100 buflen = *sizep; 101 102 switch (*name) { 103 case KERN_SYSVIPC_OMSG_INFO: 104 #ifdef SYSVMSG 105 infosize = sizeof(msgsi->msginfo); 106 nds = msginfo.msgmni; 107 dssize = sizeof(msgsi->msgids[0]); 108 break; 109 #else 110 return EINVAL; 111 #endif 112 case KERN_SYSVIPC_OSEM_INFO: 113 #ifdef SYSVSEM 114 infosize = sizeof(semsi->seminfo); 115 nds = seminfo.semmni; 116 dssize = sizeof(semsi->semids[0]); 117 break; 118 #else 119 return EINVAL; 120 #endif 121 case KERN_SYSVIPC_OSHM_INFO: 122 #ifdef SYSVSHM 123 infosize = sizeof(shmsi->shminfo); 124 nds = shminfo.shmmni; 125 dssize = sizeof(shmsi->shmids[0]); 126 break; 127 #else 128 return EINVAL; 129 #endif 130 default: 131 return EPASSTHROUGH; 132 } 133 /* 134 * Round infosize to 64 bit boundary if requesting more than just 135 * the info structure or getting the total data size. 136 */ 137 if (where == NULL || *sizep > infosize) 138 infosize = roundup(infosize, sizeof(quad_t)); 139 tsize = infosize + nds * dssize; 140 141 /* Return just the total size required. */ 142 if (where == NULL) { 143 *sizep = tsize; 144 return 0; 145 } 146 147 /* Not enough room for even the info struct. */ 148 if (buflen < infosize) { 149 *sizep = 0; 150 return ENOMEM; 151 } 152 bf = malloc(uimin(tsize, buflen), M_TEMP, M_WAITOK | M_ZERO); 153 154 switch (*name) { 155 #ifdef SYSVMSG 156 case KERN_SYSVIPC_OMSG_INFO: 157 msgsi = (struct msg_sysctl_info50 *)bf; 158 msgsi->msginfo = msginfo; 159 break; 160 #endif 161 #ifdef SYSVSEM 162 case KERN_SYSVIPC_OSEM_INFO: 163 semsi = (struct sem_sysctl_info50 *)bf; 164 semsi->seminfo = seminfo; 165 break; 166 #endif 167 #ifdef SYSVSHM 168 case KERN_SYSVIPC_OSHM_INFO: 169 shmsi = (struct shm_sysctl_info50 *)bf; 170 shmsi->shminfo = shminfo; 171 break; 172 #endif 173 } 174 buflen -= infosize; 175 176 ret = 0; 177 if (buflen > 0) { 178 /* Fill in the IPC data structures. */ 179 for (i = 0; i < nds; i++) { 180 if (buflen < dssize) { 181 ret = ENOMEM; 182 break; 183 } 184 switch (*name) { 185 #ifdef SYSVMSG 186 case KERN_SYSVIPC_OMSG_INFO: 187 mutex_enter(&msgmutex); 188 SYSCTL_FILL_MSG(msqs[i].msq_u, msgsi->msgids[i]); 189 mutex_exit(&msgmutex); 190 break; 191 #endif 192 #ifdef SYSVSEM 193 case KERN_SYSVIPC_OSEM_INFO: 194 SYSCTL_FILL_SEM(sema[i], semsi->semids[i]); 195 break; 196 #endif 197 #ifdef SYSVSHM 198 case KERN_SYSVIPC_OSHM_INFO: 199 SYSCTL_FILL_SHM(shmsegs[i], shmsi->shmids[i]); 200 break; 201 #endif 202 } 203 buflen -= dssize; 204 } 205 } 206 *sizep -= buflen; 207 error = copyout(bf, start, *sizep); 208 /* If copyout succeeded, use return code set earlier. */ 209 if (error == 0) 210 error = ret; 211 if (bf) 212 free(bf, M_TEMP); 213 return error; 214 } 215