.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * linux/fs/binfmt_script.c |
---|
3 | 4 | * |
---|
.. | .. |
---|
15 | 16 | #include <linux/fs.h> |
---|
16 | 17 | |
---|
17 | 18 | static inline bool spacetab(char c) { return c == ' ' || c == '\t'; } |
---|
18 | | -static inline char *next_non_spacetab(char *first, const char *last) |
---|
| 19 | +static inline const char *next_non_spacetab(const char *first, const char *last) |
---|
19 | 20 | { |
---|
20 | 21 | for (; first <= last; first++) |
---|
21 | 22 | if (!spacetab(*first)) |
---|
22 | 23 | return first; |
---|
23 | 24 | return NULL; |
---|
24 | 25 | } |
---|
25 | | -static inline char *next_terminator(char *first, const char *last) |
---|
| 26 | +static inline const char *next_terminator(const char *first, const char *last) |
---|
26 | 27 | { |
---|
27 | 28 | for (; first <= last; first++) |
---|
28 | 29 | if (spacetab(*first) || !*first) |
---|
.. | .. |
---|
32 | 33 | |
---|
33 | 34 | static int load_script(struct linux_binprm *bprm) |
---|
34 | 35 | { |
---|
35 | | - const char *i_arg, *i_name; |
---|
36 | | - char *cp, *buf_end; |
---|
| 36 | + const char *i_name, *i_sep, *i_arg, *i_end, *buf_end; |
---|
37 | 37 | struct file *file; |
---|
38 | 38 | int retval; |
---|
39 | 39 | |
---|
40 | 40 | /* Not ours to exec if we don't start with "#!". */ |
---|
41 | 41 | if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!')) |
---|
42 | 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 | 43 | |
---|
58 | 44 | /* |
---|
59 | 45 | * This section handles parsing the #! line into separate |
---|
.. | .. |
---|
70 | 56 | * parse them on its own. |
---|
71 | 57 | */ |
---|
72 | 58 | 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) |
---|
| 59 | + i_end = strnchr(bprm->buf, sizeof(bprm->buf), '\n'); |
---|
| 60 | + if (!i_end) { |
---|
| 61 | + i_end = next_non_spacetab(bprm->buf + 2, buf_end); |
---|
| 62 | + if (!i_end) |
---|
77 | 63 | return -ENOEXEC; /* Entire buf is spaces/tabs */ |
---|
78 | 64 | /* |
---|
79 | 65 | * If there is no later space/tab/NUL we must assume the |
---|
80 | 66 | * interpreter path is truncated. |
---|
81 | 67 | */ |
---|
82 | | - if (!next_terminator(cp, buf_end)) |
---|
| 68 | + if (!next_terminator(i_end, buf_end)) |
---|
83 | 69 | return -ENOEXEC; |
---|
84 | | - cp = buf_end; |
---|
| 70 | + i_end = buf_end; |
---|
85 | 71 | } |
---|
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') |
---|
| 72 | + /* Trim any trailing spaces/tabs from i_end */ |
---|
| 73 | + while (spacetab(i_end[-1])) |
---|
| 74 | + i_end--; |
---|
| 75 | + |
---|
| 76 | + /* Skip over leading spaces/tabs */ |
---|
| 77 | + i_name = next_non_spacetab(bprm->buf+2, i_end); |
---|
| 78 | + if (!i_name || (i_name == i_end)) |
---|
97 | 79 | return -ENOEXEC; /* No interpreter name found */ |
---|
98 | | - i_name = cp; |
---|
| 80 | + |
---|
| 81 | + /* Is there an optional argument? */ |
---|
99 | 82 | 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; |
---|
| 83 | + i_sep = next_terminator(i_name, i_end); |
---|
| 84 | + if (i_sep && (*i_sep != '\0')) |
---|
| 85 | + i_arg = next_non_spacetab(i_sep, i_end); |
---|
| 86 | + |
---|
| 87 | + /* |
---|
| 88 | + * If the script filename will be inaccessible after exec, typically |
---|
| 89 | + * because it is a "/dev/fd/<fd>/.." path against an O_CLOEXEC fd, give |
---|
| 90 | + * up now (on the assumption that the interpreter will want to load |
---|
| 91 | + * this file). |
---|
| 92 | + */ |
---|
| 93 | + if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE) |
---|
| 94 | + return -ENOENT; |
---|
| 95 | + |
---|
106 | 96 | /* |
---|
107 | 97 | * OK, we've parsed out the interpreter name and |
---|
108 | 98 | * (optional) argument. |
---|
.. | .. |
---|
116 | 106 | retval = remove_arg_zero(bprm); |
---|
117 | 107 | if (retval) |
---|
118 | 108 | return retval; |
---|
119 | | - retval = copy_strings_kernel(1, &bprm->interp, bprm); |
---|
| 109 | + retval = copy_string_kernel(bprm->interp, bprm); |
---|
120 | 110 | if (retval < 0) |
---|
121 | 111 | return retval; |
---|
122 | 112 | bprm->argc++; |
---|
| 113 | + *((char *)i_end) = '\0'; |
---|
123 | 114 | if (i_arg) { |
---|
124 | | - retval = copy_strings_kernel(1, &i_arg, bprm); |
---|
| 115 | + *((char *)i_sep) = '\0'; |
---|
| 116 | + retval = copy_string_kernel(i_arg, bprm); |
---|
125 | 117 | if (retval < 0) |
---|
126 | 118 | return retval; |
---|
127 | 119 | bprm->argc++; |
---|
128 | 120 | } |
---|
129 | | - retval = copy_strings_kernel(1, &i_name, bprm); |
---|
| 121 | + retval = copy_string_kernel(i_name, bprm); |
---|
130 | 122 | if (retval) |
---|
131 | 123 | return retval; |
---|
132 | 124 | bprm->argc++; |
---|
.. | .. |
---|
141 | 133 | if (IS_ERR(file)) |
---|
142 | 134 | return PTR_ERR(file); |
---|
143 | 135 | |
---|
144 | | - bprm->file = file; |
---|
145 | | - retval = prepare_binprm(bprm); |
---|
146 | | - if (retval < 0) |
---|
147 | | - return retval; |
---|
148 | | - return search_binary_handler(bprm); |
---|
| 136 | + bprm->interpreter = file; |
---|
| 137 | + return 0; |
---|
149 | 138 | } |
---|
150 | 139 | |
---|
151 | 140 | static struct linux_binfmt script_format = { |
---|