18462SApril.Chin@Sun.COM /*
28462SApril.Chin@Sun.COM * CDDL HEADER START
38462SApril.Chin@Sun.COM *
48462SApril.Chin@Sun.COM * The contents of this file are subject to the terms of the
58462SApril.Chin@Sun.COM * Common Development and Distribution License (the "License").
68462SApril.Chin@Sun.COM * You may not use this file except in compliance with the License.
78462SApril.Chin@Sun.COM *
88462SApril.Chin@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98462SApril.Chin@Sun.COM * or http://www.opensolaris.org/os/licensing.
108462SApril.Chin@Sun.COM * See the License for the specific language governing permissions
118462SApril.Chin@Sun.COM * and limitations under the License.
128462SApril.Chin@Sun.COM *
138462SApril.Chin@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
148462SApril.Chin@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158462SApril.Chin@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
168462SApril.Chin@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
178462SApril.Chin@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
188462SApril.Chin@Sun.COM *
198462SApril.Chin@Sun.COM * CDDL HEADER END
208462SApril.Chin@Sun.COM */
218462SApril.Chin@Sun.COM
228462SApril.Chin@Sun.COM /*
23*11736SDonghai.Qiao@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
248462SApril.Chin@Sun.COM * Use is subject to license terms.
258462SApril.Chin@Sun.COM */
268462SApril.Chin@Sun.COM
278462SApril.Chin@Sun.COM #include <sys/types.h>
288462SApril.Chin@Sun.COM #include <sys/param.h>
298462SApril.Chin@Sun.COM #include <sys/sysmacros.h>
308462SApril.Chin@Sun.COM #include <sys/signal.h>
318462SApril.Chin@Sun.COM #include <sys/cred.h>
328462SApril.Chin@Sun.COM #include <sys/user.h>
338462SApril.Chin@Sun.COM #include <sys/errno.h>
348462SApril.Chin@Sun.COM #include <sys/vnode.h>
358462SApril.Chin@Sun.COM #include <sys/proc.h>
368462SApril.Chin@Sun.COM #include <sys/cmn_err.h>
378462SApril.Chin@Sun.COM #include <sys/debug.h>
388462SApril.Chin@Sun.COM #include <sys/pathname.h>
398462SApril.Chin@Sun.COM #include <sys/disp.h>
408462SApril.Chin@Sun.COM #include <sys/exec.h>
418462SApril.Chin@Sun.COM #include <sys/kmem.h>
428462SApril.Chin@Sun.COM #include <sys/note.h>
438462SApril.Chin@Sun.COM
448462SApril.Chin@Sun.COM /*
458462SApril.Chin@Sun.COM * This is the loadable module wrapper.
468462SApril.Chin@Sun.COM */
478462SApril.Chin@Sun.COM #include <sys/modctl.h>
488462SApril.Chin@Sun.COM
4910205Sroland.mainz@nrubsig.org /* Local prototypes */
5010205Sroland.mainz@nrubsig.org static int
518462SApril.Chin@Sun.COM shbinexec(
528462SApril.Chin@Sun.COM struct vnode *vp,
538462SApril.Chin@Sun.COM struct execa *uap,
548462SApril.Chin@Sun.COM struct uarg *args,
558462SApril.Chin@Sun.COM struct intpdata *idatap,
568462SApril.Chin@Sun.COM int level,
578462SApril.Chin@Sun.COM long *execsz,
588462SApril.Chin@Sun.COM int setid,
598462SApril.Chin@Sun.COM caddr_t exec_file,
608462SApril.Chin@Sun.COM struct cred *cred,
618462SApril.Chin@Sun.COM int brand_action);
628462SApril.Chin@Sun.COM
638462SApril.Chin@Sun.COM #define SHBIN_CNTL(x) ((x)&037)
648462SApril.Chin@Sun.COM #define SHBINMAGIC_LEN 4
658462SApril.Chin@Sun.COM extern char shbinmagicstr[];
668462SApril.Chin@Sun.COM
678462SApril.Chin@Sun.COM /*
688462SApril.Chin@Sun.COM * Our list where we may find a copy of ksh93. The ordering is:
698462SApril.Chin@Sun.COM * 1. 64bit (may not be installed or not supported in hardware)
708462SApril.Chin@Sun.COM * 2. 32bit
718462SApril.Chin@Sun.COM * 3. Use /sbin/ksh93 when /usr is not available
728462SApril.Chin@Sun.COM *
738462SApril.Chin@Sun.COM * ([1] and [2] explicitly bypass /usr/bin/ksh93 to avoid the
748462SApril.Chin@Sun.COM * isaexec overhead).
758462SApril.Chin@Sun.COM */
768462SApril.Chin@Sun.COM static char *shell_list[] =
778462SApril.Chin@Sun.COM {
788462SApril.Chin@Sun.COM /* Bypass /usr/bin/ksh93 (which is "isaexec") for performance */
798462SApril.Chin@Sun.COM #if defined(__sparc)
808462SApril.Chin@Sun.COM "/usr/bin/sparcv9/ksh93",
818462SApril.Chin@Sun.COM "/usr/bin/sparcv7/ksh93",
828462SApril.Chin@Sun.COM #elif defined(__amd64)
838462SApril.Chin@Sun.COM "/usr/bin/amd64/ksh93",
848462SApril.Chin@Sun.COM "/usr/bin/i86/ksh93",
858462SApril.Chin@Sun.COM #elif defined(__i386)
868462SApril.Chin@Sun.COM "/usr/bin/i86/ksh93",
878462SApril.Chin@Sun.COM #else
888462SApril.Chin@Sun.COM #error "Unrecognized platform/CPU (use /usr/bin/ksh93 when in doubt)."
898462SApril.Chin@Sun.COM #endif
908462SApril.Chin@Sun.COM "/sbin/ksh93",
918462SApril.Chin@Sun.COM NULL
928462SApril.Chin@Sun.COM };
938462SApril.Chin@Sun.COM
948462SApril.Chin@Sun.COM static struct execsw esw = {
958462SApril.Chin@Sun.COM shbinmagicstr,
968462SApril.Chin@Sun.COM 0,
978462SApril.Chin@Sun.COM SHBINMAGIC_LEN,
988462SApril.Chin@Sun.COM shbinexec,
998462SApril.Chin@Sun.COM NULL
1008462SApril.Chin@Sun.COM };
1018462SApril.Chin@Sun.COM
1028462SApril.Chin@Sun.COM /*
1038462SApril.Chin@Sun.COM * Module linkage information for the kernel.
1048462SApril.Chin@Sun.COM */
1058462SApril.Chin@Sun.COM extern struct mod_ops mod_execops;
1068462SApril.Chin@Sun.COM
1078462SApril.Chin@Sun.COM static struct modlexec modlexec = {
1088462SApril.Chin@Sun.COM &mod_execops, "exec mod for shell binaries (ksh93)", &esw
1098462SApril.Chin@Sun.COM };
1108462SApril.Chin@Sun.COM
1118462SApril.Chin@Sun.COM static struct modlinkage modlinkage = {
1128462SApril.Chin@Sun.COM MODREV_1, (void *)&modlexec, NULL
1138462SApril.Chin@Sun.COM };
1148462SApril.Chin@Sun.COM
1158462SApril.Chin@Sun.COM int
_init(void)1168462SApril.Chin@Sun.COM _init(void)
1178462SApril.Chin@Sun.COM {
1188462SApril.Chin@Sun.COM return (mod_install(&modlinkage));
1198462SApril.Chin@Sun.COM }
1208462SApril.Chin@Sun.COM
1218462SApril.Chin@Sun.COM int
_fini(void)1228462SApril.Chin@Sun.COM _fini(void)
1238462SApril.Chin@Sun.COM {
1248462SApril.Chin@Sun.COM return (mod_remove(&modlinkage));
1258462SApril.Chin@Sun.COM }
1268462SApril.Chin@Sun.COM
1278462SApril.Chin@Sun.COM int
_info(struct modinfo * modinfop)1288462SApril.Chin@Sun.COM _info(struct modinfo *modinfop)
1298462SApril.Chin@Sun.COM {
1308462SApril.Chin@Sun.COM return (mod_info(&modlinkage, modinfop));
1318462SApril.Chin@Sun.COM }
1328462SApril.Chin@Sun.COM
1338462SApril.Chin@Sun.COM static int
checkshbinmagic(struct vnode * vp)1348462SApril.Chin@Sun.COM checkshbinmagic(struct vnode *vp)
1358462SApril.Chin@Sun.COM {
1368462SApril.Chin@Sun.COM int error;
1378462SApril.Chin@Sun.COM char linep[SHBINMAGIC_LEN];
1388462SApril.Chin@Sun.COM ssize_t resid;
1398462SApril.Chin@Sun.COM
1408462SApril.Chin@Sun.COM /*
1418462SApril.Chin@Sun.COM * Read the entire line and confirm that it starts with the magic
1428462SApril.Chin@Sun.COM * sequence for compiled ksh93 shell scripts.
1438462SApril.Chin@Sun.COM */
1448462SApril.Chin@Sun.COM if (error = vn_rdwr(UIO_READ, vp, linep, sizeof (linep), (offset_t)0,
1458462SApril.Chin@Sun.COM UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid))
1468462SApril.Chin@Sun.COM return (error);
1478462SApril.Chin@Sun.COM
1488462SApril.Chin@Sun.COM if (memcmp(linep, shbinmagicstr, SHBINMAGIC_LEN) != 0)
1498462SApril.Chin@Sun.COM return (ENOEXEC);
1508462SApril.Chin@Sun.COM
1518462SApril.Chin@Sun.COM return (0);
1528462SApril.Chin@Sun.COM }
1538462SApril.Chin@Sun.COM
15410205Sroland.mainz@nrubsig.org static int
shbinexec(struct vnode * vp,struct execa * uap,struct uarg * args,struct intpdata * idatap,int level,long * execsz,int setid,caddr_t exec_file,struct cred * cred,int brand_action)1558462SApril.Chin@Sun.COM shbinexec(
1568462SApril.Chin@Sun.COM struct vnode *vp,
1578462SApril.Chin@Sun.COM struct execa *uap,
1588462SApril.Chin@Sun.COM struct uarg *args,
1598462SApril.Chin@Sun.COM struct intpdata *idatap,
1608462SApril.Chin@Sun.COM int level,
1618462SApril.Chin@Sun.COM long *execsz,
1628462SApril.Chin@Sun.COM int setid,
1638462SApril.Chin@Sun.COM caddr_t exec_file,
1648462SApril.Chin@Sun.COM struct cred *cred,
1658462SApril.Chin@Sun.COM int brand_action)
1668462SApril.Chin@Sun.COM {
1678462SApril.Chin@Sun.COM _NOTE(ARGUNUSED(brand_action))
1688462SApril.Chin@Sun.COM vnode_t *nvp;
1698462SApril.Chin@Sun.COM int error = 0;
1708462SApril.Chin@Sun.COM struct intpdata idata;
1718462SApril.Chin@Sun.COM struct pathname intppn;
1728462SApril.Chin@Sun.COM struct pathname resolvepn;
1738462SApril.Chin@Sun.COM char *opath;
1748462SApril.Chin@Sun.COM char devfd[19]; /* 32-bit int fits in 10 digits + 8 for "/dev/fd/" */
1758462SApril.Chin@Sun.COM int fd = -1;
1768462SApril.Chin@Sun.COM int i;
1778462SApril.Chin@Sun.COM
1788462SApril.Chin@Sun.COM if (level) { /* Can't recurse */
1798462SApril.Chin@Sun.COM error = ENOEXEC;
1808462SApril.Chin@Sun.COM goto bad;
1818462SApril.Chin@Sun.COM }
1828462SApril.Chin@Sun.COM
1838462SApril.Chin@Sun.COM ASSERT(idatap == (struct intpdata *)NULL);
1848462SApril.Chin@Sun.COM
1858462SApril.Chin@Sun.COM /*
1868462SApril.Chin@Sun.COM * Check whether the executable has the correct magic value.
1878462SApril.Chin@Sun.COM */
1888462SApril.Chin@Sun.COM if (error = checkshbinmagic(vp))
1898462SApril.Chin@Sun.COM goto fail;
1908462SApril.Chin@Sun.COM
1918462SApril.Chin@Sun.COM pn_alloc(&resolvepn);
1928462SApril.Chin@Sun.COM
1938462SApril.Chin@Sun.COM /*
1948462SApril.Chin@Sun.COM * Travel the list of shells and look for one which is available...
1958462SApril.Chin@Sun.COM */
1968462SApril.Chin@Sun.COM for (i = 0; shell_list[i] != NULL; i++) {
1978462SApril.Chin@Sun.COM error = pn_get(shell_list[i], UIO_SYSSPACE, &intppn);
1988462SApril.Chin@Sun.COM if (error != 0) {
1998462SApril.Chin@Sun.COM break;
2008462SApril.Chin@Sun.COM }
2018462SApril.Chin@Sun.COM
2028462SApril.Chin@Sun.COM error = lookuppn(&intppn, &resolvepn, FOLLOW, NULLVPP, &nvp);
2038462SApril.Chin@Sun.COM if (!error) {
2048462SApril.Chin@Sun.COM /* Found match */
2058462SApril.Chin@Sun.COM break;
2068462SApril.Chin@Sun.COM }
2078462SApril.Chin@Sun.COM
2088462SApril.Chin@Sun.COM /* No match found ? Then continue with the next item... */
2098462SApril.Chin@Sun.COM pn_free(&intppn);
2108462SApril.Chin@Sun.COM }
2118462SApril.Chin@Sun.COM
2128462SApril.Chin@Sun.COM if (error) {
2138462SApril.Chin@Sun.COM pn_free(&resolvepn);
2148462SApril.Chin@Sun.COM goto fail;
2158462SApril.Chin@Sun.COM }
2168462SApril.Chin@Sun.COM
21710205Sroland.mainz@nrubsig.org /*
21810205Sroland.mainz@nrubsig.org * Setup interpreter data
21910205Sroland.mainz@nrubsig.org * "--" is passed to mark the end-of-arguments before adding
22010205Sroland.mainz@nrubsig.org * the scripts file name, preventing problems when a
22110205Sroland.mainz@nrubsig.org * a script's name starts with a '-' character.
22210205Sroland.mainz@nrubsig.org */
22310205Sroland.mainz@nrubsig.org idata.intp = NULL;
22410205Sroland.mainz@nrubsig.org idata.intp_name = shell_list[i];
22510205Sroland.mainz@nrubsig.org idata.intp_arg = "--";
22610205Sroland.mainz@nrubsig.org
2278462SApril.Chin@Sun.COM opath = args->pathname;
2288462SApril.Chin@Sun.COM args->pathname = resolvepn.pn_path;
2298462SApril.Chin@Sun.COM /* don't free resolvepn until we are done with args */
2308462SApril.Chin@Sun.COM pn_free(&intppn);
2318462SApril.Chin@Sun.COM
2328462SApril.Chin@Sun.COM /*
2338462SApril.Chin@Sun.COM * When we're executing a set-uid script resulting in uids
2348462SApril.Chin@Sun.COM * mismatching or when we execute with additional privileges,
2358462SApril.Chin@Sun.COM * we close the "replace script between exec and open by shell"
2368462SApril.Chin@Sun.COM * hole by passing the script as /dev/fd parameter.
2378462SApril.Chin@Sun.COM */
2388462SApril.Chin@Sun.COM if ((setid & EXECSETID_PRIVS) != 0 ||
2398462SApril.Chin@Sun.COM (setid & (EXECSETID_UGIDS|EXECSETID_SETID)) ==
2408462SApril.Chin@Sun.COM (EXECSETID_UGIDS|EXECSETID_SETID)) {
2418462SApril.Chin@Sun.COM (void) strcpy(devfd, "/dev/fd/");
2428462SApril.Chin@Sun.COM if (error = execopen(&vp, &fd))
2438462SApril.Chin@Sun.COM goto done;
2448462SApril.Chin@Sun.COM numtos(fd, &devfd[8]);
2458462SApril.Chin@Sun.COM args->fname = devfd;
2468462SApril.Chin@Sun.COM }
2478462SApril.Chin@Sun.COM
2488462SApril.Chin@Sun.COM error = gexec(&nvp, uap, args, &idata, ++level, execsz, exec_file, cred,
2498462SApril.Chin@Sun.COM EBA_NONE);
250*11736SDonghai.Qiao@Sun.COM
251*11736SDonghai.Qiao@Sun.COM if (!error) {
252*11736SDonghai.Qiao@Sun.COM /*
253*11736SDonghai.Qiao@Sun.COM * Close this script as the sh interpreter
254*11736SDonghai.Qiao@Sun.COM * will open and close it later on.
255*11736SDonghai.Qiao@Sun.COM */
256*11736SDonghai.Qiao@Sun.COM (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, cred, NULL);
257*11736SDonghai.Qiao@Sun.COM }
2588462SApril.Chin@Sun.COM done:
2598462SApril.Chin@Sun.COM VN_RELE(nvp);
2608462SApril.Chin@Sun.COM args->pathname = opath;
2618462SApril.Chin@Sun.COM pn_free(&resolvepn);
2628462SApril.Chin@Sun.COM fail:
2638462SApril.Chin@Sun.COM if (error && fd != -1)
2648462SApril.Chin@Sun.COM (void) execclose(fd);
2658462SApril.Chin@Sun.COM bad:
2668462SApril.Chin@Sun.COM return (error);
2678462SApril.Chin@Sun.COM }
268