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 }