Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/exec/intp/intp.c
+++ new/usr/src/uts/common/exec/intp/intp.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 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 * Copyright 2012 Milan Jurik. All rights reserved.
25 25 */
26 26
27 27 /* Copyright (c) 1988 AT&T */
28 28 /* All Rights Reserved */
29 29
30 30
31 31 /* from S5R4 1.6 */
32 32
33 33 #include <sys/types.h>
34 34 #include <sys/param.h>
35 35 #include <sys/sysmacros.h>
36 36 #include <sys/signal.h>
37 37 #include <sys/cred.h>
38 38 #include <sys/user.h>
39 39 #include <sys/errno.h>
40 40 #include <sys/vnode.h>
41 41 #include <sys/proc.h>
42 42 #include <sys/cmn_err.h>
43 43 #include <sys/debug.h>
44 44 #include <sys/pathname.h>
45 45 #include <sys/disp.h>
46 46 #include <sys/exec.h>
47 47 #include <sys/kmem.h>
48 48 #include <sys/note.h>
49 49 #include <sys/sdt.h>
50 50
51 51 /*
52 52 * This is the loadable module wrapper.
53 53 */
54 54 #include <sys/modctl.h>
55 55
56 56 extern int intpexec(struct vnode *, struct execa *, struct uarg *,
57 57 struct intpdata *, int, long *, int, caddr_t, struct cred *, int);
58 58
59 59 static struct execsw esw = {
60 60 intpmagicstr,
61 61 0,
62 62 2,
63 63 intpexec,
64 64 NULL
65 65 };
66 66
↓ open down ↓ |
66 lines elided |
↑ open up ↑ |
67 67 /*
68 68 * Module linkage information for the kernel.
69 69 */
70 70 extern struct mod_ops mod_execops;
71 71
72 72 static struct modlexec modlexec = {
73 73 &mod_execops, "exec mod for interp", &esw
74 74 };
75 75
76 76 static struct modlinkage modlinkage = {
77 - MODREV_1, (void *)&modlexec, NULL
77 + MODREV_1, { (void *)&modlexec, NULL }
78 78 };
79 79
80 80 int
81 81 _init()
82 82 {
83 83 return (mod_install(&modlinkage));
84 84 }
85 85
86 86 int
87 87 _fini()
88 88 {
89 89 return (mod_remove(&modlinkage));
90 90 }
91 91
92 92 int
93 93 _info(struct modinfo *modinfop)
94 94 {
95 95 return (mod_info(&modlinkage, modinfop));
96 96 }
97 97
98 98
99 99 /*
100 100 * Crack open a '#!' line.
101 101 */
102 102 static int
103 103 getintphead(struct vnode *vp, struct intpdata *idatap)
104 104 {
105 105 int error;
106 106 char *cp, *linep = idatap->intp;
107 107 ssize_t resid;
108 108
109 109 /*
110 110 * Read the entire line and confirm that it starts with '#!'.
111 111 */
112 112 if (error = vn_rdwr(UIO_READ, vp, linep, INTPSZ, (offset_t)0,
113 113 UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid))
114 114 return (error);
115 115 if (resid > INTPSZ-2 || linep[0] != '#' || linep[1] != '!')
116 116 return (ENOEXEC);
117 117 /*
118 118 * Blank all white space and find the newline.
119 119 */
120 120 for (cp = &linep[2]; cp < &linep[INTPSZ] && *cp != '\n'; cp++)
121 121 if (*cp == '\t')
122 122 *cp = ' ';
123 123 if (cp >= &linep[INTPSZ])
124 124 return (ENOEXEC);
125 125 ASSERT(*cp == '\n');
126 126 *cp = '\0';
127 127
128 128 /*
129 129 * Locate the beginning and end of the interpreter name.
130 130 * In addition to the name, one additional argument may
131 131 * optionally be included here, to be prepended to the
132 132 * arguments provided on the command line. Thus, for
133 133 * example, you can say
134 134 *
135 135 * #! /usr/bin/awk -f
136 136 */
137 137 for (cp = &linep[2]; *cp == ' '; cp++)
138 138 ;
139 139 if (*cp == '\0')
140 140 return (ENOEXEC);
141 141 idatap->intp_name[0] = cp;
142 142 while (*cp && *cp != ' ')
143 143 cp++;
144 144 if (*cp == '\0') {
145 145 idatap->intp_arg[0] = NULL;
146 146 } else {
147 147 *cp++ = '\0';
148 148 while (*cp == ' ')
149 149 cp++;
150 150 if (*cp == '\0')
151 151 idatap->intp_arg[0] = NULL;
152 152 else {
153 153 idatap->intp_arg[0] = cp;
154 154 while (*cp && *cp != ' ')
155 155 cp++;
156 156 *cp = '\0';
157 157 }
158 158 }
159 159 return (0);
160 160 }
161 161
162 162 /*
163 163 * We support nested interpreters up to a depth of INTP_MAXDEPTH (this value
164 164 * matches the depth on Linux). When a nested interpreter is in use, the
165 165 * previous name and argument must be passed along. We use the intpdata_t
166 166 * name and argument arrays for this. In the normal, non-nested case, only the
167 167 * first element in those arrays will be populated.
168 168 *
169 169 * For setid scripts the "script hole" is a security race condition between
170 170 * when we exec the interpreter and when the interpreter reads the script. We
171 171 * handle this below for the initial script, but we don't allow setid scripts
172 172 * when using nested interpreters. Because gexec only modifies the credentials
173 173 * for a setid script at level 0, then if we come back through for a nested
174 174 * interpreter we know that args->fname will be set (the first script is setid)
175 175 * and we can return an error. If an intermediate nested interpreter is setid
176 176 * then it will not be run with different credentials because of the gexec
177 177 * handling, so it is effectively no longer setid and we don't have to worry
178 178 * about the "script hole".
179 179 */
180 180 int
181 181 intpexec(
182 182 struct vnode *vp,
183 183 struct execa *uap,
184 184 struct uarg *args,
185 185 struct intpdata *idatap,
186 186 int level,
187 187 long *execsz,
188 188 int setid,
189 189 caddr_t exec_file,
190 190 struct cred *cred,
191 191 int brand_action)
192 192 {
193 193 _NOTE(ARGUNUSED(brand_action))
194 194 vnode_t *nvp;
195 195 int error = 0;
196 196 struct intpdata idata;
197 197 struct pathname intppn;
198 198 struct pathname resolvepn;
199 199 char *opath;
200 200 char devfd[19]; /* 32-bit int fits in 10 digits + 8 for "/dev/fd/" */
201 201 int fd = -1;
202 202
203 203 if (level >= INTP_MAXDEPTH) { /* Can't recurse past maxdepth */
204 204 error = ELOOP;
205 205 goto bad;
206 206 }
207 207
208 208 if (level == 0)
209 209 ASSERT(idatap == (struct intpdata *)NULL);
210 210
211 211 bzero(&idata, sizeof (intpdata_t));
212 212
213 213 /*
214 214 * Allocate a buffer to read in the interpreter pathname.
215 215 */
216 216 idata.intp = kmem_alloc(INTPSZ, KM_SLEEP);
217 217 if (error = getintphead(vp, &idata))
218 218 goto fail;
219 219
220 220 /*
221 221 * Look the new vnode up.
222 222 */
223 223 if (error = pn_get(idata.intp_name[0], UIO_SYSSPACE, &intppn))
224 224 goto fail;
225 225 pn_alloc(&resolvepn);
226 226 if (error = lookuppn(&intppn, &resolvepn, FOLLOW, NULLVPP, &nvp)) {
227 227 pn_free(&resolvepn);
228 228 pn_free(&intppn);
229 229 goto fail;
230 230 }
231 231
232 232 if (level > 0) {
233 233 /*
234 234 * We have a nested interpreter. The previous name(s) and
235 235 * argument(s) need to be passed along. We also keep track
236 236 * of how often this zone uses nested interpreters.
237 237 */
238 238 int i;
239 239
240 240 atomic_inc_32(&curproc->p_zone->zone_nested_intp);
241 241
242 242 ASSERT(idatap != NULL);
243 243 /* since we're shifting up, loop stops one short */
244 244 for (i = 0; i < (INTP_MAXDEPTH - 1); i++) {
245 245 idata.intp_name[i + 1] = idatap->intp_name[i];
246 246 idata.intp_arg[i + 1] = idatap->intp_arg[i];
247 247 }
248 248
249 249 DTRACE_PROBE3(nested__intp, int, level, void *, &idata,
250 250 void *, nvp);
251 251 }
252 252
253 253 opath = args->pathname;
254 254 args->pathname = resolvepn.pn_path;
255 255 /* don't free resolvepn until we are done with args */
256 256 pn_free(&intppn);
257 257
258 258 /*
259 259 * Disallow setuid or additional privilege execution for nested
260 260 * interpreters.
261 261 */
262 262 if (level > 0 && args->fname != NULL) {
263 263 error = ENOEXEC;
264 264 goto done;
265 265 }
266 266
267 267 /*
268 268 * When we're executing a set-uid script resulting in uids
269 269 * mismatching or when we execute with additional privileges,
270 270 * we close the "replace script between exec and open by shell"
271 271 * hole by passing the script as /dev/fd parameter.
272 272 */
273 273 if ((setid & EXECSETID_PRIVS) != 0 ||
274 274 (setid & (EXECSETID_UGIDS|EXECSETID_SETID)) ==
275 275 (EXECSETID_UGIDS|EXECSETID_SETID)) {
276 276 (void) strcpy(devfd, "/dev/fd/");
277 277 if (error = execopen(&vp, &fd))
278 278 goto done;
279 279 numtos(fd, &devfd[8]);
280 280 args->fname = devfd;
281 281 }
282 282
283 283 error = gexec(&nvp, uap, args, &idata, ++level, execsz, exec_file, cred,
284 284 EBA_NONE);
285 285
286 286 if (!error) {
287 287 /*
288 288 * Close this executable as the interpreter
289 289 * will open and close it later on.
290 290 */
291 291 (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, cred, NULL);
292 292 }
293 293 done:
294 294 VN_RELE(nvp);
295 295 args->pathname = opath;
296 296 pn_free(&resolvepn);
297 297 fail:
298 298 kmem_free(idata.intp, INTPSZ);
299 299 if (error && fd != -1)
300 300 (void) execclose(fd);
301 301 bad:
302 302 return (error);
303 303 }
↓ open down ↓ |
216 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX