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