From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.71) id 1W1OT9-0004jp-Vw for mharc-grub-devel@gnu.org; Thu, 09 Jan 2014 17:52:56 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:60013) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1W1OT2-0004ji-3o for grub-devel@gnu.org; Thu, 09 Jan 2014 17:52:53 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1W1OSw-0005GF-4A for grub-devel@gnu.org; Thu, 09 Jan 2014 17:52:48 -0500 Received: from mail-ea0-x22b.google.com ([2a00:1450:4013:c01::22b]:63534) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1W1OSv-0005Fz-OX for grub-devel@gnu.org; Thu, 09 Jan 2014 17:52:42 -0500 Received: by mail-ea0-f171.google.com with SMTP id h10so1766731eak.30 for ; Thu, 09 Jan 2014 14:52:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=message-id:date:from:user-agent:mime-version:to:subject:references :in-reply-to:content-type; bh=OdyrMnSzOYTVLs1xhl+M86JAMSGZYWyhMjXruX+AmP0=; b=vNgL/Bki2Oa7gbFT8cAYgv+SumJYRlb1fv8qIaPLdK2lF4bPNMjuzURTtMulM86xxd KkfdYZ1bzOLs50fWTXGANjgTvlbpAd1vtPD3feuJzKzdmBQ0n2u7uFC0xcHstS3r0rHg CoRZYlXP50dF1QRpv6Y9tyefzmdDr9sPQbzKDbBUACGja6Qd7vmvOidgMzJwDZGFdr7C z7IS/r/lzjoutLCzSLW6EcQIM1l+1XjQLCaAP2dBnw/Js1Y/Enj9XWIYC/zEO7G4WL13 CjkYYY81piIWtm8S0azmW7CmaaXHECj0ysGAiuCRFDEDHTlVsyNEC4ERBOb7thzphDI9 0tIw== X-Received: by 10.14.110.134 with SMTP id u6mr5575126eeg.87.1389307958425; Thu, 09 Jan 2014 14:52:38 -0800 (PST) Received: from [192.168.1.16] (85-188.196-178.cust.bluewin.ch. [178.196.188.85]) by mx.google.com with ESMTPSA id o13sm9584928eex.19.2014.01.09.14.52.35 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 09 Jan 2014 14:52:37 -0800 (PST) Message-ID: <52CF282C.4070408@gmail.com> Date: Thu, 09 Jan 2014 23:52:28 +0100 From: =?UTF-8?B?VmxhZGltaXIgJ8+GLWNvZGVyL3BoY29kZXInIFNlcmJpbmVua28=?= User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20131103 Icedove/17.0.10 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> In-Reply-To: <1389301657-8236-1-git-send-email-tilmann@bubecks.de> X-Enigmail-Version: 1.6 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="huDLb478UfDvL7Oj2fddexkFft1oOmjkI" X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a00:1450:4013:c01::22b 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: Thu, 09 Jan 2014 22:52:54 -0000 This is an OpenPGP/MIME signed message (RFC 4880 and 3156) --huDLb478UfDvL7Oj2fddexkFft1oOmjkI Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable 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 par= tition > without the need to use (unsafe) block lists. >=20 > It is realized using the ioctl(EXT4_IOC_SWAP_BOOT) introduced into > Linux 3.10. This ioctl basically swaps the data blocks of the associate= d > file with the EXT2_BOOT_LOADER_INO inode. After using the ioctl the cod= e > of core.img is stored in the BOOT_LOADER incode of the filesystem and i= t > is not accessible to file system tools anymore. This ensures, that the = boot > code is safe and installation into a partition is possible. >=20 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_roo= t_d.patch > to work correctly. >=20 > Signed-off-by: Dr. Tilmann Bubeck > --- > grub-core/fs/ext2.c | 212 ++++++++++++++++++++++++++++++++++++++++++++= ++++++-- > util/setup.c | 11 ++- > 2 files changed, 215 insertions(+), 8 deletions(-) >=20 > 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+"); > =20 > #define EXT4_EXTENTS_FLAG 0x80000 > =20 > +/* > + * 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,= > } > =20 > static grub_disk_addr_t > -grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t filebl= ock) > +grub_ext2_read_block2 (struct grub_ext2_data *data, > + struct grub_ext2_inode *inode, > + grub_disk_addr_t fileblock) > { > - struct grub_ext2_data *data =3D node->data; > - struct grub_ext2_inode *inode =3D &node->inode; > unsigned int blksz =3D EXT2_BLOCK_SIZE (data); > grub_disk_addr_t blksz_quarter =3D blksz / 4; > int log2_blksz =3D LOG2_EXT2_BLOCK_SIZE (data); > @@ -497,6 +505,12 @@ indirect: > return grub_le_to_cpu32 (indir); > } > =20 > +static grub_disk_addr_t > +grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t filebl= ock) > +{ > + 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 =3D disk; > =20 > data->diropen.data =3D data; > - data->diropen.ino =3D 2; > + data->diropen.ino =3D EXT2_ROOT_INO; > data->diropen.inode_read =3D 1; > =20 > data->inode =3D &data->diropen.inode; > =20 > - grub_ext2_read_inode (data, 2, data->inode); > + grub_ext2_read_inode (data, EXT2_ROOT_INO, data->inode); > if (grub_errno) > goto fail; > =20 > @@ -977,6 +991,193 @@ grub_ext2_mtime (grub_device_t device, grub_int32= _t *tm) > =20 > } > =20 > +#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 =3D grub_ext2_mount (device->disk); > + if (! data) { > + return grub_error (grub_errno, N_("Unable to mount device")); > + } > + > + err =3D grub_ext2_read_inode (data, ino, &inode); > + if (err) > + return grub_error (err, N_("Unable to read inode #%d"), ino); > + > + size =3D grub_le_to_cpu32 (inode.size); > + size |=3D ((grub_off_t) grub_le_to_cpu32 (inode.size_high)) << 32; > + > + fileblock_count =3D size / EXT2_BLOCK_SIZE(data); > + if ( size % EXT2_BLOCK_SIZE(data) !=3D 0 ) fileblock_count++; > + > + sectors_per_block =3D EXT2_BLOCK_SIZE(data) / GRUB_DISK_SECTOR_SIZE;= > + *sectors =3D grub_malloc (fileblock_count * sectors_per_block > + * sizeof (**sectors)); > + *nsectors =3D 0; > + for ( fileblock =3D 0; fileblock < fileblock_count; fileblock++ ) { > + (*sectors)[*nsectors] =3D grub_ext2_read_block2 (data, &inode, fil= eblock) > + * sectors_per_block; > + for ( i =3D 1; i < sectors_per_block; i++) { > + (*sectors)[(*nsectors) + i] =3D (*sectors)[*nsectors] + i; > + } > + (*nsectors) +=3D 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 !=3D 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 =3D grub_xasprintf ("%s,%s", device->disk->name, > + grub_partition_get_name(device->disk->partition)); > + else > + device_name =3D grub_xasprintf ("%s", device->disk->name); > + > + nsectors_wanted =3D *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 =3D grub_ext2_read_sectorlist (device, EXT2_BOOT_LOADER_INO, > + nsectors, sectors); > + if (!err && *nsectors >=3D nsectors_wanted && *nsectors <=3D max_nse= ctors) { > + 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 =3D NULL; > + entries =3D grub_read_mountinfo (); > + if ( entries ) { > + for ( i =3D 0; entries[i].enc_root[0] !=3D 0; i++) { > + char *grub_dev_of_mount; > + grub_errno =3D GRUB_ERR_NONE; /* Clear errno set previously *= / > + grub_dev_of_mount =3D grub_util_get_grub_dev (entries[i].device)= ; > + if ( grub_dev_of_mount ) { > + if ( grub_strcmp (grub_dev_of_mount, device_name) =3D=3D 0 ) { > + mountpoint =3D grub_strdup (entries[i].enc_path); > + break; > + } > + } > + } > + free (entries); > + } > + > + grub_errno =3D 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 loa= der: */ > + core_name =3D grub_util_path_concat (2, mountpoint, ".core.img"); > + free (mountpoint); > + out =3D 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 =3D 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 =3D ioctl (out, EXT4_IOC_SWAP_BOOT); > + if ( ioctl_err ) { > + err =3D grub_error (GRUB_ERR_BAD_FS, > + N_("Error in ioctl(EXT4_IOC_SWAP_BOOT);" > + "you need Linux >=3D 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 load= er. */ > + grub_util_unlink (core_name); > + > + /* [2.5] Invalidate disk cache and read block list again: */ > + grub_disk_cache_invalidate_all (); > + > + err =3D 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 sector= s"), > + *nsectors); > + > + return GRUB_ERR_NONE; > +} > +#endif > + > =20 > =0C > static struct grub_fs grub_ext2_fs =3D > @@ -990,6 +1191,7 @@ static struct grub_fs grub_ext2_fs =3D > .uuid =3D grub_ext2_uuid, > .mtime =3D grub_ext2_mtime, > #ifdef GRUB_UTIL > + .embed =3D grub_ext2_embed, > .reserved_first_sector =3D 1, > .blocklist_install =3D 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 =3D 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); > } > =20 > if (err) > @@ -583,10 +585,13 @@ SETUP (const char *dir, > } > =20 > /* Write the core image onto the disk. */ > - for (i =3D 0; i < nsec; i++) > + for (i =3D 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); > + } > =20 > grub_free (sectors); > =20 >=20 --huDLb478UfDvL7Oj2fddexkFft1oOmjkI Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 Comment: Using GnuPG with Icedove - http://www.enigmail.net/ iF4EAREKAAYFAlLPKDIACgkQmBXlbbo5nOvjdwD9F8actn6TYRrStQEDr9blqktL z88aI2r3ybq5eqU1opAA/2rGKM3MqRb8JShK3A32nDQk3p/bcAB0jlUSYwSLs4V+ =lI8E -----END PGP SIGNATURE----- --huDLb478UfDvL7Oj2fddexkFft1oOmjkI--