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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <assert.h> 27 #include <alloca.h> 28 #include <errno.h> 29 #include <fcntl.h> 30 #include <strings.h> 31 #include <macros.h> 32 #include <sys/brand.h> 33 #include <sys/reboot.h> 34 #include <sys/stat.h> 35 #include <sys/syscall.h> 36 #include <sys/sysmacros.h> 37 #include <sys/systeminfo.h> 38 #include <sys/types.h> 39 #include <sys/lx_types.h> 40 #include <sys/lx_debug.h> 41 #include <sys/lx_misc.h> 42 #include <sys/lx_stat.h> 43 #include <sys/lx_syscall.h> 44 #include <sys/lx_thunk_server.h> 45 #include <sys/lx_fcntl.h> 46 #include <unistd.h> 47 #include <libintl.h> 48 #include <zone.h> 49 50 extern int sethostname(char *, int); 51 52 /* ARGUSED */ 53 int 54 lx_rename(uintptr_t p1, uintptr_t p2) 55 { 56 int ret; 57 58 ret = rename((const char *)p1, (const char *)p2); 59 60 if (ret < 0) { 61 /* 62 * If rename(2) failed and we're in install mode, return 63 * success if the the reason we failed was either because the 64 * source file didn't actually exist or if it was because we 65 * tried to rename it to be the name of a device currently in 66 * use (resulting in an EBUSY.) 67 * 68 * To help install along further, if the failure was due 69 * to an EBUSY, delete the original file so we don't leave 70 * extra files lying around. 71 */ 72 if (lx_install != 0) { 73 if (errno == ENOENT) 74 return (0); 75 76 if (errno == EBUSY) { 77 (void) unlink((const char *)p1); 78 return (0); 79 } 80 } 81 82 return (-errno); 83 } 84 85 return (0); 86 } 87 88 int 89 lx_renameat(uintptr_t ext1, uintptr_t p1, uintptr_t ext2, uintptr_t p2) 90 { 91 int ret; 92 int atfd1 = (int)ext1; 93 int atfd2 = (int)ext2; 94 95 if (atfd1 == LX_AT_FDCWD) 96 atfd1 = AT_FDCWD; 97 98 if (atfd2 == LX_AT_FDCWD) 99 atfd2 = AT_FDCWD; 100 101 ret = renameat(atfd1, (const char *)p1, atfd2, (const char *)p2); 102 103 if (ret < 0) { 104 /* see lx_rename() for why we check lx_install */ 105 if (lx_install != 0) { 106 if (errno == ENOENT) 107 return (0); 108 109 if (errno == EBUSY) { 110 (void) unlinkat(ext1, (const char *)p1, 0); 111 return (0); 112 } 113 } 114 115 return (-errno); 116 } 117 118 return (0); 119 } 120 121 /*ARGSUSED*/ 122 int 123 lx_reboot(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4) 124 { 125 int magic = (int)p1; 126 int magic2 = (int)p2; 127 uint_t flag = (int)p3; 128 int rc; 129 130 if (magic != LINUX_REBOOT_MAGIC1) 131 return (-EINVAL); 132 if (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A && 133 magic2 != LINUX_REBOOT_MAGIC2B && magic2 != LINUX_REBOOT_MAGIC2C && 134 magic2 != LINUX_REBOOT_MAGIC2D) 135 return (-EINVAL); 136 137 if (geteuid() != 0) 138 return (-EPERM); 139 140 switch (flag) { 141 case LINUX_REBOOT_CMD_CAD_ON: 142 case LINUX_REBOOT_CMD_CAD_OFF: 143 /* ignored */ 144 rc = 0; 145 break; 146 case LINUX_REBOOT_CMD_POWER_OFF: 147 case LINUX_REBOOT_CMD_HALT: 148 rc = reboot(RB_HALT, NULL); 149 break; 150 case LINUX_REBOOT_CMD_RESTART: 151 case LINUX_REBOOT_CMD_RESTART2: 152 /* RESTART2 may need more work */ 153 lx_msg(gettext("Restarting system.\n")); 154 rc = reboot(RB_AUTOBOOT, NULL); 155 break; 156 default: 157 return (-EINVAL); 158 } 159 160 return ((rc == -1) ? -errno : rc); 161 } 162 163 /* 164 * getcwd() - Linux syscall semantics are slightly different; we need to return 165 * the length of the pathname copied (+ 1 for the terminating NULL byte.) 166 */ 167 int 168 lx_getcwd(uintptr_t p1, uintptr_t p2) 169 { 170 char *buf; 171 size_t buflen = (size_t)p2; 172 size_t copylen, local_len; 173 size_t len = 0; 174 175 if ((getcwd((char *)p1, (size_t)p2)) == NULL) 176 return (-errno); 177 178 /* 179 * We need the length of the pathname getcwd() copied but we never want 180 * to dereference a Linux pointer for any reason. 181 * 182 * Thus, to get the string length we will uucopy() up to copylen bytes 183 * at a time into a local buffer and will walk each chunk looking for 184 * the string-terminating NULL byte. 185 * 186 * We can use strlen() to find the length of the string in the 187 * local buffer by delimiting the buffer with a NULL byte in the 188 * last element that will never be overwritten. 189 */ 190 copylen = min(buflen, MAXPATHLEN + 1); 191 buf = SAFE_ALLOCA(copylen + 1); 192 if (buf == NULL) 193 return (-ENOMEM); 194 buf[copylen] = '\0'; 195 196 for (;;) { 197 if (uucopy((char *)p1 + len, buf, copylen) != 0) 198 return (-errno); 199 200 local_len = strlen(buf); 201 len += local_len; 202 203 /* 204 * If the strlen() is less than copylen, we found the 205 * real end of the string -- not the NULL byte used to 206 * delimit the end of our buffer. 207 */ 208 if (local_len != copylen) 209 break; 210 211 /* prepare to check the next chunk of the string */ 212 buflen -= copylen; 213 copylen = min(buflen, copylen); 214 } 215 216 return (len + 1); 217 } 218 219 int 220 lx_get_kern_version(void) 221 { 222 /* 223 * Since this function is called quite often, and zone_getattr is slow, 224 * we cache the kernel version in kvers_cache. -1 signifies that no 225 * value has yet been cached. 226 */ 227 static int kvers_cache = -1; 228 /* dummy variable for use in zone_getattr */ 229 int kvers; 230 231 if (kvers_cache != -1) 232 return (kvers_cache); 233 if (zone_getattr(getzoneid(), LX_KERN_VERSION_NUM, &kvers, sizeof (int)) 234 != sizeof (int)) 235 return (kvers_cache = LX_KERN_2_4); 236 else 237 return (kvers_cache = kvers); 238 } 239 240 int 241 lx_uname(uintptr_t p1) 242 { 243 struct lx_utsname *un = (struct lx_utsname *)p1; 244 char buf[LX_SYS_UTS_LN + 1]; 245 246 if (gethostname(un->nodename, sizeof (un->nodename)) == -1) 247 return (-errno); 248 249 (void) strlcpy(un->sysname, LX_UNAME_SYSNAME, LX_SYS_UTS_LN); 250 (void) strlcpy(un->release, lx_release, LX_SYS_UTS_LN); 251 (void) strlcpy(un->version, LX_UNAME_VERSION, LX_SYS_UTS_LN); 252 (void) strlcpy(un->machine, LX_UNAME_MACHINE, LX_SYS_UTS_LN); 253 if ((sysinfo(SI_SRPC_DOMAIN, buf, LX_SYS_UTS_LN) < 0)) 254 un->domainname[0] = '\0'; 255 else 256 (void) strlcpy(un->domainname, buf, LX_SYS_UTS_LN); 257 258 return (0); 259 } 260 261 /* 262 * {get,set}groups16() - Handle the conversion between 16-bit Linux gids and 263 * 32-bit Solaris gids. 264 */ 265 int 266 lx_getgroups16(uintptr_t p1, uintptr_t p2) 267 { 268 int count = (int)p1; 269 lx_gid16_t *grouplist = (lx_gid16_t *)p2; 270 gid_t *grouplist32; 271 int ret; 272 int i; 273 274 grouplist32 = SAFE_ALLOCA(count * sizeof (gid_t)); 275 if (grouplist32 == NULL) 276 return (-ENOMEM); 277 if ((ret = getgroups(count, grouplist32)) < 0) 278 return (-errno); 279 280 for (i = 0; i < ret; i++) 281 grouplist[i] = LX_GID32_TO_GID16(grouplist32[i]); 282 283 return (ret); 284 } 285 286 int 287 lx_setgroups16(uintptr_t p1, uintptr_t p2) 288 { 289 int count = (int)p1; 290 lx_gid16_t *grouplist = (lx_gid16_t *)p2; 291 gid_t *grouplist32; 292 int i; 293 294 grouplist32 = SAFE_ALLOCA(count * sizeof (gid_t)); 295 if (grouplist32 == NULL) 296 return (-ENOMEM); 297 for (i = 0; i < count; i++) 298 grouplist32[i] = LX_GID16_TO_GID32(grouplist[i]); 299 300 return (setgroups(count, grouplist32) ? -errno : 0); 301 } 302 303 /* 304 * personality() - Solaris doesn't support Linux personalities, but we have to 305 * emulate enough to show that we support the basic personality. 306 */ 307 #define LX_PER_LINUX 0x0 308 309 int 310 lx_personality(uintptr_t p1) 311 { 312 int per = (int)p1; 313 314 switch (per) { 315 case -1: 316 /* Request current personality */ 317 return (LX_PER_LINUX); 318 case LX_PER_LINUX: 319 return (0); 320 default: 321 return (-EINVAL); 322 } 323 } 324 325 /* 326 * mknod() - Since we don't have the SYS_CONFIG privilege within a zone, the 327 * only mode we have to support is S_IFIFO. We also have to distinguish between 328 * an invalid type and insufficient privileges. 329 */ 330 #define LX_S_IFMT 0170000 331 #define LX_S_IFDIR 0040000 332 #define LX_S_IFCHR 0020000 333 #define LX_S_IFBLK 0060000 334 #define LX_S_IFREG 0100000 335 #define LX_S_IFIFO 0010000 336 #define LX_S_IFLNK 0120000 337 #define LX_S_IFSOCK 0140000 338 339 /*ARGSUSED*/ 340 int 341 lx_mknod(uintptr_t p1, uintptr_t p2, uintptr_t p3) 342 { 343 char *path = (char *)p1; 344 lx_dev_t lx_dev = (lx_dev_t)p3; 345 struct sockaddr_un sockaddr; 346 struct stat statbuf; 347 mode_t mode, type; 348 dev_t dev; 349 int fd; 350 351 type = ((mode_t)p2 & LX_S_IFMT); 352 mode = ((mode_t)p2 & 07777); 353 354 switch (type) { 355 case 0: 356 case LX_S_IFREG: 357 /* create a regular file */ 358 if (stat(path, &statbuf) == 0) 359 return (-EEXIST); 360 361 if (errno != ENOENT) 362 return (-errno); 363 364 if ((fd = creat(path, mode)) < 0) 365 return (-errno); 366 367 (void) close(fd); 368 return (0); 369 370 case LX_S_IFSOCK: 371 /* 372 * Create a UNIX domain socket. 373 * 374 * Most programmers aren't even aware you can do this. 375 * 376 * Note you can also do this via Solaris' mknod(2), but 377 * Linux allows anyone who can create a UNIX domain 378 * socket via bind(2) to create one via mknod(2); 379 * Solaris requires the caller to be privileged. 380 */ 381 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) 382 return (-errno); 383 384 if (stat(path, &statbuf) == 0) 385 return (-EEXIST); 386 387 if (errno != ENOENT) 388 return (-errno); 389 390 if (uucopy(path, &sockaddr.sun_path, 391 sizeof (sockaddr.sun_path)) < 0) 392 return (-errno); 393 394 /* assure NULL termination of sockaddr.sun_path */ 395 sockaddr.sun_path[sizeof (sockaddr.sun_path) - 1] = '\0'; 396 sockaddr.sun_family = AF_UNIX; 397 398 if (bind(fd, (struct sockaddr *)&sockaddr, 399 strlen(sockaddr.sun_path) + 400 sizeof (sockaddr.sun_family)) < 0) 401 return (-errno); 402 403 (void) close(fd); 404 return (0); 405 406 case LX_S_IFIFO: 407 dev = 0; 408 break; 409 410 case LX_S_IFCHR: 411 case LX_S_IFBLK: 412 /* 413 * The "dev" RPM package wants to create all possible Linux 414 * device nodes, so just report its mknod()s as having 415 * succeeded if we're in install mode. 416 */ 417 if (lx_install != 0) { 418 lx_debug("lx_mknod: install mode spoofed creation of " 419 "Linux device [%lld, %lld]\n", 420 LX_GETMAJOR(lx_dev), LX_GETMINOR(lx_dev)); 421 422 return (0); 423 } 424 425 dev = makedevice(LX_GETMAJOR(lx_dev), LX_GETMINOR(lx_dev)); 426 break; 427 428 default: 429 return (-EINVAL); 430 } 431 432 return (mknod(path, mode | type, dev) ? -errno : 0); 433 } 434 435 int 436 lx_sethostname(uintptr_t p1, uintptr_t p2) 437 { 438 char *name = (char *)p1; 439 int len = (size_t)p2; 440 441 return (sethostname(name, len) ? -errno : 0); 442 } 443 444 int 445 lx_setdomainname(uintptr_t p1, uintptr_t p2) 446 { 447 char *name = (char *)p1; 448 int len = (size_t)p2; 449 long rval; 450 451 if (len < 0 || len >= LX_SYS_UTS_LN) 452 return (-EINVAL); 453 454 rval = sysinfo(SI_SET_SRPC_DOMAIN, name, len); 455 456 return ((rval < 0) ? -errno : 0); 457 } 458 459 int 460 lx_getpid(void) 461 { 462 int pid; 463 464 /* First call the thunk server hook. */ 465 if (lxt_server_pid(&pid) != 0) 466 return (pid); 467 468 pid = syscall(SYS_brand, B_EMULATE_SYSCALL + 20); 469 return ((pid == -1) ? -errno : pid); 470 } 471 472 int 473 lx_execve(uintptr_t p1, uintptr_t p2, uintptr_t p3) 474 { 475 char *filename = (char *)p1; 476 char **argv = (char **)p2; 477 char **envp = (char **)p3; 478 char *nullist[] = { NULL }; 479 char path[64]; 480 481 /* First call the thunk server hook. */ 482 lxt_server_exec_check(); 483 484 /* Get a copy of the executable we're trying to run */ 485 path[0] = '\0'; 486 (void) uucopystr(filename, path, sizeof (path)); 487 488 /* Check if we're trying to run a native binary */ 489 if (strncmp(path, "/native/usr/lib/brand/lx/lx_native", 490 sizeof (path)) == 0) { 491 /* Skip the first element in the argv array */ 492 argv++; 493 494 /* 495 * The name of the new program to execute was the first 496 * parameter passed to lx_native. 497 */ 498 if (uucopy(argv, &filename, sizeof (char *)) != 0) 499 return (-errno); 500 501 (void) syscall(SYS_brand, B_EXEC_NATIVE, filename, argv, envp, 502 NULL, NULL, NULL); 503 return (-errno); 504 } 505 506 if (argv == NULL) 507 argv = nullist; 508 509 /* This is a normal exec call. */ 510 (void) execve(filename, argv, envp); 511 512 return (-errno); 513 } 514 515 int 516 lx_setgroups(uintptr_t p1, uintptr_t p2) 517 { 518 int ng = (int)p1; 519 gid_t *glist = NULL; 520 int i, r; 521 522 lx_debug("\tlx_setgroups(%d, 0x%p", ng, p2); 523 524 if (ng > 0) { 525 if ((glist = (gid_t *)SAFE_ALLOCA(ng * sizeof (gid_t))) == NULL) 526 return (-ENOMEM); 527 528 if (uucopy((void *)p2, glist, ng * sizeof (gid_t)) != 0) 529 return (-errno); 530 531 /* 532 * Linux doesn't check the validity of the group IDs, but 533 * Solaris does. Change any invalid group IDs to a known, valid 534 * value (yuck). 535 */ 536 for (i = 0; i < ng; i++) { 537 if (glist[i] > MAXUID) 538 glist[i] = MAXUID; 539 } 540 } 541 542 r = syscall(SYS_brand, B_EMULATE_SYSCALL + LX_SYS_setgroups32, 543 ng, glist); 544 545 return ((r == -1) ? -errno : r); 546 }