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
This commit is contained in:
Mike Fleetwood 2017-10-20 19:47:00 +01:00 committed by Curtis Gedak
parent 9b52666bdb
commit 8dff80edc6
2 changed files with 30 additions and 2 deletions

View File

@ -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

View File

@ -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
@ -579,8 +581,18 @@ int Utils::execute_command( const Glib::ustring & command,
Glib::ustring & output,
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 {