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.

102 lines
3.4 KiB

  1. From: Tony Cook <tony@develop-help.com>
  2. Date: Wed, 27 Jan 2016 00:52:15 +0000 (+1100)
  3. Subject: remove duplicate environment variables from environ
  4. X-Git-Url: http://perl5.git.perl.org/perl.git/commitdiff_plain/ae37b791a73a9e78dedb89fb2429d2628cf58076
  5. remove duplicate environment variables from environ
  6. If we see duplicate environment variables while iterating over
  7. environ[]:
  8. a) make sure we use the same value in %ENV that getenv() returns.
  9. Previously on a duplicate, %ENV would have the last entry for the name
  10. from environ[], but a typical getenv() would return the first entry.
  11. Rather than assuming all getenv() implementations return the first entry
  12. explicitly call getenv() to ensure they agree.
  13. b) remove duplicate entries from environ
  14. Previously if there was a duplicate definition for a name in environ[]
  15. setting that name in %ENV could result in an unsafe value being passed
  16. to a child process, so ensure environ[] has no duplicates.
  17. CVE-2016-2381
  18. ---
  19. --- a/perl.c
  20. +++ b/perl.c
  21. @@ -4298,23 +4298,70 @@ S_init_postdump_symbols(pTHX_ int argc,
  22. }
  23. if (env) {
  24. char *s, *old_var;
  25. + STRLEN nlen;
  26. SV *sv;
  27. + HV *dups = newHV();
  28. +
  29. for (; *env; env++) {
  30. old_var = *env;
  31. if (!(s = strchr(old_var,'=')) || s == old_var)
  32. continue;
  33. + nlen = s - old_var;
  34. #if defined(MSDOS) && !defined(DJGPP)
  35. *s = '\0';
  36. (void)strupr(old_var);
  37. *s = '=';
  38. #endif
  39. - sv = newSVpv(s+1, 0);
  40. - (void)hv_store(hv, old_var, s - old_var, sv, 0);
  41. + if (hv_exists(hv, old_var, nlen)) {
  42. + const char *name = savepvn(old_var, nlen);
  43. +
  44. + /* make sure we use the same value as getenv(), otherwise code that
  45. + uses getenv() (like setlocale()) might see a different value to %ENV
  46. + */
  47. + sv = newSVpv(PerlEnv_getenv(name), 0);
  48. +
  49. + /* keep a count of the dups of this name so we can de-dup environ later */
  50. + if (hv_exists(dups, name, nlen))
  51. + ++SvIVX(*hv_fetch(dups, name, nlen, 0));
  52. + else
  53. + (void)hv_store(dups, name, nlen, newSViv(1), 0);
  54. +
  55. + Safefree(name);
  56. + }
  57. + else {
  58. + sv = newSVpv(s+1, 0);
  59. + }
  60. + (void)hv_store(hv, old_var, nlen, sv, 0);
  61. if (env_is_not_environ)
  62. mg_set(sv);
  63. }
  64. + if (HvKEYS(dups)) {
  65. + /* environ has some duplicate definitions, remove them */
  66. + HE *entry;
  67. + hv_iterinit(dups);
  68. + while ((entry = hv_iternext_flags(dups, 0))) {
  69. + STRLEN nlen;
  70. + const char *name = HePV(entry, nlen);
  71. + IV count = SvIV(HeVAL(entry));
  72. + IV i;
  73. + SV **valp = hv_fetch(hv, name, nlen, 0);
  74. +
  75. + assert(valp);
  76. +
  77. + /* try to remove any duplicate names, depending on the
  78. + * implementation used in my_setenv() the iteration might
  79. + * not be necessary, but let's be safe.
  80. + */
  81. + for (i = 0; i < count; ++i)
  82. + my_setenv(name, 0);
  83. +
  84. + /* and set it back to the value we set $ENV{name} to */
  85. + my_setenv(name, SvPV_nolen(*valp));
  86. + }
  87. + }
  88. + SvREFCNT_dec_NN(dups);
  89. }
  90. #endif /* USE_ENVIRON_ARRAY */
  91. #endif /* !PERL_MICRO */