1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. 25 * Copyright 2018, Joyent, Inc. 26 * Copyright 2026 Oxide Computer Company 27 */ 28 29 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 30 /* All Rights Reserved */ 31 32 /* 33 * Portions of this source code were derived from Berkeley 4.3 BSD 34 * under license from the Regents of the University of California. 35 */ 36 37 38 #include <sys/param.h> 39 #include <sys/isa_defs.h> 40 #include <sys/types.h> 41 #include <sys/sysmacros.h> 42 #include <sys/systm.h> 43 #include <sys/errno.h> 44 #include <sys/fcntl.h> 45 #include <sys/flock.h> 46 #include <sys/vnode.h> 47 #include <sys/file.h> 48 #include <sys/mode.h> 49 #include <sys/proc.h> 50 #include <sys/filio.h> 51 #include <sys/share.h> 52 #include <sys/debug.h> 53 #include <sys/rctl.h> 54 #include <sys/nbmlock.h> 55 56 #include <sys/cmn_err.h> 57 58 static int flock_check(vnode_t *, flock64_t *, offset_t, offset_t); 59 static int flock_get_start(vnode_t *, flock64_t *, offset_t, u_offset_t *); 60 61 /* 62 * File control. 63 */ 64 int 65 fcntl(int fdes, int cmd, intptr_t arg, intptr_t arg1) 66 { 67 int iarg; 68 int error = 0; 69 int retval; 70 proc_t *p; 71 file_t *fp; 72 vnode_t *vp; 73 u_offset_t offset; 74 u_offset_t start; 75 struct vattr vattr; 76 int in_crit; 77 int flag; 78 struct flock sbf; 79 struct flock64 bf; 80 struct o_flock obf; 81 struct flock64_32 bf64_32; 82 struct fshare fsh; 83 struct shrlock shr; 84 struct shr_locowner shr_own; 85 offset_t maxoffset; 86 model_t datamodel; 87 int fdres; 88 89 #if defined(_ILP32) && !defined(lint) && defined(_SYSCALL32) 90 ASSERT(sizeof (struct flock) == sizeof (struct flock32)); 91 ASSERT(sizeof (struct flock64) == sizeof (struct flock64_32)); 92 #endif 93 #if defined(_LP64) && !defined(lint) && defined(_SYSCALL32) 94 ASSERT(sizeof (struct flock) == sizeof (struct flock64_64)); 95 ASSERT(sizeof (struct flock64) == sizeof (struct flock64_64)); 96 #endif 97 98 /* 99 * Most fcntl() calls take either 2 or 3 arguments. The introduction of 100 * F_DUP3FD added a version that takes a 4th argument (referred to as 101 * arg1). While fcntl() traditionally has had loose validation, we 102 * strictly validate this new arg. 103 */ 104 switch (cmd) { 105 case F_DUP3FD: 106 if ((arg1 & ~(FD_CLOEXEC | FD_CLOFORK)) != 0) { 107 error = EINVAL; 108 goto out; 109 } 110 break; 111 default: 112 if (arg1 != 0) { 113 error = EINVAL; 114 goto out; 115 } 116 break; 117 } 118 119 /* 120 * First, for speed, deal with the subset of cases 121 * that do not require getf() / releasef(). 122 */ 123 switch (cmd) { 124 case F_GETFD: 125 if ((error = f_getfd_error(fdes, &flag)) == 0) 126 retval = flag; 127 goto out; 128 129 case F_SETFD: 130 error = f_setfd_error(fdes, (int)arg); 131 retval = 0; 132 goto out; 133 134 case F_GETFL: 135 if ((error = f_getfl(fdes, &flag)) == 0) { 136 retval = (flag & (FMASK | FASYNC)); 137 if ((flag & (FSEARCH | FEXEC)) == 0) 138 retval += FOPEN; 139 else 140 retval |= (flag & (FSEARCH | FEXEC)); 141 } 142 goto out; 143 144 case F_GETXFL: 145 if ((error = f_getfl(fdes, &flag)) == 0) { 146 retval = flag; 147 if ((flag & (FSEARCH | FEXEC)) == 0) 148 retval += FOPEN; 149 } 150 goto out; 151 152 case F_BADFD: 153 if ((error = f_badfd(fdes, &fdres, (int)arg)) == 0) 154 retval = fdres; 155 goto out; 156 } 157 158 /* 159 * Second, for speed, deal with the subset of cases that 160 * require getf() / releasef() but do not require copyin. 161 */ 162 if ((fp = getf(fdes)) == NULL) { 163 error = EBADF; 164 goto out; 165 } 166 iarg = (int)arg; 167 168 switch (cmd) { 169 case F_DUPFD: 170 case F_DUPFD_CLOEXEC: 171 case F_DUPFD_CLOFORK: 172 p = curproc; 173 if ((uint_t)iarg >= p->p_fno_ctl) { 174 if (iarg >= 0) 175 fd_too_big(p); 176 error = EINVAL; 177 goto done; 178 } 179 /* 180 * We need to increment the f_count reference counter 181 * before allocating a new file descriptor. 182 * Doing it other way round opens a window for race condition 183 * with closeandsetf() on the target file descriptor which can 184 * close the file still referenced by the original 185 * file descriptor. 186 */ 187 mutex_enter(&fp->f_tlock); 188 fp->f_count++; 189 mutex_exit(&fp->f_tlock); 190 if ((retval = ufalloc_file(iarg, fp)) == -1) { 191 /* 192 * New file descriptor can't be allocated. 193 * Revert the reference count. 194 */ 195 mutex_enter(&fp->f_tlock); 196 fp->f_count--; 197 mutex_exit(&fp->f_tlock); 198 error = EMFILE; 199 } else { 200 if (cmd == F_DUPFD_CLOEXEC) { 201 f_setfd_or(retval, FD_CLOEXEC); 202 } 203 204 if (cmd == F_DUPFD_CLOFORK) { 205 f_setfd_or(retval, FD_CLOFORK); 206 } 207 } 208 goto done; 209 210 case F_DUP2FD_CLOEXEC: 211 case F_DUP2FD_CLOFORK: 212 if (fdes == iarg) { 213 error = EINVAL; 214 goto done; 215 } 216 217 /*FALLTHROUGH*/ 218 219 case F_DUP2FD: 220 case F_DUP3FD: 221 /* 222 * For equal descriptors dup2() and dup3() are a no-op and 223 * must leave FD_CLOEXEC and FD_CLOFORK unchanged. Return here 224 * rather than calling fdup2() which would clear those flags. 225 */ 226 if (fdes == iarg) { 227 retval = iarg; 228 goto done; 229 } 230 231 /* 232 * fdup2() takes its own hold on fdes so release ours first 233 * (it cannot be held across the closeandsetf() in there 234 * without creating a window for deadlock against a 235 * concurrent dup2() in the opposite direction). 236 */ 237 releasef(fdes); 238 if ((error = fdup2(fdes, iarg)) == 0) { 239 if (cmd == F_DUP2FD_CLOEXEC) { 240 f_setfd_or(iarg, FD_CLOEXEC); 241 } else if (cmd == F_DUP2FD_CLOFORK) { 242 f_setfd_or(iarg, FD_CLOFORK); 243 } else if (cmd == F_DUP3FD) { 244 f_setfd_or(iarg, (int)arg1); 245 } 246 retval = iarg; 247 } 248 goto out; 249 250 case F_SETFL: 251 vp = fp->f_vnode; 252 flag = fp->f_flag; 253 if ((iarg & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY)) 254 iarg &= ~FNDELAY; 255 if ((error = VOP_SETFL(vp, flag, iarg, fp->f_cred, NULL)) == 256 0) { 257 iarg &= FMASK; 258 mutex_enter(&fp->f_tlock); 259 fp->f_flag &= ~FMASK | (FREAD|FWRITE); 260 fp->f_flag |= (iarg - FOPEN) & ~(FREAD|FWRITE); 261 mutex_exit(&fp->f_tlock); 262 } 263 retval = 0; 264 goto done; 265 } 266 267 /* 268 * Finally, deal with the expensive cases. 269 */ 270 retval = 0; 271 in_crit = 0; 272 maxoffset = MAXOFF_T; 273 datamodel = DATAMODEL_NATIVE; 274 #if defined(_SYSCALL32_IMPL) 275 if ((datamodel = get_udatamodel()) == DATAMODEL_ILP32) 276 maxoffset = MAXOFF32_T; 277 #endif 278 279 vp = fp->f_vnode; 280 flag = fp->f_flag; 281 offset = fp->f_offset; 282 283 switch (cmd) { 284 /* 285 * The file system and vnode layers understand and implement 286 * locking with flock64 structures. So here once we pass through 287 * the test for compatibility as defined by LFS API, (for F_SETLK, 288 * F_SETLKW, F_GETLK, F_GETLKW, F_OFD_GETLK, F_OFD_SETLK, F_OFD_SETLKW, 289 * F_FREESP) we transform the flock structure to a flock64 structure 290 * and send it to the lower layers. Similarly in case of GETLK and 291 * OFD_GETLK the returned flock64 structure is transformed to a flock 292 * structure if everything fits in nicely, otherwise we return 293 * EOVERFLOW. 294 */ 295 296 case F_GETLK: 297 case F_O_GETLK: 298 case F_SETLK: 299 case F_SETLKW: 300 case F_SETLK_NBMAND: 301 case F_OFD_GETLK: 302 case F_OFD_SETLK: 303 case F_OFD_SETLKW: 304 case F_FLOCK: 305 case F_FLOCKW: 306 307 /* 308 * Copy in input fields only. 309 */ 310 311 if (cmd == F_O_GETLK) { 312 if (datamodel != DATAMODEL_ILP32) { 313 error = EINVAL; 314 break; 315 } 316 317 if (copyin((void *)arg, &obf, sizeof (obf))) { 318 error = EFAULT; 319 break; 320 } 321 bf.l_type = obf.l_type; 322 bf.l_whence = obf.l_whence; 323 bf.l_start = (off64_t)obf.l_start; 324 bf.l_len = (off64_t)obf.l_len; 325 bf.l_sysid = (int)obf.l_sysid; 326 bf.l_pid = obf.l_pid; 327 } else if (datamodel == DATAMODEL_NATIVE) { 328 if (copyin((void *)arg, &sbf, sizeof (sbf))) { 329 error = EFAULT; 330 break; 331 } 332 /* 333 * XXX In an LP64 kernel with an LP64 application 334 * there's no need to do a structure copy here 335 * struct flock == struct flock64. However, 336 * we did it this way to avoid more conditional 337 * compilation. 338 */ 339 bf.l_type = sbf.l_type; 340 bf.l_whence = sbf.l_whence; 341 bf.l_start = (off64_t)sbf.l_start; 342 bf.l_len = (off64_t)sbf.l_len; 343 bf.l_sysid = sbf.l_sysid; 344 bf.l_pid = sbf.l_pid; 345 } 346 #if defined(_SYSCALL32_IMPL) 347 else { 348 struct flock32 sbf32; 349 if (copyin((void *)arg, &sbf32, sizeof (sbf32))) { 350 error = EFAULT; 351 break; 352 } 353 bf.l_type = sbf32.l_type; 354 bf.l_whence = sbf32.l_whence; 355 bf.l_start = (off64_t)sbf32.l_start; 356 bf.l_len = (off64_t)sbf32.l_len; 357 bf.l_sysid = sbf32.l_sysid; 358 bf.l_pid = sbf32.l_pid; 359 } 360 #endif /* _SYSCALL32_IMPL */ 361 362 /* 363 * 64-bit support: check for overflow for 32-bit lock ops 364 */ 365 if ((error = flock_check(vp, &bf, offset, maxoffset)) != 0) 366 break; 367 368 if (cmd == F_FLOCK || cmd == F_FLOCKW) { 369 /* FLOCK* locking is always over the entire file. */ 370 if (bf.l_whence != 0 || bf.l_start != 0 || 371 bf.l_len != 0) { 372 error = EINVAL; 373 break; 374 } 375 if (bf.l_type < F_RDLCK || bf.l_type > F_UNLCK) { 376 error = EINVAL; 377 break; 378 } 379 } 380 381 if (cmd == F_OFD_GETLK || cmd == F_OFD_SETLK || 382 cmd == F_OFD_SETLKW) { 383 /* 384 * TBD OFD-style locking is currently limited to 385 * covering the entire file. 386 */ 387 if (bf.l_whence != 0 || bf.l_start != 0 || 388 bf.l_len != 0) { 389 error = EINVAL; 390 break; 391 } 392 } 393 394 /* 395 * Not all of the filesystems understand F_O_GETLK, and 396 * there's no need for them to know. Map it to F_GETLK. 397 * 398 * The *_frlock functions in the various file systems basically 399 * do some validation and then funnel everything through the 400 * fs_frlock function. For OFD-style locks fs_frlock will do 401 * nothing so that once control returns here we can call the 402 * ofdlock function with the correct fp. For OFD-style locks 403 * the unsupported remote file systems, such as NFS, detect and 404 * reject the OFD-style cmd argument. 405 */ 406 if ((error = VOP_FRLOCK(vp, (cmd == F_O_GETLK) ? F_GETLK : cmd, 407 &bf, flag, offset, NULL, fp->f_cred, NULL)) != 0) 408 break; 409 410 if (cmd == F_FLOCK || cmd == F_FLOCKW || cmd == F_OFD_GETLK || 411 cmd == F_OFD_SETLK || cmd == F_OFD_SETLKW) { 412 /* 413 * This is an OFD-style lock so we need to handle it 414 * here. Because OFD-style locks are associated with 415 * the file_t we didn't have enough info down the 416 * VOP_FRLOCK path immediately above. 417 */ 418 if ((error = ofdlock(fp, cmd, &bf, flag, offset)) != 0) 419 break; 420 } 421 422 /* 423 * If command is GETLK and no lock is found, only 424 * the type field is changed. 425 */ 426 if ((cmd == F_O_GETLK || cmd == F_GETLK || 427 cmd == F_OFD_GETLK) && bf.l_type == F_UNLCK) { 428 /* l_type always first entry, always a short */ 429 if (copyout(&bf.l_type, &((struct flock *)arg)->l_type, 430 sizeof (bf.l_type))) 431 error = EFAULT; 432 break; 433 } 434 435 if (cmd == F_O_GETLK) { 436 /* 437 * Return an SVR3 flock structure to the user. 438 */ 439 obf.l_type = (int16_t)bf.l_type; 440 obf.l_whence = (int16_t)bf.l_whence; 441 obf.l_start = (int32_t)bf.l_start; 442 obf.l_len = (int32_t)bf.l_len; 443 if (bf.l_sysid > SHRT_MAX || bf.l_pid > SHRT_MAX) { 444 /* 445 * One or both values for the above fields 446 * is too large to store in an SVR3 flock 447 * structure. 448 */ 449 error = EOVERFLOW; 450 break; 451 } 452 obf.l_sysid = (int16_t)bf.l_sysid; 453 obf.l_pid = (int16_t)bf.l_pid; 454 if (copyout(&obf, (void *)arg, sizeof (obf))) 455 error = EFAULT; 456 } else if (cmd == F_GETLK || cmd == F_OFD_GETLK) { 457 /* 458 * Copy out SVR4 flock. 459 */ 460 int i; 461 462 if (bf.l_start > maxoffset || bf.l_len > maxoffset) { 463 error = EOVERFLOW; 464 break; 465 } 466 467 if (datamodel == DATAMODEL_NATIVE) { 468 for (i = 0; i < 4; i++) 469 sbf.l_pad[i] = 0; 470 /* 471 * XXX In an LP64 kernel with an LP64 472 * application there's no need to do a 473 * structure copy here as currently 474 * struct flock == struct flock64. 475 * We did it this way to avoid more 476 * conditional compilation. 477 */ 478 sbf.l_type = bf.l_type; 479 sbf.l_whence = bf.l_whence; 480 sbf.l_start = (off_t)bf.l_start; 481 sbf.l_len = (off_t)bf.l_len; 482 sbf.l_sysid = bf.l_sysid; 483 sbf.l_pid = bf.l_pid; 484 if (copyout(&sbf, (void *)arg, sizeof (sbf))) 485 error = EFAULT; 486 } 487 #if defined(_SYSCALL32_IMPL) 488 else { 489 struct flock32 sbf32; 490 if (bf.l_start > MAXOFF32_T || 491 bf.l_len > MAXOFF32_T) { 492 error = EOVERFLOW; 493 break; 494 } 495 for (i = 0; i < 4; i++) 496 sbf32.l_pad[i] = 0; 497 sbf32.l_type = (int16_t)bf.l_type; 498 sbf32.l_whence = (int16_t)bf.l_whence; 499 sbf32.l_start = (off32_t)bf.l_start; 500 sbf32.l_len = (off32_t)bf.l_len; 501 sbf32.l_sysid = (int32_t)bf.l_sysid; 502 sbf32.l_pid = (pid32_t)bf.l_pid; 503 if (copyout(&sbf32, 504 (void *)arg, sizeof (sbf32))) 505 error = EFAULT; 506 } 507 #endif 508 } 509 break; 510 511 case F_CHKFL: 512 /* 513 * This is for internal use only, to allow the vnode layer 514 * to validate a flags setting before applying it. User 515 * programs can't issue it. 516 */ 517 error = EINVAL; 518 break; 519 520 case F_ALLOCSP: 521 case F_FREESP: 522 case F_ALLOCSP64: 523 case F_FREESP64: 524 /* 525 * Test for not-a-regular-file (and returning EINVAL) 526 * before testing for open-for-writing (and returning EBADF). 527 * This is relied upon by posix_fallocate() in libc. 528 */ 529 if (vp->v_type != VREG) { 530 error = EINVAL; 531 break; 532 } 533 534 if ((flag & FWRITE) == 0) { 535 error = EBADF; 536 break; 537 } 538 539 if (datamodel != DATAMODEL_ILP32 && 540 (cmd == F_ALLOCSP64 || cmd == F_FREESP64)) { 541 error = EINVAL; 542 break; 543 } 544 545 #if defined(_ILP32) || defined(_SYSCALL32_IMPL) 546 if (datamodel == DATAMODEL_ILP32 && 547 (cmd == F_ALLOCSP || cmd == F_FREESP)) { 548 struct flock32 sbf32; 549 /* 550 * For compatibility we overlay an SVR3 flock on an SVR4 551 * flock. This works because the input field offsets 552 * in "struct flock" were preserved. 553 */ 554 if (copyin((void *)arg, &sbf32, sizeof (sbf32))) { 555 error = EFAULT; 556 break; 557 } else { 558 bf.l_type = sbf32.l_type; 559 bf.l_whence = sbf32.l_whence; 560 bf.l_start = (off64_t)sbf32.l_start; 561 bf.l_len = (off64_t)sbf32.l_len; 562 bf.l_sysid = sbf32.l_sysid; 563 bf.l_pid = sbf32.l_pid; 564 } 565 } 566 #endif /* _ILP32 || _SYSCALL32_IMPL */ 567 568 #if defined(_LP64) 569 if (datamodel == DATAMODEL_LP64 && 570 (cmd == F_ALLOCSP || cmd == F_FREESP)) { 571 if (copyin((void *)arg, &bf, sizeof (bf))) { 572 error = EFAULT; 573 break; 574 } 575 } 576 #endif /* defined(_LP64) */ 577 578 #if !defined(_LP64) || defined(_SYSCALL32_IMPL) 579 if (datamodel == DATAMODEL_ILP32 && 580 (cmd == F_ALLOCSP64 || cmd == F_FREESP64)) { 581 if (copyin((void *)arg, &bf64_32, sizeof (bf64_32))) { 582 error = EFAULT; 583 break; 584 } else { 585 /* 586 * Note that the size of flock64 is different in 587 * the ILP32 and LP64 models, due to the l_pad 588 * field. We do not want to assume that the 589 * flock64 structure is laid out the same in 590 * ILP32 and LP64 environments, so we will 591 * copy in the ILP32 version of flock64 592 * explicitly and copy it to the native 593 * flock64 structure. 594 */ 595 bf.l_type = (short)bf64_32.l_type; 596 bf.l_whence = (short)bf64_32.l_whence; 597 bf.l_start = bf64_32.l_start; 598 bf.l_len = bf64_32.l_len; 599 bf.l_sysid = (int)bf64_32.l_sysid; 600 bf.l_pid = (pid_t)bf64_32.l_pid; 601 } 602 } 603 #endif /* !defined(_LP64) || defined(_SYSCALL32_IMPL) */ 604 605 if (cmd == F_ALLOCSP || cmd == F_FREESP) 606 error = flock_check(vp, &bf, offset, maxoffset); 607 else if (cmd == F_ALLOCSP64 || cmd == F_FREESP64) 608 error = flock_check(vp, &bf, offset, MAXOFFSET_T); 609 if (error) 610 break; 611 612 if (vp->v_type == VREG && bf.l_len == 0 && 613 bf.l_start > OFFSET_MAX(fp)) { 614 error = EFBIG; 615 break; 616 } 617 618 /* 619 * Make sure that there are no conflicting non-blocking 620 * mandatory locks in the region being manipulated. If 621 * there are such locks then return EACCES. 622 */ 623 if ((error = flock_get_start(vp, &bf, offset, &start)) != 0) 624 break; 625 626 if (nbl_need_check(vp)) { 627 u_offset_t begin; 628 ssize_t length; 629 630 nbl_start_crit(vp, RW_READER); 631 in_crit = 1; 632 vattr.va_mask = AT_SIZE; 633 if ((error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL)) 634 != 0) 635 break; 636 begin = start > vattr.va_size ? vattr.va_size : start; 637 length = vattr.va_size > start ? vattr.va_size - start : 638 start - vattr.va_size; 639 if (nbl_conflict(vp, NBL_WRITE, begin, length, 0, 640 NULL)) { 641 error = EACCES; 642 break; 643 } 644 } 645 646 if (cmd == F_ALLOCSP64) 647 cmd = F_ALLOCSP; 648 else if (cmd == F_FREESP64) 649 cmd = F_FREESP; 650 651 error = VOP_SPACE(vp, cmd, &bf, flag, offset, fp->f_cred, NULL); 652 653 break; 654 655 #if !defined(_LP64) || defined(_SYSCALL32_IMPL) 656 case F_GETLK64: 657 case F_SETLK64: 658 case F_SETLKW64: 659 case F_SETLK64_NBMAND: 660 case F_OFD_GETLK64: 661 case F_OFD_SETLK64: 662 case F_OFD_SETLKW64: 663 case F_FLOCK64: 664 case F_FLOCKW64: 665 /* 666 * Large Files: Here we set cmd as *LK and send it to 667 * lower layers. *LK64 is only for the user land. 668 * Most of the comments described above for F_SETLK 669 * applies here too. 670 * Large File support is only needed for ILP32 apps! 671 */ 672 if (datamodel != DATAMODEL_ILP32) { 673 error = EINVAL; 674 break; 675 } 676 677 if (cmd == F_GETLK64) 678 cmd = F_GETLK; 679 else if (cmd == F_SETLK64) 680 cmd = F_SETLK; 681 else if (cmd == F_SETLKW64) 682 cmd = F_SETLKW; 683 else if (cmd == F_SETLK64_NBMAND) 684 cmd = F_SETLK_NBMAND; 685 else if (cmd == F_OFD_GETLK64) 686 cmd = F_OFD_GETLK; 687 else if (cmd == F_OFD_SETLK64) 688 cmd = F_OFD_SETLK; 689 else if (cmd == F_OFD_SETLKW64) 690 cmd = F_OFD_SETLKW; 691 else if (cmd == F_FLOCK64) 692 cmd = F_FLOCK; 693 else if (cmd == F_FLOCKW64) 694 cmd = F_FLOCKW; 695 696 /* 697 * Note that the size of flock64 is different in the ILP32 698 * and LP64 models, due to the sucking l_pad field. 699 * We do not want to assume that the flock64 structure is 700 * laid out in the same in ILP32 and LP64 environments, so 701 * we will copy in the ILP32 version of flock64 explicitly 702 * and copy it to the native flock64 structure. 703 */ 704 705 if (copyin((void *)arg, &bf64_32, sizeof (bf64_32))) { 706 error = EFAULT; 707 break; 708 } 709 710 bf.l_type = (short)bf64_32.l_type; 711 bf.l_whence = (short)bf64_32.l_whence; 712 bf.l_start = bf64_32.l_start; 713 bf.l_len = bf64_32.l_len; 714 bf.l_sysid = (int)bf64_32.l_sysid; 715 bf.l_pid = (pid_t)bf64_32.l_pid; 716 717 if ((error = flock_check(vp, &bf, offset, MAXOFFSET_T)) != 0) 718 break; 719 720 if (cmd == F_FLOCK || cmd == F_FLOCKW) { 721 /* FLOCK* locking is always over the entire file. */ 722 if (bf.l_whence != 0 || bf.l_start != 0 || 723 bf.l_len != 0) { 724 error = EINVAL; 725 break; 726 } 727 if (bf.l_type < F_RDLCK || bf.l_type > F_UNLCK) { 728 error = EINVAL; 729 break; 730 } 731 } 732 733 if (cmd == F_OFD_GETLK || cmd == F_OFD_SETLK || 734 cmd == F_OFD_SETLKW) { 735 /* 736 * TBD OFD-style locking is currently limited to 737 * covering the entire file. 738 */ 739 if (bf.l_whence != 0 || bf.l_start != 0 || 740 bf.l_len != 0) { 741 error = EINVAL; 742 break; 743 } 744 } 745 746 /* 747 * The *_frlock functions in the various file systems basically 748 * do some validation and then funnel everything through the 749 * fs_frlock function. For OFD-style locks fs_frlock will do 750 * nothing so that once control returns here we can call the 751 * ofdlock function with the correct fp. For OFD-style locks 752 * the unsupported remote file systems, such as NFS, detect and 753 * reject the OFD-style cmd argument. 754 */ 755 if ((error = VOP_FRLOCK(vp, cmd, &bf, flag, offset, 756 NULL, fp->f_cred, NULL)) != 0) 757 break; 758 759 if (cmd == F_FLOCK || cmd == F_FLOCKW || cmd == F_OFD_GETLK || 760 cmd == F_OFD_SETLK || cmd == F_OFD_SETLKW) { 761 /* 762 * This is an OFD-style lock so we need to handle it 763 * here. Because OFD-style locks are associated with 764 * the file_t we didn't have enough info down the 765 * VOP_FRLOCK path immediately above. 766 */ 767 if ((error = ofdlock(fp, cmd, &bf, flag, offset)) != 0) 768 break; 769 } 770 771 if ((cmd == F_GETLK || cmd == F_OFD_GETLK) && 772 bf.l_type == F_UNLCK) { 773 if (copyout(&bf.l_type, &((struct flock *)arg)->l_type, 774 sizeof (bf.l_type))) 775 error = EFAULT; 776 break; 777 } 778 779 if (cmd == F_GETLK || cmd == F_OFD_GETLK) { 780 int i; 781 782 /* 783 * We do not want to assume that the flock64 structure 784 * is laid out in the same in ILP32 and LP64 785 * environments, so we will copy out the ILP32 version 786 * of flock64 explicitly after copying the native 787 * flock64 structure to it. 788 */ 789 for (i = 0; i < 4; i++) 790 bf64_32.l_pad[i] = 0; 791 bf64_32.l_type = (int16_t)bf.l_type; 792 bf64_32.l_whence = (int16_t)bf.l_whence; 793 bf64_32.l_start = bf.l_start; 794 bf64_32.l_len = bf.l_len; 795 bf64_32.l_sysid = (int32_t)bf.l_sysid; 796 bf64_32.l_pid = (pid32_t)bf.l_pid; 797 if (copyout(&bf64_32, (void *)arg, sizeof (bf64_32))) 798 error = EFAULT; 799 } 800 break; 801 #endif /* !defined(_LP64) || defined(_SYSCALL32_IMPL) */ 802 803 case F_SHARE: 804 case F_SHARE_NBMAND: 805 case F_UNSHARE: 806 807 /* 808 * Copy in input fields only. 809 */ 810 if (copyin((void *)arg, &fsh, sizeof (fsh))) { 811 error = EFAULT; 812 break; 813 } 814 815 /* 816 * Local share reservations always have this simple form 817 */ 818 shr.s_access = fsh.f_access; 819 shr.s_deny = fsh.f_deny; 820 shr.s_sysid = 0; 821 shr.s_pid = ttoproc(curthread)->p_pid; 822 shr_own.sl_pid = shr.s_pid; 823 shr_own.sl_id = fsh.f_id; 824 shr.s_own_len = sizeof (shr_own); 825 shr.s_owner = (caddr_t)&shr_own; 826 error = VOP_SHRLOCK(vp, cmd, &shr, flag, fp->f_cred, NULL); 827 break; 828 829 default: 830 error = EINVAL; 831 break; 832 } 833 834 if (in_crit) 835 nbl_end_crit(vp); 836 837 done: 838 releasef(fdes); 839 out: 840 if (error) 841 return (set_errno(error)); 842 return (retval); 843 } 844 845 int 846 flock_check(vnode_t *vp, flock64_t *flp, offset_t offset, offset_t max) 847 { 848 struct vattr vattr; 849 int error; 850 u_offset_t start, end; 851 852 /* 853 * Determine the starting point of the request 854 */ 855 switch (flp->l_whence) { 856 case 0: /* SEEK_SET */ 857 start = (u_offset_t)flp->l_start; 858 if (start > max) 859 return (EINVAL); 860 break; 861 case 1: /* SEEK_CUR */ 862 if (flp->l_start > (max - offset)) 863 return (EOVERFLOW); 864 start = (u_offset_t)(flp->l_start + offset); 865 if (start > max) 866 return (EINVAL); 867 break; 868 case 2: /* SEEK_END */ 869 vattr.va_mask = AT_SIZE; 870 if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL)) 871 return (error); 872 if (flp->l_start > (max - (offset_t)vattr.va_size)) 873 return (EOVERFLOW); 874 start = (u_offset_t)(flp->l_start + (offset_t)vattr.va_size); 875 if (start > max) 876 return (EINVAL); 877 break; 878 default: 879 return (EINVAL); 880 } 881 882 /* 883 * Determine the range covered by the request. 884 */ 885 if (flp->l_len == 0) 886 end = MAXEND; 887 else if ((offset_t)flp->l_len > 0) { 888 if (flp->l_len > (max - start + 1)) 889 return (EOVERFLOW); 890 end = (u_offset_t)(start + (flp->l_len - 1)); 891 ASSERT(end <= max); 892 } else { 893 /* 894 * Negative length; why do we even allow this ? 895 * Because this allows easy specification of 896 * the last n bytes of the file. 897 */ 898 end = start; 899 start += (u_offset_t)flp->l_len; 900 (start)++; 901 if (start > max) 902 return (EINVAL); 903 ASSERT(end <= max); 904 } 905 ASSERT(start <= max); 906 if (flp->l_type == F_UNLCK && flp->l_len > 0 && 907 end == (offset_t)max) { 908 flp->l_len = 0; 909 } 910 if (start > end) 911 return (EINVAL); 912 return (0); 913 } 914 915 static int 916 flock_get_start(vnode_t *vp, flock64_t *flp, offset_t offset, u_offset_t *start) 917 { 918 struct vattr vattr; 919 int error; 920 921 /* 922 * Determine the starting point of the request. Assume that it is 923 * a valid starting point. 924 */ 925 switch (flp->l_whence) { 926 case 0: /* SEEK_SET */ 927 *start = (u_offset_t)flp->l_start; 928 break; 929 case 1: /* SEEK_CUR */ 930 *start = (u_offset_t)(flp->l_start + offset); 931 break; 932 case 2: /* SEEK_END */ 933 vattr.va_mask = AT_SIZE; 934 if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL)) 935 return (error); 936 *start = (u_offset_t)(flp->l_start + (offset_t)vattr.va_size); 937 break; 938 default: 939 return (EINVAL); 940 } 941 942 return (0); 943 } 944