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
|