11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  linux/fs/binfmt_script.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
496de0e252cedffad61b3cb5e05662c591898e69aJan Engelhardt *  Copyright (C) 1996  Martin von Löwis
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  original #!-checking implemented by tytso.
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/stat.h>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/binfmts.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/file.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/err.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int load_script(struct linux_binprm *bprm,struct pt_regs *regs)
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19d7627467b7a8dd6944885290a03a07ceb28c10ebDavid Howells	const char *i_arg, *i_name;
20d7627467b7a8dd6944885290a03a07ceb28c10ebDavid Howells	char *cp;
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct file *file;
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char interp[BINPRM_BUF_SIZE];
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25bf2a9a39639b8b51377905397a5005f444e9a892Kirill A. Shutemov	if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') ||
26bf2a9a39639b8b51377905397a5005f444e9a892Kirill A. Shutemov	    (bprm->recursion_depth > BINPRM_MAX_RECURSION))
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOEXEC;
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * This section does the #! interpretation.
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Sorta complicated, but hopefully it will work.  -TYT
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33bf2a9a39639b8b51377905397a5005f444e9a892Kirill A. Shutemov	bprm->recursion_depth++;
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	allow_write_access(bprm->file);
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fput(bprm->file);
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bprm->file = NULL;
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bprm->buf[BINPRM_BUF_SIZE - 1] = '\0';
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((cp = strchr(bprm->buf, '\n')) == NULL)
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cp = bprm->buf+BINPRM_BUF_SIZE-1;
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*cp = '\0';
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (cp > bprm->buf) {
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cp--;
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((*cp == ' ') || (*cp == '\t'))
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*cp = '\0';
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (cp = bprm->buf+2; (*cp == ' ') || (*cp == '\t'); cp++);
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (*cp == '\0')
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOEXEC; /* No interpreter name found */
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i_name = cp;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i_arg = NULL;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++)
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* nothing */ ;
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((*cp == ' ') || (*cp == '\t'))
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*cp++ = '\0';
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (*cp)
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i_arg = cp;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy (interp, i_name);
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * OK, we've parsed out the interpreter name and
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * (optional) argument.
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Splice in (1) the interpreter's name for argv[0]
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *           (2) (optional) argument to interpreter
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *           (3) filename of shell script (replace argv[0])
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * This is done in reverse order, because of how the
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * user environment and arguments are stored.
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
71b6a2fea39318e43fee84fa7b0b90d68bed92d2baOllie Wild	retval = remove_arg_zero(bprm);
72b6a2fea39318e43fee84fa7b0b90d68bed92d2baOllie Wild	if (retval)
73b6a2fea39318e43fee84fa7b0b90d68bed92d2baOllie Wild		return retval;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = copy_strings_kernel(1, &bprm->interp, bprm);
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) return retval;
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bprm->argc++;
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i_arg) {
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = copy_strings_kernel(1, &i_arg, bprm);
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (retval < 0) return retval;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bprm->argc++;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = copy_strings_kernel(1, &i_name, bprm);
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval) return retval;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bprm->argc++;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bprm->interp = interp;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * OK, now restart the process with the interpreter's dentry.
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	file = open_exec(interp);
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (IS_ERR(file))
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return PTR_ERR(file);
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bprm->file = file;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = prepare_binprm(bprm);
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0)
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return search_binary_handler(bprm,regs);
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct linux_binfmt script_format = {
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.module		= THIS_MODULE,
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.load_binary	= load_script,
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init_script_binfmt(void)
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return register_binfmt(&script_format);
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit exit_script_binfmt(void)
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_binfmt(&script_format);
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscore_initcall(init_script_binfmt);
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(exit_script_binfmt);
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
119