Add initial loading of LUKS mapping details (#760080)

Load basic details of active Device-mapper encryption mappings from the
kernel.  Use dmsetup active targets.

    # cryptsetup luksFormat /dev/sdb5
    # cryptsetup luksFormat /dev/sdb6
    # cryptsetup luksOpen /dev/sdb6 sdb6_crypt
    # ls -l /dev/mapper/sdb6_crypt /dev/dm-0
    lrwxrwxrwx. 1 root root 7 Nov 15 09:03 /dev/mapper/sdb6_crypt -> ../dm-0
    brw-rw----. 1 root disk 253, 0 Nov 15 09:03 /dev/dm-0
    # ls -l /dev/sdb6
    brw-rw----. 1 root disk 8, 22 Nov 15 09:02 /dev/sdb6
    # dmsetup table --target crypt
    sdb6_crypt: 0 1044480 crypt aes-cbc-essiv:sha256 0000000000000000000000000000000000000000000000000000000000000000 0 8:22 4096

So far just load the mapping name and underlying block device reference
(path or major, minor pair).

Note that all supported kernels appear to report the underlying block
device as major, minor pair in the dmsetup output.  Underlying block
device paths are added to the cache when found during a search to avoid
stat(2) call on subsequent searches for the same path.

Prints debugging to show results, like this:

    # ./gpartedbin
    ======================
    libparted : 2.4
    ======================
    DEBUG: /dev/sdb5: LUKS closed
    DEBUG: /dev/sdb6: LUKS open mapping /dev/mapper/sdb6_crypt

Bug 760080 - Implement read-only LUKS support
This commit is contained in:
Mike Fleetwood 2015-04-16 19:50:56 +01:00 committed by Curtis Gedak
parent 1b55dfad5b
commit b77a6be76b
7 changed files with 202 additions and 0 deletions

View file

@ -92,6 +92,7 @@ private:
void set_device_partitions( Device & device, PedDevice* lp_device, PedDisk* lp_disk ) ;
void set_device_one_partition( Device & device, PedDevice * lp_device, FILESYSTEM fstype,
std::vector<Glib::ustring> & messages );
void debug_luks_partition( Partition & partition );
void set_partition_label_and_uuid( Partition & partition );
static FILESYSTEM detect_filesystem_internal( PedDevice * lp_device, PedPartition * lp_partition );
static FILESYSTEM detect_filesystem( PedDevice * lp_device, PedPartition * lp_partition,

42
include/LUKS_Info.h Normal file
View file

@ -0,0 +1,42 @@
/* Copyright (C) 2015 Mike Fleetwood
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/* LUKS_Info
*
* Cache of active Linux kernel Device-mapper encryption mappings.
* (Named LUKS because only encryption using the LUKS on disk format is
* recognised and handled).
*/
#ifndef GPARTED_LUKS_INFO_H
#define GPARTED_LUKS_INFO_H
#include <glibmm/ustring.h>
namespace GParted
{
class LUKS_Info
{
public:
static void load_cache();
static Glib::ustring get_mapping_name( const Glib::ustring & path );
};
}//GParted
#endif /* GPARTED_LUKS_INFO_H */

View file

@ -24,6 +24,7 @@ EXTRA_DIST = \
GParted_Core.h \
HBoxOperations.h \
LVM2_PV_Info.h \
LUKS_Info.h \
Operation.h \
OperationChangeUUID.h \
OperationCheck.h \

View file

@ -21,6 +21,7 @@ src/FileSystem.cc
src/GParted_Core.cc
src/HBoxOperations.cc
src/LVM2_PV_Info.cc
src/LUKS_Info.cc
src/OperationChangeUUID.cc
src/OperationCopy.cc
src/OperationCheck.cc

View file

@ -20,6 +20,7 @@
#include "../include/DMRaid.h"
#include "../include/FS_Info.h"
#include "../include/LVM2_PV_Info.h"
#include "../include/LUKS_Info.h"
#include "../include/Operation.h"
#include "../include/OperationCopy.h"
#include "../include/Partition.h"
@ -161,6 +162,7 @@ void GParted_Core::set_devices_thread( std::vector<Device> * pdevices )
LVM2_PV_Info::clear_cache(); // Cache automatically loaded if and when needed
btrfs::clear_cache(); // Cache incrementally loaded if and when needed
SWRaid_Info::load_cache();
LUKS_Info::load_cache();
init_maps() ;
@ -1299,6 +1301,9 @@ void GParted_Core::set_device_partitions( Device & device, PedDevice* lp_device,
partition_temp->add_paths( pp_info.get_alternate_paths( partition_temp->get_path() ) );
set_flags( *partition_temp, lp_partition );
if ( filesystem == FS_LUKS )
debug_luks_partition( *partition_temp );
if ( partition_temp->busy && partition_temp->partition_number > device.highest_busy )
device.highest_busy = partition_temp->partition_number;
break ;
@ -1405,6 +1410,9 @@ void GParted_Core::set_device_one_partition( Device & device, PedDevice * lp_dev
partition_temp->messages = messages;
partition_temp->add_paths( pp_info.get_alternate_paths( partition_temp->get_path() ) );
if ( fstype == FS_LUKS )
debug_luks_partition( *partition_temp );
if ( partition_temp->busy )
device.highest_busy = 1;
@ -1413,6 +1421,17 @@ void GParted_Core::set_device_one_partition( Device & device, PedDevice * lp_dev
device.partitions.push_back_adopt( partition_temp );
}
void GParted_Core::debug_luks_partition( Partition & partition )
{
// FIXME: Temporary debugging of LUKS mapping.
Glib::ustring name = LUKS_Info::get_mapping_name( partition.get_path() );
if ( name.empty() )
std::cout << "DEBUG: " << partition.get_path() << ": LUKS closed" << std::endl;
else
std::cout << "DEBUG: " << partition.get_path()
<< ": LUKS open mapping " << DEV_MAPPER_PATH << name << std::endl;
}
void GParted_Core::set_partition_label_and_uuid( Partition & partition )
{
FS_Info fs_info; // Use cache of file system information

137
src/LUKS_Info.cc Normal file
View file

@ -0,0 +1,137 @@
/* Copyright (C) 2015 Mike Fleetwood
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "../include/LUKS_Info.h"
#include "../include/Utils.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
namespace GParted
{
struct LUKS_Mapping
{
Glib::ustring name; // Name of the dm-crypt mapping
unsigned long major; // Major device number of the underlying block device
unsigned long minor; // Minor device number of the underlying block device
Glib::ustring path; // Path of the underlying block device
};
// Cache of active dm-crypt mappings.
// Example entry:
// {name="sdb6_crypt", major=8, minor=22, path="/dev/sdb6"}
static std::vector<LUKS_Mapping> luks_mapping_cache;
void LUKS_Info::load_cache()
{
luks_mapping_cache.clear();
Glib::ustring output;
Glib::ustring error;
Utils::execute_command( "dmsetup table --target crypt", output, error, true );
// dmsetup output is one line per dm-crypt mapping containing fields:
// NAME: START LENGTH TARGET CIPHER KEY IVOFFSET DEVPATH OFFSET ...
// or the text:
// No devices found
// First 4 fields are defined by the dmsetup program by the print call in the
// _status() function:
// https://git.fedorahosted.org/cgit/lvm2.git/tree/tools/dmsetup.c?id=v2_02_118#n1715
// Field 5 onwards are called parameters and documented in the kernel source:
// https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/device-mapper/dm-crypt.txt?id=v4.0
std::vector<Glib::ustring> lines;
Utils::tokenize( output, lines, "\n" );
for ( unsigned int i = 0 ; i < lines.size() ; i ++ )
{
LUKS_Mapping luks_map;
std::vector<Glib::ustring> fields;
Utils::tokenize( lines[i], fields, " " );
const unsigned DMCRYPT_FIELD_Name = 0;
const unsigned DMCRYPT_FIELD_devpath = 7;
if ( fields.size() <= DMCRYPT_FIELD_devpath )
continue;
// Extract LUKS mapping name
Glib::ustring name = fields[DMCRYPT_FIELD_Name];
size_t len = name.length();
if ( len <= 1 || name[len-1] != ':' )
continue;
luks_map.name = name.substr( 0, len-1 );
// Extract LUKS underlying device containing the encrypted data. May be
// either a device name (/dev/sda1) or major, minor pair (8:1).
luks_map.major = 0UL;
luks_map.minor = 0UL;
luks_map.path.clear();
Glib::ustring devpath = fields[DMCRYPT_FIELD_devpath];
unsigned long maj = 0;
unsigned long min = 0;
if ( devpath.length() > 0 && devpath[0] == '/' )
luks_map.path = devpath;
else if ( sscanf( devpath.c_str(), "%lu:%lu", &maj, &min ) == 2 )
{
luks_map.major = maj;
luks_map.minor = min;
}
else
continue;
luks_mapping_cache.push_back( luks_map );
}
}
// Return name of the active LUKS mapping for the underlying block device path,
// or "" when no such mapping exists.
Glib::ustring LUKS_Info::get_mapping_name( const Glib::ustring & path )
{
// First scan the cache looking for an underlying block device path match.
// (Totally in memory)
for ( unsigned int i = 0 ; i < luks_mapping_cache.size() ; i ++ )
{
if ( path == luks_mapping_cache[i].path )
return luks_mapping_cache[i].name;
}
// Second scan the cache looking for an underlying block device major, minor
// match. (Requires single stat(2) call per search)
struct stat sb;
if ( stat( path.c_str(), &sb ) == 0 && S_ISBLK( sb.st_mode ) )
{
unsigned long maj = major( sb.st_rdev );
unsigned long min = minor( sb.st_rdev );
for ( unsigned int i = 0 ; i < luks_mapping_cache.size() ; i ++ )
{
if ( maj == luks_mapping_cache[i].major && min == luks_mapping_cache[i].minor )
{
// Store path in cache to avoid stat() call on subsequent
// query for the same path.
luks_mapping_cache[i].path = path;
return luks_mapping_cache[i].name;
}
}
}
return "";
}
//Private methods
}//GParted

View file

@ -35,6 +35,7 @@ gpartedbin_SOURCES = \
GParted_Core.cc \
HBoxOperations.cc \
LVM2_PV_Info.cc \
LUKS_Info.cc \
Operation.cc \
OperationChangeUUID.cc \
OperationCheck.cc \