From a3c0896d80d21545bd8036deb5e1ad4027db5677 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Fri, 5 Nov 2021 11:16:28 +1030 Subject: asan: alpha-vms: objdump buffer overflows * vms-alpha.c (evax_bfd_print_desc): Sanity check buffer access. (evax_bfd_print_valspec, evax_bfd_print_typspec): Likewise. (evax_bfd_print_dst): Likewise. --- bfd/vms-alpha.c | 519 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 344 insertions(+), 175 deletions(-) (limited to 'bfd') diff --git a/bfd/vms-alpha.c b/bfd/vms-alpha.c index aed2e26..f4f16ef 100644 --- a/bfd/vms-alpha.c +++ b/bfd/vms-alpha.c @@ -7040,8 +7040,12 @@ evax_bfd_get_dsc_name (unsigned int v) } static void -evax_bfd_print_desc (const unsigned char *buf, int indent, FILE *file) +evax_bfd_print_desc (const unsigned char *buf, unsigned int bufsize, + int indent, FILE *file) { + if (bufsize < 8) + return; + unsigned char bclass = buf[3]; unsigned char dtype = buf[2]; unsigned int len = (unsigned)bfd_getl16 (buf); @@ -7070,38 +7074,47 @@ evax_bfd_print_desc (const unsigned char *buf, int indent, FILE *file) evax_bfd_print_indent (indent, file); fprintf (file, _("non-contiguous array of %s\n"), evax_bfd_get_dsc_name (dsc->dtype)); - evax_bfd_print_indent (indent + 1, file); - fprintf (file, - /* xgettext:c-format */ - _("dimct: %u, aflags: 0x%02x, digits: %u, scale: %u\n"), - dsc->dimct, dsc->aflags, dsc->digits, dsc->scale); - evax_bfd_print_indent (indent + 1, file); - fprintf (file, - /* xgettext:c-format */ - _("arsize: %u, a0: 0x%08x\n"), - (unsigned)bfd_getl32 (dsc->arsize), - (unsigned)bfd_getl32 (dsc->a0)); - evax_bfd_print_indent (indent + 1, file); - fprintf (file, _("Strides:\n")); - b = buf + sizeof (*dsc); - for (i = 0; i < dsc->dimct; i++) - { - evax_bfd_print_indent (indent + 2, file); - fprintf (file, "[%u]: %u\n", i + 1, - (unsigned)bfd_getl32 (b)); - b += 4; - } - evax_bfd_print_indent (indent + 1, file); - fprintf (file, _("Bounds:\n")); - b = buf + sizeof (*dsc); - for (i = 0; i < dsc->dimct; i++) + if (bufsize >= sizeof (*dsc)) { - evax_bfd_print_indent (indent + 2, file); - /* xgettext:c-format */ - fprintf (file, _("[%u]: Lower: %u, upper: %u\n"), i + 1, - (unsigned)bfd_getl32 (b + 0), - (unsigned)bfd_getl32 (b + 4)); - b += 8; + evax_bfd_print_indent (indent + 1, file); + fprintf (file, + /* xgettext:c-format */ + _("dimct: %u, aflags: 0x%02x, digits: %u, scale: %u\n"), + dsc->dimct, dsc->aflags, dsc->digits, dsc->scale); + evax_bfd_print_indent (indent + 1, file); + fprintf (file, + /* xgettext:c-format */ + _("arsize: %u, a0: 0x%08x\n"), + (unsigned) bfd_getl32 (dsc->arsize), + (unsigned) bfd_getl32 (dsc->a0)); + evax_bfd_print_indent (indent + 1, file); + fprintf (file, _("Strides:\n")); + b = buf + sizeof (*dsc); + bufsize -= sizeof (*dsc); + for (i = 0; i < dsc->dimct; i++) + { + if (bufsize < 4) + break; + evax_bfd_print_indent (indent + 2, file); + fprintf (file, "[%u]: %u\n", i + 1, + (unsigned) bfd_getl32 (b)); + b += 4; + bufsize -= 4; + } + evax_bfd_print_indent (indent + 1, file); + fprintf (file, _("Bounds:\n")); + for (i = 0; i < dsc->dimct; i++) + { + if (bufsize < 8) + break; + evax_bfd_print_indent (indent + 2, file); + /* xgettext:c-format */ + fprintf (file, _("[%u]: Lower: %u, upper: %u\n"), i + 1, + (unsigned) bfd_getl32 (b + 0), + (unsigned) bfd_getl32 (b + 4)); + b += 8; + bufsize -= 8; + } } } break; @@ -7112,12 +7125,15 @@ evax_bfd_print_desc (const unsigned char *buf, int indent, FILE *file) evax_bfd_print_indent (indent, file); fprintf (file, _("unaligned bit-string of %s\n"), evax_bfd_get_dsc_name (ubs->dtype)); - evax_bfd_print_indent (indent + 1, file); - fprintf (file, - /* xgettext:c-format */ - _("base: %u, pos: %u\n"), - (unsigned)bfd_getl32 (ubs->base), - (unsigned)bfd_getl32 (ubs->pos)); + if (bufsize >= sizeof (*ubs)) + { + evax_bfd_print_indent (indent + 1, file); + fprintf (file, + /* xgettext:c-format */ + _("base: %u, pos: %u\n"), + (unsigned) bfd_getl32 (ubs->base), + (unsigned) bfd_getl32 (ubs->pos)); + } } break; default: @@ -7128,16 +7144,21 @@ evax_bfd_print_desc (const unsigned char *buf, int indent, FILE *file) } static unsigned int -evax_bfd_print_valspec (const unsigned char *buf, int indent, FILE *file) +evax_bfd_print_valspec (const unsigned char *buf, unsigned int bufsize, + int indent, FILE *file) { + if (bufsize < 5) + return bufsize; + unsigned int vflags = buf[0]; - unsigned int value = (unsigned)bfd_getl32 (buf + 1); + unsigned int value = (unsigned) bfd_getl32 (buf + 1); unsigned int len = 5; evax_bfd_print_indent (indent, file); /* xgettext:c-format */ fprintf (file, _("vflags: 0x%02x, value: 0x%08x "), vflags, value); buf += 5; + bufsize -= 5; switch (vflags) { @@ -7152,7 +7173,8 @@ evax_bfd_print_valspec (const unsigned char *buf, int indent, FILE *file) break; case DST__K_VFLAGS_DSC: fprintf (file, _("(descriptor)\n")); - evax_bfd_print_desc (buf + value, indent + 1, file); + if (value <= bufsize) + evax_bfd_print_desc (buf + value, bufsize - value, indent + 1, file); break; case DST__K_VFLAGS_TVS: fprintf (file, _("(trailing value)\n")); @@ -7191,29 +7213,36 @@ evax_bfd_print_valspec (const unsigned char *buf, int indent, FILE *file) } static void -evax_bfd_print_typspec (const unsigned char *buf, int indent, FILE *file) +evax_bfd_print_typspec (const unsigned char *buf, unsigned int bufsize, + int indent, FILE *file) { + if (bufsize < 3) + return; + unsigned char kind = buf[2]; - unsigned int len = (unsigned)bfd_getl16 (buf); + unsigned int len = (unsigned) bfd_getl16 (buf); evax_bfd_print_indent (indent, file); /* xgettext:c-format */ fprintf (file, _("len: %2u, kind: %2u "), len, kind); buf += 3; + bufsize -= 3; switch (kind) { case DST__K_TS_ATOM: /* xgettext:c-format */ - fprintf (file, _("atomic, type=0x%02x %s\n"), - buf[0], evax_bfd_get_dsc_name (buf[0])); + if (bufsize >= 1) + fprintf (file, _("atomic, type=0x%02x %s\n"), + buf[0], evax_bfd_get_dsc_name (buf[0])); break; case DST__K_TS_IND: - fprintf (file, _("indirect, defined at 0x%08x\n"), - (unsigned)bfd_getl32 (buf)); + if (bufsize >= 4) + fprintf (file, _("indirect, defined at 0x%08x\n"), + (unsigned) bfd_getl32 (buf)); break; case DST__K_TS_TPTR: fprintf (file, _("typed pointer\n")); - evax_bfd_print_typspec (buf, indent + 1, file); + evax_bfd_print_typspec (buf, bufsize, indent + 1, file); break; case DST__K_TS_PTR: fprintf (file, _("pointer\n")); @@ -7221,29 +7250,51 @@ evax_bfd_print_typspec (const unsigned char *buf, int indent, FILE *file) case DST__K_TS_ARRAY: { const unsigned char *vs; + unsigned int vs_len; unsigned int vec_len; unsigned int i; + if (bufsize == 0) + return; fprintf (file, _("array, dim: %u, bitmap: "), buf[0]); + --bufsize; vec_len = (buf[0] + 1 + 7) / 8; for (i = 0; i < vec_len; i++) - fprintf (file, " %02x", buf[i + 1]); + { + if (bufsize == 0) + break; + fprintf (file, " %02x", buf[i + 1]); + --bufsize; + } fputc ('\n', file); + if (bufsize == 0) + return; vs = buf + 1 + vec_len; evax_bfd_print_indent (indent, file); fprintf (file, _("array descriptor:\n")); - vs += evax_bfd_print_valspec (vs, indent + 1, file); - for (i = 0; i < buf[0] + 1U; i++) - if (buf[1 + i / 8] & (1 << (i % 8))) - { - evax_bfd_print_indent (indent, file); - if (i == 0) - fprintf (file, _("type spec for element:\n")); - else - fprintf (file, _("type spec for subscript %u:\n"), i); - evax_bfd_print_typspec (vs, indent + 1, file); - vs += bfd_getl16 (vs); - } + vs_len = evax_bfd_print_valspec (vs, bufsize, indent + 1, file); + vs += vs_len; + if (bufsize > vs_len) + { + bufsize -= vs_len; + for (i = 0; i < buf[0] + 1U; i++) + if (buf[1 + i / 8] & (1 << (i % 8))) + { + evax_bfd_print_indent (indent, file); + if (i == 0) + fprintf (file, _("type spec for element:\n")); + else + fprintf (file, _("type spec for subscript %u:\n"), i); + evax_bfd_print_typspec (vs, bufsize, indent + 1, file); + if (bufsize < 2) + break; + vs_len = bfd_getl16 (vs); + if (bufsize <= vs_len) + break; + vs += vs_len; + bufsize -= vs_len; + } + } } break; default: @@ -7277,20 +7328,24 @@ evax_bfd_print_dst (struct bfd *abfd, unsigned int dst_size, FILE *file) /* xgettext:c-format */ fprintf (file, _(" type: %3u, len: %3u (at 0x%08x): "), type, len, off); - if (len == 0) + if (len < sizeof (dsth)) { fputc ('\n', file); break; } - len++; dst_size -= len; off += len; len -= sizeof (dsth); - buf = _bfd_malloc_and_read (abfd, len, len); - if (buf == NULL) + if (len == 0) + buf = NULL; + else { - fprintf (file, _("cannot read DST symbol\n")); - return; + buf = _bfd_malloc_and_read (abfd, len, len); + if (buf == NULL) + { + fprintf (file, _("cannot read DST symbol\n")); + return; + } } switch (type) { @@ -7334,7 +7389,7 @@ evax_bfd_print_dst (struct bfd *abfd, unsigned int dst_size, FILE *file) case DSC__K_DTYPE_VT2: fprintf (file, _("standard data: %s\n"), evax_bfd_get_dsc_name (type)); - evax_bfd_print_valspec (buf, 4, file); + evax_bfd_print_valspec (buf, len, 4, file); fprintf (file, _(" name: %.*s\n"), buf[5], buf + 6); break; case DST__K_MODBEG: @@ -7343,6 +7398,8 @@ evax_bfd_print_dst (struct bfd *abfd, unsigned int dst_size, FILE *file) const char *name = (const char *)buf + sizeof (*dst); fprintf (file, _("modbeg\n")); + if (len < sizeof (*dst)) + break; /* xgettext:c-format */ fprintf (file, _(" flags: %d, language: %u, " "major: %u, minor: %u\n"), @@ -7350,11 +7407,21 @@ evax_bfd_print_dst (struct bfd *abfd, unsigned int dst_size, FILE *file) (unsigned)bfd_getl32 (dst->language), (unsigned)bfd_getl16 (dst->major), (unsigned)bfd_getl16 (dst->minor)); - fprintf (file, _(" module name: %.*s\n"), - name[0], name + 1); - name += name[0] + 1; - fprintf (file, _(" compiler : %.*s\n"), - name[0], name + 1); + len -= sizeof (*dst); + if (len > 0) + { + int nlen = len - 1; + fprintf (file, _(" module name: %.*s\n"), + name[0] > nlen ? nlen : name[0], name + 1); + if (name[0] < nlen) + { + len -= name[0] + 1; + name += name[0] + 1; + nlen = len - 1; + fprintf (file, _(" compiler : %.*s\n"), + name[0] > nlen ? nlen: name[0], name + 1); + } + } } break; case DST__K_MODEND: @@ -7366,39 +7433,51 @@ evax_bfd_print_dst (struct bfd *abfd, unsigned int dst_size, FILE *file) const char *name = (const char *)buf + sizeof (*dst); fputs (_("rtnbeg\n"), file); - /* xgettext:c-format */ - fprintf (file, _(" flags: %u, address: 0x%08x, " - "pd-address: 0x%08x\n"), - dst->flags, - (unsigned)bfd_getl32 (dst->address), - (unsigned)bfd_getl32 (dst->pd_address)); - fprintf (file, _(" routine name: %.*s\n"), - name[0], name + 1); + if (len >= sizeof (*dst)) + { + /* xgettext:c-format */ + fprintf (file, _(" flags: %u, address: 0x%08x, " + "pd-address: 0x%08x\n"), + dst->flags, + (unsigned) bfd_getl32 (dst->address), + (unsigned) bfd_getl32 (dst->pd_address)); + len -= sizeof (*dst); + if (len > 0) + { + int nlen = len - 1; + fprintf (file, _(" routine name: %.*s\n"), + name[0] > nlen ? nlen : name[0], name + 1); + } + } } break; case DST__K_RTNEND: { struct vms_dst_rtnend *dst = (void *)buf; - fprintf (file, _("rtnend: size 0x%08x\n"), - (unsigned)bfd_getl32 (dst->size)); + if (len >= sizeof (*dst)) + fprintf (file, _("rtnend: size 0x%08x\n"), + (unsigned) bfd_getl32 (dst->size)); } break; case DST__K_PROLOG: { struct vms_dst_prolog *dst = (void *)buf; - fprintf (file, _("prolog: bkpt address 0x%08x\n"), - (unsigned)bfd_getl32 (dst->bkpt_addr)); + if (len >= sizeof (*dst)) + /* xgettext:c-format */ + fprintf (file, _("prolog: bkpt address 0x%08x\n"), + (unsigned) bfd_getl32 (dst->bkpt_addr)); } break; case DST__K_EPILOG: { struct vms_dst_epilog *dst = (void *)buf; - /* xgettext:c-format */ - fprintf (file, _("epilog: flags: %u, count: %u\n"), - dst->flags, (unsigned)bfd_getl32 (dst->count)); + if (len >= sizeof (*dst)) + /* xgettext:c-format */ + fprintf (file, _("epilog: flags: %u, count: %u\n"), + dst->flags, (unsigned) bfd_getl32 (dst->count)); } break; case DST__K_BLKBEG: @@ -7406,31 +7485,50 @@ evax_bfd_print_dst (struct bfd *abfd, unsigned int dst_size, FILE *file) struct vms_dst_blkbeg *dst = (void *)buf; const char *name = (const char *)buf + sizeof (*dst); - /* xgettext:c-format */ - fprintf (file, _("blkbeg: address: 0x%08x, name: %.*s\n"), - (unsigned)bfd_getl32 (dst->address), - name[0], name + 1); + if (len > sizeof (*dst)) + { + int nlen; + len -= sizeof (*dst); + nlen = len - 1; + /* xgettext:c-format */ + fprintf (file, _("blkbeg: address: 0x%08x, name: %.*s\n"), + (unsigned) bfd_getl32 (dst->address), + name[0] > nlen ? nlen : name[0], name + 1); + } } break; case DST__K_BLKEND: { struct vms_dst_blkend *dst = (void *)buf; - fprintf (file, _("blkend: size: 0x%08x\n"), - (unsigned)bfd_getl32 (dst->size)); + if (len >= sizeof (*dst)) + /* xgettext:c-format */ + fprintf (file, _("blkend: size: 0x%08x\n"), + (unsigned) bfd_getl32 (dst->size)); } break; case DST__K_TYPSPEC: { fprintf (file, _("typspec (len: %u)\n"), len); - fprintf (file, _(" name: %.*s\n"), buf[0], buf + 1); - evax_bfd_print_typspec (buf + 1 + buf[0], 5, file); + if (len >= 1) + { + int nlen = len - 1; + fprintf (file, _(" name: %.*s\n"), + buf[0] > nlen ? nlen : buf[0], buf + 1); + if (nlen > buf[0]) + evax_bfd_print_typspec (buf + 1 + buf[0], len - (1 + buf[0]), + 5, file); + } } break; case DST__K_SEPTYP: { - fprintf (file, _("septyp, name: %.*s\n"), buf[5], buf + 6); - evax_bfd_print_valspec (buf, 4, file); + if (len >= 6) + { + fprintf (file, _("septyp, name: %.*s\n"), + buf[5] > len - 6 ? len - 6 : buf[5], buf + 6); + evax_bfd_print_valspec (buf, len, 4, file); + } } break; case DST__K_RECBEG: @@ -7438,23 +7536,36 @@ evax_bfd_print_dst (struct bfd *abfd, unsigned int dst_size, FILE *file) struct vms_dst_recbeg *recbeg = (void *)buf; const char *name = (const char *)buf + sizeof (*recbeg); - fprintf (file, _("recbeg: name: %.*s\n"), name[0], name + 1); - evax_bfd_print_valspec (buf, 4, file); - fprintf (file, _(" len: %u bits\n"), - (unsigned)bfd_getl32 (name + 1 + name[0])); + if (len > sizeof (*recbeg)) + { + int nlen = len - sizeof (*recbeg) - 1; + if (name[0] < nlen) + nlen = name[0]; + fprintf (file, _("recbeg: name: %.*s\n"), nlen, name + 1); + evax_bfd_print_valspec (buf, len, 4, file); + len -= 1 + nlen; + if (len >= 4) + fprintf (file, _(" len: %u bits\n"), + (unsigned) bfd_getl32 (name + 1 + nlen)); + } } break; case DST__K_RECEND: fprintf (file, _("recend\n")); break; case DST__K_ENUMBEG: - /* xgettext:c-format */ - fprintf (file, _("enumbeg, len: %u, name: %.*s\n"), - buf[0], buf[1], buf + 2); + if (len >= 2) + /* xgettext:c-format */ + fprintf (file, _("enumbeg, len: %u, name: %.*s\n"), + buf[0], buf[1] > len - 2 ? len - 2 : buf[1], buf + 2); break; case DST__K_ENUMELT: - fprintf (file, _("enumelt, name: %.*s\n"), buf[5], buf + 6); - evax_bfd_print_valspec (buf, 4, file); + if (len >= 6) + { + fprintf (file, _("enumelt, name: %.*s\n"), + buf[5] > len - 6 ? len - 6 : buf[5], buf + 6); + evax_bfd_print_valspec (buf, len, 4, file); + } break; case DST__K_ENUMEND: fprintf (file, _("enumend\n")); @@ -7462,26 +7573,36 @@ evax_bfd_print_dst (struct bfd *abfd, unsigned int dst_size, FILE *file) case DST__K_LABEL: { struct vms_dst_label *lab = (void *)buf; - fprintf (file, _("label, name: %.*s\n"), - lab->name[0], lab->name + 1); - fprintf (file, _(" address: 0x%08x\n"), - (unsigned)bfd_getl32 (lab->value)); + if (len >= sizeof (*lab)) + { + fprintf (file, _("label, name: %.*s\n"), + lab->name[0] > len - 1 ? len - 1 : lab->name[0], + lab->name + 1); + fprintf (file, _(" address: 0x%08x\n"), + (unsigned) bfd_getl32 (lab->value)); + } } break; case DST__K_DIS_RANGE: - { - unsigned int cnt = bfd_getl32 (buf); - unsigned char *rng = buf + 4; - unsigned int i; - - fprintf (file, _("discontiguous range (nbr: %u)\n"), cnt); - for (i = 0; i < cnt; i++, rng += 8) - /* xgettext:c-format */ - fprintf (file, _(" address: 0x%08x, size: %u\n"), - (unsigned)bfd_getl32 (rng), - (unsigned)bfd_getl32 (rng + 4)); + if (len >= 4) + { + unsigned int cnt = bfd_getl32 (buf); + unsigned char *rng = buf + 4; + unsigned int i; - } + fprintf (file, _("discontiguous range (nbr: %u)\n"), cnt); + len -= 4; + for (i = 0; i < cnt; i++, rng += 8) + { + if (len < 8) + break; + /* xgettext:c-format */ + fprintf (file, _(" address: 0x%08x, size: %u\n"), + (unsigned) bfd_getl32 (rng), + (unsigned) bfd_getl32 (rng + 4)); + len -= 8; + } + } break; case DST__K_LINE_NUM: { @@ -7491,79 +7612,101 @@ evax_bfd_print_dst (struct bfd *abfd, unsigned int dst_size, FILE *file) while (len > 0) { - signed char cmd; - unsigned char cmdlen; + int cmd; unsigned int val; + int cmdlen = -1; - cmd = buf[0]; - cmdlen = 0; + cmd = *buf++; + len--; fputs (" ", file); switch (cmd) { case DST__K_DELTA_PC_W: - val = bfd_getl16 (buf + 1); + if (len < 2) + break; + val = bfd_getl16 (buf); fprintf (file, _("delta_pc_w %u\n"), val); pc += val; line++; - cmdlen = 3; + cmdlen = 2; break; case DST__K_INCR_LINUM: - val = buf[1]; + if (len < 1) + break; + val = *buf; fprintf (file, _("incr_linum(b): +%u\n"), val); line += val; - cmdlen = 2; + cmdlen = 1; break; case DST__K_INCR_LINUM_W: - val = bfd_getl16 (buf + 1); + if (len < 2) + break; + val = bfd_getl16 (buf); fprintf (file, _("incr_linum_w: +%u\n"), val); line += val; - cmdlen = 3; + cmdlen = 2; break; case DST__K_INCR_LINUM_L: - val = bfd_getl32 (buf + 1); + if (len < 4) + break; + val = bfd_getl32 (buf); fprintf (file, _("incr_linum_l: +%u\n"), val); line += val; - cmdlen = 5; + cmdlen = 4; break; case DST__K_SET_LINUM: - line = bfd_getl16 (buf + 1); + if (len < 2) + break; + line = bfd_getl16 (buf); fprintf (file, _("set_line_num(w) %u\n"), line); - cmdlen = 3; + cmdlen = 2; break; case DST__K_SET_LINUM_B: - line = buf[1]; + if (len < 1) + break; + line = *buf; fprintf (file, _("set_line_num_b %u\n"), line); - cmdlen = 2; + cmdlen = 1; break; case DST__K_SET_LINUM_L: - line = bfd_getl32 (buf + 1); + if (len < 4) + break; + line = bfd_getl32 (buf); fprintf (file, _("set_line_num_l %u\n"), line); - cmdlen = 5; + cmdlen = 4; break; case DST__K_SET_ABS_PC: - pc = bfd_getl32 (buf + 1); + if (len < 4) + break; + pc = bfd_getl32 (buf); fprintf (file, _("set_abs_pc: 0x%08x\n"), pc); - cmdlen = 5; + cmdlen = 4; break; case DST__K_DELTA_PC_L: + if (len < 4) + break; fprintf (file, _("delta_pc_l: +0x%08x\n"), - (unsigned)bfd_getl32 (buf + 1)); - cmdlen = 5; + (unsigned) bfd_getl32 (buf)); + cmdlen = 4; break; case DST__K_TERM: - fprintf (file, _("term(b): 0x%02x"), buf[1]); - pc += buf[1]; + if (len < 1) + break; + fprintf (file, _("term(b): 0x%02x"), *buf); + pc += *buf; fprintf (file, _(" pc: 0x%08x\n"), pc); - cmdlen = 2; + cmdlen = 1; break; case DST__K_TERM_W: - val = bfd_getl16 (buf + 1); + if (len < 2) + break; + val = bfd_getl16 (buf); fprintf (file, _("term_w: 0x%04x"), val); pc += val; fprintf (file, _(" pc: 0x%08x\n"), pc); - cmdlen = 3; + cmdlen = 2; break; default: if (cmd <= 0) @@ -7574,13 +7717,13 @@ evax_bfd_print_dst (struct bfd *abfd, unsigned int dst_size, FILE *file) /* xgettext:c-format */ fprintf (file, _(" pc: 0x%08x line: %5u\n"), pc, line); - cmdlen = 1; + cmdlen = 0; } else fprintf (file, _(" *unhandled* cmd %u\n"), cmd); break; } - if (cmdlen == 0) + if (cmdlen < 0) break; len -= cmdlen; buf += cmdlen; @@ -7596,16 +7739,20 @@ evax_bfd_print_dst (struct bfd *abfd, unsigned int dst_size, FILE *file) while (len > 0) { - signed char cmd = buf[0]; - unsigned char cmdlen = 0; + int cmd = *buf++; + int cmdlen = -1; + len--; switch (cmd) { case DST__K_SRC_DECLFILE: { - struct vms_dst_src_decl_src *src = (void *)(buf + 1); + struct vms_dst_src_decl_src *src = (void *) buf; const char *name; + int nlen; + if (len < sizeof (*src)) + break; /* xgettext:c-format */ fprintf (file, _(" declfile: len: %u, flags: %u, " "fileid: %u\n"), @@ -7620,58 +7767,80 @@ evax_bfd_print_dst (struct bfd *abfd, unsigned int dst_size, FILE *file) (unsigned)bfd_getl32 (src->rms_ebk), (unsigned)bfd_getl16 (src->rms_ffb), src->rms_rfo); - name = (const char *)buf + 1 + sizeof (*src); + if (src->length > len || src->length <= sizeof (*src)) + break; + nlen = src->length - sizeof (*src) - 1; + name = (const char *) buf + sizeof (*src); fprintf (file, _(" filename : %.*s\n"), - name[0], name + 1); + name[0] > nlen ? nlen : name[0], name + 1); + if (name[0] >= nlen) + break; + nlen -= name[0] + 1; name += name[0] + 1; fprintf (file, _(" module name: %.*s\n"), - name[0], name + 1); - cmdlen = 2 + src->length; + name[0] > nlen ? nlen : name[0], name + 1); + if (name[0] > nlen) + break; + cmdlen = src->length; } break; case DST__K_SRC_SETFILE: + if (len < 2) + break; fprintf (file, _(" setfile %u\n"), - (unsigned)bfd_getl16 (buf + 1)); - cmdlen = 3; + (unsigned) bfd_getl16 (buf)); + cmdlen = 2; break; case DST__K_SRC_SETREC_W: + if (len < 2) + break; fprintf (file, _(" setrec %u\n"), - (unsigned)bfd_getl16 (buf + 1)); - cmdlen = 3; + (unsigned) bfd_getl16 (buf)); + cmdlen = 2; break; case DST__K_SRC_SETREC_L: + if (len < 4) + break; fprintf (file, _(" setrec %u\n"), - (unsigned)bfd_getl32 (buf + 1)); - cmdlen = 5; + (unsigned) bfd_getl32 (buf)); + cmdlen = 4; break; case DST__K_SRC_SETLNUM_W: + if (len < 2) + break; fprintf (file, _(" setlnum %u\n"), - (unsigned)bfd_getl16 (buf + 1)); - cmdlen = 3; + (unsigned) bfd_getl16 (buf)); + cmdlen = 2; break; case DST__K_SRC_SETLNUM_L: + if (len < 4) + break; fprintf (file, _(" setlnum %u\n"), - (unsigned)bfd_getl32 (buf + 1)); - cmdlen = 5; + (unsigned) bfd_getl32 (buf)); + cmdlen = 4; break; case DST__K_SRC_DEFLINES_W: + if (len < 2) + break; fprintf (file, _(" deflines %u\n"), - (unsigned)bfd_getl16 (buf + 1)); - cmdlen = 3; + (unsigned) bfd_getl16 (buf)); + cmdlen = 2; break; case DST__K_SRC_DEFLINES_B: - fprintf (file, _(" deflines %u\n"), buf[1]); - cmdlen = 2; + if (len < 1) + break; + fprintf (file, _(" deflines %u\n"), *buf); + cmdlen = 1; break; case DST__K_SRC_FORMFEED: fprintf (file, _(" formfeed\n")); - cmdlen = 1; + cmdlen = 0; break; default: fprintf (file, _(" *unhandled* cmd %u\n"), cmd); break; } - if (cmdlen == 0) + if (cmdlen < 0) break; len -= cmdlen; buf += cmdlen; -- cgit v1.1