1 # --- T2-COPYRIGHT-NOTE-BEGIN ---
2 # T2 SDE: package/*/ghostscript/CVE-2021-3781.patch
3 # Copyright (C) 2021 - 2022 The T2 SDE Project
5 # This Copyright note is generated by scripts/Create-CopyPatch,
6 # more information can be found in the files COPYING and README.
8 # This patch file is dual-licensed. It is available under the license the
9 # patched project is licensed under, as long as it is an OpenSource license
10 # as defined at http://www.opensource.org/ (e.g. BSD, X11) or under the terms
11 # of the GNU General Public License version 2 as used by the T2 SDE.
12 # --- T2-COPYRIGHT-NOTE-END ---
14 From: Chris Liddell <chris.liddell@artifex.com>
15 Date: Tue, 7 Sep 2021 19:36:12 +0000 (+0100)
16 Subject: Bug 704342: Include device specifier strings in access validation
17 X-Git-Tag: ghostpdl-9.55.0rc1_test_001~1
18 X-Git-Url: https://git.ghostscript.com/?p=ghostpdl.git;a=commitdiff_plain;h=a9bd3dec9fde
20 Bug 704342: Include device specifier strings in access validation
22 for the "%pipe%", %handle%" and %printer% io devices.
24 We previously validated only the part after the "%pipe%" Postscript device
25 specifier, but this proved insufficient.
27 This rebuilds the original file name string, and validates it complete. The
28 slight complication for "%pipe%" is it can be reached implicitly using
29 "|" so we have to check both prefixes.
31 Addresses CVE-2021-3781
34 diff --git a/base/gdevpipe.c b/base/gdevpipe.c
35 index 96d71f5d8..5bdc485be 100644
38 @@ -72,8 +72,28 @@ pipe_fopen(gx_io_device * iodev, const char *fname, const char *access,
40 gs_lib_ctx_t *ctx = mem->gs_lib_ctx;
41 gs_fs_list_t *fs = ctx->core->fs;
42 + /* The pipe device can be reached in two ways, explicltly with %pipe%
43 + or implicitly with "|", so we have to check for both
45 + char f[gp_file_name_sizeof];
46 + const char *pipestr = "|";
47 + const size_t pipestrlen = strlen(pipestr);
48 + const size_t preflen = strlen(iodev->dname);
49 + const size_t nlen = strlen(fname);
52 + if (preflen + nlen >= gp_file_name_sizeof)
53 + return_error(gs_error_invalidaccess);
55 + memcpy(f, iodev->dname, preflen);
56 + memcpy(f + preflen, fname, nlen + 1);
58 + code1 = gp_validate_path(mem, f, access);
60 + memcpy(f, pipestr, pipestrlen);
61 + memcpy(f + pipestrlen, fname, nlen + 1);
63 - if (gp_validate_path(mem, fname, access) != 0)
64 + if (code1 != 0 && gp_validate_path(mem, f, access) != 0 )
65 return gs_error_invalidfileaccess;
68 diff --git a/base/gp_mshdl.c b/base/gp_mshdl.c
69 index 2b964ed74..8d87ceadc 100644
72 @@ -95,8 +95,17 @@ mswin_handle_fopen(gx_io_device * iodev, const char *fname, const char *access,
73 long hfile; /* Correct for Win32, may be wrong for Win64 */
74 gs_lib_ctx_t *ctx = mem->gs_lib_ctx;
75 gs_fs_list_t *fs = ctx->core->fs;
76 + char f[gp_file_name_sizeof];
77 + const size_t preflen = strlen(iodev->dname);
78 + const size_t nlen = strlen(fname);
80 - if (gp_validate_path(mem, fname, access) != 0)
81 + if (preflen + nlen >= gp_file_name_sizeof)
82 + return_error(gs_error_invalidaccess);
84 + memcpy(f, iodev->dname, preflen);
85 + memcpy(f + preflen, fname, nlen + 1);
87 + if (gp_validate_path(mem, f, access) != 0)
88 return gs_error_invalidfileaccess;
90 /* First we try the open_handle method. */
91 diff --git a/base/gp_msprn.c b/base/gp_msprn.c
92 index ed4827968..746a974f7 100644
95 @@ -168,8 +168,16 @@ mswin_printer_fopen(gx_io_device * iodev, const char *fname, const char *access,
96 uintptr_t *ptid = &((tid_t *)(iodev->state))->tid;
97 gs_lib_ctx_t *ctx = mem->gs_lib_ctx;
98 gs_fs_list_t *fs = ctx->core->fs;
99 + const size_t preflen = strlen(iodev->dname);
100 + const size_t nlen = strlen(fname);
102 - if (gp_validate_path(mem, fname, access) != 0)
103 + if (preflen + nlen >= gp_file_name_sizeof)
104 + return_error(gs_error_invalidaccess);
106 + memcpy(pname, iodev->dname, preflen);
107 + memcpy(pname + preflen, fname, nlen + 1);
109 + if (gp_validate_path(mem, pname, access) != 0)
110 return gs_error_invalidfileaccess;
112 /* First we try the open_printer method. */
113 diff --git a/base/gp_os2pr.c b/base/gp_os2pr.c
114 index f852c71fc..ba54cde66 100644
115 --- a/base/gp_os2pr.c
116 +++ b/base/gp_os2pr.c
117 @@ -107,9 +107,20 @@ os2_printer_fopen(gx_io_device * iodev, const char *fname, const char *access,
118 FILE ** pfile, char *rfname, uint rnamelen)
120 os2_printer_t *pr = (os2_printer_t *)iodev->state;
121 - char driver_name[256];
122 + char driver_name[gp_file_name_sizeof];
123 gs_lib_ctx_t *ctx = mem->gs_lib_ctx;
124 gs_fs_list_t *fs = ctx->core->fs;
125 + const size_t preflen = strlen(iodev->dname);
126 + const int size_t = strlen(fname);
128 + if (preflen + nlen >= gp_file_name_sizeof)
129 + return_error(gs_error_invalidaccess);
131 + memcpy(driver_name, iodev->dname, preflen);
132 + memcpy(driver_name + preflen, fname, nlen + 1);
134 + if (gp_validate_path(mem, driver_name, access) != 0)
135 + return gs_error_invalidfileaccess;
137 /* First we try the open_printer method. */
138 /* Note that the loop condition here ensures we don't
139 diff --git a/base/gslibctx.c b/base/gslibctx.c
140 index 6dfed6cd5..318039fad 100644
141 --- a/base/gslibctx.c
142 +++ b/base/gslibctx.c
143 @@ -655,82 +655,39 @@ rewrite_percent_specifiers(char *s)
145 gs_add_outputfile_control_path(gs_memory_t *mem, const char *fname)
147 - char *fp, f[gp_file_name_sizeof];
148 - const int pipe = 124; /* ASCII code for '|' */
149 - const int len = strlen(fname);
151 + char f[gp_file_name_sizeof];
154 /* Be sure the string copy will fit */
155 - if (len >= gp_file_name_sizeof)
156 + if (strlen(fname) >= gp_file_name_sizeof)
157 return gs_error_rangecheck;
160 /* Try to rewrite any %d (or similar) in the string */
161 rewrite_percent_specifiers(f);
162 - for (i = 0; i < len; i++) {
163 - if (f[i] == pipe) {
165 - /* Because we potentially have to check file permissions at two levels
166 - for the output file (gx_device_open_output_file and the low level
167 - fopen API, if we're using a pipe, we have to add both the full string,
168 - (including the '|', and just the command to which we pipe - since at
169 - the pipe_fopen(), the leading '|' has been stripped.
171 - code = gs_add_control_path(mem, gs_permit_file_writing, f);
174 - code = gs_add_control_path(mem, gs_permit_file_control, f);
179 - if (!IS_WHITESPACE(f[i]))
182 - code = gs_add_control_path(mem, gs_permit_file_control, fp);
184 + code = gs_add_control_path(mem, gs_permit_file_control, f);
187 - return gs_add_control_path(mem, gs_permit_file_writing, fp);
188 + return gs_add_control_path(mem, gs_permit_file_writing, f);
192 gs_remove_outputfile_control_path(gs_memory_t *mem, const char *fname)
194 - char *fp, f[gp_file_name_sizeof];
195 - const int pipe = 124; /* ASCII code for '|' */
196 - const int len = strlen(fname);
198 + char f[gp_file_name_sizeof];
201 /* Be sure the string copy will fit */
202 - if (len >= gp_file_name_sizeof)
203 + if (strlen(fname) >= gp_file_name_sizeof)
204 return gs_error_rangecheck;
207 /* Try to rewrite any %d (or similar) in the string */
208 - for (i = 0; i < len; i++) {
209 - if (f[i] == pipe) {
211 - /* Because we potentially have to check file permissions at two levels
212 - for the output file (gx_device_open_output_file and the low level
213 - fopen API, if we're using a pipe, we have to add both the full string,
214 - (including the '|', and just the command to which we pipe - since at
215 - the pipe_fopen(), the leading '|' has been stripped.
217 - code = gs_remove_control_path(mem, gs_permit_file_writing, f);
220 - code = gs_remove_control_path(mem, gs_permit_file_control, f);
225 - if (!IS_WHITESPACE(f[i]))
228 - code = gs_remove_control_path(mem, gs_permit_file_control, fp);
229 + rewrite_percent_specifiers(f);
231 + code = gs_remove_control_path(mem, gs_permit_file_control, f);
234 - return gs_remove_control_path(mem, gs_permit_file_writing, fp);
235 + return gs_remove_control_path(mem, gs_permit_file_writing, f);