xref: /openbmc/linux/fs/binfmt_script.c (revision 0c7beb2d)
1 /*
2  *  linux/fs/binfmt_script.c
3  *
4  *  Copyright (C) 1996  Martin von Löwis
5  *  original #!-checking implemented by tytso.
6  */
7 
8 #include <linux/module.h>
9 #include <linux/string.h>
10 #include <linux/stat.h>
11 #include <linux/binfmts.h>
12 #include <linux/init.h>
13 #include <linux/file.h>
14 #include <linux/err.h>
15 #include <linux/fs.h>
16 
17 static inline bool spacetab(char c) { return c == ' ' || c == '\t'; }
18 static inline char *next_non_spacetab(char *first, const char *last)
19 {
20 	for (; first <= last; first++)
21 		if (!spacetab(*first))
22 			return first;
23 	return NULL;
24 }
25 static inline char *next_terminator(char *first, const char *last)
26 {
27 	for (; first <= last; first++)
28 		if (spacetab(*first) || !*first)
29 			return first;
30 	return NULL;
31 }
32 
33 static int load_script(struct linux_binprm *bprm)
34 {
35 	const char *i_arg, *i_name;
36 	char *cp, *buf_end;
37 	struct file *file;
38 	int retval;
39 
40 	/* Not ours to exec if we don't start with "#!". */
41 	if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
42 		return -ENOEXEC;
43 
44 	/*
45 	 * If the script filename will be inaccessible after exec, typically
46 	 * because it is a "/dev/fd/<fd>/.." path against an O_CLOEXEC fd, give
47 	 * up now (on the assumption that the interpreter will want to load
48 	 * this file).
49 	 */
50 	if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE)
51 		return -ENOENT;
52 
53 	/* Release since we are not mapping a binary into memory. */
54 	allow_write_access(bprm->file);
55 	fput(bprm->file);
56 	bprm->file = NULL;
57 
58 	/*
59 	 * This section handles parsing the #! line into separate
60 	 * interpreter path and argument strings. We must be careful
61 	 * because bprm->buf is not yet guaranteed to be NUL-terminated
62 	 * (though the buffer will have trailing NUL padding when the
63 	 * file size was smaller than the buffer size).
64 	 *
65 	 * We do not want to exec a truncated interpreter path, so either
66 	 * we find a newline (which indicates nothing is truncated), or
67 	 * we find a space/tab/NUL after the interpreter path (which
68 	 * itself may be preceded by spaces/tabs). Truncating the
69 	 * arguments is fine: the interpreter can re-read the script to
70 	 * parse them on its own.
71 	 */
72 	buf_end = bprm->buf + sizeof(bprm->buf) - 1;
73 	cp = strnchr(bprm->buf, sizeof(bprm->buf), '\n');
74 	if (!cp) {
75 		cp = next_non_spacetab(bprm->buf + 2, buf_end);
76 		if (!cp)
77 			return -ENOEXEC; /* Entire buf is spaces/tabs */
78 		/*
79 		 * If there is no later space/tab/NUL we must assume the
80 		 * interpreter path is truncated.
81 		 */
82 		if (!next_terminator(cp, buf_end))
83 			return -ENOEXEC;
84 		cp = buf_end;
85 	}
86 	/* NUL-terminate the buffer and any trailing spaces/tabs. */
87 	*cp = '\0';
88 	while (cp > bprm->buf) {
89 		cp--;
90 		if ((*cp == ' ') || (*cp == '\t'))
91 			*cp = '\0';
92 		else
93 			break;
94 	}
95 	for (cp = bprm->buf+2; (*cp == ' ') || (*cp == '\t'); cp++);
96 	if (*cp == '\0')
97 		return -ENOEXEC; /* No interpreter name found */
98 	i_name = cp;
99 	i_arg = NULL;
100 	for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++)
101 		/* nothing */ ;
102 	while ((*cp == ' ') || (*cp == '\t'))
103 		*cp++ = '\0';
104 	if (*cp)
105 		i_arg = cp;
106 	/*
107 	 * OK, we've parsed out the interpreter name and
108 	 * (optional) argument.
109 	 * Splice in (1) the interpreter's name for argv[0]
110 	 *           (2) (optional) argument to interpreter
111 	 *           (3) filename of shell script (replace argv[0])
112 	 *
113 	 * This is done in reverse order, because of how the
114 	 * user environment and arguments are stored.
115 	 */
116 	retval = remove_arg_zero(bprm);
117 	if (retval)
118 		return retval;
119 	retval = copy_strings_kernel(1, &bprm->interp, bprm);
120 	if (retval < 0)
121 		return retval;
122 	bprm->argc++;
123 	if (i_arg) {
124 		retval = copy_strings_kernel(1, &i_arg, bprm);
125 		if (retval < 0)
126 			return retval;
127 		bprm->argc++;
128 	}
129 	retval = copy_strings_kernel(1, &i_name, bprm);
130 	if (retval)
131 		return retval;
132 	bprm->argc++;
133 	retval = bprm_change_interp(i_name, bprm);
134 	if (retval < 0)
135 		return retval;
136 
137 	/*
138 	 * OK, now restart the process with the interpreter's dentry.
139 	 */
140 	file = open_exec(i_name);
141 	if (IS_ERR(file))
142 		return PTR_ERR(file);
143 
144 	bprm->file = file;
145 	retval = prepare_binprm(bprm);
146 	if (retval < 0)
147 		return retval;
148 	return search_binary_handler(bprm);
149 }
150 
151 static struct linux_binfmt script_format = {
152 	.module		= THIS_MODULE,
153 	.load_binary	= load_script,
154 };
155 
156 static int __init init_script_binfmt(void)
157 {
158 	register_binfmt(&script_format);
159 	return 0;
160 }
161 
162 static void __exit exit_script_binfmt(void)
163 {
164 	unregister_binfmt(&script_format);
165 }
166 
167 core_initcall(init_script_binfmt);
168 module_exit(exit_script_binfmt);
169 MODULE_LICENSE("GPL");
170