| .. | .. |
|---|
| 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 = { |
|---|