1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 1994-1995 Søren Schmidt 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 ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/syscallsubr.h> 35 #include <sys/sysproto.h> 36 #include <sys/proc.h> 37 #include <sys/limits.h> 38 #include <sys/msg.h> 39 #include <sys/sem.h> 40 #include <sys/shm.h> 41 #include <sys/stat.h> 42 43 #include "opt_compat.h" 44 45 #ifdef COMPAT_LINUX32 46 #include <machine/../linux32/linux.h> 47 #include <machine/../linux32/linux32_proto.h> 48 #else 49 #include <machine/../linux/linux.h> 50 #include <machine/../linux/linux_proto.h> 51 #endif 52 #include <compat/linux/linux_ipc.h> 53 #include <compat/linux/linux_ipc64.h> 54 #include <compat/linux/linux_util.h> 55 56 /* 57 * old, pre 2.4 kernel 58 */ 59 struct l_ipc_perm { 60 l_key_t key; 61 l_uid16_t uid; 62 l_gid16_t gid; 63 l_uid16_t cuid; 64 l_gid16_t cgid; 65 l_ushort mode; 66 l_ushort seq; 67 }; 68 69 struct l_seminfo { 70 l_int semmap; 71 l_int semmni; 72 l_int semmns; 73 l_int semmnu; 74 l_int semmsl; 75 l_int semopm; 76 l_int semume; 77 l_int semusz; 78 l_int semvmx; 79 l_int semaem; 80 }; 81 82 struct l_shminfo { 83 l_int shmmax; 84 l_int shmmin; 85 l_int shmmni; 86 l_int shmseg; 87 l_int shmall; 88 }; 89 90 struct l_shm_info { 91 l_int used_ids; 92 l_ulong shm_tot; /* total allocated shm */ 93 l_ulong shm_rss; /* total resident shm */ 94 l_ulong shm_swp; /* total swapped shm */ 95 l_ulong swap_attempts; 96 l_ulong swap_successes; 97 }; 98 99 struct l_msginfo { 100 l_int msgpool; 101 l_int msgmap; 102 l_int msgmax; 103 l_int msgmnb; 104 l_int msgmni; 105 l_int msgssz; 106 l_int msgtql; 107 l_ushort msgseg; 108 }; 109 110 static void 111 bsd_to_linux_shminfo( struct shminfo *bpp, struct l_shminfo64 *lpp) 112 { 113 114 lpp->shmmax = bpp->shmmax; 115 lpp->shmmin = bpp->shmmin; 116 lpp->shmmni = bpp->shmmni; 117 lpp->shmseg = bpp->shmseg; 118 lpp->shmall = bpp->shmall; 119 } 120 121 static void 122 bsd_to_linux_shm_info( struct shm_info *bpp, struct l_shm_info *lpp) 123 { 124 125 lpp->used_ids = bpp->used_ids; 126 lpp->shm_tot = bpp->shm_tot; 127 lpp->shm_rss = bpp->shm_rss; 128 lpp->shm_swp = bpp->shm_swp; 129 lpp->swap_attempts = bpp->swap_attempts; 130 lpp->swap_successes = bpp->swap_successes; 131 } 132 133 static void 134 linux_to_bsd_ipc_perm(struct l_ipc64_perm *lpp, struct ipc_perm *bpp) 135 { 136 137 bpp->key = lpp->key; 138 bpp->uid = lpp->uid; 139 bpp->gid = lpp->gid; 140 bpp->cuid = lpp->cuid; 141 bpp->cgid = lpp->cgid; 142 bpp->mode = lpp->mode; 143 bpp->seq = lpp->seq; 144 } 145 146 static void 147 bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct l_ipc64_perm *lpp) 148 { 149 150 lpp->key = bpp->key; 151 lpp->uid = bpp->uid; 152 lpp->gid = bpp->gid; 153 lpp->cuid = bpp->cuid; 154 lpp->cgid = bpp->cgid; 155 lpp->mode = bpp->mode & (S_IRWXU|S_IRWXG|S_IRWXO); 156 lpp->seq = bpp->seq; 157 } 158 159 struct l_msqid_ds { 160 struct l_ipc_perm msg_perm; 161 l_uintptr_t msg_first; /* first message on queue,unused */ 162 l_uintptr_t msg_last; /* last message in queue,unused */ 163 l_time_t msg_stime; /* last msgsnd time */ 164 l_time_t msg_rtime; /* last msgrcv time */ 165 l_time_t msg_ctime; /* last change time */ 166 l_ulong msg_lcbytes; /* Reuse junk fields for 32 bit */ 167 l_ulong msg_lqbytes; /* ditto */ 168 l_ushort msg_cbytes; /* current number of bytes on queue */ 169 l_ushort msg_qnum; /* number of messages in queue */ 170 l_ushort msg_qbytes; /* max number of bytes on queue */ 171 l_pid_t msg_lspid; /* pid of last msgsnd */ 172 l_pid_t msg_lrpid; /* last receive pid */ 173 }; 174 175 struct l_semid_ds { 176 struct l_ipc_perm sem_perm; 177 l_time_t sem_otime; 178 l_time_t sem_ctime; 179 l_uintptr_t sem_base; 180 l_uintptr_t sem_pending; 181 l_uintptr_t sem_pending_last; 182 l_uintptr_t undo; 183 l_ushort sem_nsems; 184 }; 185 186 struct l_shmid_ds { 187 struct l_ipc_perm shm_perm; 188 l_int shm_segsz; 189 l_time_t shm_atime; 190 l_time_t shm_dtime; 191 l_time_t shm_ctime; 192 l_ushort shm_cpid; 193 l_ushort shm_lpid; 194 l_short shm_nattch; 195 l_ushort private1; 196 l_uintptr_t private2; 197 l_uintptr_t private3; 198 }; 199 200 static void 201 linux_to_bsd_semid_ds(struct l_semid64_ds *lsp, struct semid_ds *bsp) 202 { 203 204 linux_to_bsd_ipc_perm(&lsp->sem_perm, &bsp->sem_perm); 205 bsp->sem_otime = lsp->sem_otime; 206 bsp->sem_ctime = lsp->sem_ctime; 207 bsp->sem_nsems = lsp->sem_nsems; 208 } 209 210 static void 211 bsd_to_linux_semid_ds(struct semid_ds *bsp, struct l_semid64_ds *lsp) 212 { 213 214 bsd_to_linux_ipc_perm(&bsp->sem_perm, &lsp->sem_perm); 215 lsp->sem_otime = bsp->sem_otime; 216 lsp->sem_ctime = bsp->sem_ctime; 217 lsp->sem_nsems = bsp->sem_nsems; 218 } 219 220 static void 221 linux_to_bsd_shmid_ds(struct l_shmid64_ds *lsp, struct shmid_ds *bsp) 222 { 223 224 linux_to_bsd_ipc_perm(&lsp->shm_perm, &bsp->shm_perm); 225 bsp->shm_segsz = lsp->shm_segsz; 226 bsp->shm_lpid = lsp->shm_lpid; 227 bsp->shm_cpid = lsp->shm_cpid; 228 bsp->shm_nattch = lsp->shm_nattch; 229 bsp->shm_atime = lsp->shm_atime; 230 bsp->shm_dtime = lsp->shm_dtime; 231 bsp->shm_ctime = lsp->shm_ctime; 232 } 233 234 static void 235 bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct l_shmid64_ds *lsp) 236 { 237 238 bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm); 239 lsp->shm_segsz = bsp->shm_segsz; 240 lsp->shm_lpid = bsp->shm_lpid; 241 lsp->shm_cpid = bsp->shm_cpid; 242 lsp->shm_nattch = bsp->shm_nattch; 243 lsp->shm_atime = bsp->shm_atime; 244 lsp->shm_dtime = bsp->shm_dtime; 245 lsp->shm_ctime = bsp->shm_ctime; 246 } 247 248 static void 249 linux_to_bsd_msqid_ds(struct l_msqid64_ds *lsp, struct msqid_ds *bsp) 250 { 251 252 linux_to_bsd_ipc_perm(&lsp->msg_perm, &bsp->msg_perm); 253 bsp->msg_cbytes = lsp->msg_cbytes; 254 bsp->msg_qnum = lsp->msg_qnum; 255 bsp->msg_qbytes = lsp->msg_qbytes; 256 bsp->msg_lspid = lsp->msg_lspid; 257 bsp->msg_lrpid = lsp->msg_lrpid; 258 bsp->msg_stime = lsp->msg_stime; 259 bsp->msg_rtime = lsp->msg_rtime; 260 bsp->msg_ctime = lsp->msg_ctime; 261 } 262 263 static void 264 bsd_to_linux_msqid_ds(struct msqid_ds *bsp, struct l_msqid64_ds *lsp) 265 { 266 267 bsd_to_linux_ipc_perm(&bsp->msg_perm, &lsp->msg_perm); 268 lsp->msg_cbytes = bsp->msg_cbytes; 269 lsp->msg_qnum = bsp->msg_qnum; 270 lsp->msg_qbytes = bsp->msg_qbytes; 271 lsp->msg_lspid = bsp->msg_lspid; 272 lsp->msg_lrpid = bsp->msg_lrpid; 273 lsp->msg_stime = bsp->msg_stime; 274 lsp->msg_rtime = bsp->msg_rtime; 275 lsp->msg_ctime = bsp->msg_ctime; 276 } 277 278 static int 279 linux_ipc64_perm_to_ipc_perm(struct l_ipc64_perm *in, struct l_ipc_perm *out) 280 { 281 282 out->key = in->key; 283 out->uid = in->uid; 284 out->gid = in->gid; 285 out->cuid = in->cuid; 286 out->cgid = in->cgid; 287 out->mode = in->mode; 288 out->seq = in->seq; 289 290 /* Linux does not check overflow */ 291 if (out->uid != in->uid || out->gid != in->gid || 292 out->cuid != in->cuid || out->cgid != in->cgid || 293 out->mode != in->mode) 294 return (EOVERFLOW); 295 else 296 return (0); 297 } 298 299 static int 300 linux_msqid_pullup(l_int ver, struct l_msqid64_ds *linux_msqid64, caddr_t uaddr) 301 { 302 struct l_msqid_ds linux_msqid; 303 int error; 304 305 if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64)) 306 return (copyin(uaddr, linux_msqid64, sizeof(*linux_msqid64))); 307 else { 308 error = copyin(uaddr, &linux_msqid, sizeof(linux_msqid)); 309 if (error != 0) 310 return (error); 311 312 bzero(linux_msqid64, sizeof(*linux_msqid64)); 313 314 linux_msqid64->msg_perm.uid = linux_msqid.msg_perm.uid; 315 linux_msqid64->msg_perm.gid = linux_msqid.msg_perm.gid; 316 linux_msqid64->msg_perm.mode = linux_msqid.msg_perm.mode; 317 if (linux_msqid.msg_qbytes == 0) 318 linux_msqid64->msg_qbytes = linux_msqid.msg_lqbytes; 319 else 320 linux_msqid64->msg_qbytes = linux_msqid.msg_qbytes; 321 return (0); 322 } 323 } 324 325 static int 326 linux_msqid_pushdown(l_int ver, struct l_msqid64_ds *linux_msqid64, caddr_t uaddr) 327 { 328 struct l_msqid_ds linux_msqid; 329 int error; 330 331 if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64)) 332 return (copyout(linux_msqid64, uaddr, sizeof(*linux_msqid64))); 333 else { 334 bzero(&linux_msqid, sizeof(linux_msqid)); 335 336 error = linux_ipc64_perm_to_ipc_perm(&linux_msqid64->msg_perm, 337 &linux_msqid.msg_perm); 338 if (error != 0) 339 return (error); 340 341 linux_msqid.msg_stime = linux_msqid64->msg_stime; 342 linux_msqid.msg_rtime = linux_msqid64->msg_rtime; 343 linux_msqid.msg_ctime = linux_msqid64->msg_ctime; 344 345 if (linux_msqid64->msg_cbytes > USHRT_MAX) 346 linux_msqid.msg_cbytes = USHRT_MAX; 347 else 348 linux_msqid.msg_cbytes = linux_msqid64->msg_cbytes; 349 linux_msqid.msg_lcbytes = linux_msqid64->msg_cbytes; 350 if (linux_msqid64->msg_qnum > USHRT_MAX) 351 linux_msqid.msg_qnum = USHRT_MAX; 352 else 353 linux_msqid.msg_qnum = linux_msqid64->msg_qnum; 354 if (linux_msqid64->msg_qbytes > USHRT_MAX) 355 linux_msqid.msg_qbytes = USHRT_MAX; 356 else 357 linux_msqid.msg_qbytes = linux_msqid64->msg_qbytes; 358 linux_msqid.msg_lqbytes = linux_msqid64->msg_qbytes; 359 linux_msqid.msg_lspid = linux_msqid64->msg_lspid; 360 linux_msqid.msg_lrpid = linux_msqid64->msg_lrpid; 361 362 /* Linux does not check overflow */ 363 if (linux_msqid.msg_stime != linux_msqid64->msg_stime || 364 linux_msqid.msg_rtime != linux_msqid64->msg_rtime || 365 linux_msqid.msg_ctime != linux_msqid64->msg_ctime) 366 return (EOVERFLOW); 367 368 return (copyout(&linux_msqid, uaddr, sizeof(linux_msqid))); 369 } 370 } 371 372 static int 373 linux_semid_pullup(l_int ver, struct l_semid64_ds *linux_semid64, caddr_t uaddr) 374 { 375 struct l_semid_ds linux_semid; 376 int error; 377 378 if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64)) 379 return (copyin(uaddr, linux_semid64, sizeof(*linux_semid64))); 380 else { 381 error = copyin(uaddr, &linux_semid, sizeof(linux_semid)); 382 if (error != 0) 383 return (error); 384 385 bzero(linux_semid64, sizeof(*linux_semid64)); 386 387 linux_semid64->sem_perm.uid = linux_semid.sem_perm.uid; 388 linux_semid64->sem_perm.gid = linux_semid.sem_perm.gid; 389 linux_semid64->sem_perm.mode = linux_semid.sem_perm.mode; 390 return (0); 391 } 392 } 393 394 static int 395 linux_semid_pushdown(l_int ver, struct l_semid64_ds *linux_semid64, caddr_t uaddr) 396 { 397 struct l_semid_ds linux_semid; 398 int error; 399 400 if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64)) 401 return (copyout(linux_semid64, uaddr, sizeof(*linux_semid64))); 402 else { 403 bzero(&linux_semid, sizeof(linux_semid)); 404 405 error = linux_ipc64_perm_to_ipc_perm(&linux_semid64->sem_perm, 406 &linux_semid.sem_perm); 407 if (error != 0) 408 return (error); 409 410 linux_semid.sem_otime = linux_semid64->sem_otime; 411 linux_semid.sem_ctime = linux_semid64->sem_ctime; 412 linux_semid.sem_nsems = linux_semid64->sem_nsems; 413 414 /* Linux does not check overflow */ 415 if (linux_semid.sem_otime != linux_semid64->sem_otime || 416 linux_semid.sem_ctime != linux_semid64->sem_ctime || 417 linux_semid.sem_nsems != linux_semid64->sem_nsems) 418 return (EOVERFLOW); 419 420 return (copyout(&linux_semid, uaddr, sizeof(linux_semid))); 421 } 422 } 423 424 static int 425 linux_shmid_pullup(l_int ver, struct l_shmid64_ds *linux_shmid64, caddr_t uaddr) 426 { 427 struct l_shmid_ds linux_shmid; 428 int error; 429 430 if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64)) 431 return (copyin(uaddr, linux_shmid64, sizeof(*linux_shmid64))); 432 else { 433 error = copyin(uaddr, &linux_shmid, sizeof(linux_shmid)); 434 if (error != 0) 435 return (error); 436 437 bzero(linux_shmid64, sizeof(*linux_shmid64)); 438 439 linux_shmid64->shm_perm.uid = linux_shmid.shm_perm.uid; 440 linux_shmid64->shm_perm.gid = linux_shmid.shm_perm.gid; 441 linux_shmid64->shm_perm.mode = linux_shmid.shm_perm.mode; 442 return (0); 443 } 444 } 445 446 static int 447 linux_shmid_pushdown(l_int ver, struct l_shmid64_ds *linux_shmid64, caddr_t uaddr) 448 { 449 struct l_shmid_ds linux_shmid; 450 int error; 451 452 if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64)) 453 return (copyout(linux_shmid64, uaddr, sizeof(*linux_shmid64))); 454 else { 455 bzero(&linux_shmid, sizeof(linux_shmid)); 456 457 error = linux_ipc64_perm_to_ipc_perm(&linux_shmid64->shm_perm, 458 &linux_shmid.shm_perm); 459 if (error != 0) 460 return (error); 461 462 linux_shmid.shm_segsz = linux_shmid64->shm_segsz; 463 linux_shmid.shm_atime = linux_shmid64->shm_atime; 464 linux_shmid.shm_dtime = linux_shmid64->shm_dtime; 465 linux_shmid.shm_ctime = linux_shmid64->shm_ctime; 466 linux_shmid.shm_cpid = linux_shmid64->shm_cpid; 467 linux_shmid.shm_lpid = linux_shmid64->shm_lpid; 468 linux_shmid.shm_nattch = linux_shmid64->shm_nattch; 469 470 /* Linux does not check overflow */ 471 if (linux_shmid.shm_segsz != linux_shmid64->shm_segsz || 472 linux_shmid.shm_atime != linux_shmid64->shm_atime || 473 linux_shmid.shm_dtime != linux_shmid64->shm_dtime || 474 linux_shmid.shm_ctime != linux_shmid64->shm_ctime || 475 linux_shmid.shm_cpid != linux_shmid64->shm_cpid || 476 linux_shmid.shm_lpid != linux_shmid64->shm_lpid || 477 linux_shmid.shm_nattch != linux_shmid64->shm_nattch) 478 return (EOVERFLOW); 479 480 return (copyout(&linux_shmid, uaddr, sizeof(linux_shmid))); 481 } 482 } 483 484 static int 485 linux_shminfo_pushdown(l_int ver, struct l_shminfo64 *linux_shminfo64, 486 caddr_t uaddr) 487 { 488 struct l_shminfo linux_shminfo; 489 490 if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64)) 491 return (copyout(linux_shminfo64, uaddr, 492 sizeof(*linux_shminfo64))); 493 else { 494 bzero(&linux_shminfo, sizeof(linux_shminfo)); 495 496 linux_shminfo.shmmax = linux_shminfo64->shmmax; 497 linux_shminfo.shmmin = linux_shminfo64->shmmin; 498 linux_shminfo.shmmni = linux_shminfo64->shmmni; 499 linux_shminfo.shmseg = linux_shminfo64->shmseg; 500 linux_shminfo.shmall = linux_shminfo64->shmall; 501 502 return (copyout(&linux_shminfo, uaddr, 503 sizeof(linux_shminfo))); 504 } 505 } 506 507 int 508 linux_semop(struct thread *td, struct linux_semop_args *args) 509 { 510 struct semop_args /* { 511 int semid; 512 struct sembuf *sops; 513 int nsops; 514 } */ bsd_args; 515 516 if (args->nsops < 1 || args->semid < 0) 517 return (EINVAL); 518 bsd_args.semid = args->semid; 519 bsd_args.sops = PTRIN(args->tsops); 520 bsd_args.nsops = args->nsops; 521 return (sys_semop(td, &bsd_args)); 522 } 523 524 int 525 linux_semget(struct thread *td, struct linux_semget_args *args) 526 { 527 struct semget_args /* { 528 key_t key; 529 int nsems; 530 int semflg; 531 } */ bsd_args; 532 533 if (args->nsems < 0) 534 return (EINVAL); 535 bsd_args.key = args->key; 536 bsd_args.nsems = args->nsems; 537 bsd_args.semflg = args->semflg; 538 return (sys_semget(td, &bsd_args)); 539 } 540 541 int 542 linux_semctl(struct thread *td, struct linux_semctl_args *args) 543 { 544 struct l_semid64_ds linux_semid64; 545 struct l_seminfo linux_seminfo; 546 struct semid_ds semid; 547 union semun semun; 548 register_t rval; 549 int cmd, error; 550 551 memset(&linux_seminfo, 0, sizeof(linux_seminfo)); 552 memset(&linux_semid64, 0, sizeof(linux_semid64)); 553 554 switch (args->cmd & ~LINUX_IPC_64) { 555 case LINUX_IPC_RMID: 556 cmd = IPC_RMID; 557 break; 558 case LINUX_GETNCNT: 559 cmd = GETNCNT; 560 break; 561 case LINUX_GETPID: 562 cmd = GETPID; 563 break; 564 case LINUX_GETVAL: 565 cmd = GETVAL; 566 break; 567 case LINUX_GETZCNT: 568 cmd = GETZCNT; 569 break; 570 case LINUX_SETVAL: 571 cmd = SETVAL; 572 semun.val = args->arg.val; 573 break; 574 case LINUX_IPC_SET: 575 cmd = IPC_SET; 576 error = linux_semid_pullup(args->cmd & LINUX_IPC_64, 577 &linux_semid64, PTRIN(args->arg.buf)); 578 if (error != 0) 579 return (error); 580 linux_to_bsd_semid_ds(&linux_semid64, &semid); 581 semun.buf = &semid; 582 return (kern_semctl(td, args->semid, args->semnum, cmd, &semun, 583 td->td_retval)); 584 case LINUX_IPC_STAT: 585 cmd = IPC_STAT; 586 semun.buf = &semid; 587 error = kern_semctl(td, args->semid, args->semnum, cmd, &semun, 588 &rval); 589 if (error != 0) 590 return (error); 591 bsd_to_linux_semid_ds(&semid, &linux_semid64); 592 return (linux_semid_pushdown(args->cmd & LINUX_IPC_64, 593 &linux_semid64, PTRIN(args->arg.buf))); 594 case LINUX_SEM_STAT: 595 cmd = SEM_STAT; 596 semun.buf = &semid; 597 error = kern_semctl(td, args->semid, args->semnum, cmd, &semun, 598 &rval); 599 if (error != 0) 600 return (error); 601 bsd_to_linux_semid_ds(&semid, &linux_semid64); 602 error = linux_semid_pushdown(args->cmd & LINUX_IPC_64, 603 &linux_semid64, PTRIN(args->arg.buf)); 604 if (error == 0) 605 td->td_retval[0] = rval; 606 return (error); 607 case LINUX_IPC_INFO: 608 case LINUX_SEM_INFO: 609 bcopy(&seminfo, &linux_seminfo.semmni, sizeof(linux_seminfo) - 610 sizeof(linux_seminfo.semmap) ); 611 /* 612 * Linux does not use the semmap field but populates it with 613 * the defined value from SEMMAP, which really is redefined to 614 * SEMMNS, which they define as SEMMNI * SEMMSL. Try to 615 * simulate this returning our dynamic semmns value. 616 */ 617 linux_seminfo.semmap = linux_seminfo.semmns; 618 /* XXX BSD equivalent? 619 #define used_semids 10 620 #define used_sems 10 621 linux_seminfo.semusz = used_semids; 622 linux_seminfo.semaem = used_sems; 623 */ 624 error = copyout(&linux_seminfo, 625 PTRIN(args->arg.buf), sizeof(linux_seminfo)); 626 if (error != 0) 627 return (error); 628 /* 629 * TODO: Linux return the last assigned id, not the semmni. 630 */ 631 td->td_retval[0] = seminfo.semmni; 632 return (0); 633 case LINUX_GETALL: 634 cmd = GETALL; 635 semun.array = PTRIN(args->arg.array); 636 break; 637 case LINUX_SETALL: 638 cmd = SETALL; 639 semun.array = PTRIN(args->arg.array); 640 break; 641 default: 642 linux_msg(td, "ipc type %d is not implemented", 643 args->cmd & ~LINUX_IPC_64); 644 return (EINVAL); 645 } 646 return (kern_semctl(td, args->semid, args->semnum, cmd, &semun, 647 td->td_retval)); 648 } 649 650 int 651 linux_msgsnd(struct thread *td, struct linux_msgsnd_args *args) 652 { 653 const void *msgp; 654 long mtype; 655 l_long lmtype; 656 int error; 657 658 if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)msginfo.msgmax) 659 return (EINVAL); 660 msgp = PTRIN(args->msgp); 661 if ((error = copyin(msgp, &lmtype, sizeof(lmtype))) != 0) 662 return (error); 663 mtype = (long)lmtype; 664 return (kern_msgsnd(td, args->msqid, 665 (const char *)msgp + sizeof(lmtype), 666 args->msgsz, args->msgflg, mtype)); 667 } 668 669 int 670 linux_msgrcv(struct thread *td, struct linux_msgrcv_args *args) 671 { 672 void *msgp; 673 long mtype; 674 l_long lmtype; 675 int error; 676 677 if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)msginfo.msgmax) 678 return (EINVAL); 679 msgp = PTRIN(args->msgp); 680 if ((error = kern_msgrcv(td, args->msqid, 681 (char *)msgp + sizeof(lmtype), args->msgsz, 682 args->msgtyp, args->msgflg, &mtype)) != 0) 683 return (error); 684 lmtype = (l_long)mtype; 685 return (copyout(&lmtype, msgp, sizeof(lmtype))); 686 } 687 688 int 689 linux_msgget(struct thread *td, struct linux_msgget_args *args) 690 { 691 struct msgget_args /* { 692 key_t key; 693 int msgflg; 694 } */ bsd_args; 695 696 bsd_args.key = args->key; 697 bsd_args.msgflg = args->msgflg; 698 return (sys_msgget(td, &bsd_args)); 699 } 700 701 int 702 linux_msgctl(struct thread *td, struct linux_msgctl_args *args) 703 { 704 int error, bsd_cmd; 705 struct l_msqid64_ds linux_msqid64; 706 struct msqid_ds bsd_msqid; 707 708 memset(&linux_msqid64, 0, sizeof(linux_msqid64)); 709 710 bsd_cmd = args->cmd & ~LINUX_IPC_64; 711 switch (bsd_cmd) { 712 case LINUX_IPC_INFO: 713 case LINUX_MSG_INFO: { 714 struct l_msginfo linux_msginfo; 715 716 memset(&linux_msginfo, 0, sizeof(linux_msginfo)); 717 /* 718 * XXX MSG_INFO uses the same data structure but returns different 719 * dynamic counters in msgpool, msgmap, and msgtql fields. 720 */ 721 linux_msginfo.msgpool = (long)msginfo.msgmni * 722 (long)msginfo.msgmnb / 1024L; /* XXX MSG_INFO. */ 723 linux_msginfo.msgmap = msginfo.msgmnb; /* XXX MSG_INFO. */ 724 linux_msginfo.msgmax = msginfo.msgmax; 725 linux_msginfo.msgmnb = msginfo.msgmnb; 726 linux_msginfo.msgmni = msginfo.msgmni; 727 linux_msginfo.msgssz = msginfo.msgssz; 728 linux_msginfo.msgtql = msginfo.msgtql; /* XXX MSG_INFO. */ 729 linux_msginfo.msgseg = msginfo.msgseg; 730 error = copyout(&linux_msginfo, PTRIN(args->buf), 731 sizeof(linux_msginfo)); 732 if (error == 0) 733 td->td_retval[0] = msginfo.msgmni; /* XXX */ 734 735 return (error); 736 } 737 738 /* 739 * TODO: implement this 740 * case LINUX_MSG_STAT: 741 */ 742 case LINUX_IPC_STAT: 743 /* NOTHING */ 744 break; 745 746 case LINUX_IPC_SET: 747 error = linux_msqid_pullup(args->cmd & LINUX_IPC_64, 748 &linux_msqid64, PTRIN(args->buf)); 749 if (error != 0) 750 return (error); 751 linux_to_bsd_msqid_ds(&linux_msqid64, &bsd_msqid); 752 break; 753 754 case LINUX_IPC_RMID: 755 /* NOTHING */ 756 break; 757 758 default: 759 return (EINVAL); 760 break; 761 } 762 763 error = kern_msgctl(td, args->msqid, bsd_cmd, &bsd_msqid); 764 if (error != 0) { 765 if (bsd_cmd == LINUX_IPC_RMID && error == EACCES) 766 return (EPERM); 767 if (bsd_cmd != LINUX_IPC_RMID || error != EINVAL) 768 return (error); 769 } 770 771 if (bsd_cmd == LINUX_IPC_STAT) { 772 bsd_to_linux_msqid_ds(&bsd_msqid, &linux_msqid64); 773 return (linux_msqid_pushdown(args->cmd & LINUX_IPC_64, 774 &linux_msqid64, PTRIN(args->buf))); 775 } 776 777 return (0); 778 } 779 780 int 781 linux_shmat(struct thread *td, struct linux_shmat_args *args) 782 { 783 struct shmat_args /* { 784 int shmid; 785 void *shmaddr; 786 int shmflg; 787 } */ bsd_args; 788 789 bsd_args.shmid = args->shmid; 790 bsd_args.shmaddr = PTRIN(args->shmaddr); 791 bsd_args.shmflg = args->shmflg; 792 return (sys_shmat(td, &bsd_args)); 793 } 794 795 int 796 linux_shmdt(struct thread *td, struct linux_shmdt_args *args) 797 { 798 struct shmdt_args /* { 799 void *shmaddr; 800 } */ bsd_args; 801 802 bsd_args.shmaddr = PTRIN(args->shmaddr); 803 return (sys_shmdt(td, &bsd_args)); 804 } 805 806 int 807 linux_shmget(struct thread *td, struct linux_shmget_args *args) 808 { 809 struct shmget_args /* { 810 key_t key; 811 int size; 812 int shmflg; 813 } */ bsd_args; 814 815 bsd_args.key = args->key; 816 bsd_args.size = args->size; 817 bsd_args.shmflg = args->shmflg; 818 return (sys_shmget(td, &bsd_args)); 819 } 820 821 int 822 linux_shmctl(struct thread *td, struct linux_shmctl_args *args) 823 { 824 struct l_shmid64_ds linux_shmid64; 825 struct l_shminfo64 linux_shminfo64; 826 struct l_shm_info linux_shm_info; 827 struct shmid_ds bsd_shmid; 828 int error; 829 830 memset(&linux_shm_info, 0, sizeof(linux_shm_info)); 831 memset(&linux_shmid64, 0, sizeof(linux_shmid64)); 832 memset(&linux_shminfo64, 0, sizeof(linux_shminfo64)); 833 834 switch (args->cmd & ~LINUX_IPC_64) { 835 case LINUX_IPC_INFO: { 836 struct shminfo bsd_shminfo; 837 838 /* Perform shmctl wanting removed segments lookup */ 839 error = kern_shmctl(td, args->shmid, IPC_INFO, 840 (void *)&bsd_shminfo, NULL); 841 if (error != 0) 842 return (error); 843 844 bsd_to_linux_shminfo(&bsd_shminfo, &linux_shminfo64); 845 846 return (linux_shminfo_pushdown(args->cmd & LINUX_IPC_64, 847 &linux_shminfo64, PTRIN(args->buf))); 848 } 849 850 case LINUX_SHM_INFO: { 851 struct shm_info bsd_shm_info; 852 853 /* Perform shmctl wanting removed segments lookup */ 854 error = kern_shmctl(td, args->shmid, SHM_INFO, 855 (void *)&bsd_shm_info, NULL); 856 if (error != 0) 857 return (error); 858 859 bsd_to_linux_shm_info(&bsd_shm_info, &linux_shm_info); 860 861 return (copyout(&linux_shm_info, PTRIN(args->buf), 862 sizeof(struct l_shm_info))); 863 } 864 865 case LINUX_IPC_STAT: 866 /* Perform shmctl wanting removed segments lookup */ 867 error = kern_shmctl(td, args->shmid, IPC_STAT, 868 (void *)&bsd_shmid, NULL); 869 if (error != 0) 870 return (error); 871 872 bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid64); 873 874 return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64, 875 &linux_shmid64, PTRIN(args->buf))); 876 877 case LINUX_SHM_STAT: 878 /* Perform shmctl wanting removed segments lookup */ 879 error = kern_shmctl(td, args->shmid, IPC_STAT, 880 (void *)&bsd_shmid, NULL); 881 if (error != 0) 882 return (error); 883 884 bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid64); 885 886 return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64, 887 &linux_shmid64, PTRIN(args->buf))); 888 889 case LINUX_IPC_SET: 890 error = linux_shmid_pullup(args->cmd & LINUX_IPC_64, 891 &linux_shmid64, PTRIN(args->buf)); 892 if (error != 0) 893 return (error); 894 895 linux_to_bsd_shmid_ds(&linux_shmid64, &bsd_shmid); 896 897 /* Perform shmctl wanting removed segments lookup */ 898 return (kern_shmctl(td, args->shmid, IPC_SET, 899 (void *)&bsd_shmid, NULL)); 900 901 case LINUX_IPC_RMID: { 902 void *buf; 903 904 if (args->buf == 0) 905 buf = NULL; 906 else { 907 error = linux_shmid_pullup(args->cmd & LINUX_IPC_64, 908 &linux_shmid64, PTRIN(args->buf)); 909 if (error != 0) 910 return (error); 911 linux_to_bsd_shmid_ds(&linux_shmid64, &bsd_shmid); 912 buf = (void *)&bsd_shmid; 913 } 914 return (kern_shmctl(td, args->shmid, IPC_RMID, buf, NULL)); 915 } 916 917 case LINUX_SHM_LOCK: 918 /* FALLTHROUGH */ 919 case LINUX_SHM_UNLOCK: 920 /* FALLTHROUGH */ 921 default: 922 linux_msg(td, "ipc type %d not implemented", 923 args->cmd & ~LINUX_IPC_64); 924 return (EINVAL); 925 } 926 } 927 928 MODULE_DEPEND(linux, sysvmsg, 1, 1, 1); 929 MODULE_DEPEND(linux, sysvsem, 1, 1, 1); 930 MODULE_DEPEND(linux, sysvshm, 1, 1, 1); 931