merge patched into master

This commit is contained in:
Julian Andres Klode 2022-06-10 10:30:47 +02:00
commit 574e41e0da
19 changed files with 503 additions and 169 deletions

2
debian/.git-dpm vendored
View File

@ -1,6 +1,6 @@
# see git-dpm(1) from git-dpm package # see git-dpm(1) from git-dpm package
dbcbb3e5b9fac665b92d630eb24de7bd8c43652e dbcbb3e5b9fac665b92d630eb24de7bd8c43652e
dbcbb3e5b9fac665b92d630eb24de7bd8c43652e 589500ad3777d1335c8e5cb139f7c0c6089112a8
21f954425ffe2a934b6b26c0c948d340c91a16bb 21f954425ffe2a934b6b26c0c948d340c91a16bb
21f954425ffe2a934b6b26c0c948d340c91a16bb 21f954425ffe2a934b6b26c0c948d340c91a16bb
grub2_2.06.orig.tar.xz grub2_2.06.orig.tar.xz

View File

@ -27,10 +27,20 @@
GRUB_MOD_LICENSE ("GPLv3+"); GRUB_MOD_LICENSE ("GPLv3+");
static grub_err_t (*grub_loader_boot_func) (void); static grub_err_t (*grub_loader_boot_func) (void *);
static grub_err_t (*grub_loader_unload_func) (void); static grub_err_t (*grub_loader_unload_func) (void *);
static void *grub_loader_context;
static int grub_loader_flags; static int grub_loader_flags;
struct grub_simple_loader_hooks
{
grub_err_t (*boot) (void);
grub_err_t (*unload) (void);
};
/* Don't heap allocate this to avoid making grub_loader_set fallible. */
static struct grub_simple_loader_hooks simple_loader_hooks;
struct grub_preboot struct grub_preboot
{ {
grub_err_t (*preboot_func) (int); grub_err_t (*preboot_func) (int);
@ -44,6 +54,29 @@ static int grub_loader_loaded;
static struct grub_preboot *preboots_head = 0, static struct grub_preboot *preboots_head = 0,
*preboots_tail = 0; *preboots_tail = 0;
static grub_err_t
grub_simple_boot_hook (void *context)
{
struct grub_simple_loader_hooks *hooks;
hooks = (struct grub_simple_loader_hooks *) context;
return hooks->boot ();
}
static grub_err_t
grub_simple_unload_hook (void *context)
{
struct grub_simple_loader_hooks *hooks;
grub_err_t ret;
hooks = (struct grub_simple_loader_hooks *) context;
ret = hooks->unload ();
grub_memset (hooks, 0, sizeof (*hooks));
return ret;
}
int int
grub_loader_is_loaded (void) grub_loader_is_loaded (void)
{ {
@ -110,28 +143,45 @@ grub_loader_unregister_preboot_hook (struct grub_preboot *hnd)
} }
void void
grub_loader_set (grub_err_t (*boot) (void), grub_loader_set_ex (grub_err_t (*boot) (void *),
grub_err_t (*unload) (void), grub_err_t (*unload) (void *),
int flags) void *context,
int flags)
{ {
if (grub_loader_loaded && grub_loader_unload_func) if (grub_loader_loaded && grub_loader_unload_func)
grub_loader_unload_func (); grub_loader_unload_func (grub_loader_context);
grub_loader_boot_func = boot; grub_loader_boot_func = boot;
grub_loader_unload_func = unload; grub_loader_unload_func = unload;
grub_loader_context = context;
grub_loader_flags = flags; grub_loader_flags = flags;
grub_loader_loaded = 1; grub_loader_loaded = 1;
} }
void
grub_loader_set (grub_err_t (*boot) (void),
grub_err_t (*unload) (void),
int flags)
{
grub_loader_set_ex (grub_simple_boot_hook,
grub_simple_unload_hook,
&simple_loader_hooks,
flags);
simple_loader_hooks.boot = boot;
simple_loader_hooks.unload = unload;
}
void void
grub_loader_unset(void) grub_loader_unset(void)
{ {
if (grub_loader_loaded && grub_loader_unload_func) if (grub_loader_loaded && grub_loader_unload_func)
grub_loader_unload_func (); grub_loader_unload_func (grub_loader_context);
grub_loader_boot_func = 0; grub_loader_boot_func = 0;
grub_loader_unload_func = 0; grub_loader_unload_func = 0;
grub_loader_context = 0;
grub_loader_loaded = 0; grub_loader_loaded = 0;
} }
@ -158,7 +208,7 @@ grub_loader_boot (void)
return err; return err;
} }
} }
err = (grub_loader_boot_func) (); err = (grub_loader_boot_func) (grub_loader_context);
for (cur = preboots_tail; cur; cur = cur->prev) for (cur = preboots_tail; cur; cur = cur->prev)
if (! err) if (! err)

View File

@ -912,6 +912,23 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
return grub_error (GRUB_ERR_BAD_FS, return grub_error (GRUB_ERR_BAD_FS,
"couldn't find the chunk descriptor"); "couldn't find the chunk descriptor");
if (!chsize)
{
grub_dprintf ("btrfs", "zero-size chunk\n");
return grub_error (GRUB_ERR_BAD_FS,
"got an invalid zero-size chunk");
}
/*
* The space being allocated for a chunk should at least be able to
* contain one chunk item.
*/
if (chsize < sizeof (struct grub_btrfs_chunk_item))
{
grub_dprintf ("btrfs", "chunk-size too small\n");
return grub_error (GRUB_ERR_BAD_FS,
"got an invalid chunk size");
}
chunk = grub_malloc (chsize); chunk = grub_malloc (chsize);
if (!chunk) if (!chunk)
return grub_errno; return grub_errno;
@ -970,6 +987,16 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
stripe_length = grub_divmod64 (grub_le_to_cpu64 (chunk->size), stripe_length = grub_divmod64 (grub_le_to_cpu64 (chunk->size),
nstripes, nstripes,
NULL); NULL);
/* For single, there should be exactly 1 stripe. */
if (grub_le_to_cpu16 (chunk->nstripes) != 1)
{
grub_dprintf ("btrfs", "invalid RAID_SINGLE: nstripes != 1 (%u)\n",
grub_le_to_cpu16 (chunk->nstripes));
return grub_error (GRUB_ERR_BAD_FS,
"invalid RAID_SINGLE: nstripes != 1 (%u)",
grub_le_to_cpu16 (chunk->nstripes));
}
if (stripe_length == 0) if (stripe_length == 0)
stripe_length = 512; stripe_length = 512;
stripen = grub_divmod64 (off, stripe_length, &stripe_offset); stripen = grub_divmod64 (off, stripe_length, &stripe_offset);
@ -989,6 +1016,19 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
stripen = 0; stripen = 0;
stripe_offset = off; stripe_offset = off;
csize = grub_le_to_cpu64 (chunk->size) - off; csize = grub_le_to_cpu64 (chunk->size) - off;
/*
* Redundancy, and substripes only apply to RAID10, and there
* should be exactly 2 sub-stripes.
*/
if (grub_le_to_cpu16 (chunk->nstripes) != redundancy)
{
grub_dprintf ("btrfs", "invalid RAID1: nstripes != %u (%u)\n",
redundancy, grub_le_to_cpu16 (chunk->nstripes));
return grub_error (GRUB_ERR_BAD_FS,
"invalid RAID1: nstripes != %u (%u)",
redundancy, grub_le_to_cpu16 (chunk->nstripes));
}
break; break;
} }
case GRUB_BTRFS_CHUNK_TYPE_RAID0: case GRUB_BTRFS_CHUNK_TYPE_RAID0:
@ -1025,6 +1065,20 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
stripe_offset = low + chunk_stripe_length stripe_offset = low + chunk_stripe_length
* high; * high;
csize = chunk_stripe_length - low; csize = chunk_stripe_length - low;
/*
* Substripes only apply to RAID10, and there
* should be exactly 2 sub-stripes.
*/
if (grub_le_to_cpu16 (chunk->nsubstripes) != 2)
{
grub_dprintf ("btrfs", "invalid RAID10: nsubstripes != 2 (%u)",
grub_le_to_cpu16 (chunk->nsubstripes));
return grub_error (GRUB_ERR_BAD_FS,
"invalid RAID10: nsubstripes != 2 (%u)",
grub_le_to_cpu16 (chunk->nsubstripes));
}
break; break;
} }
case GRUB_BTRFS_CHUNK_TYPE_RAID5: case GRUB_BTRFS_CHUNK_TYPE_RAID5:
@ -1122,8 +1176,17 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
if (csize > (grub_uint64_t) size) if (csize > (grub_uint64_t) size)
csize = size; csize = size;
/*
* The space for a chunk stripe is limited to the space provide in the super-block's
* bootstrap mapping with an initial btrfs key at the start of each chunk.
*/
grub_size_t avail_stripes = sizeof (data->sblock.bootstrap_mapping) /
(sizeof (struct grub_btrfs_key) + sizeof (struct grub_btrfs_chunk_stripe));
for (j = 0; j < 2; j++) for (j = 0; j < 2; j++)
{ {
grub_size_t est_chunk_alloc = 0;
grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T
"+0x%" PRIxGRUB_UINT64_T "+0x%" PRIxGRUB_UINT64_T
" (%d stripes (%d substripes) of %" " (%d stripes (%d substripes) of %"
@ -1136,6 +1199,22 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
grub_dprintf ("btrfs", "reading laddr 0x%" PRIxGRUB_UINT64_T "\n", grub_dprintf ("btrfs", "reading laddr 0x%" PRIxGRUB_UINT64_T "\n",
addr); addr);
if (grub_mul (sizeof (struct grub_btrfs_chunk_stripe),
grub_le_to_cpu16 (chunk->nstripes), &est_chunk_alloc) ||
grub_add (est_chunk_alloc,
sizeof (struct grub_btrfs_chunk_item), &est_chunk_alloc) ||
est_chunk_alloc > chunk->size)
{
err = GRUB_ERR_BAD_FS;
break;
}
if (grub_le_to_cpu16 (chunk->nstripes) > avail_stripes)
{
err = GRUB_ERR_BAD_FS;
break;
}
if (is_raid56) if (is_raid56)
{ {
err = btrfs_read_from_chunk (data, chunk, stripen, err = btrfs_read_from_chunk (data, chunk, stripen,
@ -1961,6 +2040,7 @@ grub_btrfs_dir (grub_device_t device, const char *path,
int r = 0; int r = 0;
grub_uint64_t tree; grub_uint64_t tree;
grub_uint8_t type; grub_uint8_t type;
grub_size_t est_size = 0;
if (!data) if (!data)
return grub_errno; return grub_errno;
@ -2019,6 +2099,18 @@ grub_btrfs_dir (grub_device_t device, const char *path,
break; break;
} }
if (direl == NULL ||
grub_add (grub_le_to_cpu16 (direl->n),
grub_le_to_cpu16 (direl->m), &est_size) ||
grub_add (est_size, sizeof (*direl), &est_size) ||
grub_sub (est_size, sizeof (direl->name), &est_size) ||
est_size > allocated)
{
grub_errno = GRUB_ERR_OUT_OF_RANGE;
r = -grub_errno;
goto out;
}
for (cdirel = direl; for (cdirel = direl;
(grub_uint8_t *) cdirel - (grub_uint8_t *) direl (grub_uint8_t *) cdirel - (grub_uint8_t *) direl
< (grub_ssize_t) elemsize; < (grub_ssize_t) elemsize;
@ -2029,6 +2121,19 @@ grub_btrfs_dir (grub_device_t device, const char *path,
char c; char c;
struct grub_btrfs_inode inode; struct grub_btrfs_inode inode;
struct grub_dirhook_info info; struct grub_dirhook_info info;
if (cdirel == NULL ||
grub_add (grub_le_to_cpu16 (cdirel->n),
grub_le_to_cpu16 (cdirel->m), &est_size) ||
grub_add (est_size, sizeof (*cdirel), &est_size) ||
grub_sub (est_size, sizeof (cdirel->name), &est_size) ||
est_size > allocated)
{
grub_errno = GRUB_ERR_OUT_OF_RANGE;
r = -grub_errno;
goto out;
}
err = grub_btrfs_read_inode (data, &inode, cdirel->key.object_id, err = grub_btrfs_read_inode (data, &inode, cdirel->key.object_id,
tree); tree);
grub_memset (&info, 0, sizeof (info)); grub_memset (&info, 0, sizeof (info));

View File

@ -122,6 +122,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
#define F2FS_INLINE_DOTS 0x10 /* File having implicit dot dentries. */ #define F2FS_INLINE_DOTS 0x10 /* File having implicit dot dentries. */
#define MAX_VOLUME_NAME 512 #define MAX_VOLUME_NAME 512
#define MAX_NAT_BITMAP_SIZE 3900
enum FILE_TYPE enum FILE_TYPE
{ {
@ -183,7 +184,7 @@ struct grub_f2fs_checkpoint
grub_uint32_t checksum_offset; grub_uint32_t checksum_offset;
grub_uint64_t elapsed_time; grub_uint64_t elapsed_time;
grub_uint8_t alloc_type[MAX_ACTIVE_LOGS]; grub_uint8_t alloc_type[MAX_ACTIVE_LOGS];
grub_uint8_t sit_nat_version_bitmap[3900]; grub_uint8_t sit_nat_version_bitmap[MAX_NAT_BITMAP_SIZE];
grub_uint32_t checksum; grub_uint32_t checksum;
} GRUB_PACKED; } GRUB_PACKED;
@ -302,6 +303,7 @@ struct grub_f2fs_data
struct grub_f2fs_nat_journal nat_j; struct grub_f2fs_nat_journal nat_j;
char *nat_bitmap; char *nat_bitmap;
grub_uint32_t nat_bitmap_size;
grub_disk_t disk; grub_disk_t disk;
struct grub_f2fs_node *inode; struct grub_f2fs_node *inode;
@ -377,15 +379,20 @@ sum_blk_addr (struct grub_f2fs_data *data, int base, int type)
} }
static void * static void *
nat_bitmap_ptr (struct grub_f2fs_data *data) nat_bitmap_ptr (struct grub_f2fs_data *data, grub_uint32_t *nat_bitmap_size)
{ {
struct grub_f2fs_checkpoint *ckpt = &data->ckpt; struct grub_f2fs_checkpoint *ckpt = &data->ckpt;
grub_uint32_t offset; grub_uint32_t offset;
*nat_bitmap_size = MAX_NAT_BITMAP_SIZE;
if (grub_le_to_cpu32 (data->sblock.cp_payload) > 0) if (grub_le_to_cpu32 (data->sblock.cp_payload) > 0)
return ckpt->sit_nat_version_bitmap; return ckpt->sit_nat_version_bitmap;
offset = grub_le_to_cpu32 (ckpt->sit_ver_bitmap_bytesize); offset = grub_le_to_cpu32 (ckpt->sit_ver_bitmap_bytesize);
if (offset >= MAX_NAT_BITMAP_SIZE)
return NULL;
*nat_bitmap_size = *nat_bitmap_size - offset;
return ckpt->sit_nat_version_bitmap + offset; return ckpt->sit_nat_version_bitmap + offset;
} }
@ -438,11 +445,15 @@ grub_f2fs_crc_valid (grub_uint32_t blk_crc, void *buf, const grub_uint32_t len)
} }
static int static int
grub_f2fs_test_bit (grub_uint32_t nr, const char *p) grub_f2fs_test_bit (grub_uint32_t nr, const char *p, grub_uint32_t len)
{ {
int mask; int mask;
grub_uint32_t shifted_nr = (nr >> 3);
p += (nr >> 3); if (shifted_nr >= len)
return -1;
p += shifted_nr;
mask = 1 << (7 - (nr & 0x07)); mask = 1 << (7 - (nr & 0x07));
return mask & *p; return mask & *p;
@ -632,23 +643,27 @@ get_nat_journal (struct grub_f2fs_data *data)
return err; return err;
} }
static grub_uint32_t static grub_err_t
get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid) get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid,
grub_uint32_t *blkaddr)
{ {
grub_uint16_t n = grub_le_to_cpu16 (data->nat_j.n_nats); grub_uint16_t n = grub_le_to_cpu16 (data->nat_j.n_nats);
grub_uint32_t blkaddr = 0;
grub_uint16_t i; grub_uint16_t i;
if (n >= NAT_JOURNAL_ENTRIES)
return grub_error (GRUB_ERR_BAD_FS,
"invalid number of nat journal entries");
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
{ {
if (grub_le_to_cpu32 (data->nat_j.entries[i].nid) == nid) if (grub_le_to_cpu32 (data->nat_j.entries[i].nid) == nid)
{ {
blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr); *blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr);
break; break;
} }
} }
return blkaddr; return GRUB_ERR_NONE;
} }
static grub_uint32_t static grub_uint32_t
@ -656,10 +671,14 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid)
{ {
struct grub_f2fs_nat_block *nat_block; struct grub_f2fs_nat_block *nat_block;
grub_uint32_t seg_off, block_off, entry_off, block_addr; grub_uint32_t seg_off, block_off, entry_off, block_addr;
grub_uint32_t blkaddr; grub_uint32_t blkaddr = 0;
grub_err_t err; grub_err_t err;
int result_bit;
err = get_blkaddr_from_nat_journal (data, nid, &blkaddr);
if (err != GRUB_ERR_NONE)
return 0;
blkaddr = get_blkaddr_from_nat_journal (data, nid);
if (blkaddr) if (blkaddr)
return blkaddr; return blkaddr;
@ -675,8 +694,15 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid)
((seg_off * data->blocks_per_seg) << 1) + ((seg_off * data->blocks_per_seg) << 1) +
(block_off & (data->blocks_per_seg - 1)); (block_off & (data->blocks_per_seg - 1));
if (grub_f2fs_test_bit (block_off, data->nat_bitmap)) result_bit = grub_f2fs_test_bit (block_off, data->nat_bitmap,
data->nat_bitmap_size);
if (result_bit > 0)
block_addr += data->blocks_per_seg; block_addr += data->blocks_per_seg;
else if (result_bit == -1)
{
grub_free (nat_block);
return 0;
}
err = grub_f2fs_block_read (data, block_addr, nat_block); err = grub_f2fs_block_read (data, block_addr, nat_block);
if (err) if (err)
@ -826,7 +852,9 @@ grub_f2fs_mount (grub_disk_t disk)
if (err) if (err)
goto fail; goto fail;
data->nat_bitmap = nat_bitmap_ptr (data); data->nat_bitmap = nat_bitmap_ptr (data, &data->nat_bitmap_size);
if (data->nat_bitmap == NULL)
goto fail;
err = get_nat_journal (data); err = get_nat_journal (data);
if (err) if (err)
@ -975,6 +1003,10 @@ grub_f2fs_check_dentries (struct grub_f2fs_dir_iter_ctx *ctx)
ftype = ctx->dentry[i].file_type; ftype = ctx->dentry[i].file_type;
name_len = grub_le_to_cpu16 (ctx->dentry[i].name_len); name_len = grub_le_to_cpu16 (ctx->dentry[i].name_len);
if (name_len >= F2FS_NAME_LEN)
return 0;
filename = grub_malloc (name_len + 1); filename = grub_malloc (name_len + 1);
if (!filename) if (!filename)
return 0; return 0;

View File

@ -119,10 +119,11 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)),
void **context __attribute__ ((unused)), void **context __attribute__ ((unused)),
enum grub_verify_flags *flags) enum grub_verify_flags *flags)
{ {
*flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; *flags = GRUB_VERIFY_FLAGS_NONE;
switch (type & GRUB_FILE_TYPE_MASK) switch (type & GRUB_FILE_TYPE_MASK)
{ {
/* Files we check. */
case GRUB_FILE_TYPE_LINUX_KERNEL: case GRUB_FILE_TYPE_LINUX_KERNEL:
case GRUB_FILE_TYPE_MULTIBOOT_KERNEL: case GRUB_FILE_TYPE_MULTIBOOT_KERNEL:
case GRUB_FILE_TYPE_BSD_KERNEL: case GRUB_FILE_TYPE_BSD_KERNEL:
@ -130,11 +131,43 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)),
case GRUB_FILE_TYPE_PLAN9_KERNEL: case GRUB_FILE_TYPE_PLAN9_KERNEL:
case GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE: case GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE:
*flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK; *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK;
/* Fall through. */
default:
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
/* Files that do not affect secureboot state. */
case GRUB_FILE_TYPE_NONE:
case GRUB_FILE_TYPE_LOOPBACK:
case GRUB_FILE_TYPE_LINUX_INITRD:
case GRUB_FILE_TYPE_OPENBSD_RAMDISK:
case GRUB_FILE_TYPE_XNU_RAMDISK:
case GRUB_FILE_TYPE_SIGNATURE:
case GRUB_FILE_TYPE_PUBLIC_KEY:
case GRUB_FILE_TYPE_PUBLIC_KEY_TRUST:
case GRUB_FILE_TYPE_PRINT_BLOCKLIST:
case GRUB_FILE_TYPE_TESTLOAD:
case GRUB_FILE_TYPE_GET_SIZE:
case GRUB_FILE_TYPE_FONT:
case GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY:
case GRUB_FILE_TYPE_CAT:
case GRUB_FILE_TYPE_HEXCAT:
case GRUB_FILE_TYPE_CMP:
case GRUB_FILE_TYPE_HASHLIST:
case GRUB_FILE_TYPE_TO_HASH:
case GRUB_FILE_TYPE_KEYBOARD_LAYOUT:
case GRUB_FILE_TYPE_PIXMAP:
case GRUB_FILE_TYPE_GRUB_MODULE_LIST:
case GRUB_FILE_TYPE_CONFIG:
case GRUB_FILE_TYPE_THEME:
case GRUB_FILE_TYPE_GETTEXT_CATALOG:
case GRUB_FILE_TYPE_FS_SEARCH:
case GRUB_FILE_TYPE_LOADENV:
case GRUB_FILE_TYPE_SAVEENV:
case GRUB_FILE_TYPE_VERIFY_SIGNATURE:
*flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
return GRUB_ERR_NONE;
/* Other files. */
default:
return grub_error (GRUB_ERR_ACCESS_DENIED, N_("prohibited by secure boot policy"));
} }
} }

View File

@ -79,6 +79,7 @@ grub_file_open (const char *name, enum grub_file_type type)
device = grub_device_open (device_name); device = grub_device_open (device_name);
grub_free (device_name); grub_free (device_name);
device_name = NULL;
if (! device) if (! device)
goto fail; goto fail;
@ -131,6 +132,7 @@ grub_file_open (const char *name, enum grub_file_type type)
return file; return file;
fail: fail:
grub_free (device_name);
if (device) if (device)
grub_device_close (device); grub_device_close (device);

View File

@ -44,33 +44,28 @@ GRUB_MOD_LICENSE ("GPLv3+");
static grub_dl_t my_mod; static grub_dl_t my_mod;
static grub_efi_physical_address_t address;
static grub_efi_uintn_t pages;
static grub_efi_device_path_t *file_path;
static grub_efi_handle_t image_handle;
static grub_efi_char16_t *cmdline;
static grub_err_t static grub_err_t
grub_chainloader_unload (void) grub_chainloader_unload (void *context)
{ {
grub_efi_handle_t image_handle = (grub_efi_handle_t) context;
grub_efi_loaded_image_t *loaded_image;
grub_efi_boot_services_t *b; grub_efi_boot_services_t *b;
loaded_image = grub_efi_get_loaded_image (image_handle);
if (loaded_image != NULL)
grub_free (loaded_image->load_options);
b = grub_efi_system_table->boot_services; b = grub_efi_system_table->boot_services;
efi_call_1 (b->unload_image, image_handle); efi_call_1 (b->unload_image, image_handle);
efi_call_2 (b->free_pages, address, pages);
grub_free (file_path);
grub_free (cmdline);
cmdline = 0;
file_path = 0;
grub_dl_unref (my_mod); grub_dl_unref (my_mod);
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }
static grub_err_t static grub_err_t
grub_chainloader_boot (void) grub_chainloader_boot (void *context)
{ {
grub_efi_handle_t image_handle = (grub_efi_handle_t) context;
grub_efi_boot_services_t *b; grub_efi_boot_services_t *b;
grub_efi_status_t status; grub_efi_status_t status;
grub_efi_uintn_t exit_data_size; grub_efi_uintn_t exit_data_size;
@ -140,7 +135,7 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename)
char *dir_start; char *dir_start;
char *dir_end; char *dir_end;
grub_size_t size; grub_size_t size;
grub_efi_device_path_t *d; grub_efi_device_path_t *d, *file_path;
dir_start = grub_strchr (filename, ')'); dir_start = grub_strchr (filename, ')');
if (! dir_start) if (! dir_start)
@ -222,11 +217,15 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
grub_efi_status_t status; grub_efi_status_t status;
grub_efi_boot_services_t *b; grub_efi_boot_services_t *b;
grub_device_t dev = 0; grub_device_t dev = 0;
grub_efi_device_path_t *dp = 0; grub_efi_device_path_t *dp = NULL, *file_path = NULL;
grub_efi_loaded_image_t *loaded_image; grub_efi_loaded_image_t *loaded_image;
char *filename; char *filename;
void *boot_image = 0; void *boot_image = 0;
grub_efi_handle_t dev_handle = 0; grub_efi_handle_t dev_handle = 0;
grub_efi_physical_address_t address = 0;
grub_efi_uintn_t pages = 0;
grub_efi_char16_t *cmdline = NULL;
grub_efi_handle_t image_handle = NULL;
if (argc == 0) if (argc == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
@ -234,11 +233,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
grub_dl_ref (my_mod); grub_dl_ref (my_mod);
/* Initialize some global variables. */
address = 0;
image_handle = 0;
file_path = 0;
b = grub_efi_system_table->boot_services; b = grub_efi_system_table->boot_services;
file = grub_file_open (filename, GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE); file = grub_file_open (filename, GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE);
@ -408,7 +402,11 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
grub_file_close (file); grub_file_close (file);
grub_device_close (dev); grub_device_close (dev);
grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0); /* We're finished with the source image buffer and file path now. */
efi_call_2 (b->free_pages, address, pages);
grub_free (file_path);
grub_loader_set_ex (grub_chainloader_boot, grub_chainloader_unload, image_handle, 0);
return 0; return 0;
fail: fail:
@ -419,11 +417,15 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
if (file) if (file)
grub_file_close (file); grub_file_close (file);
grub_free (cmdline);
grub_free (file_path); grub_free (file_path);
if (address) if (address)
efi_call_2 (b->free_pages, address, pages); efi_call_2 (b->free_pages, address, pages);
if (image_handle != NULL)
efi_call_1 (b->unload_image, image_handle);
grub_dl_unref (my_mod); grub_dl_unref (my_mod);
return grub_errno; return grub_errno;

View File

@ -146,11 +146,18 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head,
int *length, char *set) int *length, char *set)
{ {
const char *readable_ptr = check_with; const char *readable_ptr = check_with;
int readable_len;
const grub_uint8_t *ptr; const grub_uint8_t *ptr;
char *optr = set; char *optr = set;
int bytes_processed = 0; int bytes_processed = 0;
if (length) if (length)
*length = 0; *length = 0;
if (readable_ptr != NULL)
readable_len = grub_strlen (readable_ptr);
else
readable_len = 0;
for (ptr = name_at; ptr < tail && bytes_processed < tail - head + 2; ) for (ptr = name_at; ptr < tail && bytes_processed < tail - head + 2; )
{ {
/* End marker. */ /* End marker. */
@ -172,13 +179,16 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head,
ptr = head + (((ptr[0] & 0x3f) << 8) | ptr[1]); ptr = head + (((ptr[0] & 0x3f) << 8) | ptr[1]);
continue; continue;
} }
if (readable_ptr && grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0) if (readable_ptr != NULL && (*ptr > readable_len || grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0))
return 0; return 0;
if (grub_memchr (ptr + 1, 0, *ptr) if (grub_memchr (ptr + 1, 0, *ptr)
|| grub_memchr (ptr + 1, '.', *ptr)) || grub_memchr (ptr + 1, '.', *ptr))
return 0; return 0;
if (readable_ptr) if (readable_ptr)
readable_ptr += *ptr; {
readable_ptr += *ptr;
readable_len -= *ptr;
}
if (readable_ptr && *readable_ptr != '.' && *readable_ptr != 0) if (readable_ptr && *readable_ptr != '.' && *readable_ptr != 0)
return 0; return 0;
bytes_processed += *ptr + 1; bytes_processed += *ptr + 1;
@ -192,7 +202,10 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head,
if (optr) if (optr)
*optr++ = '.'; *optr++ = '.';
if (readable_ptr && *readable_ptr) if (readable_ptr && *readable_ptr)
readable_ptr++; {
readable_ptr++;
readable_len--;
}
ptr += *ptr + 1; ptr += *ptr + 1;
} }
return 0; return 0;
@ -667,9 +680,11 @@ grub_cmd_nslookup (struct grub_command *cmd __attribute__ ((unused)),
grub_net_addr_to_str (&addresses[i], buf); grub_net_addr_to_str (&addresses[i], buf);
grub_printf ("%s\n", buf); grub_printf ("%s\n", buf);
} }
grub_free (addresses);
if (naddresses) if (naddresses)
return GRUB_ERR_NONE; {
grub_free (addresses);
return GRUB_ERR_NONE;
}
return grub_error (GRUB_ERR_NET_NO_DOMAIN, N_("no DNS record found")); return grub_error (GRUB_ERR_NET_NO_DOMAIN, N_("no DNS record found"));
} }

View File

@ -68,7 +68,15 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len)
char *end = ptr + len; char *end = ptr + len;
while (end > ptr && *(end - 1) == '\r') while (end > ptr && *(end - 1) == '\r')
end--; end--;
/* LF without CR. */
if (end == ptr + len)
{
data->errmsg = grub_strdup (_("invalid HTTP header - LF without CR"));
return GRUB_ERR_NONE;
}
*end = 0; *end = 0;
/* Trailing CRLF. */ /* Trailing CRLF. */
if (data->in_chunk_len == 1) if (data->in_chunk_len == 1)
{ {
@ -190,9 +198,7 @@ http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)),
int have_line = 1; int have_line = 1;
char *t; char *t;
ptr = grub_memchr (nb->data, '\n', nb->tail - nb->data); ptr = grub_memchr (nb->data, '\n', nb->tail - nb->data);
if (ptr) if (ptr == NULL)
ptr++;
else
{ {
have_line = 0; have_line = 0;
ptr = (char *) nb->tail; ptr = (char *) nb->tail;
@ -422,7 +428,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
return err; return err;
} }
for (i = 0; !data->headers_recv && i < 100; i++) for (i = 0; data->sock && !data->headers_recv && i < 100; i++)
{ {
grub_net_tcp_retransmit (); grub_net_tcp_retransmit ();
grub_net_poll_cards (300, &data->headers_recv); grub_net_poll_cards (300, &data->headers_recv);
@ -430,7 +436,8 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
if (!data->headers_recv) if (!data->headers_recv)
{ {
grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); if (data->sock)
grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT);
if (data->err) if (data->err)
{ {
char *str = data->errmsg; char *str = data->errmsg;

View File

@ -25,6 +25,7 @@
#include <grub/net/netbuff.h> #include <grub/net/netbuff.h>
#include <grub/mm.h> #include <grub/mm.h>
#include <grub/priority_queue.h> #include <grub/priority_queue.h>
#include <grub/safemath.h>
#include <grub/time.h> #include <grub/time.h>
struct iphdr { struct iphdr {
@ -551,7 +552,14 @@ grub_net_recv_ip4_packets (struct grub_net_buff *nb,
{ {
rsm->total_len = (8 * (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK) rsm->total_len = (8 * (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK)
+ (nb->tail - nb->data)); + (nb->tail - nb->data));
rsm->total_len -= ((iph->verhdrlen & 0xf) * sizeof (grub_uint32_t));
if (grub_sub (rsm->total_len, (iph->verhdrlen & 0xf) * sizeof (grub_uint32_t),
&rsm->total_len))
{
grub_dprintf ("net", "IP reassembly size underflow\n");
return GRUB_ERR_NONE;
}
rsm->asm_netbuff = grub_netbuff_alloc (rsm->total_len); rsm->asm_netbuff = grub_netbuff_alloc (rsm->total_len);
if (!rsm->asm_netbuff) if (!rsm->asm_netbuff)
{ {

View File

@ -1548,7 +1548,8 @@ grub_net_fs_close (grub_file_t file)
grub_netbuff_free (file->device->net->packs.first->nb); grub_netbuff_free (file->device->net->packs.first->nb);
grub_net_remove_packet (file->device->net->packs.first); grub_net_remove_packet (file->device->net->packs.first);
} }
file->device->net->protocol->close (file); if (!file->device->net->broken)
file->device->net->protocol->close (file);
grub_free (file->device->net->name); grub_free (file->device->net->name);
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }
@ -1770,7 +1771,10 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset)
file->device->net->stall = 0; file->device->net->stall = 0;
err = file->device->net->protocol->open (file, file->device->net->name); err = file->device->net->protocol->open (file, file->device->net->name);
if (err) if (err)
return err; {
file->device->net->broken = 1;
return err;
}
grub_net_fs_read_real (file, NULL, offset); grub_net_fs_read_real (file, NULL, offset);
return grub_errno; return grub_errno;
} }
@ -1779,6 +1783,9 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset)
static grub_ssize_t static grub_ssize_t
grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len) grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len)
{ {
if (file->device->net->broken)
return -1;
if (file->offset != file->device->net->offset) if (file->offset != file->device->net->offset)
{ {
grub_err_t err; grub_err_t err;

View File

@ -79,10 +79,23 @@ grub_netbuff_alloc (grub_size_t len)
COMPILE_TIME_ASSERT (NETBUFF_ALIGN % sizeof (grub_properly_aligned_t) == 0); COMPILE_TIME_ASSERT (NETBUFF_ALIGN % sizeof (grub_properly_aligned_t) == 0);
/*
* The largest size of a TCP packet is 64 KiB, and everything else
* should be a lot smaller - most MTUs are 1500 or less. Cap data
* size at 64 KiB + a buffer.
*/
if (len > 0xffffUL + 0x1000UL)
{
grub_error (GRUB_ERR_BUG,
"attempted to allocate a packet that is too big");
return NULL;
}
if (len < NETBUFFMINLEN) if (len < NETBUFFMINLEN)
len = NETBUFFMINLEN; len = NETBUFFMINLEN;
len = ALIGN_UP (len, NETBUFF_ALIGN); len = ALIGN_UP (len, NETBUFF_ALIGN);
#ifdef GRUB_MACHINE_EMU #ifdef GRUB_MACHINE_EMU
data = grub_malloc (len + sizeof (*nb)); data = grub_malloc (len + sizeof (*nb));
#else #else

View File

@ -251,9 +251,9 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)),
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
case TFTP_ERROR: case TFTP_ERROR:
data->have_oack = 1; data->have_oack = 1;
grub_netbuff_free (nb);
grub_error (GRUB_ERR_IO, "%s", tftph->u.err.errmsg); grub_error (GRUB_ERR_IO, "%s", tftph->u.err.errmsg);
grub_error_save (&data->save_err); grub_error_save (&data->save_err);
grub_netbuff_free (nb);
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
default: default:
grub_netbuff_free (nb); grub_netbuff_free (nb);
@ -404,6 +404,7 @@ tftp_open (struct grub_file *file, const char *filename)
{ {
grub_net_udp_close (data->sock); grub_net_udp_close (data->sock);
grub_free (data); grub_free (data);
file->data = NULL;
return grub_errno; return grub_errno;
} }

View File

@ -395,6 +395,8 @@ grub_unicode_estimate_width (const struct grub_unicode_glyph *c)
{ {
if (grub_unicode_get_comb_type (c->base)) if (grub_unicode_get_comb_type (c->base))
return 0; return 0;
if (((unsigned long) (c->base >> 3)) >= ARRAY_SIZE (widthspec))
return 1;
if (widthspec[c->base >> 3] & (1 << (c->base & 7))) if (widthspec[c->base >> 3] & (1 << (c->base & 7)))
return 2; return 2;
else else

View File

@ -23,6 +23,7 @@
#include <grub/mm.h> #include <grub/mm.h>
#include <grub/misc.h> #include <grub/misc.h>
#include <grub/bufio.h> #include <grub/bufio.h>
#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+"); GRUB_MOD_LICENSE ("GPLv3+");
@ -109,9 +110,17 @@ static grub_uint8_t
grub_jpeg_get_byte (struct grub_jpeg_data *data) grub_jpeg_get_byte (struct grub_jpeg_data *data)
{ {
grub_uint8_t r; grub_uint8_t r;
grub_ssize_t bytes_read;
r = 0; r = 0;
grub_file_read (data->file, &r, 1); bytes_read = grub_file_read (data->file, &r, 1);
if (bytes_read != 1)
{
grub_error (GRUB_ERR_BAD_FILE_TYPE,
"jpeg: unexpected end of data");
return 0;
}
return r; return r;
} }
@ -120,9 +129,17 @@ static grub_uint16_t
grub_jpeg_get_word (struct grub_jpeg_data *data) grub_jpeg_get_word (struct grub_jpeg_data *data)
{ {
grub_uint16_t r; grub_uint16_t r;
grub_ssize_t bytes_read;
r = 0; r = 0;
grub_file_read (data->file, &r, sizeof (grub_uint16_t)); bytes_read = grub_file_read (data->file, &r, sizeof (grub_uint16_t));
if (bytes_read != sizeof (grub_uint16_t))
{
grub_error (GRUB_ERR_BAD_FILE_TYPE,
"jpeg: unexpected end of data");
return 0;
}
return grub_be_to_cpu16 (r); return grub_be_to_cpu16 (r);
} }
@ -135,6 +152,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data)
if (data->bit_mask == 0) if (data->bit_mask == 0)
{ {
data->bit_save = grub_jpeg_get_byte (data); data->bit_save = grub_jpeg_get_byte (data);
if (grub_errno != GRUB_ERR_NONE) {
grub_error (GRUB_ERR_BAD_FILE_TYPE,
"jpeg: file read error");
return 0;
}
if (data->bit_save == JPEG_ESC_CHAR) if (data->bit_save == JPEG_ESC_CHAR)
{ {
if (grub_jpeg_get_byte (data) != 0) if (grub_jpeg_get_byte (data) != 0)
@ -143,6 +165,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data)
"jpeg: invalid 0xFF in data stream"); "jpeg: invalid 0xFF in data stream");
return 0; return 0;
} }
if (grub_errno != GRUB_ERR_NONE)
{
grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: file read error");
return 0;
}
} }
data->bit_mask = 0x80; data->bit_mask = 0x80;
} }
@ -161,7 +188,7 @@ grub_jpeg_get_number (struct grub_jpeg_data *data, int num)
return 0; return 0;
msb = value = grub_jpeg_get_bit (data); msb = value = grub_jpeg_get_bit (data);
for (i = 1; i < num; i++) for (i = 1; i < num && grub_errno == GRUB_ERR_NONE; i++)
value = (value << 1) + (grub_jpeg_get_bit (data) != 0); value = (value << 1) + (grub_jpeg_get_bit (data) != 0);
if (!msb) if (!msb)
value += 1 - (1 << num); value += 1 - (1 << num);
@ -202,6 +229,8 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data)
while (data->file->offset + sizeof (count) + 1 <= next_marker) while (data->file->offset + sizeof (count) + 1 <= next_marker)
{ {
id = grub_jpeg_get_byte (data); id = grub_jpeg_get_byte (data);
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
ac = (id >> 4) & 1; ac = (id >> 4) & 1;
id &= 0xF; id &= 0xF;
if (id > 1) if (id > 1)
@ -217,6 +246,9 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data)
n += count[i]; n += count[i];
id += ac * 2; id += ac * 2;
if (data->huff_value[id] != NULL)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"jpeg: attempt to reallocate huffman table");
data->huff_value[id] = grub_malloc (n); data->huff_value[id] = grub_malloc (n);
if (grub_errno) if (grub_errno)
return grub_errno; return grub_errno;
@ -252,6 +284,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data)
next_marker = data->file->offset; next_marker = data->file->offset;
next_marker += grub_jpeg_get_word (data); next_marker += grub_jpeg_get_word (data);
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
if (next_marker > data->file->size) if (next_marker > data->file->size)
{ {
@ -263,6 +297,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data)
<= next_marker) <= next_marker)
{ {
id = grub_jpeg_get_byte (data); id = grub_jpeg_get_byte (data);
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
if (id >= 0x10) /* Upper 4-bit is precision. */ if (id >= 0x10) /* Upper 4-bit is precision. */
return grub_error (GRUB_ERR_BAD_FILE_TYPE, return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"jpeg: only 8-bit precision is supported"); "jpeg: only 8-bit precision is supported");
@ -294,6 +330,9 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data)
next_marker = data->file->offset; next_marker = data->file->offset;
next_marker += grub_jpeg_get_word (data); next_marker += grub_jpeg_get_word (data);
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
if (grub_jpeg_get_byte (data) != 8) if (grub_jpeg_get_byte (data) != 8)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"jpeg: only 8-bit precision is supported"); "jpeg: only 8-bit precision is supported");
@ -319,6 +358,8 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index");
ss = grub_jpeg_get_byte (data); /* Sampling factor. */ ss = grub_jpeg_get_byte (data); /* Sampling factor. */
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
if (!id) if (!id)
{ {
grub_uint8_t vs, hs; grub_uint8_t vs, hs;
@ -498,7 +539,7 @@ grub_jpeg_idct_transform (jpeg_data_unit_t du)
} }
} }
static void static grub_err_t
grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du)
{ {
int h1, h2, qt; int h1, h2, qt;
@ -513,6 +554,9 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du)
data->dc_value[id] += data->dc_value[id] +=
grub_jpeg_get_number (data, grub_jpeg_get_huff_code (data, h1)); grub_jpeg_get_number (data, grub_jpeg_get_huff_code (data, h1));
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
du[0] = data->dc_value[id] * (int) data->quan_table[qt][0]; du[0] = data->dc_value[id] * (int) data->quan_table[qt][0];
pos = 1; pos = 1;
while (pos < ARRAY_SIZE (data->quan_table[qt])) while (pos < ARRAY_SIZE (data->quan_table[qt]))
@ -527,11 +571,13 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du)
num >>= 4; num >>= 4;
pos += num; pos += num;
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
if (pos >= ARRAY_SIZE (jpeg_zigzag_order)) if (pos >= ARRAY_SIZE (jpeg_zigzag_order))
{ {
grub_error (GRUB_ERR_BAD_FILE_TYPE, return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"jpeg: invalid position in zigzag order!?"); "jpeg: invalid position in zigzag order!?");
return;
} }
du[jpeg_zigzag_order[pos]] = val * (int) data->quan_table[qt][pos]; du[jpeg_zigzag_order[pos]] = val * (int) data->quan_table[qt][pos];
@ -539,6 +585,7 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du)
} }
grub_jpeg_idct_transform (du); grub_jpeg_idct_transform (du);
return GRUB_ERR_NONE;
} }
static void static void
@ -597,7 +644,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data)
data_offset += grub_jpeg_get_word (data); data_offset += grub_jpeg_get_word (data);
cc = grub_jpeg_get_byte (data); cc = grub_jpeg_get_byte (data);
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
if (cc != 3 && cc != 1) if (cc != 3 && cc != 1)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"jpeg: component count must be 1 or 3"); "jpeg: component count must be 1 or 3");
@ -610,7 +658,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data)
id = grub_jpeg_get_byte (data) - 1; id = grub_jpeg_get_byte (data) - 1;
if ((id < 0) || (id >= 3)) if ((id < 0) || (id >= 3))
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index");
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
ht = grub_jpeg_get_byte (data); ht = grub_jpeg_get_byte (data);
data->comp_index[id][1] = (ht >> 4); data->comp_index[id][1] = (ht >> 4);
data->comp_index[id][2] = (ht & 0xF) + 2; data->comp_index[id][2] = (ht & 0xF) + 2;
@ -618,14 +667,20 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data)
if ((data->comp_index[id][1] < 0) || (data->comp_index[id][1] > 3) || if ((data->comp_index[id][1] < 0) || (data->comp_index[id][1] > 3) ||
(data->comp_index[id][2] < 0) || (data->comp_index[id][2] > 3)) (data->comp_index[id][2] < 0) || (data->comp_index[id][2] > 3))
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid hufftable index"); return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid hufftable index");
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
} }
grub_jpeg_get_byte (data); /* Skip 3 unused bytes. */ grub_jpeg_get_byte (data); /* Skip 3 unused bytes. */
grub_jpeg_get_word (data); grub_jpeg_get_word (data);
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
if (data->file->offset != data_offset) if (data->file->offset != data_offset)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos"); return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos");
if (*data->bitmap)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many start of scan blocks");
if (grub_video_bitmap_create (data->bitmap, data->image_width, if (grub_video_bitmap_create (data->bitmap, data->image_width,
data->image_height, data->image_height,
GRUB_VIDEO_BLIT_FORMAT_RGB_888)) GRUB_VIDEO_BLIT_FORMAT_RGB_888))
@ -639,7 +694,9 @@ static grub_err_t
grub_jpeg_decode_data (struct grub_jpeg_data *data) grub_jpeg_decode_data (struct grub_jpeg_data *data)
{ {
unsigned c1, vb, hb, nr1, nc1; unsigned c1, vb, hb, nr1, nc1;
unsigned stride_a, stride_b, stride;
int rst = data->dri; int rst = data->dri;
grub_err_t err = GRUB_ERR_NONE;
vb = 8 << data->log_vs; vb = 8 << data->log_vs;
hb = 8 << data->log_hs; hb = 8 << data->log_hs;
@ -647,11 +704,17 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data)
nc1 = (data->image_width + hb - 1) >> (3 + data->log_hs); nc1 = (data->image_width + hb - 1) >> (3 + data->log_hs);
if (data->bitmap_ptr == NULL) if (data->bitmap_ptr == NULL)
return grub_error(GRUB_ERR_BAD_FILE_TYPE, return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"jpeg: attempted to decode data before start of stream"); "jpeg: attempted to decode data before start of stream");
if (grub_mul(vb, data->image_width, &stride_a) ||
grub_mul(hb, nc1, &stride_b) ||
grub_sub(stride_a, stride_b, &stride))
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"jpeg: cannot decode image with these dimensions");
for (; data->r1 < nr1 && (!data->dri || rst); for (; data->r1 < nr1 && (!data->dri || rst);
data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) data->r1++, data->bitmap_ptr += stride * 3)
for (c1 = 0; c1 < nc1 && (!data->dri || rst); for (c1 = 0; c1 < nc1 && (!data->dri || rst);
c1++, rst--, data->bitmap_ptr += hb * 3) c1++, rst--, data->bitmap_ptr += hb * 3)
{ {
@ -660,17 +723,22 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data)
for (r2 = 0; r2 < (1U << data->log_vs); r2++) for (r2 = 0; r2 < (1U << data->log_vs); r2++)
for (c2 = 0; c2 < (1U << data->log_hs); c2++) for (c2 = 0; c2 < (1U << data->log_hs); c2++)
grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]); {
err = grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]);
if (err != GRUB_ERR_NONE)
return err;
}
if (data->color_components >= 3) if (data->color_components >= 3)
{ {
grub_jpeg_decode_du (data, 1, data->cbdu); err = grub_jpeg_decode_du (data, 1, data->cbdu);
grub_jpeg_decode_du (data, 2, data->crdu); if (err != GRUB_ERR_NONE)
return err;
err = grub_jpeg_decode_du (data, 2, data->crdu);
if (err != GRUB_ERR_NONE)
return err;
} }
if (grub_errno)
return grub_errno;
nr2 = (data->r1 == nr1 - 1) ? (data->image_height - data->r1 * vb) : vb; nr2 = (data->r1 == nr1 - 1) ? (data->image_height - data->r1 * vb) : vb;
nc2 = (c1 == nc1 - 1) ? (data->image_width - c1 * hb) : hb; nc2 = (c1 == nc1 - 1) ? (data->image_width - c1 * hb) : hb;

View File

@ -100,7 +100,7 @@ struct grub_png_data
unsigned image_width, image_height; unsigned image_width, image_height;
int bpp, is_16bit; int bpp, is_16bit;
int raw_bytes, is_gray, is_alpha, is_palette; int raw_bytes, is_alpha, is_palette;
int row_bytes, color_bits; int row_bytes, color_bits;
grub_uint8_t *image_data; grub_uint8_t *image_data;
@ -142,6 +142,7 @@ static grub_uint8_t
grub_png_get_byte (struct grub_png_data *data) grub_png_get_byte (struct grub_png_data *data)
{ {
grub_uint8_t r; grub_uint8_t r;
grub_ssize_t bytes_read = 0;
if ((data->inside_idat) && (data->idat_remain == 0)) if ((data->inside_idat) && (data->idat_remain == 0))
{ {
@ -175,7 +176,14 @@ grub_png_get_byte (struct grub_png_data *data)
} }
r = 0; r = 0;
grub_file_read (data->file, &r, 1); bytes_read = grub_file_read (data->file, &r, 1);
if (bytes_read != 1)
{
grub_error (GRUB_ERR_BAD_FILE_TYPE,
"png: unexpected end of data");
return 0;
}
if (data->inside_idat) if (data->inside_idat)
data->idat_remain--; data->idat_remain--;
@ -231,15 +239,16 @@ grub_png_decode_image_palette (struct grub_png_data *data,
if (len == 0) if (len == 0)
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
for (i = 0; 3 * i < len && i < 256; i++) grub_errno = GRUB_ERR_NONE;
for (i = 0; 3 * i < len && i < 256 && grub_errno == GRUB_ERR_NONE; i++)
for (j = 0; j < 3; j++) for (j = 0; j < 3; j++)
data->palette[i][j] = grub_png_get_byte (data); data->palette[i][j] = grub_png_get_byte (data);
for (i *= 3; i < len; i++) for (i *= 3; i < len && grub_errno == GRUB_ERR_NONE; i++)
grub_png_get_byte (data); grub_png_get_byte (data);
grub_png_get_dword (data); grub_png_get_dword (data);
return GRUB_ERR_NONE; return grub_errno;
} }
static grub_err_t static grub_err_t
@ -249,6 +258,9 @@ grub_png_decode_image_header (struct grub_png_data *data)
int color_bits; int color_bits;
enum grub_video_blit_format blt; enum grub_video_blit_format blt;
if (data->image_width || data->image_height)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: two image headers found");
data->image_width = grub_png_get_dword (data); data->image_width = grub_png_get_dword (data);
data->image_height = grub_png_get_dword (data); data->image_height = grub_png_get_dword (data);
@ -256,9 +268,13 @@ grub_png_decode_image_header (struct grub_png_data *data)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: invalid image size"); return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: invalid image size");
color_bits = grub_png_get_byte (data); color_bits = grub_png_get_byte (data);
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
data->is_16bit = (color_bits == 16); data->is_16bit = (color_bits == 16);
color_type = grub_png_get_byte (data); color_type = grub_png_get_byte (data);
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
/* According to PNG spec, no other types are valid. */ /* According to PNG spec, no other types are valid. */
if ((color_type & ~(PNG_COLOR_MASK_ALPHA | PNG_COLOR_MASK_COLOR)) if ((color_type & ~(PNG_COLOR_MASK_ALPHA | PNG_COLOR_MASK_COLOR))
@ -280,13 +296,13 @@ grub_png_decode_image_header (struct grub_png_data *data)
data->bpp = 3; data->bpp = 3;
else else
{ {
data->is_gray = 1; return grub_error (GRUB_ERR_BAD_FILE_TYPE,
data->bpp = 1; "png: color type not supported");
} }
if ((color_bits != 8) && (color_bits != 16) if ((color_bits != 8) && (color_bits != 16)
&& (color_bits != 4 && (color_bits != 4
|| !(data->is_gray || data->is_palette))) || !data->is_palette))
return grub_error (GRUB_ERR_BAD_FILE_TYPE, return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"png: bit depth must be 8 or 16"); "png: bit depth must be 8 or 16");
@ -315,7 +331,7 @@ grub_png_decode_image_header (struct grub_png_data *data)
} }
#ifndef GRUB_CPU_WORDS_BIGENDIAN #ifndef GRUB_CPU_WORDS_BIGENDIAN
if (data->is_16bit || data->is_gray || data->is_palette) if (data->is_16bit || data->is_palette)
#endif #endif
{ {
data->image_data = grub_calloc (data->image_height, data->row_bytes); data->image_data = grub_calloc (data->image_height, data->row_bytes);
@ -340,14 +356,20 @@ grub_png_decode_image_header (struct grub_png_data *data)
if (grub_png_get_byte (data) != PNG_COMPRESSION_BASE) if (grub_png_get_byte (data) != PNG_COMPRESSION_BASE)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"png: compression method not supported"); "png: compression method not supported");
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
if (grub_png_get_byte (data) != PNG_FILTER_TYPE_BASE) if (grub_png_get_byte (data) != PNG_FILTER_TYPE_BASE)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"png: filter method not supported"); "png: filter method not supported");
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
if (grub_png_get_byte (data) != PNG_INTERLACE_NONE) if (grub_png_get_byte (data) != PNG_INTERLACE_NONE)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"png: interlace method not supported"); "png: interlace method not supported");
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
/* Skip crc checksum. */ /* Skip crc checksum. */
grub_png_get_dword (data); grub_png_get_dword (data);
@ -416,6 +438,13 @@ grub_png_insert_huff_item (struct huff_table *ht, int code, int len)
for (i = len; i < ht->max_length; i++) for (i = len; i < ht->max_length; i++)
n += ht->maxval[i]; n += ht->maxval[i];
if (n > ht->num_values)
{
grub_error (GRUB_ERR_BAD_FILE_TYPE,
"png: out of range inserting huffman table item");
return;
}
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
ht->values[ht->num_values - i] = ht->values[ht->num_values - i - 1]; ht->values[ht->num_values - i] = ht->values[ht->num_values - i - 1];
@ -449,7 +478,7 @@ grub_png_get_huff_code (struct grub_png_data *data, struct huff_table *ht)
int code, i; int code, i;
code = 0; code = 0;
for (i = 0; i < ht->max_length; i++) for (i = 0; i < ht->max_length && grub_errno == GRUB_ERR_NONE; i++)
{ {
code = (code << 1) + grub_png_get_bits (data, 1); code = (code << 1) + grub_png_get_bits (data, 1);
if (code < ht->maxval[i]) if (code < ht->maxval[i])
@ -504,8 +533,14 @@ grub_png_init_dynamic_block (struct grub_png_data *data)
grub_uint8_t lens[DEFLATE_HCLEN_MAX]; grub_uint8_t lens[DEFLATE_HCLEN_MAX];
nl = DEFLATE_HLIT_BASE + grub_png_get_bits (data, 5); nl = DEFLATE_HLIT_BASE + grub_png_get_bits (data, 5);
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
nd = DEFLATE_HDIST_BASE + grub_png_get_bits (data, 5); nd = DEFLATE_HDIST_BASE + grub_png_get_bits (data, 5);
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
nb = DEFLATE_HCLEN_BASE + grub_png_get_bits (data, 4); nb = DEFLATE_HCLEN_BASE + grub_png_get_bits (data, 4);
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
if ((nl > DEFLATE_HLIT_MAX) || (nd > DEFLATE_HDIST_MAX) || if ((nl > DEFLATE_HLIT_MAX) || (nd > DEFLATE_HDIST_MAX) ||
(nb > DEFLATE_HCLEN_MAX)) (nb > DEFLATE_HCLEN_MAX))
@ -533,7 +568,7 @@ grub_png_init_dynamic_block (struct grub_png_data *data)
data->dist_offset); data->dist_offset);
prev = 0; prev = 0;
for (i = 0; i < nl + nd; i++) for (i = 0; i < nl + nd && grub_errno == GRUB_ERR_NONE; i++)
{ {
int n, code; int n, code;
struct huff_table *ht; struct huff_table *ht;
@ -718,20 +753,30 @@ grub_png_read_dynamic_block (struct grub_png_data *data)
int len, dist, pos; int len, dist, pos;
n -= 257; n -= 257;
if (((unsigned int) n) >= ARRAY_SIZE (cplens))
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"png: invalid huff code");
len = cplens[n]; len = cplens[n];
if (cplext[n]) if (cplext[n])
len += grub_png_get_bits (data, cplext[n]); len += grub_png_get_bits (data, cplext[n]);
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
n = grub_png_get_huff_code (data, &data->dist_table); n = grub_png_get_huff_code (data, &data->dist_table);
if (((unsigned int) n) >= ARRAY_SIZE (cpdist))
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"png: invalid huff code");
dist = cpdist[n]; dist = cpdist[n];
if (cpdext[n]) if (cpdext[n])
dist += grub_png_get_bits (data, cpdext[n]); dist += grub_png_get_bits (data, cpdext[n]);
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
pos = data->wp - dist; pos = data->wp - dist;
if (pos < 0) if (pos < 0)
pos += WSIZE; pos += WSIZE;
while (len > 0) while (len > 0 && grub_errno == GRUB_ERR_NONE)
{ {
data->slide[data->wp] = data->slide[pos]; data->slide[data->wp] = data->slide[pos];
grub_png_output_byte (data, data->slide[data->wp]); grub_png_output_byte (data, data->slide[data->wp]);
@ -759,7 +804,11 @@ grub_png_decode_image_data (struct grub_png_data *data)
int final; int final;
cmf = grub_png_get_byte (data); cmf = grub_png_get_byte (data);
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
flg = grub_png_get_byte (data); flg = grub_png_get_byte (data);
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
if ((cmf & 0xF) != Z_DEFLATED) if ((cmf & 0xF) != Z_DEFLATED)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, return grub_error (GRUB_ERR_BAD_FILE_TYPE,
@ -774,7 +823,11 @@ grub_png_decode_image_data (struct grub_png_data *data)
int block_type; int block_type;
final = grub_png_get_bits (data, 1); final = grub_png_get_bits (data, 1);
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
block_type = grub_png_get_bits (data, 2); block_type = grub_png_get_bits (data, 2);
if (grub_errno != GRUB_ERR_NONE)
return grub_errno;
switch (block_type) switch (block_type)
{ {
@ -790,7 +843,7 @@ grub_png_decode_image_data (struct grub_png_data *data)
grub_png_get_byte (data); grub_png_get_byte (data);
grub_png_get_byte (data); grub_png_get_byte (data);
for (i = 0; i < len; i++) for (i = 0; i < len && grub_errno == GRUB_ERR_NONE; i++)
grub_png_output_byte (data, grub_png_get_byte (data)); grub_png_output_byte (data, grub_png_get_byte (data));
break; break;
@ -859,27 +912,8 @@ grub_png_convert_image (struct grub_png_data *data)
int shift; int shift;
int mask = (1 << data->color_bits) - 1; int mask = (1 << data->color_bits) - 1;
unsigned j; unsigned j;
if (data->is_gray)
{
/* Generic formula is
(0xff * i) / ((1U << data->color_bits) - 1)
but for allowed bit depth of 1, 2 and for it's
equivalent to
(0xff / ((1U << data->color_bits) - 1)) * i
Precompute the multipliers to avoid division.
*/
const grub_uint8_t multipliers[5] = { 0xff, 0xff, 0x55, 0x24, 0x11 }; grub_memcpy (palette, data->palette, 3 << data->color_bits);
for (i = 0; i < (1U << data->color_bits); i++)
{
grub_uint8_t col = multipliers[data->color_bits] * i;
palette[i][0] = col;
palette[i][1] = col;
palette[i][2] = col;
}
}
else
grub_memcpy (palette, data->palette, 3 << data->color_bits);
d1c = d1; d1c = d1;
d2c = d2; d2c = d2;
for (j = 0; j < data->image_height; j++, d1c += data->image_width * 3, for (j = 0; j < data->image_height; j++, d1c += data->image_width * 3,
@ -916,60 +950,6 @@ grub_png_convert_image (struct grub_png_data *data)
} }
return; return;
} }
if (data->is_gray)
{
switch (data->bpp)
{
case 4:
/* 16-bit gray with alpha. */
for (i = 0; i < (data->image_width * data->image_height);
i++, d1 += 4, d2 += 4)
{
d1[R4] = d2[3];
d1[G4] = d2[3];
d1[B4] = d2[3];
d1[A4] = d2[1];
}
break;
case 2:
if (data->is_16bit)
/* 16-bit gray without alpha. */
{
for (i = 0; i < (data->image_width * data->image_height);
i++, d1 += 4, d2 += 2)
{
d1[R3] = d2[1];
d1[G3] = d2[1];
d1[B3] = d2[1];
}
}
else
/* 8-bit gray with alpha. */
{
for (i = 0; i < (data->image_width * data->image_height);
i++, d1 += 4, d2 += 2)
{
d1[R4] = d2[1];
d1[G4] = d2[1];
d1[B4] = d2[1];
d1[A4] = d2[0];
}
}
break;
/* 8-bit gray without alpha. */
case 1:
for (i = 0; i < (data->image_width * data->image_height);
i++, d1 += 3, d2++)
{
d1[R3] = d2[0];
d1[G3] = d2[0];
d1[B3] = d2[0];
}
break;
}
return;
}
{ {
/* Only copy the upper 8 bit. */ /* Only copy the upper 8 bit. */
@ -1045,6 +1025,8 @@ grub_png_decode_png (struct grub_png_data *data)
len = grub_png_get_dword (data); len = grub_png_get_dword (data);
type = grub_png_get_dword (data); type = grub_png_get_dword (data);
if (grub_errno != GRUB_ERR_NONE)
break;
data->next_offset = data->file->offset + len + 4; data->next_offset = data->file->offset + len + 4;
switch (type) switch (type)

View File

@ -40,6 +40,11 @@ void EXPORT_FUNC (grub_loader_set) (grub_err_t (*boot) (void),
grub_err_t (*unload) (void), grub_err_t (*unload) (void),
int flags); int flags);
void EXPORT_FUNC (grub_loader_set_ex) (grub_err_t (*boot) (void *),
grub_err_t (*unload) (void *),
void *context,
int flags);
/* Unset current loader, if any. */ /* Unset current loader, if any. */
void EXPORT_FUNC (grub_loader_unset) (void); void EXPORT_FUNC (grub_loader_unset) (void);

View File

@ -277,6 +277,7 @@ typedef struct grub_net
grub_fs_t fs; grub_fs_t fs;
int eof; int eof;
int stall; int stall;
int broken;
} *grub_net_t; } *grub_net_t;
extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name); extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name);

View File

@ -24,6 +24,7 @@
enum grub_verify_flags enum grub_verify_flags
{ {
GRUB_VERIFY_FLAGS_NONE = 0,
GRUB_VERIFY_FLAGS_SKIP_VERIFICATION = 1, GRUB_VERIFY_FLAGS_SKIP_VERIFICATION = 1,
GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2, GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2,
/* Defer verification to another authority. */ /* Defer verification to another authority. */