Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions devel/212_2703.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# 212_2703

## 如何测试
Open Mogan STEM, insert a PS/EPS image, and verify it renders correctly.
To reproduce the bug: use a macOS account whose full name contains a space
(e.g. "John Doe"), then insert a PS/EPS image.

## 2026/02/25 Fix gs path quoting for paths with spaces on macOS

### What
In `gs_utilities.cpp`, replaced `sys_concretize(url)` with `raw_quote(concretize(url))`
for all file paths passed to Ghostscript commands.

### Why
`sys_concretize` backslash-escapes spaces (e.g. `/tmp/path\ with\ spaces/file.eps`),
which the shell handles fine for standalone args. But GS parses option values like
`-sOutputFile=...` as raw strings and does not interpret the backslash, so it splits
at the space. Double-quoting with `raw_quote` fixes this.

### How
Replace `sys_concretize(u)` with `raw_quote(concretize(u))` in `gs_utilities.cpp`.
Same pattern already used in `gs_prefix()` on Windows.
26 changes: 14 additions & 12 deletions src/Plugins/Ghostscript/gs_utilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ gs_image_size (url image, int& w_pt, int& h_pt) {
// reading a ps page
// real eps pages with proper bounding boxes have been recognized
// before this and will have their BoundingBox respected
cmd << sys_concretize (image);
cmd << raw_quote (concretize (image));
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

raw_quote(concretize(image)) is not shell-safe on macOS/Linux: raw_quote just wraps in double quotes and does not escape $, backticks, or ". Since lolly::system::call uses wordexp(..., flags=0) (command substitution enabled), a crafted filename could trigger expansion/command execution. For positional file args, sys_concretize(image) already handles spaces via backslash-escaping while also escaping metacharacters; consider keeping sys_concretize here and only changing the truly GS-option-value cases, or introduce a dedicated safe quoting/escaping helper for wordexp.

Suggested change
cmd << raw_quote (concretize (image));
cmd << sys_concretize (image);

Copilot uses AI. Check for mistakes.
lolly::system::check_stderr (cmd, buf);
if (DEBUG_CONVERT)
debug_convert << "gs cmd :" << cmd << LF << "answer :" << buf;
Expand Down Expand Up @@ -159,18 +159,20 @@ gs_PDFimage_size (url image, int& w_pt, int& h_pt) {
string buf;
string cmd= gs_prefix ();
if (gs_version () >= 9.50)
cmd << "--permit-file-read=" << sys_concretize (image) << " ";
cmd << "--permit-file-read=" << raw_quote (concretize (image)) << " ";
cmd << "-dNODISPLAY -q -sFile=";
cmd << sys_concretize (image);
cmd << raw_quote (concretize (image));
cmd << " pdf_info.ps";
Comment on lines 161 to 165
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using raw_quote(concretize(...)) inside --permit-file-read= / -sFile= is unsafe with the current subprocess implementation: on macOS/Linux lolly::system::call relies on wordexp without WRDE_NOCMD, and raw_quote does not escape $/backticks/", so paths like $(...) can be expanded. Please switch to a shell-safe quoting function (e.g., single-quote with proper escaping, or escape $, `, \, and " inside double quotes) or avoid wordexp for argument splitting.

Copilot uses AI. Check for mistakes.
buf= eval_system (cmd);
if (occurs ("Unrecoverable error", buf)) {
cmd= gs_prefix ();
if (gs_version () >= 9.50)
cmd << "--permit-file-read=" << sys_concretize (image) << " ";
cmd << "--permit-file-read=" << raw_quote (concretize (image)) << " ";
cmd << "-dNODISPLAY -q -sFile=";
cmd << sys_concretize (image);
cmd << " " << sys_concretize ("$TEXMACS_PATH/misc/convert/pdf_info.ps");
cmd << raw_quote (concretize (image));
cmd << " "
<< raw_quote (
concretize (url ("$TEXMACS_PATH/misc/convert/pdf_info.ps")));
buf= eval_system (cmd);
}
if (DEBUG_CONVERT)
Expand Down Expand Up @@ -241,22 +243,22 @@ gs_to_eps (url image,
cmd= gs_prefix ();
cmd << "-dQUIET -dNOPAUSE -dBATCH -dSAFER ";
cmd << "-sDEVICE=" << eps_device ();
cmd << " -sOutputFile=" << sys_concretize (eps) << " ";
cmd << " -sOutputFile=" << raw_quote (concretize (eps)) << " ";
if (suffix (image) == "pdf") {
Comment on lines 244 to 247
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

raw_quote(concretize(eps)) does not escape $/backticks/" and is therefore not safe to embed in a command string that is later parsed by wordexp (used by lolly::system::call on macOS/Linux). This is a potential command-injection vector via crafted filenames/paths. Please use a shell-safe quoting/escaping routine for paths here (or avoid string-based command parsing altogether).

Copilot uses AI. Check for mistakes.
image_size (image, bx2, by2);
bx1= by1= 0;
cmd << "-dUseCropBox "
<< " -dDEVICEWIDTHPOINTS=" << as_string (bx2)
<< " -dDEVICEHEIGHTPOINTS=" << as_string (by2) << " "
<< sys_concretize (image);
<< raw_quote (concretize (image));
}
else {
ps_bounding_box (image, bx1, by1, bx2, by2);
cmd << " -dDEVICEWIDTHPOINTS=" << as_string (bx2 - bx1)
<< " -dDEVICEHEIGHTPOINTS=" << as_string (by2 - by1) << " ";
// don't use -dEPSCrop which works incorrectly if (bx1 != 0 || by1 != 0)
cmd << "-c \" " << as_string (-bx1) << " " << as_string (-by1)
<< " translate gsave \" " << sys_concretize (image)
<< " translate gsave \" " << raw_quote (concretize (image))
<< " -c \" grestore \"";
}
string ans= eval_system (cmd);
Expand All @@ -283,8 +285,8 @@ gs_to_ps (url doc, url ps, bool landscape, double paper_h, double paper_w) {
<< " -dDEVICEHEIGHTPOINTS="
<< as_string ((int) (28.36 * paper_h + 0.5));

cmd << " -sOutputFile=" << sys_concretize (ps) << " ";
cmd << sys_concretize (doc);
cmd << " -sOutputFile=" << raw_quote (concretize (ps)) << " ";
cmd << raw_quote (concretize (doc));
cmd << " -c \"[ /Title (" << as_string (tail (ps)) << ") /DOCINFO pdfmark\" ";
Comment on lines +288 to 290
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new raw_quote(concretize(ps/doc)) usage is not safe with the current subprocess implementation on macOS/Linux: raw_quote does not escape $, backticks, or embedded quotes, and lolly::system::call uses wordexp with command substitution enabled. A malicious filename could be expanded/executed. Please switch to a shell-safe quoting approach (or pass argv without wordexp).

Copilot uses AI. Check for mistakes.

// NOTE: when converting from pdf to ps the title of the document is
Expand All @@ -301,6 +303,6 @@ void
tm_gs (url image) {
string cmd= gs_prefix ();
cmd << "-q -sDEVICE=x11alpha -dBATCH -dNOPAUSE -dSAFER -dNOEPS ";
cmd << sys_concretize (image);
cmd << raw_quote (concretize (image));
lolly::system::call (cmd);
Comment on lines 304 to 307
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

raw_quote(concretize(image)) is not a safe way to quote a path for execution on macOS/Linux because raw_quote does not escape $/backticks/", and lolly::system::call uses wordexp (command substitution enabled). This allows command substitution if an image path contains $(...)/backticks. Please use a shell-safe quoting/escaping function for paths passed to subprocesses.

Copilot uses AI. Check for mistakes.
}