Add cheatmounting

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2011-04-22 19:20:46 +02:00
parent dcd73ec05e
commit 24089d19e2
4 changed files with 166 additions and 40 deletions

View file

@ -25,6 +25,15 @@
#include <grub/crypto.h> #include <grub/crypto.h>
#include <grub/extcmd.h> #include <grub/extcmd.h>
#include <grub/i18n.h> #include <grub/i18n.h>
#ifdef GRUB_UTIL
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <grub/emu/hostdisk.h>
#include <unistd.h>
#include <string.h>
#endif
GRUB_MOD_LICENSE ("GPLv3+"); GRUB_MOD_LICENSE ("GPLv3+");
@ -80,6 +89,10 @@ struct grub_luks
unsigned long id, source_id; unsigned long id, source_id;
enum grub_disk_dev_id source_dev_id; enum grub_disk_dev_id source_dev_id;
char uuid[sizeof (((struct grub_luks_phdr *) 0)->uuid) + 1]; char uuid[sizeof (((struct grub_luks_phdr *) 0)->uuid) + 1];
#ifdef GRUB_UTIL
char *cheat;
int cheat_fd;
#endif
struct grub_luks *next; struct grub_luks *next;
}; };
typedef struct grub_luks *grub_luks_t; typedef struct grub_luks *grub_luks_t;
@ -497,6 +510,12 @@ grub_luks_scan_device_real (const char *name, grub_disk_t source)
} }
newdev->source = grub_strdup (name); newdev->source = grub_strdup (name);
if (!newdev->source)
{
grub_free (newdev);
return grub_errno;
}
newdev->source_id = source->id; newdev->source_id = source->id;
newdev->source_dev_id = source->dev->id; newdev->source_dev_id = source->dev->id;
newdev->next = luks_list; newdev->next = luks_list;
@ -507,6 +526,48 @@ grub_luks_scan_device_real (const char *name, grub_disk_t source)
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }
#ifdef GRUB_UTIL
grub_err_t
grub_luks_cheat_mount (const char *sourcedev, const char *cheat)
{
grub_err_t err;
struct grub_luks_phdr header;
grub_luks_t newdev;
grub_disk_t source;
/* Try to open disk. */
source = grub_disk_open (sourcedev);
if (!source)
return grub_errno;
/* Read the LUKS header. */
err = grub_disk_read (source, 0, 0, sizeof (header), &header);
if (err)
return err;
newdev = configure_ciphers (&header);
grub_disk_close (source);
if (!newdev)
return grub_errno;
newdev->cheat = grub_strdup (cheat);
newdev->source = grub_strdup (sourcedev);
if (!newdev->source || !newdev->cheat)
{
grub_free (newdev->source);
grub_free (newdev->cheat);
grub_free (newdev);
return grub_errno;
}
newdev->cheat_fd = -1;
newdev->source_id = source->id;
newdev->source_dev_id = source->dev->id;
newdev->next = luks_list;
luks_list = newdev;
return GRUB_ERR_NONE;
}
#endif
static int static int
grub_luks_scan_device (const char *name) grub_luks_scan_device (const char *name)
{ {
@ -575,6 +636,17 @@ grub_luks_open (const char *name, grub_disk_t disk,
if (!dev) if (!dev)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such device"); return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such device");
#ifdef GRUB_UTIL
if (dev->cheat)
{
if (dev->cheat_fd == -1)
dev->cheat_fd = open (dev->cheat, O_RDONLY);
if (dev->cheat_fd == -1)
return grub_error (GRUB_ERR_IO, "couldn't open %s: %s",
dev->cheat, strerror (errno));
}
#endif
if (!dev->source_disk) if (!dev->source_disk)
{ {
grub_dprintf ("luks", "Opening device %s\n", name); grub_dprintf ("luks", "Opening device %s\n", name);
@ -599,11 +671,17 @@ grub_luks_close (grub_disk_t disk)
dev->ref--; dev->ref--;
if (dev->ref == 0) if (dev->ref != 0)
return;
#ifdef GRUB_UTIL
if (dev->cheat)
{ {
grub_disk_close (dev->source_disk); close (dev->cheat_fd);
dev->source_disk = NULL; dev->cheat_fd = -1;
} }
#endif
grub_disk_close (dev->source_disk);
dev->source_disk = NULL;
} }
static grub_err_t static grub_err_t
@ -612,6 +690,21 @@ grub_luks_read (grub_disk_t disk, grub_disk_addr_t sector,
{ {
grub_luks_t dev = (grub_luks_t) disk->data; grub_luks_t dev = (grub_luks_t) disk->data;
grub_err_t err; grub_err_t err;
#ifdef GRUB_UTIL
if (dev->cheat)
{
err = grub_util_fd_sector_seek (dev->cheat_fd, dev->cheat, sector);
if (err)
return err;
if (grub_util_fd_read (dev->cheat_fd, buf, size << GRUB_DISK_SECTOR_BITS)
!= (ssize_t) (size << GRUB_DISK_SECTOR_BITS))
return grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'",
dev->cheat);
return GRUB_ERR_NONE;
}
#endif
grub_dprintf ("luks", grub_dprintf ("luks",
"Reading %" PRIuGRUB_SIZE " sectors from sector 0x%" "Reading %" PRIuGRUB_SIZE " sectors from sector 0x%"
PRIxGRUB_UINT64_T " with offset of %" PRIuGRUB_UINT32_T "\n", PRIxGRUB_UINT64_T " with offset of %" PRIuGRUB_UINT32_T "\n",

View file

@ -865,7 +865,9 @@ out:
void void
grub_util_pull_device (const char *os_dev) grub_util_pull_device (const char *os_dev)
{ {
switch (grub_util_get_dev_abstraction (os_dev)) int ab;
ab = grub_util_get_dev_abstraction (os_dev);
switch (ab)
{ {
case GRUB_DEV_ABSTRACTION_LVM: case GRUB_DEV_ABSTRACTION_LVM:
case GRUB_DEV_ABSTRACTION_LUKS: case GRUB_DEV_ABSTRACTION_LUKS:
@ -875,6 +877,7 @@ grub_util_pull_device (const char *os_dev)
struct dm_tree_node *node; struct dm_tree_node *node;
struct dm_tree_node *child; struct dm_tree_node *child;
void *handle = NULL; void *handle = NULL;
char *lastsubdev = NULL;
if (!grub_util_open_dm (os_dev, &tree, &node)) if (!grub_util_open_dm (os_dev, &tree, &node))
return; return;
@ -887,9 +890,26 @@ grub_util_pull_device (const char *os_dev)
continue; continue;
subdev = grub_find_device ("/dev", makedev (dm->major, dm->minor)); subdev = grub_find_device ("/dev", makedev (dm->major, dm->minor));
if (subdev) if (subdev)
grub_util_pull_device (subdev); {
lastsubdev = subdev;
grub_util_pull_device (subdev);
}
} }
dm_tree_free (tree); if (ab == GRUB_DEV_ABSTRACTION_LUKS && lastsubdev)
{
char *grdev = grub_util_get_grub_dev (lastsubdev);
dm_tree_free (tree);
if (grdev)
{
grub_err_t err;
err = grub_luks_cheat_mount (grdev, os_dev);
if (err)
grub_util_error ("Can't mount LUKS: %s", grub_errmsg);
}
grub_free (grdev);
}
else
dm_tree_free (tree);
} }
#endif #endif
return; return;

View file

@ -631,6 +631,37 @@ linux_find_partition (char *dev, unsigned long sector)
} }
#endif /* __linux__ */ #endif /* __linux__ */
#if defined(__linux__) && (!defined(__GLIBC__) || \
((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
/* Maybe libc doesn't have large file support. */
grub_err_t
grub_util_fd_sector_seek (int fd, const char *name, grub_disk_addr_t sector)
{
loff_t offset, result;
static int _llseek (uint filedes, ulong hi, ulong lo,
loff_t *res, uint wh);
_syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
loff_t *, res, uint, wh);
offset = (loff_t) sector << GRUB_DISK_SECTOR_BITS;
if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
{
return grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", name);
}
return GRUB_ERR_NONE;
}
#else
grub_err_t
grub_util_fd_sector_seek (int fd, const char *name, grub_disk_addr_t sector)
{
off_t offset = (off_t) sector << GRUB_DISK_SECTOR_BITS;
if (lseek (fd, offset, SEEK_SET) != offset)
return grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", name);
return 0;
}
#endif
static int static int
open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags) open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
{ {
@ -781,44 +812,19 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
configure_device_driver (fd); configure_device_driver (fd);
#endif /* defined(__NetBSD__) */ #endif /* defined(__NetBSD__) */
#if defined(__linux__) && (!defined(__GLIBC__) || \ if (grub_util_fd_sector_seek (fd, map[disk->id].device, sector))
((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))) {
/* Maybe libc doesn't have large file support. */ close (fd);
{ return -1;
loff_t offset, result; }
static int _llseek (uint filedes, ulong hi, ulong lo,
loff_t *res, uint wh);
_syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
loff_t *, res, uint, wh);
offset = (loff_t) sector << GRUB_DISK_SECTOR_BITS;
if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
{
grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device);
close (fd);
return -1;
}
}
#else
{
off_t offset = (off_t) sector << GRUB_DISK_SECTOR_BITS;
if (lseek (fd, offset, SEEK_SET) != offset)
{
grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device);
close (fd);
return -1;
}
}
#endif
return fd; return fd;
} }
/* Read LEN bytes from FD in BUF. Return less than or equal to zero if an /* Read LEN bytes from FD in BUF. Return less than or equal to zero if an
error occurs, otherwise return LEN. */ error occurs, otherwise return LEN. */
static ssize_t ssize_t
nread (int fd, char *buf, size_t len) grub_util_fd_read (int fd, char *buf, size_t len)
{ {
ssize_t size = len; ssize_t size = len;
@ -901,7 +907,8 @@ grub_util_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
sectors that are read together with the MBR in one read. It sectors that are read together with the MBR in one read. It
should only remap the MBR, so we split the read in two should only remap the MBR, so we split the read in two
parts. -jochen */ parts. -jochen */
if (nread (fd, buf, GRUB_DISK_SECTOR_SIZE) != GRUB_DISK_SECTOR_SIZE) if (grub_util_fd_read (fd, buf, GRUB_DISK_SECTOR_SIZE)
!= GRUB_DISK_SECTOR_SIZE)
{ {
grub_error (GRUB_ERR_READ_ERROR, "cannot read `%s'", map[disk->id].device); grub_error (GRUB_ERR_READ_ERROR, "cannot read `%s'", map[disk->id].device);
return grub_errno; return grub_errno;
@ -912,7 +919,7 @@ grub_util_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
} }
#endif /* __linux__ */ #endif /* __linux__ */
if (nread (fd, buf, size << GRUB_DISK_SECTOR_BITS) if (grub_util_fd_read (fd, buf, size << GRUB_DISK_SECTOR_BITS)
!= (ssize_t) (size << GRUB_DISK_SECTOR_BITS)) != (ssize_t) (size << GRUB_DISK_SECTOR_BITS))
grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'", map[disk->id].device); grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'", map[disk->id].device);

View file

@ -21,6 +21,7 @@
#define GRUB_BIOSDISK_MACHINE_UTIL_HEADER 1 #define GRUB_BIOSDISK_MACHINE_UTIL_HEADER 1
#include <grub/disk.h> #include <grub/disk.h>
#include <sys/types.h>
void grub_util_biosdisk_init (const char *dev_map); void grub_util_biosdisk_init (const char *dev_map);
void grub_util_biosdisk_fini (void); void grub_util_biosdisk_fini (void);
@ -30,5 +31,10 @@ int grub_util_biosdisk_is_present (const char *name);
int grub_util_biosdisk_is_floppy (grub_disk_t disk); int grub_util_biosdisk_is_floppy (grub_disk_t disk);
grub_err_t grub_util_biosdisk_flush (struct grub_disk *disk); grub_err_t grub_util_biosdisk_flush (struct grub_disk *disk);
void grub_util_pull_device (const char *osname); void grub_util_pull_device (const char *osname);
grub_err_t
grub_util_fd_sector_seek (int fd, const char *name, grub_disk_addr_t sector);
ssize_t grub_util_fd_read (int fd, char *buf, size_t len);
grub_err_t
grub_luks_cheat_mount (const char *sourcedev, const char *cheat);
#endif /* ! GRUB_BIOSDISK_MACHINE_UTIL_HEADER */ #endif /* ! GRUB_BIOSDISK_MACHINE_UTIL_HEADER */