!30 【openEuler-20.03-LTS-SP3】Fix CVE-2021-3781

From: @yang_zhuang_zhuang 
Reviewed-by: @xiezhipeng1 
Signed-off-by: @xiezhipeng1
This commit is contained in:
openeuler-ci-bot 2022-03-01 08:03:16 +00:00 committed by Gitee
commit 233768964f
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
4 changed files with 379 additions and 1 deletions

View File

@ -0,0 +1,229 @@
From a9bd3dec9fde03327a4a2c69dad1036bf9632e20 Mon Sep 17 00:00:00 2001
From: Chris Liddell <chris.liddell@artifex.com>
Date: Tue, 7 Sep 2021 20:36:12 +0100
Subject: [PATCH] Bug 704342: Include device specifier strings in access
validation
for the "%pipe%", %handle%" and %printer% io devices.
We previously validated only the part after the "%pipe%" Postscript device
specifier, but this proved insufficient.
This rebuilds the original file name string, and validates it complete. The
slight complication for "%pipe%" is it can be reached implicitly using
"|" so we have to check both prefixes.
Addresses CVE-2021-3781
---
base/gdevpipe.c | 22 +++++++++++++++-
base/gp_mshdl.c | 11 +++++++-
base/gp_msprn.c | 10 ++++++-
base/gp_os2pr.c | 13 +++++++++-
base/gslibctx.c | 69 ++++++++++---------------------------------------
5 files changed, 65 insertions(+), 60 deletions(-)
diff --git a/base/gdevpipe.c b/base/gdevpipe.c
index 96d71f5d81..5bdc485be0 100644
--- a/base/gdevpipe.c
+++ b/base/gdevpipe.c
@@ -72,8 +72,28 @@ pipe_fopen(gx_io_device * iodev, const char *fname, const char *access,
#else
gs_lib_ctx_t *ctx = mem->gs_lib_ctx;
gs_fs_list_t *fs = ctx->core->fs;
+ /* The pipe device can be reached in two ways, explicltly with %pipe%
+ or implicitly with "|", so we have to check for both
+ */
+ char f[gp_file_name_sizeof];
+ const char *pipestr = "|";
+ const size_t pipestrlen = strlen(pipestr);
+ const size_t preflen = strlen(iodev->dname);
+ const size_t nlen = strlen(fname);
+ int code1;
+
+ if (preflen + nlen >= gp_file_name_sizeof)
+ return_error(gs_error_invalidaccess);
+
+ memcpy(f, iodev->dname, preflen);
+ memcpy(f + preflen, fname, nlen + 1);
+
+ code1 = gp_validate_path(mem, f, access);
+
+ memcpy(f, pipestr, pipestrlen);
+ memcpy(f + pipestrlen, fname, nlen + 1);
- if (gp_validate_path(mem, fname, access) != 0)
+ if (code1 != 0 && gp_validate_path(mem, f, access) != 0 )
return gs_error_invalidfileaccess;
/*
diff --git a/base/gp_mshdl.c b/base/gp_mshdl.c
index 2b964ed749..8d87ceadc0 100644
--- a/base/gp_mshdl.c
+++ b/base/gp_mshdl.c
@@ -95,8 +95,17 @@ mswin_handle_fopen(gx_io_device * iodev, const char *fname, const char *access,
long hfile; /* Correct for Win32, may be wrong for Win64 */
gs_lib_ctx_t *ctx = mem->gs_lib_ctx;
gs_fs_list_t *fs = ctx->core->fs;
+ char f[gp_file_name_sizeof];
+ const size_t preflen = strlen(iodev->dname);
+ const size_t nlen = strlen(fname);
- if (gp_validate_path(mem, fname, access) != 0)
+ if (preflen + nlen >= gp_file_name_sizeof)
+ return_error(gs_error_invalidaccess);
+
+ memcpy(f, iodev->dname, preflen);
+ memcpy(f + preflen, fname, nlen + 1);
+
+ if (gp_validate_path(mem, f, access) != 0)
return gs_error_invalidfileaccess;
/* First we try the open_handle method. */
diff --git a/base/gp_msprn.c b/base/gp_msprn.c
index ed48279685..746a974f78 100644
--- a/base/gp_msprn.c
+++ b/base/gp_msprn.c
@@ -168,8 +168,16 @@ mswin_printer_fopen(gx_io_device * iodev, const char *fname, const char *access,
unsigned long *ptid = &((tid_t *)(iodev->state))->tid;
gs_lib_ctx_t *ctx = mem->gs_lib_ctx;
gs_fs_list_t *fs = ctx->core->fs;
+ const size_t preflen = strlen(iodev->dname);
+ const size_t nlen = strlen(fname);
- if (gp_validate_path(mem, fname, access) != 0)
+ if (preflen + nlen >= gp_file_name_sizeof)
+ return_error(gs_error_invalidaccess);
+
+ memcpy(pname, iodev->dname, preflen);
+ memcpy(pname + preflen, fname, nlen + 1);
+
+ if (gp_validate_path(mem, pname, access) != 0)
return gs_error_invalidfileaccess;
/* First we try the open_printer method. */
diff --git a/base/gp_os2pr.c b/base/gp_os2pr.c
index f852c71fc8..ba54cde66f 100644
--- a/base/gp_os2pr.c
+++ b/base/gp_os2pr.c
@@ -107,9 +107,20 @@ os2_printer_fopen(gx_io_device * iodev, const char *fname, const char *access,
FILE ** pfile, char *rfname, uint rnamelen)
{
os2_printer_t *pr = (os2_printer_t *)iodev->state;
- char driver_name[256];
+ char driver_name[gp_file_name_sizeof];
gs_lib_ctx_t *ctx = mem->gs_lib_ctx;
gs_fs_list_t *fs = ctx->core->fs;
+ const size_t preflen = strlen(iodev->dname);
+ const int size_t = strlen(fname);
+
+ if (preflen + nlen >= gp_file_name_sizeof)
+ return_error(gs_error_invalidaccess);
+
+ memcpy(driver_name, iodev->dname, preflen);
+ memcpy(driver_name + preflen, fname, nlen + 1);
+
+ if (gp_validate_path(mem, driver_name, access) != 0)
+ return gs_error_invalidfileaccess;
/* First we try the open_printer method. */
/* Note that the loop condition here ensures we don't
diff --git a/base/gslibctx.c b/base/gslibctx.c
index 6dfed6cd5a..318039fad0 100644
--- a/base/gslibctx.c
+++ b/base/gslibctx.c
@@ -655,82 +655,39 @@ rewrite_percent_specifiers(char *s)
int
gs_add_outputfile_control_path(gs_memory_t *mem, const char *fname)
{
- char *fp, f[gp_file_name_sizeof];
- const int pipe = 124; /* ASCII code for '|' */
- const int len = strlen(fname);
- int i, code;
+ char f[gp_file_name_sizeof];
+ int code;
/* Be sure the string copy will fit */
- if (len >= gp_file_name_sizeof)
+ if (strlen(fname) >= gp_file_name_sizeof)
return gs_error_rangecheck;
strcpy(f, fname);
- fp = f;
/* Try to rewrite any %d (or similar) in the string */
rewrite_percent_specifiers(f);
- for (i = 0; i < len; i++) {
- if (f[i] == pipe) {
- fp = &f[i + 1];
- /* Because we potentially have to check file permissions at two levels
- for the output file (gx_device_open_output_file and the low level
- fopen API, if we're using a pipe, we have to add both the full string,
- (including the '|', and just the command to which we pipe - since at
- the pipe_fopen(), the leading '|' has been stripped.
- */
- code = gs_add_control_path(mem, gs_permit_file_writing, f);
- if (code < 0)
- return code;
- code = gs_add_control_path(mem, gs_permit_file_control, f);
- if (code < 0)
- return code;
- break;
- }
- if (!IS_WHITESPACE(f[i]))
- break;
- }
- code = gs_add_control_path(mem, gs_permit_file_control, fp);
+
+ code = gs_add_control_path(mem, gs_permit_file_control, f);
if (code < 0)
return code;
- return gs_add_control_path(mem, gs_permit_file_writing, fp);
+ return gs_add_control_path(mem, gs_permit_file_writing, f);
}
int
gs_remove_outputfile_control_path(gs_memory_t *mem, const char *fname)
{
- char *fp, f[gp_file_name_sizeof];
- const int pipe = 124; /* ASCII code for '|' */
- const int len = strlen(fname);
- int i, code;
+ char f[gp_file_name_sizeof];
+ int code;
/* Be sure the string copy will fit */
- if (len >= gp_file_name_sizeof)
+ if (strlen(fname) >= gp_file_name_sizeof)
return gs_error_rangecheck;
strcpy(f, fname);
- fp = f;
/* Try to rewrite any %d (or similar) in the string */
- for (i = 0; i < len; i++) {
- if (f[i] == pipe) {
- fp = &f[i + 1];
- /* Because we potentially have to check file permissions at two levels
- for the output file (gx_device_open_output_file and the low level
- fopen API, if we're using a pipe, we have to add both the full string,
- (including the '|', and just the command to which we pipe - since at
- the pipe_fopen(), the leading '|' has been stripped.
- */
- code = gs_remove_control_path(mem, gs_permit_file_writing, f);
- if (code < 0)
- return code;
- code = gs_remove_control_path(mem, gs_permit_file_control, f);
- if (code < 0)
- return code;
- break;
- }
- if (!IS_WHITESPACE(f[i]))
- break;
- }
- code = gs_remove_control_path(mem, gs_permit_file_control, fp);
+ rewrite_percent_specifiers(f);
+
+ code = gs_remove_control_path(mem, gs_permit_file_control, f);
if (code < 0)
return code;
- return gs_remove_control_path(mem, gs_permit_file_writing, fp);
+ return gs_remove_control_path(mem, gs_permit_file_writing, f);
}
int

View File

@ -0,0 +1,28 @@
From 9daf042fd7bb19e93388d89d9686a2fa4496f382 Mon Sep 17 00:00:00 2001
From: Chris Liddell <chris.liddell@artifex.com>
Date: Mon, 24 Aug 2020 09:24:31 +0100
Subject: [PATCH] Coverity 361429: move "break" to correct place.
We had to add the outputfile to the "control" file permission list (as well
as write), but for the "pipe" case, I accidentally added the call after the
break out of loop that checks for a pipe.
---
base/gslibctx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/base/gslibctx.c b/base/gslibctx.c
index ff8fc895ef..63dfbe2e06 100644
--- a/base/gslibctx.c
+++ b/base/gslibctx.c
@@ -668,10 +668,10 @@ gs_add_outputfile_control_path(gs_memory_t *mem, const char *fname)
code = gs_add_control_path(mem, gs_permit_file_writing, f);
if (code < 0)
return code;
- break;
code = gs_add_control_path(mem, gs_permit_file_control, f);
if (code < 0)
return code;
+ break;
}
if (!IS_WHITESPACE(f[i]))
break;

View File

@ -0,0 +1,112 @@
From 3920a727fb19e19f597e518610ce2416d08cb75f Mon Sep 17 00:00:00 2001
From: Chris Liddell <chris.liddell@artifex.com>
Date: Thu, 20 Aug 2020 17:19:09 +0100
Subject: [PATCH] Fix pdfwrite "%d" mode with file permissions
Firstly, in gx_device_delete_output_file the iodev pointer was being passed
to the delete_method incorrectly (passing a pointer to that pointer). Thus
when we attempted to use that to confirm permission to delete the file, it
crashed. Credit to Ken for finding that.
Secondly, due to the way pdfwrite works, when running with an output file per
page, it creates the current output file immediately it has completed writing
the previous one. Thus, it has to delete that partial file on exit.
Previously, the output file was not added to the "control" permission list,
so an attempt to delete it would result in an error. So add the output file
to the "control" as well as "write" list.
---
base/gsdevice.c | 2 +-
base/gslibctx.c | 20 ++++++++++++++------
2 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/base/gsdevice.c b/base/gsdevice.c
index 9131194951..ac78af93fd 100644
--- a/base/gsdevice.c
+++ b/base/gsdevice.c
@@ -1185,7 +1185,7 @@ int gx_device_delete_output_file(const gx_device * dev, const char *fname)
parsed.len = strlen(parsed.fname);
}
if (parsed.iodev)
- code = parsed.iodev->procs.delete_file((gx_io_device *)(&parsed.iodev), (const char *)parsed.fname);
+ code = parsed.iodev->procs.delete_file((gx_io_device *)(parsed.iodev), (const char *)parsed.fname);
else
code = gs_note_error(gs_error_invalidfileaccess);
diff --git a/base/gslibctx.c b/base/gslibctx.c
index d726c58b5b..ff8fc895ef 100644
--- a/base/gslibctx.c
+++ b/base/gslibctx.c
@@ -647,7 +647,7 @@ gs_add_outputfile_control_path(gs_memory_t *mem, const char *fname)
char *fp, f[gp_file_name_sizeof];
const int pipe = 124; /* ASCII code for '|' */
const int len = strlen(fname);
- int i;
+ int i, code;
/* Be sure the string copy will fit */
if (len >= gp_file_name_sizeof)
@@ -658,8 +658,6 @@ gs_add_outputfile_control_path(gs_memory_t *mem, const char *fname)
rewrite_percent_specifiers(f);
for (i = 0; i < len; i++) {
if (f[i] == pipe) {
- int code;
-
fp = &f[i + 1];
/* Because we potentially have to check file permissions at two levels
for the output file (gx_device_open_output_file and the low level
@@ -671,10 +669,16 @@ gs_add_outputfile_control_path(gs_memory_t *mem, const char *fname)
if (code < 0)
return code;
break;
+ code = gs_add_control_path(mem, gs_permit_file_control, f);
+ if (code < 0)
+ return code;
}
if (!IS_WHITESPACE(f[i]))
break;
}
+ code = gs_add_control_path(mem, gs_permit_file_control, fp);
+ if (code < 0)
+ return code;
return gs_add_control_path(mem, gs_permit_file_writing, fp);
}
@@ -684,7 +688,7 @@ gs_remove_outputfile_control_path(gs_memory_t *mem, const char *fname)
char *fp, f[gp_file_name_sizeof];
const int pipe = 124; /* ASCII code for '|' */
const int len = strlen(fname);
- int i;
+ int i, code;
/* Be sure the string copy will fit */
if (len >= gp_file_name_sizeof)
@@ -694,8 +698,6 @@ gs_remove_outputfile_control_path(gs_memory_t *mem, const char *fname)
/* Try to rewrite any %d (or similar) in the string */
for (i = 0; i < len; i++) {
if (f[i] == pipe) {
- int code;
-
fp = &f[i + 1];
/* Because we potentially have to check file permissions at two levels
for the output file (gx_device_open_output_file and the low level
@@ -704,6 +706,9 @@ gs_remove_outputfile_control_path(gs_memory_t *mem, const char *fname)
the pipe_fopen(), the leading '|' has been stripped.
*/
code = gs_remove_control_path(mem, gs_permit_file_writing, f);
+ if (code < 0)
+ return code;
+ code = gs_remove_control_path(mem, gs_permit_file_control, f);
if (code < 0)
return code;
break;
@@ -711,6 +716,9 @@ gs_remove_outputfile_control_path(gs_memory_t *mem, const char *fname)
if (!IS_WHITESPACE(f[i]))
break;
}
+ code = gs_remove_control_path(mem, gs_permit_file_control, fp);
+ if (code < 0)
+ return code;
return gs_remove_control_path(mem, gs_permit_file_writing, fp);
}

View File

@ -9,7 +9,7 @@
Name: ghostscript
Version: 9.52
Release: 6
Release: 7
Summary: An interpreter for PostScript and PDF files
License: AGPLv3+
URL: https://ghostscript.com/
@ -46,6 +46,9 @@ Patch27: oss-fuzz-23637-Fix-error-code-confusion.patch
Patch28: oss-fuzz-23946-Move-buffer-bounds-check-to-before-us.patch
Patch29: backport-CVE-2021-45944.patch
Patch30: backport-CVE-2021-45949.patch
Patch31: backport-Fix-pdfwrite-d-mode-with-file-permissions.patch
Patch32: backport-Coverity-361429-move-break-to-correct-place.patch
Patch33: backport-CVE-2021-3781-BUg-704342-Include-device-specifier-strings-in-acces.patch
BuildRequires: automake gcc
BuildRequires: adobe-mappings-cmap-devel adobe-mappings-pdf-devel
@ -206,6 +209,12 @@ install -m 0755 -d %{buildroot}%{_datadir}/%{name}/conf.d/
%{_bindir}/dvipdf
%changelog
* Tue Mar 1 2022 yangzhuangzhuang <yangzhuangzhuang1@h-partners.com> - 9.52-7
- Type:CVE
- ID:CVE-2021-3781
- SUG:NA
- DESC:fix CVE-2021-3781
* Tue Jan 11 2022 yangzhuangzhuang <yangzhuangzhuang1@huawei.com> - 9.52-6
- Type:CVE
- ID:CVE-2021-45944 CVE-2021-45949