17c2fbfb3SApril Chin /*
27c2fbfb3SApril Chin * CDDL HEADER START
37c2fbfb3SApril Chin *
47c2fbfb3SApril Chin * The contents of this file are subject to the terms of the
57c2fbfb3SApril Chin * Common Development and Distribution License (the "License").
67c2fbfb3SApril Chin * You may not use this file except in compliance with the License.
77c2fbfb3SApril Chin *
87c2fbfb3SApril Chin * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c2fbfb3SApril Chin * or http://www.opensolaris.org/os/licensing.
107c2fbfb3SApril Chin * See the License for the specific language governing permissions
117c2fbfb3SApril Chin * and limitations under the License.
127c2fbfb3SApril Chin *
137c2fbfb3SApril Chin * When distributing Covered Code, include this CDDL HEADER in each
147c2fbfb3SApril Chin * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c2fbfb3SApril Chin * If applicable, add the following below this CDDL HEADER, with the
167c2fbfb3SApril Chin * fields enclosed by brackets "[]" replaced with your own identifying
177c2fbfb3SApril Chin * information: Portions Copyright [yyyy] [name of copyright owner]
187c2fbfb3SApril Chin *
197c2fbfb3SApril Chin * CDDL HEADER END
207c2fbfb3SApril Chin */
217c2fbfb3SApril Chin
227c2fbfb3SApril Chin /*
23*a4aeef46SDonghai Qiao * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
247c2fbfb3SApril Chin * Use is subject to license terms.
257c2fbfb3SApril Chin */
267c2fbfb3SApril Chin
277c2fbfb3SApril Chin #include <sys/types.h>
287c2fbfb3SApril Chin #include <sys/param.h>
297c2fbfb3SApril Chin #include <sys/sysmacros.h>
307c2fbfb3SApril Chin #include <sys/signal.h>
317c2fbfb3SApril Chin #include <sys/cred.h>
327c2fbfb3SApril Chin #include <sys/user.h>
337c2fbfb3SApril Chin #include <sys/errno.h>
347c2fbfb3SApril Chin #include <sys/vnode.h>
357c2fbfb3SApril Chin #include <sys/proc.h>
367c2fbfb3SApril Chin #include <sys/cmn_err.h>
377c2fbfb3SApril Chin #include <sys/debug.h>
387c2fbfb3SApril Chin #include <sys/pathname.h>
397c2fbfb3SApril Chin #include <sys/disp.h>
407c2fbfb3SApril Chin #include <sys/exec.h>
417c2fbfb3SApril Chin #include <sys/kmem.h>
427c2fbfb3SApril Chin #include <sys/note.h>
437c2fbfb3SApril Chin
447c2fbfb3SApril Chin /*
457c2fbfb3SApril Chin * This is the loadable module wrapper.
467c2fbfb3SApril Chin */
477c2fbfb3SApril Chin #include <sys/modctl.h>
487c2fbfb3SApril Chin
49ce67301fSRoland Mainz /* Local prototypes */
50ce67301fSRoland Mainz static int
517c2fbfb3SApril Chin shbinexec(
527c2fbfb3SApril Chin struct vnode *vp,
537c2fbfb3SApril Chin struct execa *uap,
547c2fbfb3SApril Chin struct uarg *args,
557c2fbfb3SApril Chin struct intpdata *idatap,
567c2fbfb3SApril Chin int level,
577c2fbfb3SApril Chin long *execsz,
587c2fbfb3SApril Chin int setid,
597c2fbfb3SApril Chin caddr_t exec_file,
607c2fbfb3SApril Chin struct cred *cred,
617c2fbfb3SApril Chin int brand_action);
627c2fbfb3SApril Chin
637c2fbfb3SApril Chin #define SHBIN_CNTL(x) ((x)&037)
647c2fbfb3SApril Chin #define SHBINMAGIC_LEN 4
657c2fbfb3SApril Chin extern char shbinmagicstr[];
667c2fbfb3SApril Chin
677c2fbfb3SApril Chin /*
687c2fbfb3SApril Chin * Our list where we may find a copy of ksh93. The ordering is:
697c2fbfb3SApril Chin * 1. 64bit (may not be installed or not supported in hardware)
707c2fbfb3SApril Chin * 2. 32bit
717c2fbfb3SApril Chin * 3. Use /sbin/ksh93 when /usr is not available
727c2fbfb3SApril Chin *
737c2fbfb3SApril Chin * ([1] and [2] explicitly bypass /usr/bin/ksh93 to avoid the
747c2fbfb3SApril Chin * isaexec overhead).
757c2fbfb3SApril Chin */
767c2fbfb3SApril Chin static char *shell_list[] =
777c2fbfb3SApril Chin {
787c2fbfb3SApril Chin /* Bypass /usr/bin/ksh93 (which is "isaexec") for performance */
797c2fbfb3SApril Chin #if defined(__sparc)
807c2fbfb3SApril Chin "/usr/bin/sparcv9/ksh93",
817c2fbfb3SApril Chin "/usr/bin/sparcv7/ksh93",
827c2fbfb3SApril Chin #elif defined(__amd64)
837c2fbfb3SApril Chin "/usr/bin/amd64/ksh93",
847c2fbfb3SApril Chin "/usr/bin/i86/ksh93",
857c2fbfb3SApril Chin #elif defined(__i386)
867c2fbfb3SApril Chin "/usr/bin/i86/ksh93",
877c2fbfb3SApril Chin #else
887c2fbfb3SApril Chin #error "Unrecognized platform/CPU (use /usr/bin/ksh93 when in doubt)."
897c2fbfb3SApril Chin #endif
907c2fbfb3SApril Chin "/sbin/ksh93",
917c2fbfb3SApril Chin NULL
927c2fbfb3SApril Chin };
937c2fbfb3SApril Chin
947c2fbfb3SApril Chin static struct execsw esw = {
957c2fbfb3SApril Chin shbinmagicstr,
967c2fbfb3SApril Chin 0,
977c2fbfb3SApril Chin SHBINMAGIC_LEN,
987c2fbfb3SApril Chin shbinexec,
997c2fbfb3SApril Chin NULL
1007c2fbfb3SApril Chin };
1017c2fbfb3SApril Chin
1027c2fbfb3SApril Chin /*
1037c2fbfb3SApril Chin * Module linkage information for the kernel.
1047c2fbfb3SApril Chin */
1057c2fbfb3SApril Chin extern struct mod_ops mod_execops;
1067c2fbfb3SApril Chin
1077c2fbfb3SApril Chin static struct modlexec modlexec = {
1087c2fbfb3SApril Chin &mod_execops, "exec mod for shell binaries (ksh93)", &esw
1097c2fbfb3SApril Chin };
1107c2fbfb3SApril Chin
1117c2fbfb3SApril Chin static struct modlinkage modlinkage = {
1127c2fbfb3SApril Chin MODREV_1, (void *)&modlexec, NULL
1137c2fbfb3SApril Chin };
1147c2fbfb3SApril Chin
1157c2fbfb3SApril Chin int
_init(void)1167c2fbfb3SApril Chin _init(void)
1177c2fbfb3SApril Chin {
1187c2fbfb3SApril Chin return (mod_install(&modlinkage));
1197c2fbfb3SApril Chin }
1207c2fbfb3SApril Chin
1217c2fbfb3SApril Chin int
_fini(void)1227c2fbfb3SApril Chin _fini(void)
1237c2fbfb3SApril Chin {
1247c2fbfb3SApril Chin return (mod_remove(&modlinkage));
1257c2fbfb3SApril Chin }
1267c2fbfb3SApril Chin
1277c2fbfb3SApril Chin int
_info(struct modinfo * modinfop)1287c2fbfb3SApril Chin _info(struct modinfo *modinfop)
1297c2fbfb3SApril Chin {
1307c2fbfb3SApril Chin return (mod_info(&modlinkage, modinfop));
1317c2fbfb3SApril Chin }
1327c2fbfb3SApril Chin
1337c2fbfb3SApril Chin static int
checkshbinmagic(struct vnode * vp)1347c2fbfb3SApril Chin checkshbinmagic(struct vnode *vp)
1357c2fbfb3SApril Chin {
1367c2fbfb3SApril Chin int error;
1377c2fbfb3SApril Chin char linep[SHBINMAGIC_LEN];
1387c2fbfb3SApril Chin ssize_t resid;
1397c2fbfb3SApril Chin
1407c2fbfb3SApril Chin /*
1417c2fbfb3SApril Chin * Read the entire line and confirm that it starts with the magic
1427c2fbfb3SApril Chin * sequence for compiled ksh93 shell scripts.
1437c2fbfb3SApril Chin */
1447c2fbfb3SApril Chin if (error = vn_rdwr(UIO_READ, vp, linep, sizeof (linep), (offset_t)0,
1457c2fbfb3SApril Chin UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid))
1467c2fbfb3SApril Chin return (error);
1477c2fbfb3SApril Chin
1487c2fbfb3SApril Chin if (memcmp(linep, shbinmagicstr, SHBINMAGIC_LEN) != 0)
1497c2fbfb3SApril Chin return (ENOEXEC);
1507c2fbfb3SApril Chin
1517c2fbfb3SApril Chin return (0);
1527c2fbfb3SApril Chin }
1537c2fbfb3SApril Chin
154ce67301fSRoland Mainz 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)1557c2fbfb3SApril Chin shbinexec(
1567c2fbfb3SApril Chin struct vnode *vp,
1577c2fbfb3SApril Chin struct execa *uap,
1587c2fbfb3SApril Chin struct uarg *args,
1597c2fbfb3SApril Chin struct intpdata *idatap,
1607c2fbfb3SApril Chin int level,
1617c2fbfb3SApril Chin long *execsz,
1627c2fbfb3SApril Chin int setid,
1637c2fbfb3SApril Chin caddr_t exec_file,
1647c2fbfb3SApril Chin struct cred *cred,
1657c2fbfb3SApril Chin int brand_action)
1667c2fbfb3SApril Chin {
1677c2fbfb3SApril Chin _NOTE(ARGUNUSED(brand_action))
1687c2fbfb3SApril Chin vnode_t *nvp;
1697c2fbfb3SApril Chin int error = 0;
1707c2fbfb3SApril Chin struct intpdata idata;
1717c2fbfb3SApril Chin struct pathname intppn;
1727c2fbfb3SApril Chin struct pathname resolvepn;
1737c2fbfb3SApril Chin char *opath;
1747c2fbfb3SApril Chin char devfd[19]; /* 32-bit int fits in 10 digits + 8 for "/dev/fd/" */
1757c2fbfb3SApril Chin int fd = -1;
1767c2fbfb3SApril Chin int i;
1777c2fbfb3SApril Chin
1787c2fbfb3SApril Chin if (level) { /* Can't recurse */
1797c2fbfb3SApril Chin error = ENOEXEC;
1807c2fbfb3SApril Chin goto bad;
1817c2fbfb3SApril Chin }
1827c2fbfb3SApril Chin
1837c2fbfb3SApril Chin ASSERT(idatap == (struct intpdata *)NULL);
1847c2fbfb3SApril Chin
1857c2fbfb3SApril Chin /*
1867c2fbfb3SApril Chin * Check whether the executable has the correct magic value.
1877c2fbfb3SApril Chin */
1887c2fbfb3SApril Chin if (error = checkshbinmagic(vp))
1897c2fbfb3SApril Chin goto fail;
1907c2fbfb3SApril Chin
1917c2fbfb3SApril Chin pn_alloc(&resolvepn);
1927c2fbfb3SApril Chin
1937c2fbfb3SApril Chin /*
1947c2fbfb3SApril Chin * Travel the list of shells and look for one which is available...
1957c2fbfb3SApril Chin */
1967c2fbfb3SApril Chin for (i = 0; shell_list[i] != NULL; i++) {
1977c2fbfb3SApril Chin error = pn_get(shell_list[i], UIO_SYSSPACE, &intppn);
1987c2fbfb3SApril Chin if (error != 0) {
1997c2fbfb3SApril Chin break;
2007c2fbfb3SApril Chin }
2017c2fbfb3SApril Chin
2027c2fbfb3SApril Chin error = lookuppn(&intppn, &resolvepn, FOLLOW, NULLVPP, &nvp);
2037c2fbfb3SApril Chin if (!error) {
2047c2fbfb3SApril Chin /* Found match */
2057c2fbfb3SApril Chin break;
2067c2fbfb3SApril Chin }
2077c2fbfb3SApril Chin
2087c2fbfb3SApril Chin /* No match found ? Then continue with the next item... */
2097c2fbfb3SApril Chin pn_free(&intppn);
2107c2fbfb3SApril Chin }
2117c2fbfb3SApril Chin
2127c2fbfb3SApril Chin if (error) {
2137c2fbfb3SApril Chin pn_free(&resolvepn);
2147c2fbfb3SApril Chin goto fail;
2157c2fbfb3SApril Chin }
2167c2fbfb3SApril Chin
217ce67301fSRoland Mainz /*
218ce67301fSRoland Mainz * Setup interpreter data
219ce67301fSRoland Mainz * "--" is passed to mark the end-of-arguments before adding
220ce67301fSRoland Mainz * the scripts file name, preventing problems when a
221ce67301fSRoland Mainz * a script's name starts with a '-' character.
222ce67301fSRoland Mainz */
223ce67301fSRoland Mainz idata.intp = NULL;
224ce67301fSRoland Mainz idata.intp_name = shell_list[i];
225ce67301fSRoland Mainz idata.intp_arg = "--";
226ce67301fSRoland Mainz
2277c2fbfb3SApril Chin opath = args->pathname;
2287c2fbfb3SApril Chin args->pathname = resolvepn.pn_path;
2297c2fbfb3SApril Chin /* don't free resolvepn until we are done with args */
2307c2fbfb3SApril Chin pn_free(&intppn);
2317c2fbfb3SApril Chin
2327c2fbfb3SApril Chin /*
2337c2fbfb3SApril Chin * When we're executing a set-uid script resulting in uids
2347c2fbfb3SApril Chin * mismatching or when we execute with additional privileges,
2357c2fbfb3SApril Chin * we close the "replace script between exec and open by shell"
2367c2fbfb3SApril Chin * hole by passing the script as /dev/fd parameter.
2377c2fbfb3SApril Chin */
2387c2fbfb3SApril Chin if ((setid & EXECSETID_PRIVS) != 0 ||
2397c2fbfb3SApril Chin (setid & (EXECSETID_UGIDS|EXECSETID_SETID)) ==
2407c2fbfb3SApril Chin (EXECSETID_UGIDS|EXECSETID_SETID)) {
2417c2fbfb3SApril Chin (void) strcpy(devfd, "/dev/fd/");
2427c2fbfb3SApril Chin if (error = execopen(&vp, &fd))
2437c2fbfb3SApril Chin goto done;
2447c2fbfb3SApril Chin numtos(fd, &devfd[8]);
2457c2fbfb3SApril Chin args->fname = devfd;
2467c2fbfb3SApril Chin }
2477c2fbfb3SApril Chin
2487c2fbfb3SApril Chin error = gexec(&nvp, uap, args, &idata, ++level, execsz, exec_file, cred,
2497c2fbfb3SApril Chin EBA_NONE);
250*a4aeef46SDonghai Qiao
251*a4aeef46SDonghai Qiao if (!error) {
252*a4aeef46SDonghai Qiao /*
253*a4aeef46SDonghai Qiao * Close this script as the sh interpreter
254*a4aeef46SDonghai Qiao * will open and close it later on.
255*a4aeef46SDonghai Qiao */
256*a4aeef46SDonghai Qiao (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, cred, NULL);
257*a4aeef46SDonghai Qiao }
2587c2fbfb3SApril Chin done:
2597c2fbfb3SApril Chin VN_RELE(nvp);
2607c2fbfb3SApril Chin args->pathname = opath;
2617c2fbfb3SApril Chin pn_free(&resolvepn);
2627c2fbfb3SApril Chin fail:
2637c2fbfb3SApril Chin if (error && fd != -1)
2647c2fbfb3SApril Chin (void) execclose(fd);
2657c2fbfb3SApril Chin bad:
2667c2fbfb3SApril Chin return (error);
2677c2fbfb3SApril Chin }
268