Package: ghostscript / 9.06~dfsg-2+deb8u7

CVE-2016-7976.patch Patch series | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
Description: CVE-2016-7976: Various userparams allow %pipe% in paths, allowing remote shell command execution
Origin: backport, http://git.ghostscript.com/?p=ghostpdl.git;h=6d444c273da5499a4cd72f21cb6d4c9a5256807d
Bug: http://bugs.ghostscript.com/show_bug.cgi?id=697178
Bug-Debian: https://bugs.debian.org/839260
Forwarded: not-needed
Author: Salvatore Bonaccorso <carnil@debian.org>
Last-Update: 2016-10-07
---

--- a/base/gsicc_manage.c
+++ b/base/gsicc_manage.c
@@ -916,9 +916,12 @@ gsicc_open_search(const char* pname, int
     }
 
     /* First just try it like it is */
-    str = sfopen(pname, "rb", mem_gc);
-    if (str != NULL)
-        return(str);
+    if (gs_check_file_permission(mem_gc, pname, namelen, "r") >= 0) {
+        str = sfopen(pname, "r", mem_gc);
+        if (str != NULL) {
+            return(str);
+        }
+    }
 
     /* If that fails, try %rom% */ /* FIXME: Not sure this is needed or correct */
                                    /* A better approach might be to have built in defaults */
--- a/base/gslibctx.c
+++ b/base/gslibctx.c
@@ -111,6 +111,7 @@ int gs_lib_ctx_init( gs_memory_t *mem )
     pio->profiledir_len = 0;
     gs_lib_ctx_set_icc_directory(mem, DEFAULT_DIR_ICC, strlen(DEFAULT_DIR_ICC));
  
+    pio->client_check_file_permission = NULL;
     gp_get_realtime(pio->real_time_0);
 
     return 0;
@@ -192,3 +193,13 @@ void errflush(const gs_memory_t *mem)
         fflush(mem->gs_lib_ctx->fstderr);
     /* else nothing to flush */
 }
+
+int
+gs_check_file_permission (gs_memory_t *mem, const char *fname, const int len, const char *permission)
+{
+    int code = 0;
+    if (mem->gs_lib_ctx->client_check_file_permission != NULL) {
+        code = mem->gs_lib_ctx->client_check_file_permission(mem, fname, len, permission);
+    }
+    return code;
+}
--- a/base/gslibctx.h
+++ b/base/gslibctx.h
@@ -27,6 +27,9 @@ typedef struct name_table_s *name_table_
 #  define gs_font_dir_DEFINED
 typedef struct gs_font_dir_s gs_font_dir;
 #endif
+
+typedef int (*client_check_file_permission_t) (gs_memory_t *mem, const char *fname, const int len, const char *permission);
+
 typedef struct gs_lib_ctx_s
 {
     gs_memory_t *memory;  /* mem->gs_lib_ctx->memory == mem */
@@ -54,6 +57,7 @@ typedef struct gs_lib_ctx_s
     bool dict_auto_expand;  /* ps dictionary: false level 1 true level 2 or 3 */
     /* A table of local copies of the IODevices */
     struct gx_io_device_s **io_device_table;
+    client_check_file_permission_t client_check_file_permission;
     /* Define the default value of AccurateScreens that affects setscreen
        and setcolorscreen. */
     bool screen_accurate_screens;
@@ -91,4 +95,7 @@ gs_memory_t * gs_lib_ctx_get_non_gc_memo
 void gs_lib_ctx_set_icc_directory(const gs_memory_t *mem_gc, const char* pname,
                         int dir_namelen);
 
+int
+gs_check_file_permission (gs_memory_t *mem, const char *fname, const int len, const char *permission);
+
 #endif /* GSLIBCTX_H */
--- a/psi/imain.c
+++ b/psi/imain.c
@@ -51,6 +51,7 @@
 #include "ivmspace.h"
 #include "idisp.h"              /* for setting display device callback */
 #include "iplugin.h"
+#include "zfile.h"
 
 /* ------ Exported data ------ */
 
@@ -196,6 +197,7 @@ gs_main_init1(gs_main_instance * minst)
                                            "the_gs_name_table");
             if (code < 0)
                 return code;
+            mem->gs_lib_ctx->client_check_file_permission = z_check_file_permissions;
         }
         code = obj_init(&minst->i_ctx_p, &idmem);  /* requires name_init */
         if (code < 0)
--- a/psi/int.mak
+++ b/psi/int.mak
@@ -2044,7 +2044,8 @@ $(PSOBJ)imain.$(OBJ) : $(PSSRC)imain.c $
  $(ialloc_h) $(iconf_h) $(idebug_h) $(idict_h) $(idisp_h) $(iinit_h)\
  $(iname_h) $(interp_h) $(iplugin_h) $(isave_h) $(iscan_h) $(ivmspace_h)\
  $(iinit_h) $(main_h) $(oper_h) $(ostack_h)\
- $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h)
+ $(sfilter_h) $(store_h) $(stream_h) $(strimpl_h) $(zfile_h)\
+ $(INT_MAK) $(MAKEDIRS)
 	$(PSCC) $(PSO_)imain.$(OBJ) $(C_) $(PSSRC)imain.c
 
 #****** $(CCINT) interp.c
--- a/psi/zfile.c
+++ b/psi/zfile.c
@@ -197,6 +197,25 @@ check_file_permissions(i_ctx_t *i_ctx_p,
     return check_file_permissions_reduced(i_ctx_p, fname_reduced, rlen, permitgroup);
 }
 
+/* z_check_file_permissions: see zfile.h for explanation
+ */
+int
+z_check_file_permissions(gs_memory_t *mem, const char *fname, const int len, const char *permission)
+{
+    i_ctx_t *i_ctx_p = get_minst_from_memory(mem)->i_ctx_p;
+    gs_parsed_file_name_t pname;
+    const char *permitgroup = permission[0] == 'r' ? "PermitFileReading" : "PermitFileWriting";
+    int code = gs_parse_file_name(&pname, fname, len, imemory);
+    if (code < 0)
+        return code;
+
+    if (pname.iodev && i_ctx_p->LockFilePermissions && strcmp(pname.iodev->dname, "%pipe%") == 0)
+        return gs_error_invalidfileaccess;
+        
+    code = check_file_permissions(i_ctx_p, fname, len, permitgroup);
+    return code;
+}
+
 /* <name_string> <access_string> file <file> */
 int                             /* exported for zsysvm.c */
 zfile(i_ctx_t *i_ctx_p)
--- a/psi/zfile.h
+++ b/psi/zfile.h
@@ -22,4 +22,11 @@
 int zopen_file(i_ctx_t *i_ctx_p, const gs_parsed_file_name_t *pfn,
            const char *file_access, stream **ps, gs_memory_t *mem);
 
+/* z_check_file_permissions: a callback (via mem->gs_lib_ctx->client_check_file_permission)
+ * to allow applying the above permissions checks when opening file(s) from
+ * the graphics library
+ */
+int
+z_check_file_permissions(gs_memory_t *mem, const char *fname,
+                                 const int len, const char *permission);
 #endif