[gparted] Preview copy operation of encrypted file systems (#774818)



commit 4c70ec3aee7f4b7787eed7ba58322ddc659b0a0f
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date:   Wed Nov 2 22:05:30 2016 +0000

    Preview copy operation of encrypted file systems (#774818)
    
    Implement composing of the copy paste operation for encrypted file
    systems.
    
    Copying a closed LUKS partition would duplicate the LUKS header
    containing the UUID, passphrase and master encryption key.  From a
    security point of view having additional copies of encrypted data with
    the same master key is an extra risk, but it all depends on what is
    going to happen with that copy.  The Cryptsetup FAQ [1] talks about how
    to make a backup at the file system level and block level, preferring
    file system level with separate encryption if needed.  It strongly
    recommends separate encryption if the copy is removable or going
    off-site [2].  Also in the case of cloning the data, cloning the LUKS
    container is strongly discouraged [3].
    
    Therefore copying of encrypted file systems will be implemented by
    copying the file system inside an open LUKS encryption mapping and not
    by copying a closed LUKS partition.
    
    Also, while creating new LUKS encryption is not yet supported, copying
    an encrypted file system into a new partition will not be permitted as
    that will always decrypt the data.  An encrypted file system will be
    allowed to be copied into an existing plain partition, decrypting the
    data, or into an existing open encrypted partition, keeping it
    encrypted.  Pasting over the top of a closed encrypted partition will
    remove the LUKS encryption.  (This is planned to be removed when
    creating and removing LUKS encryption is implemented as part of full
    LUKS read-write support).
    
    Remember that when pasting into an existing partition the file system
    must fit within the available space and that encryption has overhead
    from the LUKS header.  Therefore copying from a plain partition into a
    partition of the same size with open an encryption mapping will not fit
    for space reasons.
    
    [1] The Cryptsetup FAQ, Backup and data Recovery section
    https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions
    
    [2] 6.7 Does a backup compromise security?
    "If you do network-backup or tape-backup, I strongly recommend to go the
    filesystem backup path with independent encryption, as you typically
    cannot reliably delete data in these scenarios, especially in a cloud
    setting."
    
    [3] 6.15 Can I clone a LUKS container?
    "You can, but it breaks security, because the cloned container has the
    same header and hence the same master key.  You cannot change the master
    key on a LUKS container, even if you change the passphrase(s), the
    master key stays the same. That means whoever has access to one of the
    clones can decrypt them all, completely bypassing the passphrases.
    
    The right way to do this is to first luksFormat the target container,
    then to clone the contents of the source container, with both containers
    mapped, i.e. decrypted.  You can clone the decrypted contents of a LUKS
    container in binary mode, although you may run into secondary issues
    with GUIDs in filesystems, partition tables, RAID-components and the
    like. These are just the normal problems binary cloning causes.
    
    Note that if you need to ship (e.g.) cloned LUKS containers with a
    default passphrase, that is fine as long as each container was
    individually created (and hence has its own master key). In this case,
    changing the default passphrase will make it secure again."
    
    Bug 774818 - Implement LUKS read-write actions NOT requiring a
                 passphrase

 src/Win_GParted.cc |  107 ++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 75 insertions(+), 32 deletions(-)
---
diff --git a/src/Win_GParted.cc b/src/Win_GParted.cc
index 028a5ea..6ada585 100644
--- a/src/Win_GParted.cc
+++ b/src/Win_GParted.cc
@@ -1155,13 +1155,21 @@ void Win_GParted::set_valid_operations()
                allow_new( true );
                
                // Find out if there is a partition to be copied and if it fits inside this unallocated space
-               if ( copied_partition != NULL && ! devices[current_device].readonly )
+               // FIXME:
+               // Temporarily disable copying of encrypted content into new partitions
+               // which can't yet be encrypted, until full LUKS read-write support is
+               // implemented.
+               if ( copied_partition             != NULL    &&
+                    ! devices[current_device].readonly      &&
+                    copied_partition->filesystem != FS_LUKS    )
                {
+                       const Partition & copied_filesystem_ptn = 
copied_partition->get_filesystem_partition();
                        Byte_Value required_size ;
-                       if ( copied_partition->filesystem == FS_XFS )
-                               required_size = copied_partition->estimated_min_size() * 
copied_partition->sector_size;
+                       if ( copied_filesystem_ptn.filesystem == FS_XFS )
+                               required_size = copied_filesystem_ptn.estimated_min_size() *
+                                               copied_filesystem_ptn.sector_size;
                        else
-                               required_size = copied_partition->get_byte_length();
+                               required_size = copied_filesystem_ptn.get_byte_length();
 
                        //Determine if space is needed for the Master Boot Record or
                        //  the Extended Boot Record.  Generally an an additional track or MEBIBYTE
@@ -1235,7 +1243,7 @@ void Win_GParted::set_valid_operations()
                        allow_resize( true ) ;
                        
                //only allow copying of real partitions
-               if ( selected_partition_ptr->status == STAT_REAL && fs.copy )
+               if ( selected_partition_ptr->status == STAT_REAL && fs_cap.copy )
                        allow_copy( true ) ;
                
                //only allow labelling of real partitions that support labelling
@@ -1270,10 +1278,11 @@ void Win_GParted::set_valid_operations()
                }
 
                // See if there is a partition to be copied and it fits inside this selected partition
-               if ( copied_partition != NULL &&
-                    copied_partition->get_byte_length() <= selected_partition_ptr->get_byte_length() &&
-                    selected_partition_ptr->status == STAT_REAL &&
-                    *copied_partition != *selected_partition_ptr )
+               if ( copied_partition != NULL                                              &&
+                    ( copied_partition->get_filesystem_partition().get_byte_length() <=
+                      selected_filesystem.get_byte_length()                             ) &&
+                    selected_partition_ptr->status == STAT_REAL                           &&
+                    *copied_partition != *selected_partition_ptr                             )
                        allow_paste( true );
 
                //see if we can somehow check/repair this file system....
@@ -1844,18 +1853,20 @@ void Win_GParted::activate_paste()
                return ;
        }
 
+       const Partition & copied_filesystem_ptn = copied_partition->get_filesystem_partition();
+
        if ( selected_partition_ptr->type == TYPE_UNALLOCATED )
        {
                if ( ! max_amount_prim_reached() )
                {
                        // We don't want the messages, mount points or name of the source
                        // partition for the new partition being created.
-                       Partition * part_temp = copied_partition->clone();
+                       Partition * part_temp = copied_filesystem_ptn.clone();
                        part_temp->clear_messages();
                        part_temp->clear_mountpoints();
                        part_temp->name.clear();
 
-                       Dialog_Partition_Copy dialog( gparted_core.get_fs( copied_partition->filesystem ),
+                       Dialog_Partition_Copy dialog( gparted_core.get_fs( copied_filesystem_ptn.filesystem ),
                                                      *selected_partition_ptr,
                                                      *part_temp );
                        delete part_temp;
@@ -1886,41 +1897,73 @@ void Win_GParted::activate_paste()
        }
        else
        {
+               const Partition & selected_filesystem_ptn = 
selected_partition_ptr->get_filesystem_partition();
+
                bool shown_dialog = false ;
                // VGNAME from mount mount
-               if ( selected_partition_ptr->filesystem == FS_LVM2_PV   &&
-                    ! selected_partition_ptr->get_mountpoint().empty()    )
+               if ( selected_filesystem_ptn.filesystem == FS_LVM2_PV   &&
+                    ! selected_filesystem_ptn.get_mountpoint().empty()    )
                {
                        if ( ! remove_non_empty_lvm2_pv_dialog( OPERATION_COPY ) )
                                return ;
                        shown_dialog = true ;
                }
 
-               Partition * partition_new = selected_partition_ptr->clone();
-               partition_new->alignment = ALIGN_STRICT;
-               partition_new->filesystem = copied_partition->filesystem;
-               partition_new->set_filesystem_label( copied_partition->get_filesystem_label() );
-               partition_new->uuid = copied_partition->uuid;
-               Sector new_size = partition_new->get_sector_length();
-               if ( copied_partition->get_sector_length() == new_size )
+               Partition * partition_new;
+               if ( selected_partition_ptr->filesystem == FS_LUKS && ! selected_partition_ptr->busy )
                {
-                       // Pasting into same size existing partition, therefore only block
-                       // copy operation will be performed maintaining the file system
-                       // size.
-                       partition_new->set_sector_usage(
-                                       copied_partition->sectors_used + copied_partition->sectors_unused,
-                                       copied_partition->sectors_unused );
+                       // Pasting into a closed LUKS encrypted partition will overwrite
+                       // the encryption replacing it with a non-encrypted file system.
+                       // Start with a plain Partition object instead of cloning the
+                       // existing PartitionLUKS object containing a Partition object.
+                       // FIXME:
+                       // Expect to remove this case when creating and removing LUKS
+                       // encryption is added as a separate action when full LUKS
+                       // read-write support is implemented.
+                       // WARNING:
+                       // Deliberate object slicing of *selected_partition_ptr from
+                       // PartitionLUKS to Partition.
+                       partition_new = new Partition( *selected_partition_ptr );
                }
                else
                {
-                       // Pasting into larger existing partition, therefore block copy
-                       // followed by file system grow operations (if supported) will be
-                       // performed making the file system fill the partition.
-                       partition_new->set_sector_usage(
+                       // Pasting over a file system, either a plain file system or one
+                       // within an open LUKS encryption mapping.  Start with a clone of
+                       // the existing Partition object whether it be a plain Partition
+                       // object or a PartitionLUKS object containing a Partition object.
+                       partition_new = selected_partition_ptr->clone();
+               }
+               partition_new->alignment = ALIGN_STRICT;
+
+               {
+                       // Sub-block so that filesystem_ptn_new reference goes out of
+                       // scope before partition_new pointer is deallocated.
+                       Partition & filesystem_ptn_new = partition_new->get_filesystem_partition();
+                       filesystem_ptn_new.filesystem = copied_filesystem_ptn.filesystem;
+                       filesystem_ptn_new.set_filesystem_label( copied_filesystem_ptn.get_filesystem_label() 
);
+                       filesystem_ptn_new.uuid = copied_filesystem_ptn.uuid;
+                       Sector new_size = filesystem_ptn_new.get_sector_length();
+                       if ( copied_filesystem_ptn.get_sector_length() == new_size )
+                       {
+                               // Pasting into same size existing partition, therefore
+                               // only block copy operation will be performed maintaining
+                               // the file system size.
+                               filesystem_ptn_new.set_sector_usage(
+                                       copied_filesystem_ptn.sectors_used + 
copied_filesystem_ptn.sectors_unused,
+                                       copied_filesystem_ptn.sectors_unused );
+                       }
+                       else
+                       {
+                               // Pasting into larger existing partition, therefore block
+                               // copy followed by file system grow operations (if
+                               // supported) will be performed making the file system
+                               // fill the partition.
+                               filesystem_ptn_new.set_sector_usage(
                                        new_size,
-                                       new_size - copied_partition->sectors_used );
+                                       new_size - copied_filesystem_ptn.sectors_used );
+                       }
+                       filesystem_ptn_new.clear_messages();
                }
-               partition_new->clear_messages();
  
                Operation * operation = new OperationCopy( devices[current_device],
                                                           *selected_partition_ptr,


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