Don't mount the same LUKS volume twice

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2011-04-21 11:38:51 +02:00
parent 5709ed126d
commit a89c3dd3f7

View file

@ -47,7 +47,7 @@ struct grub_luks_phdr
grub_uint8_t mkDigest[20];
grub_uint8_t mkDigestSalt[32];
grub_uint32_t mkDigestIterations;
grub_uint8_t uuid[40];
char uuid[40];
struct
{
grub_uint32_t active;
@ -65,8 +65,7 @@ typedef enum
GRUB_LUKS_MODE_ECB,
GRUB_LUKS_MODE_CBC_PLAIN,
GRUB_LUKS_MODE_CBC_ESSIV
}
luks_mode_t;
} luks_mode_t;
struct grub_luks
{
@ -77,7 +76,9 @@ struct grub_luks
grub_crypto_cipher_handle_t cipher;
grub_crypto_cipher_handle_t essiv_cipher;
luks_mode_t mode;
int id;
unsigned long id, source_id;
enum grub_disk_dev_id source_dev_id;
char uuid[sizeof (((struct grub_luks_phdr *) 0)->uuid)];
struct grub_luks *next;
};
typedef struct grub_luks *grub_luks_t;
@ -154,11 +155,9 @@ static int check_uuid, have_it;
static char *uuid;
static grub_err_t
grub_luks_scan_device_real (const char *name)
grub_luks_scan_device_real (const char *name, grub_disk_t source)
{
grub_disk_t source;
grub_err_t err;
grub_luks_t newdev;
struct grub_luks_phdr header;
grub_crypto_cipher_handle_t cipher = NULL, essiv_cipher = NULL;
const gcry_md_spec_t *hash = NULL, *essiv_hash = NULL;
@ -174,73 +173,38 @@ grub_luks_scan_device_real (const char *name)
char passphrase[MAX_PASSPHRASE] = "";
grub_uint8_t candidate_digest[sizeof (header.mkDigest)];
/* Try to open disk. */
source = grub_disk_open (name);
if (!source)
return grub_errno;
/* Read the LUKS header. */
err = grub_disk_read (source, 0, 0, sizeof (header), &header);
if (err)
{
grub_disk_close (source);
return err;
}
return err;
/* Look for LUKS magic sequence. */
if (grub_memcmp (header.magic, LUKS_MAGIC, sizeof (header.magic))
|| grub_be_to_cpu16 (header.version) != 1)
{
grub_disk_close (source);
return GRUB_ERR_NONE;
}
if (check_uuid && grub_memcmp (header.uuid, uuid,
sizeof (header.uuid)) != 0)
return 0;
newdev = grub_zalloc (sizeof (struct grub_luks));
if (!newdev)
{
grub_disk_close (source);
return grub_errno;
}
newdev->id = n;
newdev->devname = grub_xasprintf ("luks%d", n);
newdev->source = grub_strdup (name);
n++;
return GRUB_ERR_NONE;
/* Make sure that strings are null terminated. */
header.cipherName[sizeof (header.cipherName) - 1] = 0;
header.cipherMode[sizeof (header.cipherMode) - 1] = 0;
header.hashSpec[sizeof (header.hashSpec) - 1] = 0;
header.uuid[sizeof (header.uuid) - 1] = 0;
if (check_uuid && grub_strcmp (header.uuid, uuid) != 0)
return 0;
ciph = grub_crypto_lookup_cipher_by_name (header.cipherName);
if (!ciph)
{
grub_disk_close (source);
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "Cipher %s isn't available",
header.cipherName);
}
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "Cipher %s isn't available",
header.cipherName);
/* Configure the cipher used for the bulk data. */
cipher = grub_crypto_cipher_open (ciph);
if (!cipher)
{
grub_disk_close (source);
grub_free (newdev);
return grub_errno;
}
return grub_errno;
keysize = grub_be_to_cpu32 (header.keyBytes);
if (keysize > 1024)
{
grub_disk_close (source);
grub_free (newdev);
return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid keysize %d",
keysize);
}
return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid keysize %d", keysize);
/* Configure the cipher mode. */
if (grub_strncmp (header.cipherMode, "ecb", 3) == 0)
@ -258,8 +222,6 @@ grub_luks_scan_device_real (const char *name)
if (!essiv_hash)
{
grub_crypto_cipher_close (cipher);
grub_disk_close (source);
grub_free (newdev);
return grub_error (GRUB_ERR_FILE_NOT_FOUND,
"Couldn't load %s hash", hash_str);
}
@ -267,8 +229,6 @@ grub_luks_scan_device_real (const char *name)
if (!cipher)
{
grub_crypto_cipher_close (cipher);
grub_disk_close (source);
grub_free (newdev);
return grub_errno;
}
@ -278,16 +238,12 @@ grub_luks_scan_device_real (const char *name)
{
grub_crypto_cipher_close (cipher);
grub_crypto_cipher_close (essiv_cipher);
grub_disk_close (source);
grub_free (newdev);
return grub_errno;
}
}
else
{
grub_crypto_cipher_close (cipher);
grub_disk_close (source);
grub_free (newdev);
return grub_error (GRUB_ERR_BAD_ARGUMENT, "Unknown cipher mode: %s",
header.cipherMode);
}
@ -299,8 +255,6 @@ grub_luks_scan_device_real (const char *name)
grub_crypto_cipher_close (cipher);
grub_crypto_cipher_close (essiv_cipher);
grub_free (hashed_key);
grub_disk_close (source);
grub_free (newdev);
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "Couldn't load %s hash",
header.hashSpec);
}
@ -316,8 +270,6 @@ grub_luks_scan_device_real (const char *name)
grub_crypto_cipher_close (cipher);
grub_crypto_cipher_close (essiv_cipher);
grub_free (hashed_key);
grub_disk_close (source);
grub_free (newdev);
return grub_errno;
}
@ -329,8 +281,6 @@ grub_luks_scan_device_real (const char *name)
grub_crypto_cipher_close (essiv_cipher);
grub_free (hashed_key);
grub_free (split_key);
grub_disk_close (source);
grub_free (newdev);
return grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied");
}
@ -361,8 +311,6 @@ grub_luks_scan_device_real (const char *name)
grub_crypto_cipher_close (essiv_cipher);
grub_free (hashed_key);
grub_free (split_key);
grub_disk_close (source);
grub_free (newdev);
return grub_crypto_gcry_error (gcry_err);
}
@ -376,8 +324,6 @@ grub_luks_scan_device_real (const char *name)
grub_crypto_cipher_close (essiv_cipher);
grub_free (hashed_key);
grub_free (split_key);
grub_disk_close (source);
grub_free (newdev);
return grub_crypto_gcry_error (gcry_err);
}
@ -404,8 +350,6 @@ grub_luks_scan_device_real (const char *name)
grub_crypto_cipher_close (essiv_cipher);
grub_free (hashed_key);
grub_free (split_key);
grub_disk_close (source);
grub_free (newdev);
return err;
}
@ -417,8 +361,6 @@ grub_luks_scan_device_real (const char *name)
grub_crypto_cipher_close (essiv_cipher);
grub_free (hashed_key);
grub_free (split_key);
grub_disk_close (source);
grub_free (newdev);
return grub_crypto_gcry_error (gcry_err);
}
@ -431,8 +373,6 @@ grub_luks_scan_device_real (const char *name)
grub_crypto_cipher_close (essiv_cipher);
grub_free (hashed_key);
grub_free (split_key);
grub_disk_close (source);
grub_free (newdev);
return grub_crypto_gcry_error (gcry_err);
}
@ -453,8 +393,6 @@ grub_luks_scan_device_real (const char *name)
grub_crypto_cipher_close (essiv_cipher);
grub_free (hashed_key);
grub_free (split_key);
grub_disk_close (source);
grub_free (newdev);
return grub_crypto_gcry_error (gcry_err);
}
@ -464,8 +402,6 @@ grub_luks_scan_device_real (const char *name)
sizeof (header.mkDigest)) != 0)
continue;
grub_disk_close (source);
grub_printf ("Slot %d opened\n", i);
/* Set the master key. */
@ -476,12 +412,9 @@ grub_luks_scan_device_real (const char *name)
grub_crypto_cipher_close (essiv_cipher);
grub_free (hashed_key);
grub_free (split_key);
grub_free (newdev);
return grub_crypto_gcry_error (gcry_err);
}
newdev->cipher = cipher;
/* Configure ESSIV if necessary. */
if (mode == GRUB_LUKS_MODE_CBC_ESSIV)
{
@ -495,24 +428,33 @@ grub_luks_scan_device_real (const char *name)
grub_crypto_cipher_close (essiv_cipher);
grub_free (hashed_key);
grub_free (split_key);
grub_free (newdev);
return grub_crypto_gcry_error (gcry_err);
}
newdev->essiv_cipher = essiv_cipher;
}
else
{
newdev->essiv_cipher = NULL;
}
newdev->offset = grub_be_to_cpu32 (header.payloadOffset);
newdev->source_disk = NULL;
newdev->mode = mode;
{
grub_luks_t newdev;
newdev = grub_zalloc (sizeof (struct grub_luks));
if (!newdev)
return grub_errno;
newdev->id = n;
newdev->devname = grub_xasprintf ("luks%d", n);
newdev->source = grub_strdup (name);
newdev->source_id = source->id;
newdev->source_dev_id = source->dev->id;
newdev->cipher = cipher;
newdev->offset = grub_be_to_cpu32 (header.payloadOffset);
newdev->source_disk = NULL;
newdev->mode = mode;
newdev->essiv_cipher = essiv_cipher;
grub_memcpy (newdev->uuid, header.uuid, sizeof (newdev->uuid));
newdev->next = luks_list;
luks_list = newdev;
n++;
}
grub_free (split_key);
grub_free (hashed_key);
newdev->next = luks_list;
luks_list = newdev;
have_it = 1;
@ -526,7 +468,17 @@ static int
grub_luks_scan_device (const char *name)
{
grub_err_t err;
err = grub_luks_scan_device_real (name);
grub_disk_t source;
/* Try to open disk. */
source = grub_disk_open (name);
if (!source)
return grub_errno;
err = grub_luks_scan_device_real (name, source);
grub_disk_close (source);
if (err)
grub_print_error ();
return have_it && check_uuid ? 0 : 1;
@ -651,6 +603,15 @@ grub_cmd_luksmount (grub_extcmd_context_t ctxt, int argc, char **args)
have_it = 0;
if (state[0].set)
{
grub_luks_t dev;
for (dev = luks_list; dev != NULL; dev = dev->next)
if (grub_strcmp (dev->uuid, args[0]) == 0)
{
grub_dprintf ("luks", "already mounted as %s\n", dev->devname);
return GRUB_ERR_NONE;
}
check_uuid = 1;
uuid = args[0];
grub_device_iterate (&grub_luks_scan_device);
@ -659,9 +620,27 @@ grub_cmd_luksmount (grub_extcmd_context_t ctxt, int argc, char **args)
else
{
grub_err_t err;
grub_disk_t disk;
grub_luks_t dev;
check_uuid = 0;
uuid = NULL;
err = grub_luks_scan_device_real (args[0]);
disk = grub_disk_open (args[0]);
if (!disk)
return grub_errno;
for (dev = luks_list; dev != NULL; dev = dev->next)
if (dev->source_id == disk->id && dev->source_dev_id == disk->dev->id)
{
grub_dprintf ("luks", "already mounted as %s\n", dev->devname);
grub_disk_close (disk);
return GRUB_ERR_NONE;
}
err = grub_luks_scan_device_real (args[0], disk);
grub_disk_close (disk);
return err;
}
if (!have_it)