1 /* $NetBSD: linux32_ipccall.c,v 1.3 2009/02/18 14:40:14 njoly Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Nicolas Joly 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: linux32_ipccall.c,v 1.3 2009/02/18 14:40:14 njoly Exp $"); 31 32 #if defined(_KERNEL_OPT) 33 #include "opt_sysv.h" 34 #endif 35 36 #include <sys/param.h> 37 #include <sys/vnode.h> 38 #include <sys/sem.h> 39 #include <sys/shm.h> 40 41 #include <sys/syscallargs.h> 42 43 #include <compat/netbsd32/netbsd32.h> 44 45 #include <compat/linux32/common/linux32_types.h> 46 #include <compat/linux32/common/linux32_signal.h> 47 #include <compat/linux32/linux32_syscallargs.h> 48 #include <compat/linux32/common/linux32_ipc.h> 49 #include <compat/linux32/common/linux32_sem.h> 50 #include <compat/linux32/common/linux32_shm.h> 51 52 #define LINUX32_IPC_semop 1 53 #define LINUX32_IPC_semget 2 54 #define LINUX32_IPC_semctl 3 55 #define LINUX32_IPC_msgsnd 11 56 #define LINUX32_IPC_msgrcv 12 57 #define LINUX32_IPC_msgget 13 58 #define LINUX32_IPC_msgctl 14 59 #define LINUX32_IPC_shmat 21 60 #define LINUX32_IPC_shmdt 22 61 #define LINUX32_IPC_shmget 23 62 #define LINUX32_IPC_shmctl 24 63 64 #ifdef SYSVSEM 65 static void 66 bsd_to_linux32_semid_ds(struct semid_ds *, struct linux32_semid_ds *); 67 static void 68 bsd_to_linux32_semid64_ds(struct semid_ds *, struct linux32_semid64_ds *); 69 static void 70 linux32_to_bsd_semid_ds(struct linux32_semid_ds *, struct semid_ds *); 71 static void 72 linux32_to_bsd_semid64_ds(struct linux32_semid64_ds *, struct semid_ds *); 73 74 static int 75 linux32_semop(struct lwp *, const struct linux32_sys_ipc_args *, register_t *); 76 static int 77 linux32_semget(struct lwp *, const struct linux32_sys_ipc_args *, register_t *); 78 static int 79 linux32_semctl(struct lwp *, const struct linux32_sys_ipc_args *, register_t *); 80 #endif /* SYSVSEM */ 81 82 #ifdef SYSVSHM 83 static void 84 bsd_to_linux32_shmid_ds(struct shmid_ds *, struct linux32_shmid_ds *); 85 static void 86 linux32_to_bsd_shmid_ds(struct linux32_shmid_ds *, struct shmid_ds *); 87 static void 88 bsd_to_linux32_shmid64_ds(struct shmid_ds *, struct linux32_shmid64_ds *); 89 static void 90 linux32_to_bsd_shmid64_ds(struct linux32_shmid64_ds *, struct shmid_ds *); 91 92 static int 93 linux32_shmat(struct lwp *, const struct linux32_sys_ipc_args *, register_t *); 94 static int 95 linux32_shmdt(struct lwp *, const struct linux32_sys_ipc_args *, register_t *); 96 static int 97 linux32_shmget(struct lwp *, const struct linux32_sys_ipc_args *, register_t *); 98 static int 99 linux32_shmctl(struct lwp *, const struct linux32_sys_ipc_args *, register_t *); 100 #endif /* SYSVSHM */ 101 102 int 103 linux32_sys_ipc(struct lwp *l, const struct linux32_sys_ipc_args *uap, 104 register_t *retval) 105 { 106 /* { 107 syscallarg(int) what; 108 syscallarg(int) a1; 109 syscallarg(int) a2; 110 syscallarg(int) a3; 111 syscallarg(netbsd32_voidp) ptr; 112 } */ 113 114 switch (SCARG(uap, what)) { 115 #ifdef SYSVSEM 116 case LINUX32_IPC_semop: 117 return linux32_semop(l, uap, retval);; 118 case LINUX32_IPC_semget: 119 return linux32_semget(l, uap, retval); 120 case LINUX32_IPC_semctl: 121 return linux32_semctl(l, uap, retval); 122 #endif /* SYSVSEM */ 123 #ifdef SYSVSHM 124 case LINUX32_IPC_shmat: 125 return linux32_shmat(l, uap, retval); 126 case LINUX32_IPC_shmdt: 127 return linux32_shmdt(l, uap, retval); 128 case LINUX32_IPC_shmget: 129 return linux32_shmget(l, uap, retval); 130 case LINUX32_IPC_shmctl: 131 return linux32_shmctl(l, uap, retval); 132 #endif /* SYSVSHM */ 133 default: 134 return ENOSYS; 135 } 136 137 } 138 139 static void 140 bsd_to_linux32_ipc_perm(struct ipc_perm *bpp, struct linux32_ipc_perm *lpp) 141 { 142 lpp->l_key = bpp->_key; 143 lpp->l_uid = bpp->uid; 144 lpp->l_gid = bpp->gid; 145 lpp->l_cuid = bpp->cuid; 146 lpp->l_cgid = bpp->cgid; 147 lpp->l_mode = bpp->mode; 148 lpp->l_seq = bpp->_seq; 149 } 150 151 static void 152 linux32_to_bsd_ipc_perm(struct linux32_ipc_perm *lpp, struct ipc_perm *bpp) 153 { 154 bpp->_key = lpp->l_key; 155 bpp->uid = lpp->l_uid; 156 bpp->gid = lpp->l_gid; 157 bpp->cuid = lpp->l_cuid; 158 bpp->cgid = lpp->l_cgid; 159 bpp->mode = lpp->l_mode; 160 bpp->_seq = lpp->l_seq; 161 } 162 163 static void 164 bsd_to_linux32_ipc64_perm(struct ipc_perm *bpp, struct linux32_ipc64_perm *lpp) 165 { 166 lpp->l_key = bpp->_key; 167 lpp->l_uid = bpp->uid; 168 lpp->l_gid = bpp->gid; 169 lpp->l_cuid = bpp->cuid; 170 lpp->l_cgid = bpp->cgid; 171 lpp->l_mode = bpp->mode; 172 lpp->l_seq = bpp->_seq; 173 } 174 175 static void 176 linux32_to_bsd_ipc64_perm(struct linux32_ipc64_perm *lpp, struct ipc_perm *bpp) 177 { 178 bpp->_key = lpp->l_key; 179 bpp->uid = lpp->l_uid; 180 bpp->gid = lpp->l_gid; 181 bpp->cuid = lpp->l_cuid; 182 bpp->cgid = lpp->l_cgid; 183 bpp->mode = lpp->l_mode; 184 bpp->_seq = lpp->l_seq; 185 } 186 187 #ifdef SYSVSEM 188 static void 189 bsd_to_linux32_semid_ds(struct semid_ds *bsp, struct linux32_semid_ds *lsp) 190 { 191 bsd_to_linux32_ipc_perm(&bsp->sem_perm, &lsp->l_sem_perm); 192 lsp->l_sem_otime = bsp->sem_otime; 193 lsp->l_sem_ctime = bsp->sem_ctime; 194 lsp->l_sem_nsems = bsp->sem_nsems; 195 NETBSD32PTR32(lsp->l_sem_base, bsp->_sem_base); 196 } 197 198 static void 199 bsd_to_linux32_semid64_ds(struct semid_ds *bsp, struct linux32_semid64_ds *lsp) 200 { 201 bsd_to_linux32_ipc64_perm(&bsp->sem_perm, &lsp->l_sem_perm); 202 lsp->l_sem_otime = bsp->sem_otime; 203 lsp->l_sem_ctime = bsp->sem_ctime; 204 lsp->l_sem_nsems = bsp->sem_nsems; 205 } 206 207 static void 208 linux32_to_bsd_semid_ds(struct linux32_semid_ds *lsp, struct semid_ds *bsp) 209 { 210 linux32_to_bsd_ipc_perm(&lsp->l_sem_perm, &bsp->sem_perm); 211 bsp->sem_otime = lsp->l_sem_otime; 212 bsp->sem_ctime = lsp->l_sem_ctime; 213 bsp->sem_nsems = lsp->l_sem_nsems; 214 bsp->_sem_base = NETBSD32PTR64(lsp->l_sem_base); 215 } 216 217 static void 218 linux32_to_bsd_semid64_ds(struct linux32_semid64_ds *lsp, struct semid_ds *bsp) 219 { 220 linux32_to_bsd_ipc64_perm(&lsp->l_sem_perm, &bsp->sem_perm); 221 bsp->sem_otime = lsp->l_sem_otime; 222 bsp->sem_ctime = lsp->l_sem_ctime; 223 bsp->sem_nsems = lsp->l_sem_nsems; 224 } 225 226 static int 227 linux32_semop(struct lwp *l, const struct linux32_sys_ipc_args *uap, 228 register_t *retval) 229 { 230 struct sys_semop_args ua; 231 232 SCARG(&ua, semid) = SCARG(uap, a1); 233 SCARG(&ua, sops) = SCARG_P32(uap, ptr); 234 SCARG(&ua, nsops) = SCARG(uap, a2); 235 236 return sys_semop(l, &ua, retval); 237 } 238 239 static int 240 linux32_semget(struct lwp *l, const struct linux32_sys_ipc_args *uap, 241 register_t *retval) 242 { 243 struct sys_semget_args ua; 244 245 SCARG(&ua, key) = SCARG(uap, a1); 246 SCARG(&ua, nsems) = SCARG(uap, a2); 247 SCARG(&ua, semflg) = SCARG(uap, a3); 248 249 return sys_semget(l, &ua, retval); 250 } 251 252 static int 253 linux32_semctl(struct lwp *l, const struct linux32_sys_ipc_args *uap, 254 register_t *retval) 255 { 256 int cmd, error; 257 struct semid_ds bs; 258 struct linux32_semid_ds ls; 259 struct linux32_semid64_ds ls64; 260 union linux32_semun lsem; 261 union __semun bsem; 262 void *buf = NULL; 263 264 if ((error = copyin(SCARG_P32(uap, ptr), &lsem, sizeof lsem))) 265 return error; 266 267 switch (SCARG(uap, a3)) { 268 case LINUX32_IPC_RMID: 269 cmd = IPC_RMID; 270 break; 271 case LINUX32_IPC_STAT: 272 case LINUX32_IPC_STAT|LINUX32_IPC_64: 273 cmd = IPC_STAT; 274 buf = &bs; 275 break; 276 case LINUX32_IPC_SET: 277 error = copyin(NETBSD32PTR64(lsem.l_buf), &ls, sizeof ls); 278 if (error) 279 return error; 280 linux32_to_bsd_semid_ds(&ls, &bs); 281 cmd = IPC_SET; 282 buf = &bs; 283 break; 284 case LINUX32_IPC_SET|LINUX32_IPC_64: 285 error = copyin(NETBSD32PTR64(lsem.l_buf), &ls64, sizeof ls64); 286 if (error) 287 return error; 288 linux32_to_bsd_semid64_ds(&ls64, &bs); 289 cmd = IPC_SET; 290 buf = &bs; 291 break; 292 case LINUX32_GETVAL: 293 cmd = GETVAL; 294 break; 295 case LINUX32_SETVAL: 296 cmd = SETVAL; 297 bsem.val = lsem.l_val; 298 buf = &bsem; 299 break; 300 case LINUX32_GETPID: 301 cmd = GETPID; 302 break; 303 case LINUX32_GETNCNT: 304 cmd = GETNCNT; 305 break; 306 case LINUX32_GETZCNT: 307 cmd = GETZCNT; 308 break; 309 case LINUX32_GETALL: 310 cmd = GETALL; 311 bsem.array = NETBSD32PTR64(lsem.l_array); 312 buf = &bsem; 313 break; 314 case LINUX32_SETALL: 315 cmd = SETALL; 316 bsem.array = NETBSD32PTR64(lsem.l_array); 317 buf = &bsem; 318 break; 319 default: 320 return EINVAL; 321 } 322 323 error = semctl1(l, SCARG(uap, a1), SCARG(uap, a2), cmd, buf, retval); 324 if (error) 325 return error; 326 327 switch (SCARG(uap, a3)) { 328 case LINUX32_IPC_STAT: 329 bsd_to_linux32_semid_ds(&bs, &ls); 330 error = copyout(&ls, NETBSD32PTR64(lsem.l_buf), sizeof ls); 331 break; 332 case LINUX32_IPC_STAT|LINUX32_IPC_64: 333 bsd_to_linux32_semid64_ds(&bs, &ls64); 334 error = copyout(&ls64, NETBSD32PTR64(lsem.l_buf), sizeof ls64); 335 break; 336 default: 337 break; 338 } 339 340 return error; 341 } 342 #endif /* SYSVSEM */ 343 344 #ifdef SYSVSHM 345 static void 346 bsd_to_linux32_shmid_ds(struct shmid_ds *bsp, struct linux32_shmid_ds *lsp) 347 { 348 bsd_to_linux32_ipc_perm(&bsp->shm_perm, &lsp->l_shm_perm); 349 lsp->l_shm_segsz = bsp->shm_segsz; 350 lsp->l_shm_atime = bsp->shm_atime; 351 lsp->l_shm_dtime = bsp->shm_dtime; 352 lsp->l_shm_ctime = bsp->shm_ctime; 353 lsp->l_shm_cpid = bsp->shm_cpid; 354 lsp->l_shm_lpid = bsp->shm_lpid; 355 lsp->l_shm_nattch = bsp->shm_nattch; 356 NETBSD32PTR32(lsp->l_private2, bsp->_shm_internal); 357 } 358 359 static void 360 linux32_to_bsd_shmid_ds(struct linux32_shmid_ds *lsp, struct shmid_ds *bsp) 361 { 362 linux32_to_bsd_ipc_perm(&lsp->l_shm_perm, &bsp->shm_perm); 363 bsp->shm_segsz = lsp->l_shm_segsz; 364 bsp->shm_atime = lsp->l_shm_atime; 365 bsp->shm_dtime = lsp->l_shm_dtime; 366 bsp->shm_ctime = lsp->l_shm_ctime; 367 bsp->shm_cpid = lsp->l_shm_cpid; 368 bsp->shm_lpid = lsp->l_shm_lpid; 369 bsp->shm_nattch = lsp->l_shm_nattch; 370 bsp->_shm_internal = NETBSD32PTR64(lsp->l_private2); 371 } 372 373 static void 374 bsd_to_linux32_shmid64_ds(struct shmid_ds *bsp, struct linux32_shmid64_ds *lsp) 375 { 376 bsd_to_linux32_ipc64_perm(&bsp->shm_perm, &lsp->l_shm_perm); 377 lsp->l_shm_segsz = bsp->shm_segsz; 378 lsp->l_shm_atime = bsp->shm_atime; 379 lsp->l_shm_dtime = bsp->shm_dtime; 380 lsp->l_shm_ctime = bsp->shm_ctime; 381 lsp->l_shm_cpid = bsp->shm_cpid; 382 lsp->l_shm_lpid = bsp->shm_lpid; 383 lsp->l_shm_nattch = bsp->shm_nattch; 384 lsp->l___unused5 = NETBSD32PTR32I(bsp->_shm_internal); 385 } 386 387 static void 388 linux32_to_bsd_shmid64_ds(struct linux32_shmid64_ds *lsp, struct shmid_ds *bsp) 389 { 390 linux32_to_bsd_ipc64_perm(&lsp->l_shm_perm, &bsp->shm_perm); 391 bsp->shm_segsz = lsp->l_shm_segsz; 392 bsp->shm_atime = lsp->l_shm_atime; 393 bsp->shm_dtime = lsp->l_shm_dtime; 394 bsp->shm_ctime = lsp->l_shm_ctime; 395 bsp->shm_cpid = lsp->l_shm_cpid; 396 bsp->shm_lpid = lsp->l_shm_lpid; 397 bsp->shm_nattch = lsp->l_shm_nattch; 398 bsp->_shm_internal = NETBSD32IPTR64(lsp->l___unused5); 399 } 400 401 static int 402 linux32_shmat(struct lwp *l, const struct linux32_sys_ipc_args *uap, 403 register_t *retval) 404 { 405 struct sys_shmat_args ua; 406 netbsd32_pointer_t addr32; 407 int error; 408 409 SCARG(&ua, shmid) = SCARG(uap, a1); 410 SCARG(&ua, shmaddr) = SCARG_P32(uap, ptr); 411 SCARG(&ua, shmflg) = SCARG(uap, a2); 412 413 if ((error = sys_shmat(l, &ua, retval))) 414 return error; 415 416 NETBSD32PTR32(addr32, (const void *)(uintptr_t)retval[0]); 417 418 error = copyout(&addr32, NETBSD32IPTR64(SCARG(uap, a3)), sizeof addr32); 419 if (error == 0) 420 retval[0] = 0; 421 422 return error; 423 } 424 425 static int 426 linux32_shmdt(struct lwp *l, const struct linux32_sys_ipc_args *uap, 427 register_t *retval) 428 { 429 struct sys_shmdt_args ua; 430 431 SCARG(&ua, shmaddr) = SCARG_P32(uap, ptr); 432 433 return sys_shmdt(l, &ua, retval); 434 } 435 436 static int 437 linux32_shmget(struct lwp *l, const struct linux32_sys_ipc_args *uap, 438 register_t *retval) 439 { 440 struct sys_shmget_args ua; 441 442 SCARG(&ua, key) = SCARG(uap, a1); 443 SCARG(&ua, size) = SCARG(uap, a2); 444 SCARG(&ua, shmflg) = SCARG(uap, a3) | _SHM_RMLINGER; 445 446 return sys_shmget(l, &ua, retval); 447 } 448 449 static int 450 linux32_shmctl(struct lwp *l, const struct linux32_sys_ipc_args *uap, 451 register_t *retval) 452 { 453 int shmid, cmd, error; 454 struct shmid_ds bs; 455 struct linux32_shmid_ds ls; 456 struct linux32_shmid64_ds ls64; 457 458 shmid = SCARG(uap, a1); 459 cmd = SCARG(uap, a2); 460 461 switch (cmd & ~LINUX32_IPC_64) { 462 463 case LINUX32_SHM_STAT: 464 return ENOSYS; 465 466 case LINUX32_IPC_STAT: 467 error = shmctl1(l, shmid, IPC_STAT, &bs); 468 if (error != 0) 469 return error; 470 if (cmd & LINUX32_IPC_64) { 471 bsd_to_linux32_shmid64_ds(&bs, &ls64); 472 error = copyout(&ls64, SCARG_P32(uap, ptr), sizeof ls64); 473 } else { 474 bsd_to_linux32_shmid_ds(&bs, &ls); 475 error = copyout(&ls, SCARG_P32(uap, ptr), sizeof ls); 476 } 477 return error; 478 479 case LINUX32_IPC_SET: 480 if (cmd & LINUX32_IPC_64) { 481 error = copyin(SCARG_P32(uap, ptr), &ls64, sizeof ls64); 482 linux32_to_bsd_shmid64_ds(&ls64, &bs); 483 } else { 484 error = copyin(SCARG_P32(uap, ptr), &ls, sizeof ls); 485 linux32_to_bsd_shmid_ds(&ls, &bs); 486 } 487 if (error != 0) 488 return error; 489 return shmctl1(l, shmid, IPC_SET, &bs); 490 491 case LINUX32_IPC_RMID: 492 return shmctl1(l, shmid, IPC_RMID, NULL); 493 494 case LINUX32_SHM_LOCK: 495 return shmctl1(l, shmid, SHM_LOCK, NULL); 496 497 case LINUX32_SHM_UNLOCK: 498 return shmctl1(l, shmid, SHM_UNLOCK, NULL); 499 500 case LINUX32_IPC_INFO: 501 case LINUX32_SHM_INFO: 502 return ENOSYS; 503 504 default: 505 return EINVAL; 506 } 507 } 508 #endif /* SYSVSHM */ 509