Use libparted geometry to bound writing in erase_filesystem_signatures()

The code in erase_filesystem_signatures() used libparted
ped_device_write() which allowed any sector in the whole disk device to
be written.  The code only depended on calculations of somewhat
complicated zero offset ranges and the start partition offset to ensure
that it didn't zero sectors outside the target partition.  The code
doesn't overwrite partition boundaries, but there have been updates and
bug fixes to the calculation code.  To improve the safety create a
libparted geometry representing the partition, or whole disk device,
to be cleared and use ped_geometry_write() so that libparted enforces
writes are only within the partition boundary being erased.

Deliberately breaking erase_filesystem_signatures() code so that it
tries to write past the end of the partition produces this dialog:

                        Libparted Error
    (-) Attempt to write sectors 1024000-1024007 outside of
        partition on /dev/sdb.
                                      [ Cancel ] [ Ignore ]

And trying to write before the start of the partition produces this
dialog:

                       Libparted Bug
    (-) Assert (offset >= 0) at cs/geom.c:375 in function
        ped_geometry_write() failed.
                                                   [ No ]

Followed by GParted aborting and producing a core dump.  Not ideal from
libparted, but it does prevent GParted writing outside the partition
boundaries and only occurs in the case of a bug in
erase_filesystem_signatures() which is exercised on every Create and
Format Partition operation and now also unit tested.  So not something
we will let through to the users.
This commit is contained in:
Mike Fleetwood 2016-12-18 16:35:27 +00:00 committed by Curtis Gedak
parent 5255a39137
commit ad434bb651
1 changed files with 16 additions and 14 deletions

View File

@ -3742,6 +3742,7 @@ bool GParted_Core::erase_filesystem_signatures( const Partition & partition, Ope
PedDevice* lp_device = NULL ; PedDevice* lp_device = NULL ;
PedDisk* lp_disk = NULL ; PedDisk* lp_disk = NULL ;
PedPartition* lp_partition = NULL ; PedPartition* lp_partition = NULL ;
PedGeometry *lp_geom = NULL;
bool device_is_open = false ; bool device_is_open = false ;
Byte_Value bufsize = 4LL * KIBIBYTE ; Byte_Value bufsize = 4LL * KIBIBYTE ;
char * buf = NULL ; char * buf = NULL ;
@ -3749,17 +3750,20 @@ bool GParted_Core::erase_filesystem_signatures( const Partition & partition, Ope
{ {
if ( partition.type == TYPE_UNPARTITIONED ) if ( partition.type == TYPE_UNPARTITIONED )
{ {
// Virtual partition spanning whole disk device // Whole disk device; create a matching geometry
overall_success = true; lp_geom = ped_geometry_new(lp_device,
partition.sector_start,
partition.get_sector_length());
} }
else if ( get_disk( lp_device, lp_disk ) ) else if ( get_disk( lp_device, lp_disk ) )
{ {
// Partitioned device // Partitioned device; copy partition geometry
lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition.get_sector() ); lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition.get_sector() );
overall_success = ( lp_partition != NULL ); if (lp_partition)
lp_geom = ped_geometry_duplicate(&lp_partition->geom);
} }
if ( overall_success && ped_device_open( lp_device ) ) if (lp_geom != NULL && ped_device_open(lp_device))
{ {
device_is_open = true ; device_is_open = true ;
@ -3768,7 +3772,7 @@ bool GParted_Core::erase_filesystem_signatures( const Partition & partition, Ope
if ( buf ) if ( buf )
memset( buf, 0, bufsize ) ; memset( buf, 0, bufsize ) ;
} }
overall_success &= device_is_open; overall_success = device_is_open;
} }
// Erase all file system super blocks, including their signatures. The specified // Erase all file system super blocks, including their signatures. The specified
@ -3877,19 +3881,15 @@ bool GParted_Core::erase_filesystem_signatures( const Partition & partition, Ope
Utils::format_size( byte_len, 1 ), Utils::format_size( byte_len, 1 ),
byte_offset ) ) ) ; byte_offset ) ) ) ;
// Start sector of the whole disk device or the partition
Sector ptn_start = 0LL;
if ( lp_partition )
ptn_start = lp_partition->geom.start;
while ( written < byte_len ) while ( written < byte_len )
{ {
//Write in bufsize amounts. Last write may be smaller but //Write in bufsize amounts. Last write may be smaller but
// will still be a whole number of sectors. // will still be a whole number of sectors.
Byte_Value amount = std::min( bufsize, byte_len - written ) ; Byte_Value amount = std::min( bufsize, byte_len - written ) ;
zero_success = ped_device_write( lp_device, buf, zero_success = ped_geometry_write(lp_geom,
ptn_start + ( byte_offset + written ) / lp_device->sector_size, buf,
amount / lp_device->sector_size ); (byte_offset + written) / lp_device->sector_size,
amount / lp_device->sector_size);
if ( ! zero_success ) if ( ! zero_success )
break ; break ;
written += amount ; written += amount ;
@ -3901,6 +3901,8 @@ bool GParted_Core::erase_filesystem_signatures( const Partition & partition, Ope
} }
if ( buf ) if ( buf )
free( buf ) ; free( buf ) ;
if (lp_geom != NULL)
ped_geometry_destroy(lp_geom);
//Linux kernel doesn't maintain buffer cache coherency between the whole disk //Linux kernel doesn't maintain buffer cache coherency between the whole disk
// device and partition devices. So even though the file system signatures // device and partition devices. So even though the file system signatures