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 1167c2fbfb3SApril Chin _init(void) 1177c2fbfb3SApril Chin { 1187c2fbfb3SApril Chin return (mod_install(&modlinkage)); 1197c2fbfb3SApril Chin } 1207c2fbfb3SApril Chin 1217c2fbfb3SApril Chin int 1227c2fbfb3SApril Chin _fini(void) 1237c2fbfb3SApril Chin { 1247c2fbfb3SApril Chin return (mod_remove(&modlinkage)); 1257c2fbfb3SApril Chin } 1267c2fbfb3SApril Chin 1277c2fbfb3SApril Chin int 1287c2fbfb3SApril Chin _info(struct modinfo *modinfop) 1297c2fbfb3SApril Chin { 1307c2fbfb3SApril Chin return (mod_info(&modlinkage, modinfop)); 1317c2fbfb3SApril Chin } 1327c2fbfb3SApril Chin 1337c2fbfb3SApril Chin static int 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 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