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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/fstyp.h> 28 #include <sys/fsid.h> 29 30 #include <errno.h> 31 #include <unistd.h> 32 #include <stdio.h> 33 #include <sys/types.h> 34 #include <sys/stat.h> 35 #include <sys/vnode.h> 36 #include <fcntl.h> 37 #include <string.h> 38 #include <utime.h> 39 #include <atomic.h> 40 41 #include <sys/lx_syscall.h> 42 #include <sys/lx_types.h> 43 #include <sys/lx_debug.h> 44 #include <sys/lx_misc.h> 45 #include <sys/lx_fcntl.h> 46 47 static int 48 install_checkpath(uintptr_t p1) 49 { 50 int saved_errno = errno; 51 char path[MAXPATHLEN]; 52 53 /* 54 * The "dev" RPM package wants to modify /dev/pts, but /dev/pts is a 55 * lofs mounted copy of /native/dev/pts, so that won't work. 56 * 57 * Instead, if we're trying to modify /dev/pts from install mode, just 58 * act as if it succeded. 59 */ 60 if (uucopystr((void *)p1, path, MAXPATHLEN) == -1) 61 return (-errno); 62 63 if (strcmp(path, "/dev/pts") == 0) 64 return (0); 65 66 errno = saved_errno; 67 return (-errno); 68 } 69 70 /* 71 * Convert linux LX_AT_* flags to solaris AT_* flags, while verifying allowed 72 * flags have been passed. This also allows EACCESS/REMOVEDIR to be translated 73 * correctly since on linux they have the same value. 74 */ 75 int 76 ltos_at_flag(int lflag, int allow) 77 { 78 int sflag = 0; 79 80 if ((lflag & LX_AT_EACCESS) && (allow & AT_EACCESS)) { 81 lflag &= ~LX_AT_EACCESS; 82 sflag |= AT_EACCESS; 83 } 84 85 if ((lflag & LX_AT_REMOVEDIR) && (allow & AT_REMOVEDIR)) { 86 lflag &= ~LX_AT_REMOVEDIR; 87 sflag |= AT_REMOVEDIR; 88 } 89 90 if ((lflag & LX_AT_SYMLINK_NOFOLLOW) && (allow & AT_SYMLINK_NOFOLLOW)) { 91 lflag &= ~LX_AT_SYMLINK_NOFOLLOW; 92 sflag |= AT_SYMLINK_NOFOLLOW; 93 } 94 95 /* right now solaris doesn't have a _FOLLOW flag, so use a fake one */ 96 if ((lflag & LX_AT_SYMLINK_FOLLOW) && (allow & LX_AT_SYMLINK_FOLLOW)) { 97 lflag &= ~LX_AT_SYMLINK_FOLLOW; 98 sflag |= LX_AT_SYMLINK_FOLLOW; 99 } 100 101 /* if flag is not zero than some flags did not hit the above code */ 102 if (lflag) 103 return (-EINVAL); 104 105 return (sflag); 106 } 107 108 109 /* 110 * Miscellaneous file-related system calls. 111 */ 112 113 /* 114 * Linux creates half-duplex unnamed pipes and Solaris creates full-duplex 115 * pipes. Thus, to get the correct semantics, our simple pipe() system 116 * call actually needs to create a named pipe, do three opens, a close, and 117 * an unlink. This is woefully expensive. If performance becomes a real 118 * issue, we can implement a half-duplex pipe() in the brand module. 119 */ 120 #define PIPENAMESZ 32 /* enough room for /tmp/.pipe.<pid>.<num> */ 121 122 int 123 lx_pipe(uintptr_t p1) 124 { 125 static uint32_t pipecnt = 0; 126 int cnt; 127 char pipename[PIPENAMESZ]; 128 int fds[3]; 129 int r = 0; 130 131 fds[0] = -1; 132 fds[1] = -1; 133 fds[2] = -1; 134 135 /* 136 * Construct a name for the named pipe: /tmp/.pipe.<pid>.<++cnt> 137 */ 138 cnt = atomic_inc_32_nv(&pipecnt); 139 140 (void) snprintf(pipename, PIPENAMESZ, "/tmp/.pipe.%d.%d", 141 getpid(), cnt); 142 143 if (mkfifo(pipename, 0600)) 144 return (-errno); 145 146 /* 147 * To prevent either the read-only or write-only open from 148 * blocking, we first need to open the pipe for both reading and 149 * writing. 150 */ 151 if (((fds[2] = open(pipename, O_RDWR)) < 0) || 152 ((fds[0] = open(pipename, O_RDONLY)) < 0) || 153 ((fds[1] = open(pipename, O_WRONLY)) < 0)) { 154 r = errno; 155 } else { 156 /* 157 * Copy the two one-way fds back to the app's address 158 * space. 159 */ 160 if (uucopy(fds, (void *)p1, 2 * sizeof (int))) 161 r = errno; 162 } 163 164 if (fds[2] >= 0) 165 (void) close(fds[2]); 166 (void) unlink(pipename); 167 168 if (r != 0) { 169 if (fds[0] >= 0) 170 (void) close(fds[0]); 171 if (fds[1] >= 0) 172 (void) close(fds[1]); 173 } 174 175 return (-r); 176 } 177 178 /* 179 * On Linux, even root cannot create a link to a directory, so we have to 180 * add an explicit check. 181 */ 182 int 183 lx_link(uintptr_t p1, uintptr_t p2) 184 { 185 char *from = (char *)p1; 186 char *to = (char *)p2; 187 struct stat64 statbuf; 188 189 if ((stat64(from, &statbuf) == 0) && S_ISDIR(statbuf.st_mode)) 190 return (-EPERM); 191 192 return (link(from, to) ? -errno : 0); 193 } 194 195 /* 196 * On Linux, an unlink of a directory returns EISDIR, not EPERM. 197 */ 198 int 199 lx_unlink(uintptr_t p) 200 { 201 char *pathname = (char *)p; 202 struct stat64 statbuf; 203 204 if ((lstat64(pathname, &statbuf) == 0) && S_ISDIR(statbuf.st_mode)) 205 return (-EISDIR); 206 207 return (unlink(pathname) ? -errno : 0); 208 } 209 210 int 211 lx_unlinkat(uintptr_t ext1, uintptr_t p1, uintptr_t p2) 212 { 213 int atfd = (int)ext1; 214 char *pathname = (char *)p1; 215 int flag = (int)p2; 216 struct stat64 statbuf; 217 218 if (atfd == LX_AT_FDCWD) 219 atfd = AT_FDCWD; 220 221 flag = ltos_at_flag(flag, AT_REMOVEDIR); 222 if (flag < 0) 223 return (-EINVAL); 224 225 if (!(flag & AT_REMOVEDIR)) { 226 /* Behave like unlink() */ 227 if ((fstatat64(atfd, pathname, &statbuf, AT_SYMLINK_NOFOLLOW) == 228 0) && S_ISDIR(statbuf.st_mode)) 229 return (-EISDIR); 230 } 231 232 return (unlinkat(atfd, pathname, flag) ? -errno : 0); 233 } 234 235 /* 236 * fsync() and fdatasync() - On Solaris, these calls translate into a common 237 * fsync() syscall with a different parameter, so we layer on top of the librt 238 * functions instead. 239 */ 240 int 241 lx_fsync(uintptr_t fd) 242 { 243 int fildes = (int)fd; 244 struct stat64 statbuf; 245 246 if ((fstat64(fildes, &statbuf) == 0) && 247 (S_ISCHR(statbuf.st_mode) || S_ISFIFO(statbuf.st_mode))) 248 return (-EINVAL); 249 250 return (fsync((int)fd) ? -errno : 0); 251 } 252 253 int 254 lx_fdatasync(uintptr_t fd) 255 { 256 int fildes = (int)fd; 257 struct stat64 statbuf; 258 259 if ((fstat64(fildes, &statbuf) == 0) && 260 (S_ISCHR(statbuf.st_mode) || S_ISFIFO(statbuf.st_mode))) 261 return (-EINVAL); 262 263 return (fdatasync((int)fd) ? -errno : 0); 264 } 265 266 /* 267 * Linux, unlike Solaris, ALWAYS resets the setuid and setgid bits on a 268 * chown/fchown regardless of whether it was done by root or not. Therefore, 269 * we must do extra work after each chown/fchown call to emulate this behavior. 270 */ 271 #define SETUGID (S_ISUID | S_ISGID) 272 273 /* 274 * [lf]chown16() - Translate the uid/gid and pass onto the real functions. 275 */ 276 int 277 lx_chown16(uintptr_t p1, uintptr_t p2, uintptr_t p3) 278 { 279 char *filename = (char *)p1; 280 struct stat64 statbuf; 281 282 if (chown(filename, LX_UID16_TO_UID32((lx_gid16_t)p2), 283 LX_GID16_TO_GID32((lx_gid16_t)p3))) 284 return (-errno); 285 286 if (stat64(filename, &statbuf) == 0) { 287 statbuf.st_mode &= ~S_ISUID; 288 if (statbuf.st_mode & S_IXGRP) 289 statbuf.st_mode &= ~S_ISGID; 290 (void) chmod(filename, (statbuf.st_mode & MODEMASK)); 291 } 292 293 return (0); 294 } 295 296 int 297 lx_fchown16(uintptr_t p1, uintptr_t p2, uintptr_t p3) 298 { 299 int fd = (int)p1; 300 struct stat64 statbuf; 301 302 if (fchown(fd, LX_UID16_TO_UID32((lx_gid16_t)p2), 303 LX_GID16_TO_GID32((lx_gid16_t)p3))) 304 return (-errno); 305 306 if (fstat64(fd, &statbuf) == 0) { 307 statbuf.st_mode &= ~S_ISUID; 308 if (statbuf.st_mode & S_IXGRP) 309 statbuf.st_mode &= ~S_ISGID; 310 (void) fchmod(fd, (statbuf.st_mode & MODEMASK)); 311 } 312 313 return (0); 314 } 315 316 int 317 lx_lchown16(uintptr_t p1, uintptr_t p2, uintptr_t p3) 318 { 319 return (lchown((char *)p1, LX_UID16_TO_UID32((lx_gid16_t)p2), 320 LX_GID16_TO_GID32((lx_gid16_t)p3)) ? -errno : 0); 321 } 322 323 int 324 lx_chown(uintptr_t p1, uintptr_t p2, uintptr_t p3) 325 { 326 char *filename = (char *)p1; 327 struct stat64 statbuf; 328 int ret; 329 330 ret = chown(filename, (uid_t)p2, (gid_t)p3); 331 332 if (ret < 0) { 333 /* 334 * If chown() failed and we're in install mode, return success 335 * if the the reason we failed was because the source file 336 * didn't actually exist or if we're trying to modify /dev/pts. 337 */ 338 if ((lx_install != 0) && 339 ((errno == ENOENT) || (install_checkpath(p1) == 0))) 340 return (0); 341 342 return (-errno); 343 } 344 345 if (stat64(filename, &statbuf) == 0) { 346 statbuf.st_mode &= ~S_ISUID; 347 if (statbuf.st_mode & S_IXGRP) 348 statbuf.st_mode &= ~S_ISGID; 349 (void) chmod(filename, (statbuf.st_mode & MODEMASK)); 350 } 351 352 return (0); 353 } 354 355 int 356 lx_fchown(uintptr_t p1, uintptr_t p2, uintptr_t p3) 357 { 358 int fd = (int)p1; 359 struct stat64 statbuf; 360 361 if (fchown(fd, (uid_t)p2, (gid_t)p3)) 362 return (-errno); 363 364 if (fstat64(fd, &statbuf) == 0) { 365 statbuf.st_mode &= ~S_ISUID; 366 if (statbuf.st_mode & S_IXGRP) 367 statbuf.st_mode &= ~S_ISGID; 368 (void) fchmod(fd, (statbuf.st_mode & MODEMASK)); 369 } 370 371 return (0); 372 } 373 374 int 375 lx_chmod(uintptr_t p1, uintptr_t p2) 376 { 377 int ret; 378 379 ret = chmod((const char *)p1, (mode_t)p2); 380 381 if (ret < 0) { 382 /* 383 * If chown() failed and we're in install mode, return success 384 * if the the reason we failed was because the source file 385 * didn't actually exist or if we're trying to modify /dev/pts. 386 */ 387 if ((lx_install != 0) && 388 ((errno == ENOENT) || (install_checkpath(p1) == 0))) 389 return (0); 390 391 return (-errno); 392 } 393 394 return (0); 395 } 396 397 int 398 lx_utime(uintptr_t p1, uintptr_t p2) 399 { 400 int ret; 401 402 ret = utime((const char *)p1, (const struct utimbuf *)p2); 403 404 if (ret < 0) { 405 /* 406 * If chown() failed and we're in install mode, return success 407 * if the the reason we failed was because the source file 408 * didn't actually exist or if we're trying to modify /dev/pts. 409 */ 410 if ((lx_install != 0) && 411 ((errno == ENOENT) || (install_checkpath(p1) == 0))) 412 return (0); 413 414 return (-errno); 415 } 416 417 return (0); 418 } 419 420 /* 421 * llseek() - The Linux implementation takes an additional parameter, which is 422 * the resulting position in the file. 423 */ 424 int 425 lx_llseek(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, 426 uintptr_t p5) 427 { 428 offset_t ret; 429 offset_t *res = (offset_t *)p4; 430 431 /* SEEK_DATA and SEEK_HOLE are only valid in Solaris */ 432 if ((int)p5 > SEEK_END) 433 return (-EINVAL); 434 435 if ((ret = llseek((int)p1, LX_32TO64(p3, p2), p5)) < 0) 436 return (-errno); 437 438 *res = ret; 439 return (0); 440 } 441 442 /* 443 * seek() - When the resultant file offset cannot be represented in 32 bits, 444 * Linux performs the seek but Solaris doesn't, though both set EOVERFLOW. We 445 * call llseek() and then check to see if we need to return EOVERFLOW. 446 */ 447 int 448 lx_lseek(uintptr_t p1, uintptr_t p2, uintptr_t p3) 449 { 450 offset_t offset = (offset_t)(off_t)(p2); /* sign extend */ 451 offset_t ret; 452 off_t ret32; 453 454 /* SEEK_DATA and SEEK_HOLE are only valid in Solaris */ 455 if ((int)p3 > SEEK_END) 456 return (-EINVAL); 457 458 if ((ret = llseek((int)p1, offset, p3)) < 0) 459 return (-errno); 460 461 ret32 = (off_t)ret; 462 if ((offset_t)ret32 == ret) 463 return (ret32); 464 else 465 return (-EOVERFLOW); 466 } 467 468 /* 469 * Neither Solaris nor Linux actually returns anything to the caller, but glibc 470 * expects to see SOME value returned, so placate it and return 0. 471 */ 472 int 473 lx_sync(void) 474 { 475 sync(); 476 return (0); 477 } 478 479 int 480 lx_rmdir(uintptr_t p1) 481 { 482 int r; 483 484 r = rmdir((char *)p1); 485 if (r < 0) 486 return ((errno == EEXIST) ? -ENOTEMPTY : -errno); 487 return (0); 488 } 489 490 /* 491 * Exactly the same as Solaris' sysfs(2), except Linux numbers their fs indices 492 * starting at 0, and Solaris starts at 1. 493 */ 494 int 495 lx_sysfs(uintptr_t p1, uintptr_t p2, uintptr_t p3) 496 { 497 int option = (int)p1; 498 int res; 499 500 /* 501 * Linux actually doesn't have #defines for these; their sysfs(2) 502 * man page literally defines the "option" field as being 1, 2 or 3, 503 * corresponding to Solaris' GETFSIND, GETFSTYP and GETNFSTYP, 504 * respectively. 505 */ 506 switch (option) { 507 case 1: 508 if ((res = sysfs(GETFSIND, (const char *)p2)) < 0) 509 return (-errno); 510 511 return (res - 1); 512 513 case 2: 514 if ((res = sysfs(GETFSTYP, (int)p2 + 1, 515 (char *)p3)) < 0) 516 return (-errno); 517 518 return (0); 519 520 case 3: 521 if ((res = sysfs(GETNFSTYP)) < 0) 522 return (-errno); 523 524 return (res); 525 526 default: 527 break; 528 } 529 530 return (-EINVAL); 531 } 532 533 int 534 lx_faccessat(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4) 535 { 536 int atfd = (int)p1; 537 char *path = (char *)p2; 538 int mode = (mode_t)p3; 539 int flag = (int)p4; 540 541 if (atfd == LX_AT_FDCWD) 542 atfd = AT_FDCWD; 543 544 flag = ltos_at_flag(flag, AT_EACCESS); 545 if (flag < 0) 546 return (-EINVAL); 547 548 return (faccessat(atfd, path, mode, flag) ? -errno : 0); 549 } 550 551 int 552 lx_futimesat(uintptr_t p1, uintptr_t p2, uintptr_t p3) 553 { 554 int atfd = (int)p1; 555 char *path = (char *)p2; 556 struct timeval *times = (struct timeval *)p3; 557 558 if (atfd == LX_AT_FDCWD) 559 atfd = AT_FDCWD; 560 561 return (futimesat(atfd, path, times) ? -errno : 0); 562 } 563 564 565 /* 566 * Constructs an absolute path string in buf from the path of fd and the 567 * relative path string pointed to by "p1". This is required for emulating 568 * *at() system calls. 569 * Example: 570 * If the path of fd is "/foo/bar" and path is "etc" the string returned is 571 * "/foo/bar/etc", if the fd is a file fd then it fails with ENOTDIR. 572 * If path is absolute then no modifcations are made to it when copied. 573 */ 574 static int 575 getpathat(int fd, uintptr_t p1, char *outbuf, size_t outbuf_size) 576 { 577 char pathbuf[MAXPATHLEN]; 578 char fdpathbuf[MAXPATHLEN]; 579 char *fdpath; 580 struct stat64 statbuf; 581 582 if (uucopystr((void *)p1, pathbuf, MAXPATHLEN) == -1) 583 return (-errno); 584 585 /* If the path is absolute then we can early out */ 586 if ((pathbuf[0] == '/') || (fd == LX_AT_FDCWD)) { 587 (void) strlcpy(outbuf, pathbuf, outbuf_size); 588 return (0); 589 } 590 591 fdpath = lx_fd_to_path(fd, fdpathbuf, sizeof (fdpathbuf)); 592 if (fdpath == NULL) 593 return (-EBADF); 594 595 if ((fstat64(fd, &statbuf) < 0)) 596 return (-EBADF); 597 598 if (!S_ISDIR(statbuf.st_mode)) 599 return (-ENOTDIR); 600 601 if (snprintf(outbuf, outbuf_size, "%s/%s", fdpath, pathbuf) > 602 (outbuf_size-1)) 603 return (-ENAMETOOLONG); 604 605 return (0); 606 } 607 608 int 609 lx_mkdirat(uintptr_t p1, uintptr_t p2, uintptr_t p3) 610 { 611 int atfd = (int)p1; 612 mode_t mode = (mode_t)p3; 613 char pathbuf[MAXPATHLEN]; 614 int ret; 615 616 ret = getpathat(atfd, p2, pathbuf, sizeof (pathbuf)); 617 if (ret < 0) 618 return (ret); 619 620 return (mkdir(pathbuf, mode) ? -errno : 0); 621 } 622 623 int 624 lx_mknodat(uintptr_t ext1, uintptr_t p1, uintptr_t p2, uintptr_t p3) 625 { 626 int atfd = (int)ext1; 627 char pathbuf[MAXPATHLEN]; 628 int ret; 629 630 ret = getpathat(atfd, p1, pathbuf, sizeof (pathbuf)); 631 if (ret < 0) 632 return (ret); 633 634 return (lx_mknod((uintptr_t)pathbuf, p2, p3)); 635 } 636 637 int 638 lx_symlinkat(uintptr_t p1, uintptr_t ext1, uintptr_t p2) 639 { 640 int atfd = (int)ext1; 641 char pathbuf[MAXPATHLEN]; 642 int ret; 643 644 ret = getpathat(atfd, p2, pathbuf, sizeof (pathbuf)); 645 if (ret < 0) 646 return (ret); 647 648 return (symlink((char *)p1, pathbuf) ? -errno : 0); 649 } 650 651 int 652 lx_linkat(uintptr_t ext1, uintptr_t p1, uintptr_t ext2, uintptr_t p2, 653 uintptr_t p3) 654 { 655 int atfd1 = (int)ext1; 656 int atfd2 = (int)ext2; 657 char pathbuf1[MAXPATHLEN]; 658 char pathbuf2[MAXPATHLEN]; 659 int ret; 660 661 /* 662 * The flag specifies whether the hardlink will point to a symlink or 663 * not, on solaris the default behaviour of link() is to dereference a 664 * symlink and there is no obvious way to trigger the other behaviour. 665 * So for now we just ignore this flag and act like link(). 666 */ 667 /* LINTED [set but not used in function] */ 668 int flag = p3; 669 670 if (flag != p3) 671 return (flag); // workaround. 672 673 ret = getpathat(atfd1, p1, pathbuf1, sizeof (pathbuf1)); 674 if (ret < 0) 675 return (ret); 676 677 ret = getpathat(atfd2, p2, pathbuf2, sizeof (pathbuf2)); 678 if (ret < 0) 679 return (ret); 680 681 return (lx_link((uintptr_t)pathbuf1, (uintptr_t)pathbuf2)); 682 } 683 684 int 685 lx_readlinkat(uintptr_t ext1, uintptr_t p1, uintptr_t p2, uintptr_t p3) 686 { 687 int atfd = (int)ext1; 688 char pathbuf[MAXPATHLEN]; 689 int ret; 690 691 ret = getpathat(atfd, p1, pathbuf, sizeof (pathbuf)); 692 if (ret < 0) 693 return (ret); 694 695 ret = readlink(pathbuf, (char *)p2, (size_t)p3); 696 if (ret < 0) 697 return (-errno); 698 699 return (ret); 700 } 701 702 int 703 lx_fchownat(uintptr_t ext1, uintptr_t p1, uintptr_t p2, uintptr_t p3, 704 uintptr_t p4) 705 { 706 int flag; 707 int atfd = (int)ext1; 708 char pathbuf[MAXPATHLEN]; 709 int ret; 710 711 flag = ltos_at_flag(p4, AT_SYMLINK_NOFOLLOW); 712 if (flag < 0) 713 return (-EINVAL); 714 715 ret = getpathat(atfd, p1, pathbuf, sizeof (pathbuf)); 716 if (ret < 0) 717 return (ret); 718 719 if (flag & AT_SYMLINK_NOFOLLOW) 720 return (lchown(pathbuf, (uid_t)p2, (gid_t)p3) ? -errno : 0); 721 else 722 return (lx_chown((uintptr_t)pathbuf, p2, p3)); 723 } 724 725 int 726 lx_fchmodat(uintptr_t ext1, uintptr_t p1, uintptr_t p2, uintptr_t p3) 727 { 728 int atfd = (int)ext1; 729 char pathbuf[MAXPATHLEN]; 730 int ret; 731 732 /* 733 * It seems that at least some versions of glibc do not set or clear 734 * the flags arg, so checking them will result in random behaviour. 735 */ 736 /* LINTED [set but not used in function] */ 737 int flag = p3; 738 739 if (flag != p3) 740 return (flag); // workaround. 741 742 ret = getpathat(atfd, p1, pathbuf, sizeof (pathbuf)); 743 if (ret < 0) 744 return (ret); 745 746 return (lx_chmod((uintptr_t)pathbuf, p2)); 747 }