Blob Blame History Raw
From 1a318dca70b3396e5a8813ff83cc6430f61ead2f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
Date: Tue, 1 Nov 2016 14:49:50 +0100
Subject: [PATCH] Save image without a shell
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When saving into an image format, a shell meta-characters in a file
name could clash with a shell used to execute convert command.

This patch replaces the system() calls with safert IPC::Run3 calls.

<https://sourceforge.net/p/gscan2pdf/bugs/233/>

Signed-off-by: Petr Písař <ppisar@redhat.com>
---
 Makefile.PL               |  1 +
 lib/Gscan2pdf/Document.pm | 44 +++++++++++++++++++++++++++++++++-----------
 2 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/Makefile.PL b/Makefile.PL
index 937a023..f4fac2e 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -49,6 +49,7 @@ WriteMakefile(
         Gtk2::Ex::Simple::List => 0,
         Gtk2::ImageView        => 0,
         Image::Magick          => 0,
+        IPC::Run3              => 0,
         Locale::gettext        => 1.05,
         Config::General        => 2.40,
         PDF::API2              => 0,
diff --git a/lib/Gscan2pdf/Document.pm b/lib/Gscan2pdf/Document.pm
index 809cf72..c0e3eed 100644
--- a/lib/Gscan2pdf/Document.pm
+++ b/lib/Gscan2pdf/Document.pm
@@ -24,6 +24,7 @@ use Archive::Tar;                    # For session files
 use Proc::Killfam;
 use Locale::gettext 1.05;            # For translations
 use IPC::Open3 'open3';
+use IPC::Run3 ();
 use Symbol;                          # for gensym
 use Try::Tiny;
 use Set::IntSpan 1.10;               # For size method for page numbering issues
@@ -2621,17 +2622,38 @@ sub _thread_rotate {
     return;
 }
 
+sub _exec_command {
+    my ($pidfile, $command) = @_;
+
+    open(my $fh, '>', $pidfile) or return -1;
+    $fh->print($PROCESS_ID);
+    close($fh) or return -1;
+
+    $logger->info(join(' ', @$command));
+    IPC::Run3::run3($command, undef, undef, undef,
+        { return_if_system_error => 1 });
+    if ($? == 0) {
+        return 0;
+    }
+
+    if ($? == -1) {
+        $logger->info("Could not execute the command: $!");
+    } elsif ($? & 127) {
+        $logger->info("Command died with signal " . ($? & 127));
+    } else {
+        $logger->info("Command failed with exit code " . ($? >> 8));
+    }
+    return -1;
+}
+
 sub _thread_save_image {
     my ( $self, $path, $list_of_pages, $pidfile ) = @_;
 
-    # Escape quotes and spaces
-    $path =~ s/(['" ])/\\$1/gxsm;
-
     if ( @{$list_of_pages} == 1 ) {
-        my $cmd =
-"convert $list_of_pages->[0]{filename} -density $list_of_pages->[0]{resolution} $path";
-        $logger->info($cmd);
-        my $status = system "echo $PROCESS_ID > $pidfile;$cmd";
+        my $status = _exec_command($pidfile,
+            ['convert', $list_of_pages->[0]{filename}, '-density',
+                $list_of_pages->[0]{resolution}, $path]
+        );
         return if $_self->{cancel};
         if ($status) {
             $self->{status}  = 1;
@@ -2643,10 +2665,10 @@ sub _thread_save_image {
         my $i = 1;
         foreach ( @{$list_of_pages} ) {
             $current_filename = sprintf $path, $i++;
-            my $cmd = sprintf 'convert %s -density %d %s',
-              $_->{filename}, $_->{resolution},
-              $current_filename;
-            my $status = system "echo $PROCESS_ID > $pidfile;$cmd";
+            my $status = _exec_command($pidfile,
+                ['convert',  $_->{filename}, '-density', $_->{resolution},
+                    $current_filename]
+            );
             return if $_self->{cancel};
             if ($status) {
                 $self->{status}  = 1;
-- 
2.7.4