Print this page
    
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/exec/shbin/shbin.c
          +++ new/usr/src/uts/common/exec/shbin/shbin.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24   24   * Use is subject to license terms.
  25   25   * Copyright 2015, Joyent, Inc.
  26   26   */
  27   27  
  28   28  #include <sys/types.h>
  29   29  #include <sys/param.h>
  30   30  #include <sys/sysmacros.h>
  31   31  #include <sys/signal.h>
  32   32  #include <sys/cred.h>
  33   33  #include <sys/user.h>
  34   34  #include <sys/errno.h>
  35   35  #include <sys/vnode.h>
  36   36  #include <sys/proc.h>
  37   37  #include <sys/cmn_err.h>
  38   38  #include <sys/debug.h>
  39   39  #include <sys/pathname.h>
  40   40  #include <sys/disp.h>
  41   41  #include <sys/exec.h>
  42   42  #include <sys/kmem.h>
  43   43  #include <sys/note.h>
  44   44  
  45   45  /*
  46   46   * This is the loadable module wrapper.
  47   47   */
  48   48  #include <sys/modctl.h>
  49   49  
  50   50  /* Local prototypes */
  51   51  static int
  52   52  shbinexec(
  53   53          struct vnode *vp,
  54   54          struct execa *uap,
  55   55          struct uarg *args,
  56   56          struct intpdata *idatap,
  57   57          int level,
  58   58          long *execsz,
  59   59          int setid,
  60   60          caddr_t exec_file,
  61   61          struct cred *cred,
  62   62          int *brand_action);
  63   63  
  64   64  #define SHBIN_CNTL(x)   ((x)&037)
  65   65  #define SHBINMAGIC_LEN  4
  66   66  extern char shbinmagicstr[];
  67   67  
  68   68  /*
  69   69   * Our list where we may find a copy of ksh93. The ordering is:
  70   70   * 1. 64bit (may not be installed or not supported in hardware)
  71   71   * 2. 32bit
  72   72   * 3. Use /sbin/ksh93 when /usr is not available
  73   73   *
  74   74   * ([1] and [2] explicitly bypass /usr/bin/ksh93 to avoid the
  75   75   * isaexec overhead).
  76   76   */
  77   77  static char *shell_list[] =
  78   78  {
  79   79  /* Bypass /usr/bin/ksh93 (which is "isaexec") for performance */
  80   80  #if defined(__sparc)
  81   81          "/usr/bin/sparcv9/ksh93",
  82   82          "/usr/bin/sparcv7/ksh93",
  83   83  #elif defined(__amd64)
  84   84          "/usr/bin/amd64/ksh93",
  85   85          "/usr/bin/i86/ksh93",
  86   86  #elif defined(__i386)
  87   87          "/usr/bin/i86/ksh93",
  88   88  #else
  89   89  #error "Unrecognized platform/CPU (use /usr/bin/ksh93 when in doubt)."
  90   90  #endif
  91   91          "/sbin/ksh93",
  92   92          NULL
  93   93  };
  94   94  
  95   95  static struct execsw esw = {
  96   96          shbinmagicstr,
  97   97          0,
  98   98          SHBINMAGIC_LEN,
  99   99          shbinexec,
 100  100          NULL
 101  101  };
 102  102  
 103  103  /*
 104  104   * Module linkage information for the kernel.
 105  105   */
 106  106  extern struct mod_ops mod_execops;
 107  107  
 108  108  static struct modlexec modlexec = {
 109  109          &mod_execops, "exec mod for shell binaries (ksh93)", &esw
 110  110  };
 111  111  
 112  112  static struct modlinkage modlinkage = {
 113  113          MODREV_1, (void *)&modlexec, NULL
 114  114  };
 115  115  
 116  116  int
 117  117  _init(void)
 118  118  {
 119  119          return (mod_install(&modlinkage));
 120  120  }
 121  121  
 122  122  int
 123  123  _fini(void)
 124  124  {
 125  125          return (mod_remove(&modlinkage));
 126  126  }
 127  127  
 128  128  int
 129  129  _info(struct modinfo *modinfop)
 130  130  {
 131  131          return (mod_info(&modlinkage, modinfop));
 132  132  }
 133  133  
 134  134  static int
 135  135  checkshbinmagic(struct vnode *vp)
 136  136  {
 137  137          int error;
 138  138          char linep[SHBINMAGIC_LEN];
 139  139          ssize_t resid;
 140  140  
 141  141          /*
 142  142           * Read the entire line and confirm that it starts with the magic
 143  143           * sequence for compiled ksh93 shell scripts.
 144  144           */
 145  145          if (error = vn_rdwr(UIO_READ, vp, linep, sizeof (linep), (offset_t)0,
 146  146              UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid))
 147  147                  return (error);
 148  148  
 149  149          if (memcmp(linep, shbinmagicstr, SHBINMAGIC_LEN) != 0)
 150  150                  return (ENOEXEC);
 151  151  
 152  152          return (0);
 153  153  }
 154  154  
 155  155  static int
 156  156  shbinexec(
 157  157          struct vnode *vp,
 158  158          struct execa *uap,
 159  159          struct uarg *args,
 160  160          struct intpdata *idatap,
 161  161          int level,
 162  162          long *execsz,
 163  163          int setid,
 164  164          caddr_t exec_file,
 165  165          struct cred *cred,
 166  166          int *brand_action)
 167  167  {
 168  168          _NOTE(ARGUNUSED(brand_action))
 169  169          vnode_t *nvp;
 170  170          int error = 0;
 171  171          struct intpdata idata;
 172  172          struct pathname intppn;
 173  173          struct pathname resolvepn;
 174  174          char *opath;
 175  175          char devfd[19]; /* 32-bit int fits in 10 digits + 8 for "/dev/fd/" */
 176  176          int fd = -1;
 177  177          int i;
 178  178  
 179  179          if (level) {            /* Can't recurse */
 180  180                  error = ENOEXEC;
 181  181                  goto bad;
 182  182          }
 183  183  
 184  184          ASSERT(idatap == (struct intpdata *)NULL);
 185  185  
 186  186          /*
 187  187           * Check whether the executable has the correct magic value.
 188  188           */
 189  189          if (error = checkshbinmagic(vp))
 190  190                  goto fail;
 191  191  
 192  192          pn_alloc(&resolvepn);
 193  193  
 194  194          /*
 195  195           * Travel the list of shells and look for one which is available...
 196  196           */
 197  197          for (i = 0; shell_list[i] != NULL; i++) {
 198  198                  error = pn_get(shell_list[i], UIO_SYSSPACE, &intppn);
 199  199                  if (error != 0) {
 200  200                          break;
 201  201                  }
 202  202  
 203  203                  error = lookuppn(&intppn, &resolvepn, FOLLOW, NULLVPP, &nvp);
 204  204                  if (!error) {
 205  205                          /* Found match */
 206  206                          break;
 207  207                  }
 208  208  
 209  209                  /* No match found ? Then continue with the next item... */
 210  210                  pn_free(&intppn);
 211  211          }
 212  212  
 213  213          if (error) {
 214  214                  pn_free(&resolvepn);
 215  215                  goto fail;
 216  216          }
 217  217  
 218  218          /*
 219  219           * Setup interpreter data
 220  220           * "--" is passed to mark the end-of-arguments before adding
 221  221           * the scripts file name, preventing problems when a
 222  222           * a script's name starts with a '-' character.
 223  223           */
 224  224          idata.intp = NULL;
 225  225          idata.intp_name[0] = shell_list[i];
 226  226          idata.intp_arg[0] = "--";
 227  227  
 228  228          opath = args->pathname;
 229  229          args->pathname = resolvepn.pn_path;
 230  230          /* don't free resolvepn until we are done with args */
 231  231          pn_free(&intppn);
 232  232  
 233  233          /*
 234  234           * When we're executing a set-uid script resulting in uids
 235  235           * mismatching or when we execute with additional privileges,
 236  236           * we close the "replace script between exec and open by shell"
 237  237           * hole by passing the script as /dev/fd parameter.
 238  238           */
 239  239          if ((setid & EXECSETID_PRIVS) != 0 ||
 240  240              (setid & (EXECSETID_UGIDS|EXECSETID_SETID)) ==
 241  241              (EXECSETID_UGIDS|EXECSETID_SETID)) {
 242  242                  (void) strcpy(devfd, "/dev/fd/");
 243  243                  if (error = execopen(&vp, &fd))
 244  244                          goto done;
 245  245                  numtos(fd, &devfd[8]);
 246  246                  args->fname = devfd;
 247  247          }
 248  248  
 249  249          error = gexec(&nvp, uap, args, &idata, ++level, execsz, exec_file, cred,
 250  250              EBA_NONE);
 251  251  
 252  252          if (!error) {
 253  253                  /*
 254  254                   * Close this script as the sh interpreter
 255  255                   * will open and close it later on.
 256  256                   */
 257  257                  (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, cred, NULL);
 258  258          }
 259  259  done:
 260  260          VN_RELE(nvp);
 261  261          args->pathname = opath;
 262  262          pn_free(&resolvepn);
 263  263  fail:
 264  264          if (error && fd != -1)
 265  265                  (void) execclose(fd);
 266  266  bad:
 267  267          return (error);
 268  268  }
  
    | 
      ↓ open down ↓ | 
    268 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX