| @@ -1,373 +1,366 @@ | | | @@ -1,373 +1,366 @@ |
1 | /* $NetBSD: exec_script.c,v 1.68 2014/02/17 19:29:46 maxv Exp $ */ | | 1 | /* $NetBSD: exec_script.c,v 1.69 2014/02/21 08:11:59 maxv Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1993, 1994, 1996 Christopher G. Demetriou | | 4 | * Copyright (c) 1993, 1994, 1996 Christopher G. Demetriou |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
15 | * 3. All advertising materials mentioning features or use of this software | | 15 | * 3. All advertising materials mentioning features or use of this software |
16 | * must display the following acknowledgement: | | 16 | * must display the following acknowledgement: |
17 | * This product includes software developed by Christopher G. Demetriou. | | 17 | * This product includes software developed by Christopher G. Demetriou. |
18 | * 4. The name of the author may not be used to endorse or promote products | | 18 | * 4. The name of the author may not be used to endorse or promote products |
19 | * derived from this software without specific prior written permission | | 19 | * derived from this software without specific prior written permission |
20 | * | | 20 | * |
21 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 21 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
22 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 22 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
23 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 23 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
24 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | 24 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | | 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
26 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | | 26 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | | 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | | 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
30 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 30 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 | */ | | 31 | */ |
32 | | | 32 | |
33 | #include <sys/cdefs.h> | | 33 | #include <sys/cdefs.h> |
34 | __KERNEL_RCSID(0, "$NetBSD: exec_script.c,v 1.68 2014/02/17 19:29:46 maxv Exp $"); | | 34 | __KERNEL_RCSID(0, "$NetBSD: exec_script.c,v 1.69 2014/02/21 08:11:59 maxv Exp $"); |
35 | | | 35 | |
36 | #if defined(SETUIDSCRIPTS) && !defined(FDSCRIPTS) | | 36 | #if defined(SETUIDSCRIPTS) && !defined(FDSCRIPTS) |
37 | #define FDSCRIPTS /* Need this for safe set-id scripts. */ | | 37 | #define FDSCRIPTS /* Need this for safe set-id scripts. */ |
38 | #endif | | 38 | #endif |
39 | | | 39 | |
40 | #include <sys/param.h> | | 40 | #include <sys/param.h> |
41 | #include <sys/systm.h> | | 41 | #include <sys/systm.h> |
42 | #include <sys/proc.h> | | 42 | #include <sys/proc.h> |
43 | #include <sys/kmem.h> | | 43 | #include <sys/kmem.h> |
44 | #include <sys/vnode.h> | | 44 | #include <sys/vnode.h> |
45 | #include <sys/namei.h> | | 45 | #include <sys/namei.h> |
46 | #include <sys/file.h> | | 46 | #include <sys/file.h> |
47 | #ifdef SETUIDSCRIPTS | | 47 | #ifdef SETUIDSCRIPTS |
48 | #include <sys/stat.h> | | 48 | #include <sys/stat.h> |
49 | #endif | | 49 | #endif |
50 | #include <sys/filedesc.h> | | 50 | #include <sys/filedesc.h> |
51 | #include <sys/exec.h> | | 51 | #include <sys/exec.h> |
52 | #include <sys/resourcevar.h> | | 52 | #include <sys/resourcevar.h> |
53 | #include <sys/module.h> | | 53 | #include <sys/module.h> |
54 | #include <sys/exec_script.h> | | 54 | #include <sys/exec_script.h> |
55 | #include <sys/exec_elf.h> | | 55 | #include <sys/exec_elf.h> |
56 | | | 56 | |
57 | MODULE(MODULE_CLASS_EXEC, exec_script, NULL); | | 57 | MODULE(MODULE_CLASS_EXEC, exec_script, NULL); |
58 | | | 58 | |
59 | static struct execsw exec_script_execsw[] = { | | 59 | static struct execsw exec_script_execsw[] = { |
60 | { SCRIPT_HDR_SIZE, | | 60 | { SCRIPT_HDR_SIZE, |
61 | exec_script_makecmds, | | 61 | exec_script_makecmds, |
62 | { NULL }, | | 62 | { NULL }, |
63 | NULL, | | 63 | NULL, |
64 | EXECSW_PRIO_ANY, | | 64 | EXECSW_PRIO_ANY, |
65 | 0, | | 65 | 0, |
66 | NULL, | | 66 | NULL, |
67 | NULL, | | 67 | NULL, |
68 | NULL, | | 68 | NULL, |
69 | exec_setup_stack }, | | 69 | exec_setup_stack }, |
70 | }; | | 70 | }; |
71 | | | 71 | |
72 | static int | | 72 | static int |
73 | exec_script_modcmd(modcmd_t cmd, void *arg) | | 73 | exec_script_modcmd(modcmd_t cmd, void *arg) |
74 | { | | 74 | { |
75 | | | 75 | |
76 | switch (cmd) { | | 76 | switch (cmd) { |
77 | case MODULE_CMD_INIT: | | 77 | case MODULE_CMD_INIT: |
78 | return exec_add(exec_script_execsw, | | 78 | return exec_add(exec_script_execsw, |
79 | __arraycount(exec_script_execsw)); | | 79 | __arraycount(exec_script_execsw)); |
80 | | | 80 | |
81 | case MODULE_CMD_FINI: | | 81 | case MODULE_CMD_FINI: |
82 | return exec_remove(exec_script_execsw, | | 82 | return exec_remove(exec_script_execsw, |
83 | __arraycount(exec_script_execsw)); | | 83 | __arraycount(exec_script_execsw)); |
84 | | | 84 | |
85 | case MODULE_CMD_AUTOUNLOAD: | | 85 | case MODULE_CMD_AUTOUNLOAD: |
86 | /* | | 86 | /* |
87 | * We don't want to be autounloaded because our use is | | 87 | * We don't want to be autounloaded because our use is |
88 | * transient: no executables with p_execsw equal to | | 88 | * transient: no executables with p_execsw equal to |
89 | * exec_script_execsw will exist, so FINI will never | | 89 | * exec_script_execsw will exist, so FINI will never |
90 | * return EBUSY. However, the system will run scripts | | 90 | * return EBUSY. However, the system will run scripts |
91 | * often. Return EBUSY here to prevent this module from | | 91 | * often. Return EBUSY here to prevent this module from |
92 | * ping-ponging in and out of the kernel. | | 92 | * ping-ponging in and out of the kernel. |
93 | */ | | 93 | */ |
94 | return EBUSY; | | 94 | return EBUSY; |
95 | | | 95 | |
96 | default: | | 96 | default: |
97 | return ENOTTY; | | 97 | return ENOTTY; |
98 | } | | 98 | } |
99 | } | | 99 | } |
100 | | | 100 | |
101 | /* | | 101 | /* |
102 | * exec_script_makecmds(): Check if it's an executable shell script. | | 102 | * exec_script_makecmds(): Check if it's an executable shell script. |
103 | * | | 103 | * |
104 | * Given a proc pointer and an exec package pointer, see if the referent | | 104 | * Given a proc pointer and an exec package pointer, see if the referent |
105 | * of the epp is in shell script. If it is, then set thing up so that | | 105 | * of the epp is in shell script. If it is, then set thing up so that |
106 | * the script can be run. This involves preparing the address space | | 106 | * the script can be run. This involves preparing the address space |
107 | * and arguments for the shell which will run the script. | | 107 | * and arguments for the shell which will run the script. |
108 | * | | 108 | * |
109 | * This function is ultimately responsible for creating a set of vmcmds | | 109 | * This function is ultimately responsible for creating a set of vmcmds |
110 | * which can be used to build the process's vm space and inserting them | | 110 | * which can be used to build the process's vm space and inserting them |
111 | * into the exec package. | | 111 | * into the exec package. |
112 | */ | | 112 | */ |
113 | int | | 113 | int |
114 | exec_script_makecmds(struct lwp *l, struct exec_package *epp) | | 114 | exec_script_makecmds(struct lwp *l, struct exec_package *epp) |
115 | { | | 115 | { |
116 | int error, hdrlinelen, shellnamelen, shellarglen; | | 116 | int error, hdrlinelen, shellnamelen, shellarglen; |
117 | char *hdrstr = epp->ep_hdr; | | 117 | char *hdrstr = epp->ep_hdr; |
118 | char *cp, *shellname, *shellarg; | | 118 | char *cp, *shellname, *shellarg; |
119 | size_t shellargp_len; | | 119 | size_t shellargp_len; |
120 | struct exec_fakearg *shellargp; | | 120 | struct exec_fakearg *shellargp; |
121 | struct exec_fakearg *tmpsap; | | 121 | struct exec_fakearg *tmpsap; |
122 | struct pathbuf *shell_pathbuf; | | 122 | struct pathbuf *shell_pathbuf; |
123 | struct vnode *scriptvp; | | 123 | struct vnode *scriptvp; |
124 | #ifdef SETUIDSCRIPTS | | 124 | #ifdef SETUIDSCRIPTS |
125 | /* Gcc needs those initialized for spurious uninitialized warning */ | | 125 | /* Gcc needs those initialized for spurious uninitialized warning */ |
126 | uid_t script_uid = (uid_t) -1; | | 126 | uid_t script_uid = (uid_t) -1; |
127 | gid_t script_gid = NOGROUP; | | 127 | gid_t script_gid = NOGROUP; |
128 | u_short script_sbits; | | 128 | u_short script_sbits; |
129 | #endif | | 129 | #endif |
130 | | | 130 | |
131 | /* | | 131 | /* |
132 | * if the magic isn't that of a shell script, or we've already | | 132 | * if the magic isn't that of a shell script, or we've already |
133 | * done shell script processing for this exec, punt on it. | | 133 | * done shell script processing for this exec, punt on it. |
134 | */ | | 134 | */ |
135 | if ((epp->ep_flags & EXEC_INDIR) != 0 || | | 135 | if ((epp->ep_flags & EXEC_INDIR) != 0 || |
136 | epp->ep_hdrvalid < EXEC_SCRIPT_MAGICLEN || | | 136 | epp->ep_hdrvalid < EXEC_SCRIPT_MAGICLEN || |
137 | strncmp(hdrstr, EXEC_SCRIPT_MAGIC, EXEC_SCRIPT_MAGICLEN)) | | 137 | strncmp(hdrstr, EXEC_SCRIPT_MAGIC, EXEC_SCRIPT_MAGICLEN)) |
138 | return ENOEXEC; | | 138 | return ENOEXEC; |
139 | | | 139 | |
140 | /* | | 140 | /* |
141 | * check that the shell spec is terminated by a newline, | | 141 | * check that the shell spec is terminated by a newline, |
142 | * and that it isn't too large. Don't modify the | | 142 | * and that it isn't too large. Don't modify the |
143 | * buffer unless we're ready to commit to handling it. | | 143 | * buffer unless we're ready to commit to handling it. |
144 | * (The latter requirement means that we have to check | | 144 | * (The latter requirement means that we have to check |
145 | * for both spaces and tabs later on.) | | 145 | * for both spaces and tabs later on.) |
146 | */ | | 146 | */ |
147 | hdrlinelen = min(epp->ep_hdrvalid, SCRIPT_HDR_SIZE); | | 147 | hdrlinelen = min(epp->ep_hdrvalid, SCRIPT_HDR_SIZE); |
148 | for (cp = hdrstr + EXEC_SCRIPT_MAGICLEN; cp < hdrstr + hdrlinelen; | | 148 | for (cp = hdrstr + EXEC_SCRIPT_MAGICLEN; cp < hdrstr + hdrlinelen; |
149 | cp++) { | | 149 | cp++) { |
150 | if (*cp == '\n') { | | 150 | if (*cp == '\n') { |
151 | *cp = '\0'; | | 151 | *cp = '\0'; |
152 | break; | | 152 | break; |
153 | } | | 153 | } |
154 | } | | 154 | } |
155 | if (cp >= hdrstr + hdrlinelen) | | 155 | if (cp >= hdrstr + hdrlinelen) |
156 | return ENOEXEC; | | 156 | return ENOEXEC; |
157 | | | 157 | |
158 | /* | | | |
159 | * If the script has an ELF header, don't exec it. | | | |
160 | */ | | | |
161 | if (epp->ep_hdrvalid >= sizeof(ELFMAG)-1 && | | | |
162 | memcmp(hdrstr, ELFMAG, sizeof(ELFMAG)-1) == 0) | | | |
163 | return ENOEXEC; | | | |
164 | | | | |
165 | shellname = NULL; | | 158 | shellname = NULL; |
166 | shellarg = NULL; | | 159 | shellarg = NULL; |
167 | shellarglen = 0; | | 160 | shellarglen = 0; |
168 | | | 161 | |
169 | /* strip spaces before the shell name */ | | 162 | /* strip spaces before the shell name */ |
170 | for (cp = hdrstr + EXEC_SCRIPT_MAGICLEN; *cp == ' ' || *cp == '\t'; | | 163 | for (cp = hdrstr + EXEC_SCRIPT_MAGICLEN; *cp == ' ' || *cp == '\t'; |
171 | cp++) | | 164 | cp++) |
172 | ; | | 165 | ; |
173 | | | 166 | |
174 | /* collect the shell name; remember it's length for later */ | | 167 | /* collect the shell name; remember it's length for later */ |
175 | shellname = cp; | | 168 | shellname = cp; |
176 | shellnamelen = 0; | | 169 | shellnamelen = 0; |
177 | if (*cp == '\0') | | 170 | if (*cp == '\0') |
178 | goto check_shell; | | 171 | goto check_shell; |
179 | for ( /* cp = cp */ ; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++) | | 172 | for ( /* cp = cp */ ; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++) |
180 | shellnamelen++; | | 173 | shellnamelen++; |
181 | if (*cp == '\0') | | 174 | if (*cp == '\0') |
182 | goto check_shell; | | 175 | goto check_shell; |
183 | *cp++ = '\0'; | | 176 | *cp++ = '\0'; |
184 | | | 177 | |
185 | /* skip spaces before any argument */ | | 178 | /* skip spaces before any argument */ |
186 | for ( /* cp = cp */ ; *cp == ' ' || *cp == '\t'; cp++) | | 179 | for ( /* cp = cp */ ; *cp == ' ' || *cp == '\t'; cp++) |
187 | ; | | 180 | ; |
188 | if (*cp == '\0') | | 181 | if (*cp == '\0') |
189 | goto check_shell; | | 182 | goto check_shell; |
190 | | | 183 | |
191 | /* | | 184 | /* |
192 | * collect the shell argument. everything after the shell name | | 185 | * collect the shell argument. everything after the shell name |
193 | * is passed as ONE argument; that's the correct (historical) | | 186 | * is passed as ONE argument; that's the correct (historical) |
194 | * behaviour. | | 187 | * behaviour. |
195 | */ | | 188 | */ |
196 | shellarg = cp; | | 189 | shellarg = cp; |
197 | for ( /* cp = cp */ ; *cp != '\0'; cp++) | | 190 | for ( /* cp = cp */ ; *cp != '\0'; cp++) |
198 | shellarglen++; | | 191 | shellarglen++; |
199 | *cp++ = '\0'; | | 192 | *cp++ = '\0'; |
200 | | | 193 | |
201 | check_shell: | | 194 | check_shell: |
202 | #ifdef SETUIDSCRIPTS | | 195 | #ifdef SETUIDSCRIPTS |
203 | /* | | 196 | /* |
204 | * MNT_NOSUID has already taken care of by check_exec, | | 197 | * MNT_NOSUID has already taken care of by check_exec, |
205 | * so we don't need to worry about it now or later. We | | 198 | * so we don't need to worry about it now or later. We |
206 | * will need to check PSL_TRACED later, however. | | 199 | * will need to check PSL_TRACED later, however. |
207 | */ | | 200 | */ |
208 | script_sbits = epp->ep_vap->va_mode & (S_ISUID | S_ISGID); | | 201 | script_sbits = epp->ep_vap->va_mode & (S_ISUID | S_ISGID); |
209 | if (script_sbits != 0) { | | 202 | if (script_sbits != 0) { |
210 | script_uid = epp->ep_vap->va_uid; | | 203 | script_uid = epp->ep_vap->va_uid; |
211 | script_gid = epp->ep_vap->va_gid; | | 204 | script_gid = epp->ep_vap->va_gid; |
212 | } | | 205 | } |
213 | #endif | | 206 | #endif |
214 | #ifdef FDSCRIPTS | | 207 | #ifdef FDSCRIPTS |
215 | /* | | 208 | /* |
216 | * if the script isn't readable, or it's set-id, then we've | | 209 | * if the script isn't readable, or it's set-id, then we've |
217 | * gotta supply a "/dev/fd/..." for the shell to read. | | 210 | * gotta supply a "/dev/fd/..." for the shell to read. |
218 | * Note that stupid shells (csh) do the wrong thing, and | | 211 | * Note that stupid shells (csh) do the wrong thing, and |
219 | * close all open fd's when the start. That kills this | | 212 | * close all open fd's when the start. That kills this |
220 | * method of implementing "safe" set-id and x-only scripts. | | 213 | * method of implementing "safe" set-id and x-only scripts. |
221 | */ | | 214 | */ |
222 | vn_lock(epp->ep_vp, LK_EXCLUSIVE | LK_RETRY); | | 215 | vn_lock(epp->ep_vp, LK_EXCLUSIVE | LK_RETRY); |
223 | error = VOP_ACCESS(epp->ep_vp, VREAD, l->l_cred); | | 216 | error = VOP_ACCESS(epp->ep_vp, VREAD, l->l_cred); |
224 | VOP_UNLOCK(epp->ep_vp); | | 217 | VOP_UNLOCK(epp->ep_vp); |
225 | if (error == EACCES | | 218 | if (error == EACCES |
226 | #ifdef SETUIDSCRIPTS | | 219 | #ifdef SETUIDSCRIPTS |
227 | || script_sbits | | 220 | || script_sbits |
228 | #endif | | 221 | #endif |
229 | ) { | | 222 | ) { |
230 | struct file *fp; | | 223 | struct file *fp; |
231 | | | 224 | |
232 | #if defined(DIAGNOSTIC) && defined(FDSCRIPTS) | | 225 | #if defined(DIAGNOSTIC) && defined(FDSCRIPTS) |
233 | if (epp->ep_flags & EXEC_HASFD) | | 226 | if (epp->ep_flags & EXEC_HASFD) |
234 | panic("exec_script_makecmds: epp already has a fd"); | | 227 | panic("exec_script_makecmds: epp already has a fd"); |
235 | #endif | | 228 | #endif |
236 | | | 229 | |
237 | if ((error = fd_allocfile(&fp, &epp->ep_fd)) != 0) { | | 230 | if ((error = fd_allocfile(&fp, &epp->ep_fd)) != 0) { |
238 | scriptvp = NULL; | | 231 | scriptvp = NULL; |
239 | shellargp = NULL; | | 232 | shellargp = NULL; |
240 | goto fail; | | 233 | goto fail; |
241 | } | | 234 | } |
242 | epp->ep_flags |= EXEC_HASFD; | | 235 | epp->ep_flags |= EXEC_HASFD; |
243 | fp->f_type = DTYPE_VNODE; | | 236 | fp->f_type = DTYPE_VNODE; |
244 | fp->f_ops = &vnops; | | 237 | fp->f_ops = &vnops; |
245 | fp->f_data = (void *) epp->ep_vp; | | 238 | fp->f_data = (void *) epp->ep_vp; |
246 | fp->f_flag = FREAD; | | 239 | fp->f_flag = FREAD; |
247 | fd_affix(curproc, fp, epp->ep_fd); | | 240 | fd_affix(curproc, fp, epp->ep_fd); |
248 | } | | 241 | } |
249 | #endif | | 242 | #endif |
250 | | | 243 | |
251 | /* set up the fake args list */ | | 244 | /* set up the fake args list */ |
252 | shellargp_len = 4 * sizeof(*shellargp); | | 245 | shellargp_len = 4 * sizeof(*shellargp); |
253 | shellargp = kmem_alloc(shellargp_len, KM_SLEEP); | | 246 | shellargp = kmem_alloc(shellargp_len, KM_SLEEP); |
254 | tmpsap = shellargp; | | 247 | tmpsap = shellargp; |
255 | tmpsap->fa_len = shellnamelen + 1; | | 248 | tmpsap->fa_len = shellnamelen + 1; |
256 | tmpsap->fa_arg = kmem_alloc(tmpsap->fa_len, KM_SLEEP); | | 249 | tmpsap->fa_arg = kmem_alloc(tmpsap->fa_len, KM_SLEEP); |
257 | strlcpy(tmpsap->fa_arg, shellname, tmpsap->fa_len); | | 250 | strlcpy(tmpsap->fa_arg, shellname, tmpsap->fa_len); |
258 | tmpsap++; | | 251 | tmpsap++; |
259 | if (shellarg != NULL) { | | 252 | if (shellarg != NULL) { |
260 | tmpsap->fa_len = shellarglen + 1; | | 253 | tmpsap->fa_len = shellarglen + 1; |
261 | tmpsap->fa_arg = kmem_alloc(tmpsap->fa_len, KM_SLEEP); | | 254 | tmpsap->fa_arg = kmem_alloc(tmpsap->fa_len, KM_SLEEP); |
262 | strlcpy(tmpsap->fa_arg, shellarg, tmpsap->fa_len); | | 255 | strlcpy(tmpsap->fa_arg, shellarg, tmpsap->fa_len); |
263 | tmpsap++; | | 256 | tmpsap++; |
264 | } | | 257 | } |
265 | tmpsap->fa_len = MAXPATHLEN; | | 258 | tmpsap->fa_len = MAXPATHLEN; |
266 | tmpsap->fa_arg = kmem_alloc(tmpsap->fa_len, KM_SLEEP); | | 259 | tmpsap->fa_arg = kmem_alloc(tmpsap->fa_len, KM_SLEEP); |
267 | #ifdef FDSCRIPTS | | 260 | #ifdef FDSCRIPTS |
268 | if ((epp->ep_flags & EXEC_HASFD) == 0) { | | 261 | if ((epp->ep_flags & EXEC_HASFD) == 0) { |
269 | #endif | | 262 | #endif |
270 | /* normally can't fail, but check for it if diagnostic */ | | 263 | /* normally can't fail, but check for it if diagnostic */ |
271 | error = copystr(epp->ep_kname, tmpsap->fa_arg, MAXPATHLEN, | | 264 | error = copystr(epp->ep_kname, tmpsap->fa_arg, MAXPATHLEN, |
272 | (size_t *)0); | | 265 | (size_t *)0); |
273 | tmpsap++; | | 266 | tmpsap++; |
274 | #ifdef DIAGNOSTIC | | 267 | #ifdef DIAGNOSTIC |
275 | if (error != 0) | | 268 | if (error != 0) |
276 | panic("exec_script: copystr couldn't fail"); | | 269 | panic("exec_script: copystr couldn't fail"); |
277 | #endif | | 270 | #endif |
278 | #ifdef FDSCRIPTS | | 271 | #ifdef FDSCRIPTS |
279 | } else { | | 272 | } else { |
280 | snprintf(tmpsap->fa_arg, MAXPATHLEN, "/dev/fd/%d", epp->ep_fd); | | 273 | snprintf(tmpsap->fa_arg, MAXPATHLEN, "/dev/fd/%d", epp->ep_fd); |
281 | tmpsap++; | | 274 | tmpsap++; |
282 | } | | 275 | } |
283 | #endif | | 276 | #endif |
284 | tmpsap->fa_arg = NULL; | | 277 | tmpsap->fa_arg = NULL; |
285 | | | 278 | |
286 | /* Save the old vnode so we can clean it up later. */ | | 279 | /* Save the old vnode so we can clean it up later. */ |
287 | scriptvp = epp->ep_vp; | | 280 | scriptvp = epp->ep_vp; |
288 | epp->ep_vp = NULL; | | 281 | epp->ep_vp = NULL; |
289 | | | 282 | |
290 | /* Note that we're trying recursively. */ | | 283 | /* Note that we're trying recursively. */ |
291 | epp->ep_flags |= EXEC_INDIR; | | 284 | epp->ep_flags |= EXEC_INDIR; |
292 | | | 285 | |
293 | /* | | 286 | /* |
294 | * mark the header we have as invalid; check_exec will read | | 287 | * mark the header we have as invalid; check_exec will read |
295 | * the header from the new executable | | 288 | * the header from the new executable |
296 | */ | | 289 | */ |
297 | epp->ep_hdrvalid = 0; | | 290 | epp->ep_hdrvalid = 0; |
298 | | | 291 | |
299 | /* try loading the interpreter */ | | 292 | /* try loading the interpreter */ |
300 | shell_pathbuf = pathbuf_create(shellname); | | 293 | shell_pathbuf = pathbuf_create(shellname); |
301 | if (shell_pathbuf == NULL) { | | 294 | if (shell_pathbuf == NULL) { |
302 | error = ENOMEM; | | 295 | error = ENOMEM; |
303 | } else { | | 296 | } else { |
304 | error = check_exec(l, epp, shell_pathbuf); | | 297 | error = check_exec(l, epp, shell_pathbuf); |
305 | pathbuf_destroy(shell_pathbuf); | | 298 | pathbuf_destroy(shell_pathbuf); |
306 | } | | 299 | } |
307 | | | 300 | |
308 | /* note that we've clobbered the header */ | | 301 | /* note that we've clobbered the header */ |
309 | epp->ep_flags |= EXEC_DESTR; | | 302 | epp->ep_flags |= EXEC_DESTR; |
310 | | | 303 | |
311 | if (error == 0) { | | 304 | if (error == 0) { |
312 | /* | | 305 | /* |
313 | * It succeeded. Unlock the script and | | 306 | * It succeeded. Unlock the script and |
314 | * close it if we aren't using it any more. | | 307 | * close it if we aren't using it any more. |
315 | * Also, set things up so that the fake args | | 308 | * Also, set things up so that the fake args |
316 | * list will be used. | | 309 | * list will be used. |
317 | */ | | 310 | */ |
318 | if ((epp->ep_flags & EXEC_HASFD) == 0) { | | 311 | if ((epp->ep_flags & EXEC_HASFD) == 0) { |
319 | vn_lock(scriptvp, LK_EXCLUSIVE | LK_RETRY); | | 312 | vn_lock(scriptvp, LK_EXCLUSIVE | LK_RETRY); |
320 | VOP_CLOSE(scriptvp, FREAD, l->l_cred); | | 313 | VOP_CLOSE(scriptvp, FREAD, l->l_cred); |
321 | vput(scriptvp); | | 314 | vput(scriptvp); |
322 | } | | 315 | } |
323 | | | 316 | |
324 | epp->ep_flags |= (EXEC_HASARGL | EXEC_SKIPARG); | | 317 | epp->ep_flags |= (EXEC_HASARGL | EXEC_SKIPARG); |
325 | epp->ep_fa = shellargp; | | 318 | epp->ep_fa = shellargp; |
326 | epp->ep_fa_len = shellargp_len; | | 319 | epp->ep_fa_len = shellargp_len; |
327 | #ifdef SETUIDSCRIPTS | | 320 | #ifdef SETUIDSCRIPTS |
328 | /* | | 321 | /* |
329 | * set thing up so that set-id scripts will be | | 322 | * set thing up so that set-id scripts will be |
330 | * handled appropriately. PSL_TRACED will be | | 323 | * handled appropriately. PSL_TRACED will be |
331 | * checked later when the shell is actually | | 324 | * checked later when the shell is actually |
332 | * exec'd. | | 325 | * exec'd. |
333 | */ | | 326 | */ |
334 | epp->ep_vap->va_mode |= script_sbits; | | 327 | epp->ep_vap->va_mode |= script_sbits; |
335 | if (script_sbits & S_ISUID) | | 328 | if (script_sbits & S_ISUID) |
336 | epp->ep_vap->va_uid = script_uid; | | 329 | epp->ep_vap->va_uid = script_uid; |
337 | if (script_sbits & S_ISGID) | | 330 | if (script_sbits & S_ISGID) |
338 | epp->ep_vap->va_gid = script_gid; | | 331 | epp->ep_vap->va_gid = script_gid; |
339 | #endif | | 332 | #endif |
340 | return (0); | | 333 | return (0); |
341 | } | | 334 | } |
342 | | | 335 | |
343 | #ifdef FDSCRIPTS | | 336 | #ifdef FDSCRIPTS |
344 | fail: | | 337 | fail: |
345 | #endif | | 338 | #endif |
346 | | | 339 | |
347 | /* kill the opened file descriptor, else close the file */ | | 340 | /* kill the opened file descriptor, else close the file */ |
348 | if (epp->ep_flags & EXEC_HASFD) { | | 341 | if (epp->ep_flags & EXEC_HASFD) { |
349 | epp->ep_flags &= ~EXEC_HASFD; | | 342 | epp->ep_flags &= ~EXEC_HASFD; |
350 | fd_close(epp->ep_fd); | | 343 | fd_close(epp->ep_fd); |
351 | } else if (scriptvp) { | | 344 | } else if (scriptvp) { |
352 | vn_lock(scriptvp, LK_EXCLUSIVE | LK_RETRY); | | 345 | vn_lock(scriptvp, LK_EXCLUSIVE | LK_RETRY); |
353 | VOP_CLOSE(scriptvp, FREAD, l->l_cred); | | 346 | VOP_CLOSE(scriptvp, FREAD, l->l_cred); |
354 | vput(scriptvp); | | 347 | vput(scriptvp); |
355 | } | | 348 | } |
356 | | | 349 | |
357 | /* free the fake arg list, because we're not returning it */ | | 350 | /* free the fake arg list, because we're not returning it */ |
358 | if ((tmpsap = shellargp) != NULL) { | | 351 | if ((tmpsap = shellargp) != NULL) { |
359 | while (tmpsap->fa_arg != NULL) { | | 352 | while (tmpsap->fa_arg != NULL) { |
360 | kmem_free(tmpsap->fa_arg, tmpsap->fa_len); | | 353 | kmem_free(tmpsap->fa_arg, tmpsap->fa_len); |
361 | tmpsap++; | | 354 | tmpsap++; |
362 | } | | 355 | } |
363 | kmem_free(shellargp, shellargp_len); | | 356 | kmem_free(shellargp, shellargp_len); |
364 | } | | 357 | } |
365 | | | 358 | |
366 | /* | | 359 | /* |
367 | * free any vmspace-creation commands, | | 360 | * free any vmspace-creation commands, |
368 | * and release their references | | 361 | * and release their references |
369 | */ | | 362 | */ |
370 | kill_vmcmds(&epp->ep_vmcmds); | | 363 | kill_vmcmds(&epp->ep_vmcmds); |
371 | | | 364 | |
372 | return error; | | 365 | return error; |
373 | } | | 366 | } |