1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
|
.\" $OpenBSD: script.7,v 1.6 2008/09/19 05:41:29 djm Exp $
.\"
.\" $NetBSD: script.7,v 1.1 2005/05/07 02:20:34 perry Exp $
.\"
.\" Copyright (c) 2005 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This document was originally contributed to The NetBSD Foundation
.\" by Perry E. Metzger of Metzger, Dowdeswell & Co. LLC.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd $Mdocdate: September 19 2008 $
.Dt SCRIPT 7
.Os
.Sh NAME
.Nm script
.Nd interpreter script execution
.Sh DESCRIPTION
The system is capable of treating a text file containing commands
intended for an interpreter, such as
.Xr sh 1
or
.Xr awk 1 ,
as an executable program.
.Pp
An
.Dq interpreter script
is a file which has been set executable (see
.Xr chmod 2 )
and which has a first line of the form:
.Pp
.D1 Li #! Ar pathname Op Ar argument
.Pp
The
.Sq #!
must appear as the first two characters of the file.
A space between the
.Sq #!
and
.Ar pathname
is optional.
At most one
.Ar argument
may follow
.Ar pathname ,
and the length of the entire line is limited (see below).
.Pp
If such a file is executed (such as via the
.Xr execve 2
system call), the interpreter specified by the
.Ar pathname
is executed by the system.
(The
.Ar pathname
is executed without regard to the
.Ev PATH
variable, so in general
.Ar pathname
should be an absolute path.)
.Pp
The arguments passed to the interpreter will be as follows.
.Va argv[0]
will be the path to the interpreter itself, as specified on the first
line of the script.
If there is an
.Ar argument
following
.Ar pathname
on the first line of the script, it will be passed as
.Va argv[1] .
The subsequent elements of
.Va argv
will be the path to the interpreter script file itself (i.e. the
original
.Va argv[0] )
followed by any further arguments passed when
.Xr execve 2
was invoked to execute the script file.
.Pp
By convention, it is expected that an interpreter will open the script
file passed as an argument and process the commands within it.
Typical interpreters treat
.Sq #
as a comment character, and thus will ignore the initial line of the script
because it begins
.Sq #! ,
but there is no requirement for this per se.
.Pp
On
.Ox ,
the length of the interpreter line following the
.Sq #!
is limited to
.Dv MAXINTERP ,
as defined in
.Aq Pa sys/param.h .
Other operating systems impose different limits on the length of
the
.Sq #!
line (see below).
.Pp
Note that the interpreter may not itself be an interpreter script.
If
.Ar pathname
does not point to an executable binary, execution of the interpreter
script will fail.
.Ss Trampolines and Portable Scripts
Different operating systems often have interpreters located in
different locations, and the kernel executes the passed interpreter
without regard to the setting of environment variables such as
.Ev PATH .
This makes it somewhat challenging to set the
.Sq #!
line of a script so that it will run identically on different systems.
.Pp
Since the
.Xr env 1
utility executes a command passed to it on its command line, it is
often used as a
.Dq trampoline
to render scripts portable.
If the leading line of a script reads
.Pp
.Dl #! /usr/bin/env interp
.Pp
then the
.Xr env 1
command will execute the
.Dq interp
command it finds in its
.Ev PATH ,
passing on to it all subsequent arguments with which it itself was called.
Since
.Pa /usr/bin/env
is found on almost all
.Tn POSIX
style systems, this trick is frequently exploited by authors who need
a script to execute without change on multiple systems.
.Ss Historical Note: Scripts without `#!'
Shell scripts predate the invention of the
.Sq #!
convention, which is implemented in the kernel.
In the days of
.At v7 ,
there was only one interpreter used on the system,
.Pa /bin/sh ,
and the shell treated any file that failed to execute with an
.Er ENOEXEC
error
(see
.Xr intro 2 )
as a shell script.
.Pp
Most shells (such as
.Xr sh 1 )
and certain other facilities (including
.Xr execlp 3
and
.Xr execvp 3
but not other types of
.Xr exec 3
calls) still pass
interpreter scripts that do not include the
.Sq #!
(and thus fail to execute with
.Er ENOEXEC )
to
.Pa /bin/sh .
.Pp
As this behavior is implemented outside the kernel, there is no
mechanism that forces it to be respected by all programs that execute
other programs.
It is thus not completely reliable.
It is therefore important to always include
.Pp
.Dl #!/bin/sh
.Pp
in front of Bourne shell scripts, and to treat the traditional
behavior as obsolete.
.Sh EXAMPLES
Suppose that an executable binary exists in
.Pa /bin/interp
and that the file
.Pa /tmp/script
contains:
.Bd -literal -offset indent
#!/bin/interp -arg
[...]
.Ed
.Pp
and that
.Pa /tmp/script
is set mode 755.
.Pp
Executing
.Pp
.Dl $ /tmp/script one two three
.Pp
at the shell will result in
.Pa /bin/interp
being executed, receiving the following arguments in
.Va argv
(numbered from 0):
.Bd -ragged -offset indent
.Qq /bin/interp ,
.Qq "-arg" ,
.Qq /tmp/script ,
.Qq one ,
.Qq two ,
.Qq three
.Ed
.Ss Portability Note: Multiple arguments
The behavior of multiple arguments on the
.Sq #!
line is highly non-portable between different systems.
In general, only one argument can be assumed to work consistently.
.Pp
Consider the following variation on the previous example.
Suppose that an executable binary exists in
.Pa /bin/interp
and that the file
.Pa /tmp/script
contains:
.Bd -literal -offset indent
#!/bin/interp -x -y
[...]
.Ed
.Pp
and that
.Pa /tmp/script
is set mode 755.
.Pp
Executing
.Pp
.Dl $ /tmp/script one two three
.Pp
at the shell will result in
.Pa /bin/interp
being executed, receiving the following arguments in
.Va argv
(numbered from 0):
.Bd -ragged -offset indent
.Qq /bin/interp ,
.Qq "-x -y" ,
.Qq /tmp/script ,
.Qq one ,
.Qq two ,
.Qq three
.Ed
.Pp
Note that
.Qq "-x -y"
will be passed on
.Ox
as a single argument.
.Pp
Although most
.Tn POSIX
style operating systems will pass only one
.Ar argument ,
the behavior when multiple arguments are included is not
consistent between platforms.
Some, such as
.Ox ,
will concatenate multiple arguments into a single argument (as above),
some will truncate them, and at least one will pass them as multiple
arguments.
.Pp
The
.Ox
behavior is common but not universal.
Sun's
.Tn Solaris
would present the above argument as
.Qq -x ,
dropping the
.Qq " -y"
entirely.
Perhaps uniquely, recent versions of Apple's
.Tn OS X
will actually pass multiple arguments properly, i.e.:
.Bd -ragged -offset indent
.Qq /bin/interp ,
.Qq -x ,
.Qq -y ,
.Qq /tmp/script ,
.Qq one ,
.Qq two ,
.Qq three
.Ed
.Pp
The behavior of the system in the face of multiple arguments is thus
not currently standardized, should not be relied on, and may be
changed in future releases.
In general, pass at most one argument, and do not rely on multiple
arguments being concatenated.
.Sh SEE ALSO
.Xr awk 1 ,
.Xr csh 1 ,
.Xr ksh 1 ,
.Xr sh 1 ,
.Xr chmod 2 ,
.Xr execve 2 ,
.Xr intro 2 ,
.Xr execlp 3 ,
.Xr execvp 3
.Sh STANDARDS
The behavior of interpreter scripts is obliquely referred to, but
never actually described in,
.St -p1003.1-2004 .
.Pp
The behavior is partially (but not completely) described in the
.St -svid4 .
.Pp
Although it has never been formally standardized, the behavior
described is largely portable across
.Tn POSIX
style systems, with two significant exceptions: the maximum length of the
.Sq #!
line, and the behavior if multiple arguments are passed.
Please be aware that the behavior in the
face of multiple arguments is not consistent across systems.
.Sh HISTORY
The behavior of the kernel when encountering scripts that start in
.Sq #!
was not present in
.At v7 .
A Usenet posting to net.unix by Guy Harris on October 16, 1984 claims
that the idea for the
.Sq #!
behavior was first proposed by Dennis Ritchie but that the first
implementation was on
.Bx .
.Pp
Historical manuals (specifically the exec man page) indicate that the
behavior was present in
.Bx 4
at least as early as April, 1981.
Information on precisely when it was first implemented, and in which
version of
.Ux ,
is solicited.
.Sh CAVEATS
Numerous security problems are associated with setuid interpreter
scripts.
.Pp
In addition to the fact that many interpreters (and scripts) are
simply not designed to be robust in a setuid context, a race condition
exists between the moment that the kernel examines the interpreter
script file and the moment that the newly invoked interpreter opens
the file itself.
.Pp
Subtle techniques can be used to subvert even seemingly well written scripts.
Scripts executed by Bourne type shells can be subverted in numerous
ways, such as by setting the
.Ev IFS
variable before executing the script.
Other interpreters possess their own vulnerabilities.
Setting the Set-user-ID on execution (SUID) bit
is therefore very dangerous, and should not be done lightly, if at all.
|