Skip to content

Commit

Permalink
use Win32::ShellQuote for kpsewhich (#2297)
Browse files Browse the repository at this point in the history
* escape kpsewhich arguments on Windows

* remove pathname_is_nasty defensive checks

The call to kpsewhich can now receive arbitrary arguments safely on all
platforms.
  • Loading branch information
xworld21 authored Jan 28, 2024
1 parent 6ee12be commit aef0bc2
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 12 deletions.
4 changes: 3 additions & 1 deletion Makefile.PL
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,11 @@ WriteMakefile(NAME => 'LaTeXML',
'URI' => 0,
'version' => 0,
# Windows terminal handling (see Common::Error)
# Windows argument escaping (see Util::Pathname)
($^O eq 'MSWin32'
? ('Win32::Console' => 0,
'Win32::Console::ANSI' => 0)
'Win32::Console::ANSI' => 0,
'Win32::ShellQuote' => 0)
: ()),
# If we have an "old" version of XML::LibXML,
# we also need XPathContext.
Expand Down
11 changes: 2 additions & 9 deletions lib/LaTeXML/Package.pm
Original file line number Diff line number Diff line change
Expand Up @@ -2016,8 +2016,6 @@ sub FindFile_aux {
return $file . '.ltxml' if -f ($file . '.ltxml'); } # No need to search, just check if it exists.
return $file if -f $file; # No need to search, just check if it exists.
return; } # otherwise we're never going to find it.
elsif (pathname_is_nasty($file)) { # If it is a nasty filename, we won't touch it.
return; } # we DO NOT want to pass this to kpathse or such!

# Note that the strategy is complicated by the fact that
# (1) we prefer .ltxml bindings, if present
Expand All @@ -2026,7 +2024,7 @@ sub FindFile_aux {
# (4) depending on switches we may EXCLUDE .ltxml OR raw tex OR allow both.
# (5) we may allow interpreting raw TeX/sty/whatever files individually or broadly
# (6) but we may also want to override an apparently "versioned" file, preferring the ltxml
my $paths = LookupValue('SEARCHPATHS');
my $paths = LookupValue('SEARCHPATHS') // [];
my $urlbase = LookupValue('URLBASE');
my $nopaths = LookupValue('REMOTE_REQUEST');
my $ltxml_paths = $nopaths ? [] : $paths;
Expand All @@ -2053,8 +2051,7 @@ sub FindFile_aux {
# Otherwise, pass on to kpsewhich
# Depending on flags, maybe search for ltxml in texmf or for plain tex in ours!
# The main point, though, is to we make only ONE (more) call.
return if grep { pathname_is_nasty($_) } @$paths; # SECURITY! No nasty paths in cmdline
# Do we need to sanitize these environment variables?
# Do we need to sanitize these environment variables?
my @candidates = (((!$options{noltxml} && !$nopaths) ? ("$file.ltxml") : ()),
(!$options{notex} ? ($file) : ()));
local $ENV{TEXINPUTS} = join($Config::Config{'path_sep'},
Expand Down Expand Up @@ -2138,10 +2135,6 @@ sub FindFile_fallback {
else {
return; } }

sub pathname_is_nasty {
my ($pathname) = @_;
return $pathname =~ /[^\w\-_\+\=\/\\\.~\:\s]/; }

sub maybeReportSearchPaths {
if (LookupValue('SEARCHPATHS_REPORTED')) {
return (); }
Expand Down
15 changes: 13 additions & 2 deletions lib/LaTeXML/Util/Pathname.pm
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ our @EXPORT = qw( &pathname_find &pathname_findall &pathname_kpsewhich
&pathname_cwd &pathname_chdir &pathname_mkdir &pathname_copy
&pathname_installation);

my $ISWINDOWS;

BEGIN {
$ISWINDOWS = $^O =~ /^(MSWin|NetWare|cygwin)/i;
require Win32::ShellQuote if $ISWINDOWS;
}

# NOTE: For absolute pathnames, the directory component starts with
# whatever File::Spec considers to be the volume, or "/".
#======================================================================
Expand All @@ -54,7 +61,6 @@ our @EXPORT = qw( &pathname_find &pathname_findall &pathname_kpsewhich
### my $SEP = '/'; # [CONSTANT]
# Some indicators that this is not sufficient? (calls to libraries/externals???)
# PRELIMINARY test, probably need to be even more careful
my $ISWINDOWS = $^O =~ /^(MSWin|NetWare|cygwin)/i;
my $SEP = ($ISWINDOWS ? '\\' : '/'); # [CONSTANT]
my $KPATHSEP = ($ISWINDOWS ? ';' : ':'); # [CONSTANT]
my $LITERAL_RE = '(?:literal)(?=:)'; # [CONSTANT]
Expand Down Expand Up @@ -391,6 +397,8 @@ our $kpse_toolchain = "";

sub pathname_kpsewhich {
my (@candidates) = @_;
# ($kpsewhich,@candidates) MUST NOT be empty to guarantee that Perl runs $kpsewhich directly
# rather than through a shell or cmd.exe
return unless $kpsewhich && @candidates;
build_kpse_cache() unless $kpse_cache;
foreach my $file (@candidates) {
Expand All @@ -400,7 +408,10 @@ sub pathname_kpsewhich {
# For multiple calls, this is slower in general. But MiKTeX, eg., doesn't use texmf ls-R files!
if ($kpse_toolchain) {
push(@candidates, $kpse_toolchain); }
if ($kpsewhich && open(my $resfh, '-|', $kpsewhich, @candidates)) {
if ($kpsewhich && open(my $resfh, '-|',
# on Windows, ($kpsewhich, @candidates) is joined into a single string, which most binaries
# parse with CommandLineToArgvW, so the arguments must be escaped accordingly
$ISWINDOWS ? Win32::ShellQuote::quote_system_list($kpsewhich, @candidates) : ($kpsewhich, @candidates))) {
my $result = <$resfh>; # we only need the first line
{ local $/; <$resfh>; } # discard the rest of the output
close($resfh); # ignore exit status (only one of @candidates exists, usually)
Expand Down

0 comments on commit aef0bc2

Please sign in to comment.