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 815030 : static inline bool spacetab(char c) { return c == ' ' || c == '\t'; } 19 : static inline const char *next_non_spacetab(const char *first, const char *last) 20 : { 21 138260 : for (; first <= last; first++) 22 138275 : if (!spacetab(*first)) 23 : return first; 24 : return NULL; 25 : } 26 66850 : static inline const char *next_terminator(const char *first, const char *last) 27 : { 28 648820 : for (; first <= last; first++) 29 609907 : if (spacetab(*first) || !*first) 30 27937 : return first; 31 : return NULL; 32 : } 33 : 34 28574885 : static int load_script(struct linux_binprm *bprm) 35 : { 36 28574885 : const char *i_name, *i_sep, *i_arg, *i_end, *buf_end; 37 28574885 : struct file *file; 38 28574885 : int retval; 39 : 40 : /* Not ours to exec if we don't start with "#!". */ 41 28574885 : if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!')) 42 : return -ENOEXEC; 43 : 44 : /* 45 : * This section handles parsing the #! line into separate 46 : * interpreter path and argument strings. We must be careful 47 : * because bprm->buf is not yet guaranteed to be NUL-terminated 48 : * (though the buffer will have trailing NUL padding when the 49 : * file size was smaller than the buffer size). 50 : * 51 : * We do not want to exec a truncated interpreter path, so either 52 : * we find a newline (which indicates nothing is truncated), or 53 : * we find a space/tab/NUL after the interpreter path (which 54 : * itself may be preceded by spaces/tabs). Truncating the 55 : * arguments is fine: the interpreter can re-read the script to 56 : * parse them on its own. 57 : */ 58 66871 : buf_end = bprm->buf + sizeof(bprm->buf) - 1; 59 66871 : i_end = strnchr(bprm->buf, sizeof(bprm->buf), '\n'); 60 66848 : if (!i_end) { 61 0 : i_end = next_non_spacetab(bprm->buf + 2, buf_end); 62 0 : if (!i_end) 63 : return -ENOEXEC; /* Entire buf is spaces/tabs */ 64 : /* 65 : * If there is no later space/tab/NUL we must assume the 66 : * interpreter path is truncated. 67 : */ 68 0 : if (!next_terminator(i_end, buf_end)) 69 : return -ENOEXEC; 70 : i_end = buf_end; 71 : } 72 : /* Trim any trailing spaces/tabs from i_end */ 73 66848 : while (spacetab(i_end[-1])) 74 0 : i_end--; 75 : 76 : /* Skip over leading spaces/tabs */ 77 66848 : i_name = next_non_spacetab(bprm->buf+2, i_end); 78 66848 : if (!i_name || (i_name == i_end)) 79 : return -ENOEXEC; /* No interpreter name found */ 80 : 81 : /* Is there an optional argument? */ 82 66848 : i_arg = NULL; 83 66848 : i_sep = next_terminator(i_name, i_end); 84 66848 : 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 66848 : if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE) 94 : return -ENOENT; 95 : 96 : /* 97 : * OK, we've parsed out the interpreter name and 98 : * (optional) argument. 99 : * Splice in (1) the interpreter's name for argv[0] 100 : * (2) (optional) argument to interpreter 101 : * (3) filename of shell script (replace argv[0]) 102 : * 103 : * This is done in reverse order, because of how the 104 : * user environment and arguments are stored. 105 : */ 106 66848 : retval = remove_arg_zero(bprm); 107 66893 : if (retval) 108 : return retval; 109 66894 : retval = copy_string_kernel(bprm->interp, bprm); 110 66870 : if (retval < 0) 111 : return retval; 112 66870 : bprm->argc++; 113 66870 : *((char *)i_end) = '\0'; 114 66870 : if (i_arg) { 115 27957 : *((char *)i_sep) = '\0'; 116 27957 : retval = copy_string_kernel(i_arg, bprm); 117 27962 : if (retval < 0) 118 : return retval; 119 27962 : bprm->argc++; 120 : } 121 66875 : retval = copy_string_kernel(i_name, bprm); 122 66896 : if (retval) 123 : return retval; 124 66896 : bprm->argc++; 125 66896 : retval = bprm_change_interp(i_name, bprm); 126 66901 : if (retval < 0) 127 : return retval; 128 : 129 : /* 130 : * OK, now restart the process with the interpreter's dentry. 131 : */ 132 66901 : file = open_exec(i_name); 133 66891 : if (IS_ERR(file)) 134 0 : return PTR_ERR(file); 135 : 136 66891 : bprm->interpreter = file; 137 66891 : return 0; 138 : } 139 : 140 : static struct linux_binfmt script_format = { 141 : .module = THIS_MODULE, 142 : .load_binary = load_script, 143 : }; 144 : 145 0 : static int __init init_script_binfmt(void) 146 : { 147 0 : register_binfmt(&script_format); 148 0 : return 0; 149 : } 150 : 151 0 : static void __exit exit_script_binfmt(void) 152 : { 153 0 : unregister_binfmt(&script_format); 154 0 : } 155 : 156 : core_initcall(init_script_binfmt); 157 : module_exit(exit_script_binfmt); 158 : MODULE_LICENSE("GPL");