Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use Win32::ShellQuote for kpsewhich #2297

Merged
merged 2 commits into from
Jan 28, 2024

Conversation

xworld21
Copy link
Contributor

@xworld21 xworld21 commented Jan 4, 2024

Better fix for #2293: after adding some Windows-specific escaping, kpsewhich can be called with arbitrary file names, even with special characters, and so pathname_is_nasty can be removed altogether. This supersedes #2295, #2294.

The if (open(my $resfh, '-|', ...)) block can definitely be useful elsewhere. In Util::Pathname, there are two backticks left, and there are a few other not-quite-safe system calls in other modules. However, @brucemiller @dginev you should decide if and how to make that happen, e.g. a new Util module maybe?

Copy link
Collaborator

@dginev dginev left a comment

Choose a reason for hiding this comment

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

It's great you took the effort to make sure escaping works correctly in Windows - much appreciated!

I have warmed up to the idea of dispensing with the pathname_is_nasty function entirely, and avoid the class of problems from discarding too many paths.

Using the -| open pattern in as many places as possible does sound appealing. I would also defer to @brucemiller on deciding when/where to refactor the remaining bits, since we need to juggle getting the current release out the door.

As far as I'm concerned, this PR looks good to merge!

@dginev dginev requested a review from brucemiller January 4, 2024 19:23
@xworld21
Copy link
Contributor Author

xworld21 commented Jan 4, 2024

It's great you took the effort to make sure escaping works correctly in Windows - much appreciated!

Side note: it is impossible to escape arguments 100% correctly on Windows, because each binary is responsible for parsing its own command line and while most adopt the same scheme, Cygwin, MSYS2, etc sometimes do things differently, or so I hear. When it comes to kpsewhich, I understand that both MikTeX and TeX Live are built with Visual Studio, so they should be using CommandLineToArgvW under the hood. Hence Win32::ShellQuote is the correct choice for them. With Cygwin, LaTeXML is already 100% broken so let's not think about it.

The important thing is that the -| pattern with a list of arguments is guaranteed to execute the binary directly, with no risk of creating pipes, redirections, etc. so it is safe in all settings. Well, unless you know how to exploit kpsewhich (the Cygwin one!) with a weird command line argument...

# on Windows, command arguments are joined in a space-separated list to be parsed by CommandLineToArgvW
# thus calling open FILEHANDLE,MODE,EXPR,LIST is not safe in the presence of special characters
# Win32::ShellQuote::quote_system_list escapes the arguments according to CommandLineToArgvW
# WARNING: per documentation, 'you must ensure you have more than one item being quoted for the list to be usable'
Copy link
Owner

Choose a reason for hiding this comment

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

Have we ensured that? I'm unclear what this warning means. Should we only call quote_system_list when scalar(@_) > 1 or ...?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should we only call quote_system_list when scalar(@_) > 1 or ...?

Yes. This is a maddening Perl quirk. To trigger the safe call you must use open FILEHANDLE,MODE,EXPR,LIST, in which case EXPR is treated as the binary file name, no parsing.

However, if LIST is empty, the call becomes open FILEHANDLE,MODE,EXPR and Perl uses heuristics to decide if EXPR is a command line (e.g. contains >/dev/null) and possibly runs a shell on it.

So safe calls are guaranteed only when (EXPR,LIST) has length at least 2. At least that's what the Win32::ShellQuote author says: https://metacpan.org/release/HAARG/Win32-ShellQuote-0.003001/view/lib/Win32/ShellQuote.pm#quote_system_list

Copy link
Owner

Choose a reason for hiding this comment

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

OK, I think I understand; the comments are somewhat confusing out of context. So, basically, we must have both $kpsewhich and @candidates to get the proper call. And in fact we check that in the 2nd line of pathname_kpsewhich; Although arguably that line might be safer in hindsight as

return unless $kpsewhich && grep { $_; } @candidates;

And moreover this may be a case where it's clearer not to pull pathname_quote_system_list out as a separate sub, but embed it within pathname_kpsewhich. (so nobody's tempted to export it and call with less tested args).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, I moved the code around and updated the comments, hopefully for the better. The 2nd line of pathname_kpsewhich is ok: for the purposes of calling open safely, return unless @candidates would already be enough (that is to say, empty or even undefined arguments are fine, it's all about the length of @candidates).

@xworld21 xworld21 force-pushed the win32-shellquote-kpsewhich branch from fd20ee8 to 8ecd60b Compare January 7, 2024 13:48
The call to kpsewhich can now receive arbitrary arguments safely on all
platforms.
@xworld21 xworld21 force-pushed the win32-shellquote-kpsewhich branch from 8ecd60b to 4bf8291 Compare January 7, 2024 13:51
@brucemiller brucemiller linked an issue Jan 28, 2024 that may be closed by this pull request
Copy link
Owner

@brucemiller brucemiller left a comment

Choose a reason for hiding this comment

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

Looks good; Thanks for this!!

@brucemiller brucemiller merged commit aef0bc2 into brucemiller:master Jan 28, 2024
13 checks passed
@xworld21 xworld21 deleted the win32-shellquote-kpsewhich branch January 28, 2024 18:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

kpsewhich fails if parent directory contains parentheses
3 participants