_bfd_vms_slurp_eihs (bfd *abfd, unsigned int offset)
{
unsigned char *p = PRIV (recrd.rec) + offset;
- unsigned int gstvbn = bfd_getl32 (p + EIHS__L_GSTVBN);
- unsigned int gstsize ATTRIBUTE_UNUSED = bfd_getl32 (p + EIHS__L_GSTSIZE);
- unsigned int dstvbn = bfd_getl32 (p + EIHS__L_DSTVBN);
- unsigned int dstsize = bfd_getl32 (p + EIHS__L_DSTSIZE);
- unsigned int dmtvbn = bfd_getl32 (p + EIHS__L_DMTVBN);
- unsigned int dmtbytes = bfd_getl32 (p + EIHS__L_DMTBYTES);
+ unsigned int gstvbn;
+ unsigned int gstsize ATTRIBUTE_UNUSED;
+ unsigned int dstvbn;
+ unsigned int dstsize;
+ unsigned int dmtvbn;
+ unsigned int dmtbytes;
asection *section;
+ /* PR 21611: Check that offset is valid. */
+ if (offset > PRIV (recrd.rec_size) - (EIHS__L_DMTBYTES + 4))
+ {
+ _bfd_error_handler (_("Unable to read EIHS record at offset %#x"), offset);
+ bfd_set_error (bfd_error_file_truncated);
+ return FALSE;
+ }
+
+ gstvbn = bfd_getl32 (p + EIHS__L_GSTVBN);
+ gstsize = bfd_getl32 (p + EIHS__L_GSTSIZE);
+ dstvbn = bfd_getl32 (p + EIHS__L_DSTVBN);
+ dstsize = bfd_getl32 (p + EIHS__L_DSTSIZE);
+ dmtvbn = bfd_getl32 (p + EIHS__L_DMTVBN);
+ dmtbytes = bfd_getl32 (p + EIHS__L_DMTBYTES);
+
#if VMS_DEBUG
vms_debug (8, "_bfd_vms_slurp_ihs\n");
vms_debug (4, "EIHS record gstvbn %d gstsize %d dstvbn %d dstsize %d dmtvbn %d dmtbytes %d\n",
static bfd_boolean
_bfd_vms_slurp_egsd (bfd *abfd)
{
- int gsd_type, gsd_size;
+ int gsd_type;
+ unsigned int gsd_size;
unsigned char *vms_rec;
unsigned long base_addr;
vms_debug2 ((2, "EGSD\n"));
+ if (PRIV (recrd.rec_size) < 8)
+ {
+ _bfd_error_handler (_("Corrupt EGSD record: its size (%#x) is too small"),
+ PRIV (recrd.rec_size));
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
PRIV (recrd.rec) += 8; /* Skip type, size, align pad. */
PRIV (recrd.rec_size) -= 8;
/* Calculate base address for each section. */
base_addr = 0L;
- while (PRIV (recrd.rec_size) > 0)
+ while (PRIV (recrd.rec_size) > 4)
{
vms_rec = PRIV (recrd.rec);
vms_debug2 ((3, "egsd_type %d\n", gsd_type));
+ /* PR 21615: Check for size overflow. */
+ if (PRIV (recrd.rec_size) < gsd_size)
+ {
+ _bfd_error_handler (_("Corrupt EGSD record: size (%#x) is larger than remaining space (%#x)"),
+ gsd_size, PRIV (recrd.rec_size));
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
switch (gsd_type)
{
case EGSD__C_PSC:
struct vms_esdf *esdf = (struct vms_esdf *)vms_rec;
entry->value = bfd_getl64 (esdf->value);
+ if (PRIV (sections) == NULL)
+ return FALSE;
entry->section = PRIV (sections)[bfd_getl32 (esdf->psindx)];
if (old_flags & EGSY__V_NORM)
entry->symbol_vector = bfd_getl32 (egst->value);
if (old_flags & EGSY__V_REL)
- entry->section = PRIV (sections)[bfd_getl32 (egst->psindx)];
+ {
+ if (PRIV (sections) == NULL)
+ return FALSE;
+ entry->section = PRIV (sections)[bfd_getl32 (egst->psindx)];
+ }
else
entry->section = bfd_abs_section_ptr;
PRIV (recrd.rec) += gsd_size;
}
+ /* FIXME: Should we complain if PRIV (recrd.rec_size) is not zero ? */
+
if (PRIV (gsd_sym_count) > 0)
abfd->flags |= HAS_SYMS;
vms_debug2 ((4, "image_set_ptr (0x%08x, sect=%d)\n", (unsigned)vma, sect));
+ if (PRIV (sections) == NULL)
+ return;
sec = PRIV (sections)[sect];
if (info)
/* Write multiple bytes to section image. */
static bfd_boolean
-image_write (bfd *abfd, unsigned char *ptr, int size)
+image_write (bfd *abfd, unsigned char *ptr, unsigned int size)
{
#if VMS_DEBUG
_bfd_vms_debug (8, "image_write from (%p, %d) to (%ld)\n", ptr, size,
#define HIGHBIT(op) ((op & 0x80000000L) == 0x80000000L)
static void
-_bfd_vms_get_value (bfd *abfd, const unsigned char *ascic,
+_bfd_vms_get_value (bfd *abfd,
+ const unsigned char *ascic,
+ const unsigned char *max_ascic,
struct bfd_link_info *info,
bfd_vma *vma,
struct alpha_vms_link_hash_entry **hp)
{
char name[257];
- int len;
- int i;
+ unsigned int len;
+ unsigned int i;
struct alpha_vms_link_hash_entry *h;
/* Not linking. Do not try to resolve the symbol. */
}
len = *ascic;
+ if (ascic + len >= max_ascic)
+ {
+ _bfd_error_handler (_("Corrupt vms value"));
+ *vma = 0;
+ *hp = NULL;
+ return;
+ }
+
for (i = 0; i < len; i++)
name[i] = ascic[i + 1];
name[i] = 0;
alpha_vms_fix_sec_rel (bfd *abfd, struct bfd_link_info *info,
unsigned int rel, bfd_vma vma)
{
- asection *sec = PRIV (sections)[rel & RELC_MASK];
+ asection *sec;
+
+ if (PRIV (sections) == NULL)
+ return 0;
+
+ sec = PRIV (sections)[rel & RELC_MASK];
if (info)
{
ptr += 4;
+ /* PR 21589 and 21579: Check for a corrupt ETIR record. */
+ if (cmd_length < 4 || (ptr + cmd_length > maxptr + 4))
+ {
+ corrupt_etir:
+ _bfd_error_handler (_("Corrupt ETIR record encountered"));
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
#if VMS_DEBUG
_bfd_vms_debug (4, "etir: %s(%d)\n",
_bfd_vms_etir_name (cmd), cmd);
stack 32 bit value of symbol (high bits set to 0). */
case ETIR__C_STA_GBL:
- _bfd_vms_get_value (abfd, ptr, info, &op1, &h);
+ _bfd_vms_get_value (abfd, ptr, maxptr, info, &op1, &h);
_bfd_vms_push (abfd, op1, alpha_vms_sym_to_ctxt (h));
break;
stack 32 bit value, sign extend to 64 bit. */
case ETIR__C_STA_LW:
+ if (ptr + 4 >= maxptr)
+ goto corrupt_etir;
_bfd_vms_push (abfd, bfd_getl32 (ptr), RELC_NONE);
break;
stack 64 bit value of symbol. */
case ETIR__C_STA_QW:
+ if (ptr + 8 >= maxptr)
+ goto corrupt_etir;
_bfd_vms_push (abfd, bfd_getl64 (ptr), RELC_NONE);
break;
{
int psect;
+ if (ptr + 12 >= maxptr)
+ goto corrupt_etir;
psect = bfd_getl32 (ptr);
if ((unsigned int) psect >= PRIV (section_count))
{
{
int size;
+ if (ptr + 4 >= maxptr)
+ goto corrupt_etir;
size = bfd_getl32 (ptr);
_bfd_vms_pop (abfd, &op1, &rel1);
if (rel1 != RELC_NONE)
/* Store global: write symbol value
arg: cs global symbol name. */
case ETIR__C_STO_GBL:
- _bfd_vms_get_value (abfd, ptr, info, &op1, &h);
+ _bfd_vms_get_value (abfd, ptr, maxptr, info, &op1, &h);
if (h && h->sym)
{
if (h->sym->typ == EGSD__C_SYMG)
/* Store code address: write address of entry point
arg: cs global symbol name (procedure). */
case ETIR__C_STO_CA:
- _bfd_vms_get_value (abfd, ptr, info, &op1, &h);
+ _bfd_vms_get_value (abfd, ptr, maxptr, info, &op1, &h);
if (h && h->sym)
{
if (h->sym->flags & EGSY__V_NORM)
da data. */
case ETIR__C_STO_IMM:
{
- int size;
+ unsigned int size;
+ if (ptr + 4 >= maxptr)
+ goto corrupt_etir;
size = bfd_getl32 (ptr);
image_write (abfd, ptr + 4, size);
}
store global longword: store 32bit value of symbol
arg: cs symbol name. */
case ETIR__C_STO_GBL_LW:
- _bfd_vms_get_value (abfd, ptr, info, &op1, &h);
+ _bfd_vms_get_value (abfd, ptr, maxptr, info, &op1, &h);
#if 0
abort ();
#endif
da signature. */
case ETIR__C_STC_LP_PSB:
- _bfd_vms_get_value (abfd, ptr + 4, info, &op1, &h);
+ _bfd_vms_get_value (abfd, ptr + 4, maxptr, info, &op1, &h);
if (h && h->sym)
{
if (h->sym->typ == EGSD__C_SYMG)
/* Augment relocation base: increment image location counter by offset
arg: lw offset value. */
case ETIR__C_CTL_AUGRB:
+ if (ptr + 4 >= maxptr)
+ goto corrupt_etir;
op1 = bfd_getl32 (ptr);
image_inc_ptr (abfd, op1);
break;
return FALSE;
}
+ if (PRIV (sections) == NULL)
+ return FALSE;
sec = PRIV (sections)[cur_psect];
if (sec == bfd_abs_section_ptr)
{
reloc->sym_ptr_ptr = sym;
}
else if (cur_psidx >= 0)
- reloc->sym_ptr_ptr =
- PRIV (sections)[cur_psidx]->symbol_ptr_ptr;
+ {
+ if (PRIV (sections) == NULL)
+ return FALSE;
+ reloc->sym_ptr_ptr =
+ PRIV (sections)[cur_psidx]->symbol_ptr_ptr;
+ }
else
reloc->sym_ptr_ptr = NULL;
/* xgettext:c-format */
fprintf (file, _(" EMH %u (len=%u): "), subtype, rec_len);
+ /* PR 21618: Check for invalid lengths. */
+ if (rec_len < sizeof (* emh))
+ {
+ fprintf (file, _(" Error: The length is less than the length of an EMH record\n"));
+ return;
+ }
+
switch (subtype)
{
case EMH__C_MHD:
struct vms_eeom *eeom = (struct vms_eeom *)rec;
fprintf (file, _(" EEOM (len=%u):\n"), rec_len);
+
+ /* PR 21618: Check for invalid lengths. */
+ if (rec_len < sizeof (* eeom))
+ {
+ fprintf (file, _(" Error: The length is less than the length of an EEOM record\n"));
+ return;
+ }
+
fprintf (file, _(" number of cond linkage pairs: %u\n"),
(unsigned)bfd_getl32 (eeom->total_lps));
fprintf (file, _(" completion code: %u\n"),
n, type, len);
n++;
+ if (off + len > rec_len || off + len < off)
+ {
+ fprintf (file, _(" Error: length larger than remaining space in record\n"));
+ return;
+ }
+
switch (type)
{
case EGSD__C_PSC:
size = bfd_getl16 (etir->size);
buf = rec + off + sizeof (struct vms_etir);
+ if (off + size > rec_len || off + size < off)
+ {
+ fprintf (file, _(" Error: length larger than remaining space in record\n"));
+ return;
+ }
+
/* xgettext:c-format */
fprintf (file, _(" (type: %3u, size: 4+%3u): "), type, size - 4);
switch (type)
#define vms_bfd_discard_group bfd_generic_discard_group
#define vms_section_already_linked _bfd_generic_section_already_linked
#define vms_bfd_define_common_symbol bfd_generic_define_common_symbol
+#define vms_bfd_define_start_stop bfd_generic_define_start_stop
#define vms_bfd_copy_private_header_data _bfd_generic_bfd_copy_private_header_data
#define vms_bfd_copy_private_bfd_data _bfd_generic_bfd_copy_private_bfd_data
_bfd_generic_section_already_linked
#define alpha_vms_bfd_define_common_symbol bfd_generic_define_common_symbol
+#define alpha_vms_bfd_define_start_stop bfd_generic_define_start_stop
#define alpha_vms_bfd_link_just_syms _bfd_generic_link_just_syms
#define alpha_vms_bfd_copy_link_hash_symbol_type \
_bfd_generic_copy_link_hash_symbol_type