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