[gparted] Add ability for small writes to stdin of child processes (#795617)



commit 8dff80edc65b2923b400ddadebacf9bcf378d09f
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date:   Fri Oct 20 19:47:00 2017 +0100

    Add ability for small writes to stdin of child processes (#795617)
    
    As discussed in "LUKS password handling, threats and preventative
    measures" [1] GParted must be able to pass LUKS passphrases to
    cryptsetup via standard input to avoid having to write passwords to the
    file system and deal with additional security requirements.  Therefore
    add a way to write input into created child processes.  For small
    amounts of input, writing up to the pipe buffer capacity won't block
    [2].  This is 64K on versions of Linux in any currently supported
    distributions.
    
    [1] LUKS password handling, threats and preventative measures
        https://bugzilla.gnome.org/show_bug.cgi?id=627701#c56
    
        GParted must not become a password manage so it must never save
        LUKS passwords to disk across separate invocations of GParted.
        ...
    
        GParted should avoid writing a temporary file containing the LUKS
        password as it introduces extra complexity with trying to safely
        handle and erase file content.  Instead GParted must
        programmatically pass the LUKS password via standard input to the
        cryptsetup command.
    
    [2] pipe(7) manual page:
    
        Pipe capacity
            A pipe has a limited capacity.  If the pipe is full, then a
            write(2) will block or fail, depending on whether the O_NONBLOCK
            flag is set (see below).  ...
    
            In Linux versions before 2.6.11, the capacity of a pipe was the
            same as the system page size (e.g., 4096 bytes on i386).  Since
            Linux 2.6.11, the pipe capacity is 65536 bytes.
    
    Bug 795617 - Implement opening and closing of LUKS mappings

 include/Utils.h |    5 +++++
 src/Utils.cc    |   27 +++++++++++++++++++++++++--
 2 files changed, 30 insertions(+), 2 deletions(-)
---
diff --git a/include/Utils.h b/include/Utils.h
index 0f10902..93402ae 100644
--- a/include/Utils.h
+++ b/include/Utils.h
@@ -153,6 +153,11 @@ public:
                                    Glib::ustring & output,
                                    Glib::ustring & error,
                                    bool use_C_locale = false ) ;
+       static int execute_command( const Glib::ustring & command,
+                                   const char * input,
+                                   Glib::ustring & output,
+                                   Glib::ustring & error,
+                                   bool use_C_locale = false );
        static int get_failure_status( Glib::SpawnError & e );
        static int decode_wait_status( int wait_status );
        static Glib::ustring regexp_label( const Glib::ustring & text
diff --git a/src/Utils.cc b/src/Utils.cc
index a955f6a..b0d26cd 100644
--- a/src/Utils.cc
+++ b/src/Utils.cc
@@ -32,6 +32,8 @@
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <string.h>
+#include <unistd.h>
 
 namespace GParted
 {
@@ -515,7 +517,7 @@ double Utils::sector_to_unit( Sector sectors, Byte_Value sector_size, SIZE_UNIT
 int Utils::execute_command( const Glib::ustring & command )
 {
        Glib::ustring dummy ;
-       return execute_command( command, dummy, dummy ) ;
+       return execute_command( command, NULL, dummy, dummy );
 }
 
 class CommandStatus
@@ -580,7 +582,17 @@ int Utils::execute_command( const Glib::ustring & command,
                            Glib::ustring & error,
                            bool use_C_locale )
 {
+       return execute_command( command, NULL, output, error, use_C_locale );
+}
+
+int Utils::execute_command( const Glib::ustring & command,
+                            const char * input,
+                            Glib::ustring & output,
+                            Glib::ustring & error,
+                            bool use_C_locale )
+{
        Glib::Pid pid;
+       int in = -1;
        // set up pipes for capture
        int out, err;
        CommandStatus status;
@@ -595,7 +607,7 @@ int Utils::execute_command( const Glib::ustring & command,
                        Glib::SPAWN_DO_NOT_REAP_CHILD | Glib::SPAWN_SEARCH_PATH,
                        use_C_locale ? sigc::ptr_fun( set_locale ) : sigc::slot< void >(),
                        &pid,
-                       0,
+                       ( input != NULL ) ? &in : 0,
                        &out,
                        &err );
        } catch (Glib::SpawnError &e) {
@@ -616,6 +628,17 @@ int Utils::execute_command( const Glib::ustring & command,
        outputcapture.connect_signal();
        errorcapture.connect_signal();
 
+       if ( input != NULL && in != -1 )
+       {
+               // Write small amount of input to pipe to the child process.  Linux will
+               // always accept up 4096 bytes without blocking.  See pipe(7).
+               size_t len = strlen( input );
+               ssize_t written = write( in, input, len );
+               if ( written == -1 || (size_t)written < len )
+                       std::cerr << "Write to child failed: " << Glib::strerror( errno ) << std::endl;
+               close( in );
+       }
+
        if( status.foreground)
                Gtk::Main::run();
        else {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]