original development tree for Linux kernel GTP module; now long in mainline.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

119 lines
2.7 KiB

exec: do not leave bprm->interp on stack If a series of scripts are executed, each triggering module loading via unprintable bytes in the script header, kernel stack contents can leak into the command line. Normally execution of binfmt_script and binfmt_misc happens recursively. However, when modules are enabled, and unprintable bytes exist in the bprm->buf, execution will restart after attempting to load matching binfmt modules. Unfortunately, the logic in binfmt_script and binfmt_misc does not expect to get restarted. They leave bprm->interp pointing to their local stack. This means on restart bprm->interp is left pointing into unused stack memory which can then be copied into the userspace argv areas. After additional study, it seems that both recursion and restart remains the desirable way to handle exec with scripts, misc, and modules. As such, we need to protect the changes to interp. This changes the logic to require allocation for any changes to the bprm->interp. To avoid adding a new kmalloc to every exec, the default value is left as-is. Only when passing through binfmt_script or binfmt_misc does an allocation take place. For a proof of concept, see DoTest.sh from: http://www.halfdog.net/Security/2012/LinuxKernelBinfmtScriptStackDataDisclosure/ Signed-off-by: Kees Cook <keescook@chromium.org> Cc: halfdog <me@halfdog.net> Cc: P J P <ppandit@redhat.com> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
9 years ago
  1. /*
  2. * linux/fs/binfmt_script.c
  3. *
  4. * Copyright (C) 1996 Martin von Löwis
  5. * original #!-checking implemented by tytso.
  6. */
  7. #include <linux/module.h>
  8. #include <linux/string.h>
  9. #include <linux/stat.h>
  10. #include <linux/binfmts.h>
  11. #include <linux/init.h>
  12. #include <linux/file.h>
  13. #include <linux/err.h>
  14. #include <linux/fs.h>
  15. static int load_script(struct linux_binprm *bprm)
  16. {
  17. const char *i_arg, *i_name;
  18. char *cp;
  19. struct file *file;
  20. char interp[BINPRM_BUF_SIZE];
  21. int retval;
  22. if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
  23. return -ENOEXEC;
  24. /*
  25. * This section does the #! interpretation.
  26. * Sorta complicated, but hopefully it will work. -TYT
  27. */
  28. allow_write_access(bprm->file);
  29. fput(bprm->file);
  30. bprm->file = NULL;
  31. bprm->buf[BINPRM_BUF_SIZE - 1] = '\0';
  32. if ((cp = strchr(bprm->buf, '\n')) == NULL)
  33. cp = bprm->buf+BINPRM_BUF_SIZE-1;
  34. *cp = '\0';
  35. while (cp > bprm->buf) {
  36. cp--;
  37. if ((*cp == ' ') || (*cp == '\t'))
  38. *cp = '\0';
  39. else
  40. break;
  41. }
  42. for (cp = bprm->buf+2; (*cp == ' ') || (*cp == '\t'); cp++);
  43. if (*cp == '\0')
  44. return -ENOEXEC; /* No interpreter name found */
  45. i_name = cp;
  46. i_arg = NULL;
  47. for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++)
  48. /* nothing */ ;
  49. while ((*cp == ' ') || (*cp == '\t'))
  50. *cp++ = '\0';
  51. if (*cp)
  52. i_arg = cp;
  53. strcpy (interp, i_name);
  54. /*
  55. * OK, we've parsed out the interpreter name and
  56. * (optional) argument.
  57. * Splice in (1) the interpreter's name for argv[0]
  58. * (2) (optional) argument to interpreter
  59. * (3) filename of shell script (replace argv[0])
  60. *
  61. * This is done in reverse order, because of how the
  62. * user environment and arguments are stored.
  63. */
  64. retval = remove_arg_zero(bprm);
  65. if (retval)
  66. return retval;
  67. retval = copy_strings_kernel(1, &bprm->interp, bprm);
  68. if (retval < 0) return retval;
  69. bprm->argc++;
  70. if (i_arg) {
  71. retval = copy_strings_kernel(1, &i_arg, bprm);
  72. if (retval < 0) return retval;
  73. bprm->argc++;
  74. }
  75. retval = copy_strings_kernel(1, &i_name, bprm);
  76. if (retval) return retval;
  77. bprm->argc++;
  78. retval = bprm_change_interp(interp, bprm);
  79. if (retval < 0)
  80. return retval;
  81. /*
  82. * OK, now restart the process with the interpreter's dentry.
  83. */
  84. file = open_exec(interp);
  85. if (IS_ERR(file))
  86. return PTR_ERR(file);
  87. bprm->file = file;
  88. retval = prepare_binprm(bprm);
  89. if (retval < 0)
  90. return retval;
  91. return search_binary_handler(bprm);
  92. }
  93. static struct linux_binfmt script_format = {
  94. .module = THIS_MODULE,
  95. .load_binary = load_script,
  96. };
  97. static int __init init_script_binfmt(void)
  98. {
  99. register_binfmt(&script_format);
  100. return 0;
  101. }
  102. static void __exit exit_script_binfmt(void)
  103. {
  104. unregister_binfmt(&script_format);
  105. }
  106. core_initcall(init_script_binfmt);
  107. module_exit(exit_script_binfmt);
  108. MODULE_LICENSE("GPL");