From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.71) id 1W1Wqb-0001S3-3t for mharc-grub-devel@gnu.org; Fri, 10 Jan 2014 02:49:41 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54766) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1W1WqV-0001Rd-B8 for grub-devel@gnu.org; Fri, 10 Jan 2014 02:49:40 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1W1WqQ-00054H-FC for grub-devel@gnu.org; Fri, 10 Jan 2014 02:49:35 -0500 Received: from mo6-p00-ob.smtp.rzone.de ([2a01:238:20a:202:5300::9]:45582) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1W1WqQ-00053G-0F for grub-devel@gnu.org; Fri, 10 Jan 2014 02:49:30 -0500 DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; t=1389340168; l=13633; s=domk; d=bubecks.de; h=Content-Transfer-Encoding:Content-Type:In-Reply-To:References: Subject:To:MIME-Version:From:Date:X-RZG-CLASS-ID:X-RZG-AUTH; bh=QYOho8m1kksgG3m6DFbHOiAmAyY=; b=W5W6fTq65szWrA0zeUtfoPEp5itqHRHyhHW4dMLG8m6PdhS9uHfQj5wsZvC5LsPtq5N 3c9WW50Dtz6DgYo0EsmDnmQyFqWR9tXGErc6gHENrPt4rQeMcKBgCvALHoFHFQqYtBCHv MXO4X4g/O9jcKIZ/WerkNtcYDHiAzCJo8wM= X-RZG-AUTH: :OGUIeEGmdd9LocaRWNUrTCqIQctGnGgg+eszxi8Zzh68aZhci43fYAKnuMxwetsJ6Q== X-RZG-CLASS-ID: mo00 Received: from brain.bubecks.de (p5B2CEDD4.dip0.t-ipconnect.de [91.44.237.212]) by smtp.strato.de (RZmta 32.17 DYNA|AUTH) with (TLSv1:DHE-RSA-AES256-SHA encrypted) ESMTPSA id j00caeq0A7nRAI2 ; Fri, 10 Jan 2014 08:49:27 +0100 (CET) Received: from [192.168.1.100] (fw.wid.reinform.de [10.2.1.254]) (using TLSv1 with cipher DHE-RSA-CAMELLIA256-SHA (256/256 bits)) (No client certificate requested) by brain.bubecks.de (Postfix) with ESMTPSA id 79FB3884EF for ; Fri, 10 Jan 2014 08:49:26 +0100 (CET) Message-ID: <52CFA5FF.7070200@bubecks.de> Date: Fri, 10 Jan 2014 08:49:19 +0100 From: "Dr. Tilmann Bubeck" User-Agent: Mozilla/5.0 (X11; Linux i686; rv:24.0) Gecko/20100101 Thunderbird/24.2.0 MIME-Version: 1.0 To: grub-devel@gnu.org Subject: Re: [PATCH] Improve ext2 driver to allow embedding of the boot loader code. References: <1389301657-8236-1-git-send-email-tilmann@bubecks.de> <52CF282C.4070408@gmail.com> In-Reply-To: <52CF282C.4070408@gmail.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a01:238:20a:202:5300::9 X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: The development of GNU GRUB List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 10 Jan 2014 07:49:40 -0000 Vladimir, in your last email "Re: Why special linux code in grub2/util/grub-setup.c" from 25.07.2013 23:17 you request the following 3 features which I respected in my patch: > 1) have a way to reserve some space, near the beginning. E.g. IOCTL > CREATE_EMBEDDING_ZONE with argument size=5M (number coming from my > draft on LVM zones). This has to have synchronous semantics. > Blocklist is fixed after this operation. See ext2:1210 and following. You are able to create an arbitrary large space (currently setup.c asks for max_nsectors=100 but this can be changed by setup.c without any change in ext2.c). You can also request 5M if you wish. It is implemented to be synchronous. The blocklist is fixed and stable and will never change. The only open issue is "near the beginning". You probably request this because of some BIOS only able to access "near the beginning"? This limitation is really "near the beginning OF THE DISK" and not "near the beginning of the PARTITION". So I think, that any implementation inside a partition can potentially fail, if the partition itself is not near the beginning of the disk". This is something which could only be solved by either putting a partition near the beginning or by using the MBR gap. My patch allows to use a partition at the beginning (like the btrfs driver did too). And MBR is not always possible or wanted. > 2) A way to retrieve its blocklist Done, see ext2.c function grub_ext2_read_sectorlist > 3) A way to overwrite parts of its contents in a way that ensures > bypassing journal, COW, compression, encryption, hyperspace or any > other advanced features. Done. Existing code in setup.c takes the sectors given by the filesystem driver (ext2 or btrfs) and writes to that sectors. I have not changed anything here. So please take a second look at the arguments and the implementation. I do think, that embedding into ext2 is a really important feature and I think this is a robust solution. Thanks! Tilmann Am 09.01.2014 23:52, schrieb Vladimir 'φ-coder/phcoder' Serbinenko: > On 09.01.2014 22:07, Dr. Tilmann Bubeck wrote: >> This patch extends the ext2 driver to allow embedding core.img into the >> filesystem. This allows the long needed installation of GRUB into a partition >> without the need to use (unsafe) block lists. >> >> It is realized using the ioctl(EXT4_IOC_SWAP_BOOT) introduced into >> Linux 3.10. This ioctl basically swaps the data blocks of the associated >> file with the EXT2_BOOT_LOADER_INO inode. After using the ioctl the code >> of core.img is stored in the BOOT_LOADER incode of the filesystem and it >> is not accessible to file system tools anymore. This ensures, that the boot >> code is safe and installation into a partition is possible. >> > I've already commented on this design here: it not only doesn't > guarantee any kind of blockstability that we need but guarantees quite > the opposite in several scenarios (detailed in previous mails). >> The patchs needs 0001-Refactor-grub_read_mountinfo-out-of-grub_find_root_d.patch >> to work correctly. >>>> Signed-off-by: Dr. Tilmann Bubeck >> --- >> grub-core/fs/ext2.c | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++-- >> util/setup.c | 11 ++- >> 2 files changed, 215 insertions(+), 8 deletions(-) >> >> diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c >> index 5f7a2b9..643969e 100644 >> --- a/grub-core/fs/ext2.c >> +++ b/grub-core/fs/ext2.c >> @@ -133,6 +133,14 @@ GRUB_MOD_LICENSE ("GPLv3+"); >> >> #define EXT4_EXTENTS_FLAG 0x80000 >> >> +/* >> + * Special inodes numbers >> + */ >> +#define EXT2_ROOT_INO 2 /* Root inode */ >> +#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */ >> + >> +#define EXT4_IOC_SWAP_BOOT _IO('f', 17) >> + >> /* The ext2 superblock. */ >> struct grub_ext2_sblock >> { >> @@ -393,10 +401,10 @@ grub_ext4_find_leaf (struct grub_ext2_data *data, >> } >> >> static grub_disk_addr_t >> -grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) >> +grub_ext2_read_block2 (struct grub_ext2_data *data, >> + struct grub_ext2_inode *inode, >> + grub_disk_addr_t fileblock) >> { >> - struct grub_ext2_data *data = node->data; >> - struct grub_ext2_inode *inode = &node->inode; >> unsigned int blksz = EXT2_BLOCK_SIZE (data); >> grub_disk_addr_t blksz_quarter = blksz / 4; >> int log2_blksz = LOG2_EXT2_BLOCK_SIZE (data); >> @@ -497,6 +505,12 @@ indirect: >> return grub_le_to_cpu32 (indir); >> } >> >> +static grub_disk_addr_t >> +grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) >> +{ >> + return grub_ext2_read_block2(node->data, &node->inode, fileblock); >> +} >> + >> /* Read LEN bytes from the file described by DATA starting with byte >> POS. Return the amount of read bytes in READ. */ >> static grub_ssize_t >> @@ -607,12 +621,12 @@ grub_ext2_mount (grub_disk_t disk) >> data->disk = disk; >> >> data->diropen.data = data; >> - data->diropen.ino = 2; >> + data->diropen.ino = EXT2_ROOT_INO; >> data->diropen.inode_read = 1; >> >> data->inode = &data->diropen.inode; >> >> - grub_ext2_read_inode (data, 2, data->inode); >> + grub_ext2_read_inode (data, EXT2_ROOT_INO, data->inode); >> if (grub_errno) >> goto fail; >> >> @@ -977,6 +991,193 @@ grub_ext2_mtime (grub_device_t device, grub_int32_t *tm) >> >> } >> >> +#ifdef GRUB_UTIL >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +/* Read the addresses of all sectors occupied by the file with the >> + given inode from the filesystem. Return the number of sectors in >> + "nsector" and the addresses in "sectors". "sectors" is allocated >> + in this function and must be freed by the caller after usage. >> + A sector in sectors has size GRUB_DISK_SECTOR_SIZE. */ >> +static grub_err_t >> +grub_ext2_read_sectorlist(grub_device_t device, >> + int ino, >> + unsigned int *nsectors, >> + grub_disk_addr_t **sectors) >> +{ >> + struct grub_ext2_data *data; >> + struct grub_ext2_inode inode; >> + grub_off_t size; >> + grub_err_t err; >> + grub_disk_addr_t fileblock; >> + int i; >> + grub_disk_addr_t fileblock_count; >> + int sectors_per_block; >> + >> + data = grub_ext2_mount (device->disk); >> + if (! data) { >> + return grub_error (grub_errno, N_("Unable to mount device")); >> + } >> + >> + err = grub_ext2_read_inode (data, ino, &inode); >> + if (err) >> + return grub_error (err, N_("Unable to read inode #%d"), ino); >> + >> + size = grub_le_to_cpu32 (inode.size); >> + size |= ((grub_off_t) grub_le_to_cpu32 (inode.size_high)) << 32; >> + >> + fileblock_count = size / EXT2_BLOCK_SIZE(data); >> + if ( size % EXT2_BLOCK_SIZE(data) != 0 ) fileblock_count++; >> + >> + sectors_per_block = EXT2_BLOCK_SIZE(data) / GRUB_DISK_SECTOR_SIZE; >> + *sectors = grub_malloc (fileblock_count * sectors_per_block >> + * sizeof (**sectors)); >> + *nsectors = 0; >> + for ( fileblock = 0; fileblock < fileblock_count; fileblock++ ) { >> + (*sectors)[*nsectors] = grub_ext2_read_block2 (data, &inode, fileblock) >> + * sectors_per_block; >> + for ( i = 1; i < sectors_per_block; i++) { >> + (*sectors)[(*nsectors) + i] = (*sectors)[*nsectors] + i; >> + } >> + (*nsectors) += sectors_per_block; >> + } >> + >> + return GRUB_ERR_NONE; >> +} >> + >> +static grub_err_t >> +grub_ext2_embed (grub_device_t device, >> + unsigned int *nsectors, >> + unsigned int max_nsectors, >> + grub_embed_type_t embed_type, >> + grub_disk_addr_t **sectors) >> +{ >> + unsigned i; >> + grub_err_t err; >> + char *mountpoint; >> + struct mountinfo_entry *entries; >> + grub_util_fd_t out; >> + char *core_name; >> + char diskbuffer[GRUB_DISK_SECTOR_SIZE]; >> + unsigned int nsectors_wanted; >> + char *device_name; >> + int ioctl_err; >> + >> + if (embed_type != GRUB_EMBED_PCBIOS) >> + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, >> + N_("ext2 currently supports only PC-BIOS embedding")); >> + >> + if ( device->disk->partition) >> + device_name = grub_xasprintf ("%s,%s", device->disk->name, >> + grub_partition_get_name(device->disk->partition)); >> + else >> + device_name = grub_xasprintf ("%s", device->disk->name); >> + >> + nsectors_wanted = *nsectors; >> + >> + grub_util_info (N_("Embedding %d/%d sectors into ext2 filesystem of %s"), >> + nsectors_wanted, max_nsectors, device_name); >> + >> + /* [1] Check, if the existing boot loader inode exists and has the >> + wanted size: */ >> + err = grub_ext2_read_sectorlist (device, EXT2_BOOT_LOADER_INO, >> + nsectors, sectors); >> + if (!err && *nsectors >= nsectors_wanted && *nsectors <= max_nsectors) { >> + grub_util_info(N_("Reusing existing boot loader inode" >> + " offering %d sectors"), >> + *nsectors); >> + grub_free (device_name); >> + return GRUB_ERR_NONE; /* YES! Everything is fine. */ >> + } >> + >> + /* [2] We have to create a new boot loader inode. */ >> + >> + /* [2.1] Check if device is mounted and get mountpoint: */ >> + mountpoint = NULL; >> + entries = grub_read_mountinfo (); >> + if ( entries ) { >> + for ( i = 0; entries[i].enc_root[0] != 0; i++) { >> + char *grub_dev_of_mount; >> + grub_errno = GRUB_ERR_NONE; /* Clear errno set previously */ >> + grub_dev_of_mount = grub_util_get_grub_dev (entries[i].device); >> + if ( grub_dev_of_mount ) { >> + if ( grub_strcmp (grub_dev_of_mount, device_name) == 0 ) { >> + mountpoint = grub_strdup (entries[i].enc_path); >> + break; >> + } >> + } >> + } >> + free (entries); >> + } >> + >> + grub_errno = GRUB_ERR_NONE; /* Clear errno set previously */ >> + >> + if (!mountpoint) { >> + /* We were unable to find the mountpoint for the device of the >> + filesystem. Maybe it is not mounted? */ >> + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, >> + N_("We are unable to find the mountpoint of %s"), >> + device_name); >> + >> + /** ToDo: Try to mount the filesystem to a temporary location. */ >> + } >> + >> + grub_free (device_name); >> + >> + /* [2.2] Create a new (temporary) file, which then gets the boot loader: */ >> + core_name = grub_util_path_concat (2, mountpoint, ".core.img"); >> + free (mountpoint); >> + out = grub_util_fd_open (core_name, GRUB_UTIL_FD_O_WRONLY >> + | GRUB_UTIL_FD_O_CREATTRUNC); >> + if (!GRUB_UTIL_FD_IS_VALID (out)) { >> + return grub_error (GRUB_ERR_BAD_FS, >> + N_("cannot create `%s': %s"), core_name, >> + grub_util_fd_strerror ()); >> + } >> + for ( i = 0; i < max_nsectors; i++ ) { >> + grub_util_fd_write (out, diskbuffer, GRUB_DISK_SECTOR_SIZE); >> + } >> + grub_util_fd_sync (out); >> + >> + /* [2.3] Make that file to the new boot loader inode by swapping the >> + file of "out" with the boot loader inode: */ >> + ioctl_err = ioctl (out, EXT4_IOC_SWAP_BOOT); >> + if ( ioctl_err ) { >> + err = grub_error (GRUB_ERR_BAD_FS, >> + N_("Error in ioctl(EXT4_IOC_SWAP_BOOT);" >> + "you need Linux >= 3.10: %s"), >> + grub_util_fd_strerror ()); >> + grub_util_fd_close (out); >> + grub_util_unlink (core_name); >> + return err; >> + } >> + grub_util_fd_close (out); >> + >> + /* [2.4] Unlink the core file, now containing the previous boot loader. */ >> + grub_util_unlink (core_name); >> + >> + /* [2.5] Invalidate disk cache and read block list again: */ >> + grub_disk_cache_invalidate_all (); >> + >> + err = grub_ext2_read_sectorlist (device, EXT2_BOOT_LOADER_INO, >> + nsectors, sectors); >> + if ( err ) { >> + return grub_error (GRUB_ERR_BAD_FS, >> + N_("unable to read boot loader inode")); >> + } >> + >> + grub_util_info (N_("Created new boot loader inode offering %d sectors"), >> + *nsectors); >> + >> + return GRUB_ERR_NONE; >> +} >> +#endif >> + >> >> >> static struct grub_fs grub_ext2_fs = >> @@ -990,6 +1191,7 @@ static struct grub_fs grub_ext2_fs = >> .uuid = grub_ext2_uuid, >> .mtime = grub_ext2_mtime, >> #ifdef GRUB_UTIL >> + .embed = grub_ext2_embed, >> .reserved_first_sector = 1, >> .blocklist_install = 1, >> #endif >> diff --git a/util/setup.c b/util/setup.c >> index 9fb91a8..3f4a007 100644 >> --- a/util/setup.c >> +++ b/util/setup.c >> @@ -509,8 +509,10 @@ SETUP (const char *dir, >> if (!err && nsec < core_sectors) >> { >> err = grub_error (GRUB_ERR_OUT_OF_RANGE, >> - N_("Your embedding area is unusually small. " >> - "core.img won't fit in it.")); >> + N_("Your embedding area is unusually small " >> + "(only %d sectors). " >> + "core.img won't fit in it (needs %d sectors)."), >> + nsec, core_sectors); >> } >> >> if (err) >> @@ -583,10 +585,13 @@ SETUP (const char *dir, >> } >> >> /* Write the core image onto the disk. */ >> - for (i = 0; i < nsec; i++) >> + for (i = 0; i < nsec; i++) { >> + grub_util_info ("writing core.img/%d to sector %" PRIuGRUB_UINT64_T, i, >> + sectors[i]); >> grub_disk_write (dest_dev->disk, sectors[i], 0, >> GRUB_DISK_SECTOR_SIZE, >> core_img + i * GRUB_DISK_SECTOR_SIZE); >> + } >> >> grub_free (sectors); >> >> > > > > > _______________________________________________ > Grub-devel mailing list > Grub-devel@gnu.org > https://lists.gnu.org/mailman/listinfo/grub-devel > -- Mit freundlichen Gruessen, Tilmann Bubeck //// dr. tilmann bubeck, it professional & geek //// //// tilmann@bubecks.de / http://www.bubecks.de //// mobile: 0172-8842972 / fon: 0711-7227719 / fax: 0711-7227734 //// widmaierstr. 58 / 70567 stuttgart / germany