4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2012 Milan Jurik. All rights reserved.
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <sys/sysmacros.h>
36 #include <sys/signal.h>
39 #include <sys/errno.h>
40 #include <sys/vnode.h>
42 #include <sys/cmn_err.h>
43 #include <sys/debug.h>
44 #include <sys/pathname.h>
52 * This is the loadable module wrapper.
54 #include <sys/modctl.h>
56 extern int intpexec(struct vnode
*, struct execa
*, struct uarg
*,
57 struct intpdata
*, int, long *, int, caddr_t
, struct cred
*, int);
59 static struct execsw esw
= {
68 * Module linkage information for the kernel.
70 extern struct mod_ops mod_execops
;
72 static struct modlexec modlexec
= {
73 &mod_execops
, "exec mod for interp", &esw
76 static struct modlinkage modlinkage
= {
77 MODREV_1
, (void *)&modlexec
, NULL
83 return (mod_install(&modlinkage
));
89 return (mod_remove(&modlinkage
));
93 _info(struct modinfo
*modinfop
)
95 return (mod_info(&modlinkage
, modinfop
));
100 * Crack open a '#!' line.
103 getintphead(struct vnode
*vp
, struct intpdata
*idatap
)
106 char *cp
, *linep
= idatap
->intp
;
110 * Read the entire line and confirm that it starts with '#!'.
112 if (error
= vn_rdwr(UIO_READ
, vp
, linep
, INTPSZ
, (offset_t
)0,
113 UIO_SYSSPACE
, 0, (rlim64_t
)0, CRED(), &resid
))
115 if (resid
> INTPSZ
-2 || linep
[0] != '#' || linep
[1] != '!')
118 * Blank all white space and find the newline.
120 for (cp
= &linep
[2]; cp
< &linep
[INTPSZ
] && *cp
!= '\n'; cp
++)
123 if (cp
>= &linep
[INTPSZ
])
129 * Locate the beginning and end of the interpreter name.
130 * In addition to the name, one additional argument may
131 * optionally be included here, to be prepended to the
132 * arguments provided on the command line. Thus, for
133 * example, you can say
137 for (cp
= &linep
[2]; *cp
== ' '; cp
++)
141 idatap
->intp_name
[0] = cp
;
142 while (*cp
&& *cp
!= ' ')
145 idatap
->intp_arg
[0] = NULL
;
151 idatap
->intp_arg
[0] = NULL
;
153 idatap
->intp_arg
[0] = cp
;
154 while (*cp
&& *cp
!= ' ')
163 * We support nested interpreters up to a depth of INTP_MAXDEPTH (this value
164 * matches the depth on Linux). When a nested interpreter is in use, the
165 * previous name and argument must be passed along. We use the intpdata_t
166 * name and argument arrays for this. In the normal, non-nested case, only the
167 * first element in those arrays will be populated.
169 * For setid scripts the "script hole" is a security race condition between
170 * when we exec the interpreter and when the interpreter reads the script. We
171 * handle this below for the initial script, but we don't allow setid scripts
172 * when using nested interpreters. Because gexec only modifies the credentials
173 * for a setid script at level 0, then if we come back through for a nested
174 * interpreter we know that args->fname will be set (the first script is setid)
175 * and we can return an error. If an intermediate nested interpreter is setid
176 * then it will not be run with different credentials because of the gexec
177 * handling, so it is effectively no longer setid and we don't have to worry
178 * about the "script hole".
185 struct intpdata
*idatap
,
193 _NOTE(ARGUNUSED(brand_action
))
196 struct intpdata idata
;
197 struct pathname intppn
;
198 struct pathname resolvepn
;
200 char devfd
[19]; /* 32-bit int fits in 10 digits + 8 for "/dev/fd/" */
203 if (level
>= INTP_MAXDEPTH
) { /* Can't recurse past maxdepth */
209 ASSERT(idatap
== NULL
);
211 bzero(&idata
, sizeof (intpdata_t
));
214 * Allocate a buffer to read in the interpreter pathname.
216 idata
.intp
= kmem_alloc(INTPSZ
, KM_SLEEP
);
217 if (error
= getintphead(vp
, &idata
))
221 * Look the new vnode up.
223 if (error
= pn_get(idata
.intp_name
[0], UIO_SYSSPACE
, &intppn
))
225 pn_alloc(&resolvepn
);
226 if (error
= lookuppn(&intppn
, &resolvepn
, FOLLOW
, NULLVPP
, &nvp
)) {
234 * We have a nested interpreter. The previous name(s) and
235 * argument(s) need to be passed along. We also keep track
236 * of how often this zone uses nested interpreters.
240 atomic_inc_32(&curproc
->p_zone
->zone_nested_intp
);
242 ASSERT(idatap
!= NULL
);
243 /* since we're shifting up, loop stops one short */
244 for (i
= 0; i
< (INTP_MAXDEPTH
- 1); i
++) {
245 idata
.intp_name
[i
+ 1] = idatap
->intp_name
[i
];
246 idata
.intp_arg
[i
+ 1] = idatap
->intp_arg
[i
];
249 DTRACE_PROBE3(nested__intp
, int, level
, void *, &idata
,
253 opath
= args
->pathname
;
254 args
->pathname
= resolvepn
.pn_path
;
255 /* don't free resolvepn until we are done with args */
259 * Disallow setuid or additional privilege execution for nested
262 if (level
> 0 && args
->fname
!= NULL
) {
268 * When we're executing a set-uid script resulting in uids
269 * mismatching or when we execute with additional privileges,
270 * we close the "replace script between exec and open by shell"
271 * hole by passing the script as /dev/fd parameter.
273 if ((setid
& EXECSETID_PRIVS
) != 0 ||
274 (setid
& (EXECSETID_UGIDS
|EXECSETID_SETID
)) ==
275 (EXECSETID_UGIDS
|EXECSETID_SETID
)) {
276 (void) strcpy(devfd
, "/dev/fd/");
277 if (error
= execopen(&vp
, &fd
))
279 numtos(fd
, &devfd
[8]);
283 error
= gexec(&nvp
, uap
, args
, &idata
, ++level
, execsz
, exec_file
, cred
,
288 * Close this executable as the interpreter
289 * will open and close it later on.
291 (void) fop_close(vp
, FREAD
, 1, (offset_t
)0, cred
, NULL
);
295 args
->pathname
= opath
;
298 kmem_free(idata
.intp
, INTPSZ
);
299 if (error
&& fd
!= -1)
300 (void) execclose(fd
);