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