1 /* $NetBSD: linux32_ipccall.c,v 1.2 2008/09/17 20:11:51 scw 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.2 2008/09/17 20:11:51 scw 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, *bsp = NULL; 455 struct linux32_shmid_ds ls; 456 struct linux32_shmid64_ds ls64; 457 458 shmid = SCARG(uap, a1); 459 460 switch (SCARG(uap, a2)) { 461 case LINUX32_IPC_RMID: 462 cmd = IPC_RMID; 463 break; 464 case LINUX32_SHM_STAT: 465 case LINUX32_SHM_STAT|LINUX32_IPC_64: 466 return ENOSYS; 467 case LINUX32_IPC_STAT: 468 case LINUX32_IPC_STAT|LINUX32_IPC_64: 469 cmd = IPC_STAT; 470 bsp = &bs; 471 break; 472 case LINUX32_IPC_SET: 473 cmd = IPC_SET; 474 bsp = &bs; 475 if ((error = copyin(SCARG_P32(uap, ptr), &ls, sizeof ls))) 476 return error; 477 linux32_to_bsd_shmid_ds(&ls, &bs); 478 break; 479 case LINUX32_IPC_SET|LINUX32_IPC_64: 480 cmd = IPC_SET; 481 bsp = &bs; 482 if ((error = copyin(SCARG_P32(uap, ptr), &ls64, sizeof ls64))) 483 return error; 484 linux32_to_bsd_shmid64_ds(&ls64, &bs); 485 break; 486 case LINUX32_SHM_LOCK: 487 cmd = SHM_LOCK; 488 break; 489 case LINUX32_SHM_UNLOCK: 490 cmd = SHM_UNLOCK; 491 break; 492 case LINUX32_IPC_INFO: 493 case LINUX32_SHM_INFO: 494 return ENOSYS; 495 default: 496 return EINVAL; 497 } 498 499 if ((error = shmctl1(l, shmid, cmd, bsp))) 500 return error; 501 502 switch (SCARG(uap, a2)) { 503 case LINUX32_IPC_STAT: 504 case LINUX32_SHM_STAT: 505 bsd_to_linux32_shmid_ds(&bs, &ls); 506 error = copyout(&ls, SCARG_P32(uap, ptr), sizeof ls); 507 break; 508 case LINUX32_IPC_STAT|LINUX32_IPC_64: 509 case LINUX32_SHM_STAT|LINUX32_IPC_64: 510 bsd_to_linux32_shmid64_ds(&bs, &ls64); 511 error = copyout(&ls64, SCARG_P32(uap, ptr), sizeof ls64); 512 default: 513 break; 514 } 515 516 return error; 517 } 518 #endif /* SYSVSHM */ 519