From 79aef19c685984dc3da2dc090450407d9fbcff80 Mon Sep 17 00:00:00 2001
From: Ken Sharp <Ken.Sharp@artifex.com>
Date: Tue, 26 Mar 2024 12:00:14 +0000
Subject: [PATCH 1/5] Bug #707686

See bug thread for details

In addition to the noted bug; an error path (return from
gp_file_name_reduce not successful) could elad to a memory leak as we
did not free 'bufferfull'. Fix that too.

This addresses CVE-2024-33870

CVE: CVE-2024-33870

Upstream-Status: Backport [https://cgit.ghostscript.com/cgi-bin/cgit.cgi/ghostpdl.git/commit/?id=79aef19c685984dc]

Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
---
 base/gpmisc.c | 33 ++++++++++++++++++++++++++++++---
 1 file changed, 30 insertions(+), 3 deletions(-)

diff --git a/base/gpmisc.c b/base/gpmisc.c
index f9a9230..3b6fffa 100644
--- a/base/gpmisc.c
+++ b/base/gpmisc.c
@@ -1042,7 +1042,7 @@ gp_validate_path_len(const gs_memory_t *mem,
                      const uint         len,
                      const char        *mode)
 {
-    char *buffer, *bufferfull;
+    char *buffer, *bufferfull = NULL;
     uint rlen;
     int code = 0;
     const char *cdirstr = gp_file_name_current();
@@ -1095,8 +1095,10 @@ gp_validate_path_len(const gs_memory_t *mem,
             return gs_error_VMerror;

         buffer = bufferfull + prefix_len;
-        if (gp_file_name_reduce(path, (uint)len, buffer, &rlen) != gp_combine_success)
-            return gs_error_invalidfileaccess;
+	if (gp_file_name_reduce(path, (uint)len, buffer, &rlen) != gp_combine_success) {
+           code = gs_note_error(gs_error_invalidfileaccess);
+            goto exit;
+        }
         buffer[rlen] = 0;
     }
     while (1) {
@@ -1131,9 +1133,33 @@ gp_validate_path_len(const gs_memory_t *mem,
             code = gs_note_error(gs_error_invalidfileaccess);
         }
         if (code < 0 && prefix_len > 0 && buffer > bufferfull) {
+            uint newlen = rlen + cdirstrl + dirsepstrl;
+            char *newbuffer;
+            int code;
+
             buffer = bufferfull;
             memcpy(buffer, cdirstr, cdirstrl);
             memcpy(buffer + cdirstrl, dirsepstr, dirsepstrl);
+	    /* We've prepended a './' or similar for the current working directory. We need
+             * to execute file_name_reduce on that, to eliminate any '../' or similar from
+             * the (new) full path.
+             */
+            newbuffer = (char *)gs_alloc_bytes(mem->thread_safe_memory, newlen + 1, "gp_validate_path");
+            if (newbuffer == NULL) {
+                code = gs_note_error(gs_error_VMerror);
+                goto exit;
+            }
+
+            memcpy(newbuffer, buffer, rlen + cdirstrl + dirsepstrl);
+            newbuffer[newlen] = 0x00;
+
+            code = gp_file_name_reduce(newbuffer, (uint)newlen, buffer, &newlen);
+            gs_free_object(mem->thread_safe_memory, newbuffer, "gp_validate_path");
+            if (code != gp_combine_success) {
+                code = gs_note_error(gs_error_invalidfileaccess);
+                goto exit;
+            }
+
             continue;
         }
         else if (code < 0 && cdirstrl > 0 && prefix_len == 0 && buffer == bufferfull) {
@@ -1152,6 +1178,7 @@ gp_validate_path_len(const gs_memory_t *mem,
                                            gs_path_control_flag_is_scratch_file);
     }

+exit:
     gs_free_object(mem->thread_safe_memory, bufferfull, "gp_validate_path");
 #ifdef EACCES
     if (code == gs_error_invalidfileaccess)
--
2.40.0
