>From 917f94bf3f4f298adbadeb5b51cd6531a8c31770 Mon Sep 17 00:00:00 2001 From: Bernhard R. Link Date: Sun, 30 May 2010 14:23:17 +0200 Subject: start gs in a safe working directory Bug-Debian: http://bugs.debian.org/583316 Start ghostscript in a dedicated directory to avoid any security problems due to gs looking in the current directory for all files. Most of this patch is adding an option so users can switch this off in the theoretical case of having files that need to access other files in the currect directory. --- src/Ghostview.c | 11 +++++++++++ src/Ghostview.h | 3 +++ src/GhostviewP.h | 1 + src/Makefile.in | 1 + src/doc_misc.c | 5 +++-- src/doc_misc.h | 3 ++- src/gv_layout_res.dat | 2 ++ src/gv_misc_res.dat | 1 + src/main.c | 4 ++++ src/main_globals.h | 1 + src/main_resources.h | 1 + src/misc.c | 15 ++++++--------- src/options_gs.c | 19 +++++++++++++++---- src/process.c | 6 ++++++ src/ps.c | 13 ++++++++++--- src/ps.h | 3 ++- src/save.c | 2 +- src/zoom.c | 2 ++ 18 files changed, 72 insertions(+), 21 deletions(-) diff --git a/src/Ghostview.c b/src/Ghostview.c index 53607c8..dfce99e 100644 --- a/src/Ghostview.c +++ b/src/Ghostview.c @@ -162,6 +162,8 @@ static XtResource resources[] = { offset(pref_width), XtRImmediate, (XtPointer)1}, {XtNpreferredHeight, XtCPreferredHeight, XtRDimension, sizeof(Dimension), offset(pref_height), XtRImmediate, (XtPointer)1}, + {XtNsafeDir, XtCSafeDir, XtRBoolean, sizeof(Boolean), + offset(safeDir), XtRImmediate, (XtPointer)True }, {XtNsafer, XtCSafer, XtRBoolean, sizeof(Boolean), offset(safer), XtRImmediate, (XtPointer)True }, {XtNinterpreter, XtCInterpreter, XtRString, sizeof(String), @@ -960,6 +962,7 @@ SetValues(Widget current, Widget request, Widget new, ArgList unused1, Cardinal (cgvw->ghostview.quiet != ngvw->ghostview.quiet) || (cgvw->ghostview.infoVerbose != ngvw->ghostview.infoVerbose) || (cgvw->ghostview.safer != ngvw->ghostview.safer) || + (cgvw->ghostview.safeDir != ngvw->ghostview.safeDir) || strcmp(cfilename, rfilename) || (cgvw->ghostview.orientation != ngvw->ghostview.orientation) || (cgvw->ghostview.use_bpixmap != ngvw->ghostview.use_bpixmap) || @@ -1544,6 +1547,14 @@ StartInterpreter(w) close(std_in[0]); # endif } + if (gvw->ghostview.safeDir) { + if (chdir(GV_LIBDIR "/safe-gs-workdir") != 0) { + sprintf(buf, "Chdir to %s failed", + GV_LIBDIR "/safe-gs-workdir"); + perror(buf); + _exit(EXIT_STATUS_ERROR); + } + } execvp(argv[0], argv); sprintf(buf, "Exec of %s failed", argv[0]); perror(buf); diff --git a/src/Ghostview.h b/src/Ghostview.h index dfa5c38..6d6eff4 100644 --- a/src/Ghostview.h +++ b/src/Ghostview.h @@ -66,6 +66,7 @@ palette Palette Palette Color quiet Quiet Boolean True rightMargin Margin int 0 + safeDir SafeDir Boolean True safer Safer Boolean True topMargin Margin int 0 urx BoundingBox Int 612 @@ -102,6 +103,7 @@ #define XtNtopMargin "topMargin" #define XtNpreferredWidth "preferredWidth" #define XtNpreferredHeight "preferredHeight" +#define XtNsafeDir "safeDir" #define XtNsafer "safer" #define XtNinterpreter "interpreter" @@ -116,6 +118,7 @@ #define XtCPreferredWidth "PreferredWidth" #define XtCPreferredHeight "PreferredHeight" #define XtCSafer "Safer" +#define XtCSafeDir "SafeDir" #define XtCInterpreter "Interpreter" #if 0 diff --git a/src/GhostviewP.h b/src/GhostviewP.h index 4c014c0..380ed58 100644 --- a/src/GhostviewP.h +++ b/src/GhostviewP.h @@ -71,6 +71,7 @@ typedef struct { String interpreter; Boolean quiet; int infoVerbose; + Boolean safeDir; Boolean safer; Boolean use_bpixmap; String arguments; diff --git a/src/Makefile.in b/src/Makefile.in index 92b4447..dc81924 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -714,6 +714,7 @@ $(srcdir)/gv_intern_res_unix.dat : @echo "GV.gsCmdConvPDF: gs -dNOPAUSE -dQUIET -dBATCH -sDEVICE=pswrite -sOutputFile=%s -f %s -c save pop quit" >> $(srcdir)/gv_intern_res_unix.dat @echo "GV.gsX11Device: -sDEVICE=x11" >> $(srcdir)/gv_intern_res_unix.dat @echo "GV.gsX11AlphaDevice: -sDEVICE=x11 -dTextAlphaBits=4 -dGraphicsAlphaBits=2 -dMaxBitmap=10000000 -dNOPLATFONTS" >> $(srcdir)/gv_intern_res_unix.dat + @echo "GV.gsSafeDir: True" >> $(srcdir)/gv_intern_res_unix.dat @echo "GV.gsSafer: True" >> $(srcdir)/gv_intern_res_unix.dat @echo "GV.gsQuiet: True" >> $(srcdir)/gv_intern_res_unix.dat @echo "GV.infoVerbose: Warnings" >> $(srcdir)/gv_intern_res_unix.dat diff --git a/src/doc_misc.c b/src/doc_misc.c index e556523..5cee169 100644 --- a/src/doc_misc.c +++ b/src/doc_misc.c @@ -55,7 +55,7 @@ extern Media* gv_medias; /*##################################################################*/ int -doc_scanFile(fPP,docP,filename,filename_raw,filename_dscP,cmd_scan_pdf,filename_uncP,cmd_uncompress,scanstyle) +doc_scanFile(fPP,docP,filename,filename_raw,filename_dscP,cmd_scan_pdf,filename_uncP,cmd_uncompress,scanstyle,gv_gs_safeDir) FILE ** fPP; Document *docP; String filename; @@ -65,6 +65,7 @@ doc_scanFile(fPP,docP,filename,filename_raw,filename_dscP,cmd_scan_pdf,filename_ String *filename_uncP; String cmd_uncompress; int scanstyle; + int gv_gs_safeDir; { Document d; int i,ret; @@ -73,7 +74,7 @@ doc_scanFile(fPP,docP,filename,filename_raw,filename_dscP,cmd_scan_pdf,filename_ d = (Document)NULL; ret = 0; if (*fPP && filename) - d = psscan(fPP,filename,filename_raw,filename_dscP,cmd_scan_pdf,filename_uncP,cmd_uncompress,scanstyle); + d = psscan(fPP,filename,filename_raw,filename_dscP,cmd_scan_pdf,filename_uncP,cmd_uncompress,scanstyle,gv_gs_safeDir); if (d) { d->labels_useful=0; d->structured =0; diff --git a/src/doc_misc.h b/src/doc_misc.h index 3293a44..0b8bb22 100644 --- a/src/doc_misc.h +++ b/src/doc_misc.h @@ -43,7 +43,8 @@ extern int doc_scanFile ( String, String*, String, - int /* scanstyle */ + int, /* scanstyle */ + int /* gv_gs_safeDir */ #endif ); diff --git a/src/gv_layout_res.dat b/src/gv_layout_res.dat index 51b6b82..a4eac30 100644 --- a/src/gv_layout_res.dat +++ b/src/gv_layout_res.dat @@ -398,6 +398,8 @@ GV*optiongsPopup*layout:\ $bs\ gsFrame<+[1]-95%*>\ $ss\ + safeDir\ + $ss\ safer\ $ss\ quiet\ diff --git a/src/gv_misc_res.dat b/src/gv_misc_res.dat index ab0adaf..23a05f1 100644 --- a/src/gv_misc_res.dat +++ b/src/gv_misc_res.dat @@ -358,6 +358,7 @@ GV*saveDirLabel.label: Save Directory GV*scalesLabel.label: Scales GV*scaleBaseLabel.label: Scale Base +GV*safeDir.label: SafeDir GV*safer.label: Safer GV*quiet.label: Quiet GV*defaults.label: System Defaults diff --git a/src/main.c b/src/main.c index 3f61cf6..6f8864e 100644 --- a/src/main.c +++ b/src/main.c @@ -1132,6 +1132,8 @@ int main(argc, argv) Boolean b; n=0; XtSetArg(args[n], XtNinterpreter,gv_gs_interpreter); n++; + b = gv_gs_safeDir ? True : False; + XtSetArg(args[n], XtNsafeDir,b); n++; b = gv_gs_safer ? True : False; XtSetArg(args[n], XtNsafer,b); n++; b = gv_gs_quiet ? True : False; @@ -1388,6 +1390,8 @@ void main_setGhostscriptResources(db) main_setInternResource(db,&gv_gs_x11_device,"gsX11Device"); main_setInternResource(db,&gv_gs_x11_alpha_device,"gsX11AlphaDevice"); main_setInternResource(db,&gv_gs_arguments,"gsArguments"); + s = resource_getResource(db,gv_class,gv_name,"gsSafeDir",NULL); + if (!strcasecmp(s,"true")) gv_gs_safeDir = 1; else gv_gs_safeDir = 0; s = resource_getResource(db,gv_class,gv_name,"gsSafer",NULL); if (!strcasecmp(s,"true")) gv_gs_safer = 1; else gv_gs_safer = 0; s = resource_getResource(db,gv_class,gv_name,"gsQuiet",NULL); diff --git a/src/main_globals.h b/src/main_globals.h index 14409fc..55fb52a 100644 --- a/src/main_globals.h +++ b/src/main_globals.h @@ -145,6 +145,7 @@ EXTERN String gv_gs_x11_device; EXTERN String gv_gs_x11_alpha_device; EXTERN String gv_gs_cmd_scan_pdf; /* command used to extract DSC outlines from a pdf file */ EXTERN String gv_gs_cmd_conv_pdf; /* command used to convert a pdf file to ps */ +EXTERN int gv_gs_safeDir; EXTERN int gv_gs_safer; EXTERN int gv_gs_quiet; EXTERN int gv_infoVerbose; diff --git a/src/main_resources.h b/src/main_resources.h index f037f5d..ae7bf99 100644 --- a/src/main_resources.h +++ b/src/main_resources.h @@ -100,6 +100,7 @@ DECLARE_STRING(gsCmdConvPDF) DECLARE_STRING(gsX11Device) DECLARE_STRING(gsX11AlphaDevice) DECLARE_STRING(gsArguments) +DECLARE_STRING(gsSafeDir) DECLARE_STRING(gsSafer) DECLARE_STRING(gsQuiet) diff --git a/src/misc.c b/src/misc.c index 6ef6a9b..1ff4a0c 100644 --- a/src/misc.c +++ b/src/misc.c @@ -29,6 +29,8 @@ ** GNU Project ** */ +/* for canonicalize_file_name: */ +#define _GNU_SOURCE 1 #include "ac_config.h" /* @@ -417,14 +419,9 @@ String misc_changeFile(name) if (!b && file_fileIsNotUseful(p)) sprintf(p,"%s.ps",name); else b = True; if (!b && file_fileIsNotUseful(p)) sprintf(p,"%s.pdf",name); else b = True; if (!b) strcpy(p,name); - dir=file_getDirOfPath(p); - if(strcmp(dir,p)) { - chdir(dir); - /* Strip off directory from p to satisfy GS 8.00 security change */ - q=p; - while(*dir && *dir == *q) {dir++; q++;} - strcpy(p,q); - } + name = canonicalize_file_name(p); + if (name) + p = name; } name = p; INFSMESSAGE(trying to open,name) @@ -912,7 +909,7 @@ setup_ghostview() gv_filename_raw, &gv_filename_dsc,gv_gs_cmd_scan_pdf, &gv_filename_unc,gv_uncompress_command, - gv_scanstyle); + gv_scanstyle, gv_gs_safeDir); { int m; m = gv_pagemedia; diff --git a/src/options_gs.c b/src/options_gs.c index a26acb7..e3fbc4c 100644 --- a/src/options_gs.c +++ b/src/options_gs.c @@ -74,7 +74,7 @@ #include "version.h" static Widget popup=NULL,optionControl; -static Widget quietToggle,saferToggle; +static Widget quietToggle,saferToggle,safeDirToggle; static Widget scan,conv,gs,x11dev,x11alphadev,arguments; static void options_gs_setOptionsAtEntry(void); @@ -103,6 +103,7 @@ static void options_gs_setOptionsAtEntry(void) { BEGINMESSAGE(options_gs_setOptionsAtEntry) + widgets_setToggle(safeDirToggle, gv_gs_safeDir); widgets_setToggle(saferToggle, gv_gs_safer); widgets_setToggle(quietToggle, gv_gs_quiet); @@ -149,7 +150,7 @@ static void options_gs_cb_apply(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { - Arg args[5]; + Arg args[10]; Cardinal n; int i; Boolean reopen=False; @@ -165,6 +166,10 @@ static void options_gs_cb_apply(w, client_data, call_data) gv_gs_safer = SwitchIsSet(saferToggle) ? 1 : 0; if (i != gv_gs_safer) reopen=True; + i = gv_gs_safeDir; + gv_gs_safeDir = SwitchIsSet(safeDirToggle) ? 1 : 0; + if (i != gv_gs_safeDir) reopen=True; + reopen |= options_gs_change(gs,&gv_gs_interpreter,&(free[0])); reopen |= options_gs_change(scan,&gv_gs_cmd_scan_pdf,&(free[1])); options_gs_change(conv,&gv_gs_cmd_conv_pdf,&(free[2])); @@ -176,6 +181,9 @@ static void options_gs_cb_apply(w, client_data, call_data) cb_stopInterpreter(page,NULL,NULL); n=0; XtSetArg(args[n], XtNinterpreter,gv_gs_interpreter); n++; + if (gv_gs_safeDir) XtSetArg(args[n], XtNsafeDir,True); + else XtSetArg(args[n], XtNsafeDir,False); + n++; if (gv_gs_safer) XtSetArg(args[n], XtNsafer,True); else XtSetArg(args[n], XtNsafer,False); n++; @@ -217,8 +225,8 @@ void options_gs_cb_save(w, client_data, call_data) XtPointer client_data, call_data; { int argn = 0; - String argi[10]; - String argv[10]; + String argi[20]; + String argv[20]; String t = "True"; String f = "False"; @@ -233,6 +241,8 @@ void options_gs_cb_save(w, client_data, call_data) options_gs_setArg(x11alphadev,&(argi[argn]),&(argv[argn]),&argn,s_gsX11AlphaDevice ,gv_class); options_gs_setArg(arguments ,&(argi[argn]),&(argv[argn]),&argn,s_gsArguments ,gv_class); + options_setArg(&(argi[argn]),&(argv[argn]),s_gsSafeDir ,gv_class ,SwitchIsSet(safeDirToggle) ? t : f); + ++argn; options_setArg(&(argi[argn]),&(argv[argn]),s_gsSafer ,gv_class ,SwitchIsSet(saferToggle) ? t : f); ++argn; options_setArg(&(argi[argn]),&(argv[argn]),s_gsQuiet ,gv_class ,SwitchIsSet(quietToggle) ? t : f); @@ -291,6 +301,7 @@ void options_gs_create(void) n=0; optionControl = XtCreateManagedWidget("optionControl",aaaWidgetClass,popup,args,n); + safeDirToggle = XtCreateManagedWidget("safeDir",switchWidgetClass,optionControl,NULL,(Cardinal)0); saferToggle = XtCreateManagedWidget("safer",switchWidgetClass,optionControl,NULL,(Cardinal)0); quietToggle = XtCreateManagedWidget("quiet",switchWidgetClass,optionControl,NULL,(Cardinal)0); diff --git a/src/process.c b/src/process.c index a9d4d3d..668932e 100644 --- a/src/process.c +++ b/src/process.c @@ -269,6 +269,12 @@ ProcessData process_fork (name,command,notify_proc,data) */ if (!freopen("/dev/null", "r", stdin)) perror("/dev/null"); + if (gv_gs_safeDir) { + if (chdir(GV_LIBDIR "/safe-gs-workdir") != 0) { + perror("Chdir to " GV_LIBDIR "/safe-gs-workdir failed"); + _exit(EXIT_STATUS_ERROR); + } + } execvp(argv[0], argv); { diff --git a/src/ps.c b/src/ps.c index 417ce08..8b98d53 100644 --- a/src/ps.c +++ b/src/ps.c @@ -323,7 +323,7 @@ static void ps_dynMemExhaust(void) /*###########################################################*/ struct document * -psscan(fileP,filename,filename_raw,filename_dscP,cmd_scan_pdf,filename_uncP,cmd_uncompress,scanstyle) +psscan(fileP,filename,filename_raw,filename_dscP,cmd_scan_pdf,filename_uncP,cmd_uncompress,scanstyle,gv_gs_safeDir) FILE **fileP; char *filename; char *filename_raw; @@ -332,6 +332,7 @@ psscan(fileP,filename,filename_raw,filename_dscP,cmd_scan_pdf,filename_uncP,cmd_ char **filename_uncP; char *cmd_uncompress; int scanstyle; + int gv_gs_safeDir; { FILE *file; struct document *doc; @@ -430,7 +431,7 @@ unc_ok: if (!tmpfile) goto unc_exec_failed; fclose(*fileP); *fileP = tmpfile; - retval = psscan(fileP,filename_unc,filename_raw,filename_dscP,cmd_scan_pdf,NULL,NULL,scanstyle); + retval = psscan(fileP,filename_unc,filename_raw,filename_dscP,cmd_scan_pdf,NULL,NULL,scanstyle, gv_gs_safeDir); #if 0 if (!retval) { sprintf(s,"333 Scanning\n%s\nfailed.",filename_unc); @@ -514,6 +515,12 @@ unc_ok: old_umask = umask(0077); INFMESSAGE(is PDF) + if (gv_gs_safeDir) { + if (chdir(GV_LIBDIR "/safe-gs-workdir") != 0) { + strcpy(s, "Chdir to " GV_LIBDIR "/safe-gs-workdir failed"); + goto scan_failed; + } + } INFSMESSAGE(scan command,cmd) if (system(cmd) || file_fileIsNotUseful(filename_dsc)) { INFMESSAGE(scan subprocess failed) @@ -534,7 +541,7 @@ scan_ok: if (!tmpfile) goto scan_exec_failed; fclose(*fileP); *fileP = tmpfile; - retval = psscan(fileP,filename_dsc,filename_raw,filename_dscP,cmd_scan_pdf,NULL,NULL,scanstyle); + retval = psscan(fileP,filename_dsc,filename_raw,filename_dscP,cmd_scan_pdf,NULL,NULL,scanstyle,gv_gs_safeDir); if (!retval) { sprintf(s,"Scanning\n%s\nfailed.",filename_dsc); goto scan_failed; diff --git a/src/ps.h b/src/ps.h index 808e501..762f5ac 100644 --- a/src/ps.h +++ b/src/ps.h @@ -118,7 +118,8 @@ Document psscan ( char *, char **, char *, - int /* scanstyle */ + int, /* scanstyle */ + int /* gv_gs_scanDir */ #endif ); diff --git a/src/save.c b/src/save.c index dad4652..dda829c 100644 --- a/src/save.c +++ b/src/save.c @@ -270,7 +270,7 @@ save_copyToFile(save_filename,src_filename,pagelist,scanstyle) String s = GV_XtNewString(src_filename); s = file_getUsefulName(s); INFMESSAGE(scanning document) - doc_scanFile(&src_file,&src_doc,src_filename,s,NULL,NULL,NULL,NULL,scanstyle); + doc_scanFile(&src_file,&src_doc,src_filename,s,NULL,NULL,NULL,NULL,scanstyle,gv_gs_safeDir); if (src_doc) { INFMESSAGE(calling pscopydoc) pscopydoc(save_file,src_filename,src_doc,pagelist); diff --git a/src/zoom.c b/src/zoom.c index 49d809d..223c449 100644 --- a/src/zoom.c +++ b/src/zoom.c @@ -171,6 +171,8 @@ zoom_createZoom(w, call_data) XtSetArg(args[n], XtNlxdpi, (1000*p->xdpi)); n++; XtSetArg(args[n], XtNlydpi, (1000*p->ydpi)); n++; XtSetArg(args[n], XtNinterpreter,gv_gs_interpreter); n++; + b = gv_gs_safeDir ? True : False; + XtSetArg(args[n], XtNsafeDir,b); n++; b = gv_gs_safer ? True : False; XtSetArg(args[n], XtNsafer,b); n++; b = gv_gs_quiet ? True : False; -- 1.5.6.5