0002-Bug-704342-Include-device-specifier-strings-in-acces.patch 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. From a9bd3dec9fde03327a4a2c69dad1036bf9632e20 Mon Sep 17 00:00:00 2001
  2. From: Chris Liddell <chris.liddell@artifex.com>
  3. Date: Tue, 7 Sep 2021 20:36:12 +0100
  4. Subject: [PATCH] Bug 704342: Include device specifier strings in access
  5. validation
  6. for the "%pipe%", %handle%" and %printer% io devices.
  7. We previously validated only the part after the "%pipe%" Postscript device
  8. specifier, but this proved insufficient.
  9. This rebuilds the original file name string, and validates it complete. The
  10. slight complication for "%pipe%" is it can be reached implicitly using
  11. "|" so we have to check both prefixes.
  12. Addresses CVE-2021-3781
  13. Signed-off-by: Peter Korsgaard <peter@korsgaard.com>
  14. ---
  15. base/gdevpipe.c | 22 +++++++++++++++-
  16. base/gp_mshdl.c | 11 +++++++-
  17. base/gp_msprn.c | 10 ++++++-
  18. base/gp_os2pr.c | 13 +++++++++-
  19. base/gslibctx.c | 69 ++++++++++---------------------------------------
  20. 5 files changed, 65 insertions(+), 60 deletions(-)
  21. diff --git a/base/gdevpipe.c b/base/gdevpipe.c
  22. index 96d71f5d8..5bdc485be 100644
  23. --- a/base/gdevpipe.c
  24. +++ b/base/gdevpipe.c
  25. @@ -72,8 +72,28 @@ pipe_fopen(gx_io_device * iodev, const char *fname, const char *access,
  26. #else
  27. gs_lib_ctx_t *ctx = mem->gs_lib_ctx;
  28. gs_fs_list_t *fs = ctx->core->fs;
  29. + /* The pipe device can be reached in two ways, explicltly with %pipe%
  30. + or implicitly with "|", so we have to check for both
  31. + */
  32. + char f[gp_file_name_sizeof];
  33. + const char *pipestr = "|";
  34. + const size_t pipestrlen = strlen(pipestr);
  35. + const size_t preflen = strlen(iodev->dname);
  36. + const size_t nlen = strlen(fname);
  37. + int code1;
  38. +
  39. + if (preflen + nlen >= gp_file_name_sizeof)
  40. + return_error(gs_error_invalidaccess);
  41. +
  42. + memcpy(f, iodev->dname, preflen);
  43. + memcpy(f + preflen, fname, nlen + 1);
  44. +
  45. + code1 = gp_validate_path(mem, f, access);
  46. +
  47. + memcpy(f, pipestr, pipestrlen);
  48. + memcpy(f + pipestrlen, fname, nlen + 1);
  49. - if (gp_validate_path(mem, fname, access) != 0)
  50. + if (code1 != 0 && gp_validate_path(mem, f, access) != 0 )
  51. return gs_error_invalidfileaccess;
  52. /*
  53. diff --git a/base/gp_mshdl.c b/base/gp_mshdl.c
  54. index 2b964ed74..8d87ceadc 100644
  55. --- a/base/gp_mshdl.c
  56. +++ b/base/gp_mshdl.c
  57. @@ -95,8 +95,17 @@ mswin_handle_fopen(gx_io_device * iodev, const char *fname, const char *access,
  58. long hfile; /* Correct for Win32, may be wrong for Win64 */
  59. gs_lib_ctx_t *ctx = mem->gs_lib_ctx;
  60. gs_fs_list_t *fs = ctx->core->fs;
  61. + char f[gp_file_name_sizeof];
  62. + const size_t preflen = strlen(iodev->dname);
  63. + const size_t nlen = strlen(fname);
  64. - if (gp_validate_path(mem, fname, access) != 0)
  65. + if (preflen + nlen >= gp_file_name_sizeof)
  66. + return_error(gs_error_invalidaccess);
  67. +
  68. + memcpy(f, iodev->dname, preflen);
  69. + memcpy(f + preflen, fname, nlen + 1);
  70. +
  71. + if (gp_validate_path(mem, f, access) != 0)
  72. return gs_error_invalidfileaccess;
  73. /* First we try the open_handle method. */
  74. diff --git a/base/gp_msprn.c b/base/gp_msprn.c
  75. index ed4827968..746a974f7 100644
  76. --- a/base/gp_msprn.c
  77. +++ b/base/gp_msprn.c
  78. @@ -168,8 +168,16 @@ mswin_printer_fopen(gx_io_device * iodev, const char *fname, const char *access,
  79. uintptr_t *ptid = &((tid_t *)(iodev->state))->tid;
  80. gs_lib_ctx_t *ctx = mem->gs_lib_ctx;
  81. gs_fs_list_t *fs = ctx->core->fs;
  82. + const size_t preflen = strlen(iodev->dname);
  83. + const size_t nlen = strlen(fname);
  84. - if (gp_validate_path(mem, fname, access) != 0)
  85. + if (preflen + nlen >= gp_file_name_sizeof)
  86. + return_error(gs_error_invalidaccess);
  87. +
  88. + memcpy(pname, iodev->dname, preflen);
  89. + memcpy(pname + preflen, fname, nlen + 1);
  90. +
  91. + if (gp_validate_path(mem, pname, access) != 0)
  92. return gs_error_invalidfileaccess;
  93. /* First we try the open_printer method. */
  94. diff --git a/base/gp_os2pr.c b/base/gp_os2pr.c
  95. index f852c71fc..ba54cde66 100644
  96. --- a/base/gp_os2pr.c
  97. +++ b/base/gp_os2pr.c
  98. @@ -107,9 +107,20 @@ os2_printer_fopen(gx_io_device * iodev, const char *fname, const char *access,
  99. FILE ** pfile, char *rfname, uint rnamelen)
  100. {
  101. os2_printer_t *pr = (os2_printer_t *)iodev->state;
  102. - char driver_name[256];
  103. + char driver_name[gp_file_name_sizeof];
  104. gs_lib_ctx_t *ctx = mem->gs_lib_ctx;
  105. gs_fs_list_t *fs = ctx->core->fs;
  106. + const size_t preflen = strlen(iodev->dname);
  107. + const int size_t = strlen(fname);
  108. +
  109. + if (preflen + nlen >= gp_file_name_sizeof)
  110. + return_error(gs_error_invalidaccess);
  111. +
  112. + memcpy(driver_name, iodev->dname, preflen);
  113. + memcpy(driver_name + preflen, fname, nlen + 1);
  114. +
  115. + if (gp_validate_path(mem, driver_name, access) != 0)
  116. + return gs_error_invalidfileaccess;
  117. /* First we try the open_printer method. */
  118. /* Note that the loop condition here ensures we don't
  119. diff --git a/base/gslibctx.c b/base/gslibctx.c
  120. index 6dfed6cd5..318039fad 100644
  121. --- a/base/gslibctx.c
  122. +++ b/base/gslibctx.c
  123. @@ -655,82 +655,39 @@ rewrite_percent_specifiers(char *s)
  124. int
  125. gs_add_outputfile_control_path(gs_memory_t *mem, const char *fname)
  126. {
  127. - char *fp, f[gp_file_name_sizeof];
  128. - const int pipe = 124; /* ASCII code for '|' */
  129. - const int len = strlen(fname);
  130. - int i, code;
  131. + char f[gp_file_name_sizeof];
  132. + int code;
  133. /* Be sure the string copy will fit */
  134. - if (len >= gp_file_name_sizeof)
  135. + if (strlen(fname) >= gp_file_name_sizeof)
  136. return gs_error_rangecheck;
  137. strcpy(f, fname);
  138. - fp = f;
  139. /* Try to rewrite any %d (or similar) in the string */
  140. rewrite_percent_specifiers(f);
  141. - for (i = 0; i < len; i++) {
  142. - if (f[i] == pipe) {
  143. - fp = &f[i + 1];
  144. - /* Because we potentially have to check file permissions at two levels
  145. - for the output file (gx_device_open_output_file and the low level
  146. - fopen API, if we're using a pipe, we have to add both the full string,
  147. - (including the '|', and just the command to which we pipe - since at
  148. - the pipe_fopen(), the leading '|' has been stripped.
  149. - */
  150. - code = gs_add_control_path(mem, gs_permit_file_writing, f);
  151. - if (code < 0)
  152. - return code;
  153. - code = gs_add_control_path(mem, gs_permit_file_control, f);
  154. - if (code < 0)
  155. - return code;
  156. - break;
  157. - }
  158. - if (!IS_WHITESPACE(f[i]))
  159. - break;
  160. - }
  161. - code = gs_add_control_path(mem, gs_permit_file_control, fp);
  162. +
  163. + code = gs_add_control_path(mem, gs_permit_file_control, f);
  164. if (code < 0)
  165. return code;
  166. - return gs_add_control_path(mem, gs_permit_file_writing, fp);
  167. + return gs_add_control_path(mem, gs_permit_file_writing, f);
  168. }
  169. int
  170. gs_remove_outputfile_control_path(gs_memory_t *mem, const char *fname)
  171. {
  172. - char *fp, f[gp_file_name_sizeof];
  173. - const int pipe = 124; /* ASCII code for '|' */
  174. - const int len = strlen(fname);
  175. - int i, code;
  176. + char f[gp_file_name_sizeof];
  177. + int code;
  178. /* Be sure the string copy will fit */
  179. - if (len >= gp_file_name_sizeof)
  180. + if (strlen(fname) >= gp_file_name_sizeof)
  181. return gs_error_rangecheck;
  182. strcpy(f, fname);
  183. - fp = f;
  184. /* Try to rewrite any %d (or similar) in the string */
  185. - for (i = 0; i < len; i++) {
  186. - if (f[i] == pipe) {
  187. - fp = &f[i + 1];
  188. - /* Because we potentially have to check file permissions at two levels
  189. - for the output file (gx_device_open_output_file and the low level
  190. - fopen API, if we're using a pipe, we have to add both the full string,
  191. - (including the '|', and just the command to which we pipe - since at
  192. - the pipe_fopen(), the leading '|' has been stripped.
  193. - */
  194. - code = gs_remove_control_path(mem, gs_permit_file_writing, f);
  195. - if (code < 0)
  196. - return code;
  197. - code = gs_remove_control_path(mem, gs_permit_file_control, f);
  198. - if (code < 0)
  199. - return code;
  200. - break;
  201. - }
  202. - if (!IS_WHITESPACE(f[i]))
  203. - break;
  204. - }
  205. - code = gs_remove_control_path(mem, gs_permit_file_control, fp);
  206. + rewrite_percent_specifiers(f);
  207. +
  208. + code = gs_remove_control_path(mem, gs_permit_file_control, f);
  209. if (code < 0)
  210. return code;
  211. - return gs_remove_control_path(mem, gs_permit_file_writing, fp);
  212. + return gs_remove_control_path(mem, gs_permit_file_writing, f);
  213. }
  214. int
  215. --
  216. 2.20.1