Subject: PR/479: Protect against 0-divide and offset out of bounds reads Origin: FILE5_25-2-gde23336 Upstream-Author: Christos Zoulas Date: Wed Sep 16 18:25:23 2015 +0000 --- a/src/softmagic.c +++ b/src/softmagic.c @@ -57,10 +57,10 @@ private int mconvert(struct magic_set *, struct magic *, int); private int print_sep(struct magic_set *, int); private int handle_annotation(struct magic_set *, struct magic *); -private void cvt_8(union VALUETYPE *, const struct magic *); -private void cvt_16(union VALUETYPE *, const struct magic *); -private void cvt_32(union VALUETYPE *, const struct magic *); -private void cvt_64(union VALUETYPE *, const struct magic *); +private int cvt_8(union VALUETYPE *, const struct magic *); +private int cvt_16(union VALUETYPE *, const struct magic *); +private int cvt_32(union VALUETYPE *, const struct magic *); +private int cvt_64(union VALUETYPE *, const struct magic *); #define OFFSET_OOB(n, o, i) ((n) < (o) || (i) > ((n) - (o))) #define BE64(p) (((uint64_t)(p)->hq[0]<<56)|((uint64_t)(p)->hq[1]<<48)| \ @@ -858,37 +858,45 @@ p->fld *= cast m->num_mask; \ break; \ case FILE_OPDIVIDE: \ + if (cast m->num_mask == 0) \ + return -1; \ p->fld /= cast m->num_mask; \ break; \ case FILE_OPMODULO: \ + if (cast m->num_mask == 0) \ + return -1; \ p->fld %= cast m->num_mask; \ break; \ } \ if (m->mask_op & FILE_OPINVERSE) \ p->fld = ~p->fld \ -private void +private int cvt_8(union VALUETYPE *p, const struct magic *m) { DO_CVT(b, (uint8_t)); + return 0; } -private void +private int cvt_16(union VALUETYPE *p, const struct magic *m) { DO_CVT(h, (uint16_t)); + return 0; } -private void +private int cvt_32(union VALUETYPE *p, const struct magic *m) { DO_CVT(l, (uint32_t)); + return 0; } -private void +private int cvt_64(union VALUETYPE *p, const struct magic *m) { DO_CVT(q, (uint64_t)); + return 0; } #define DO_CVT2(fld, cast) \ @@ -904,20 +912,24 @@ p->fld *= cast m->num_mask; \ break; \ case FILE_OPDIVIDE: \ + if (cast m->num_mask == 0) \ + return -1; \ p->fld /= cast m->num_mask; \ break; \ } \ -private void +private int cvt_float(union VALUETYPE *p, const struct magic *m) { DO_CVT2(f, (float)); + return 0; } -private void +private int cvt_double(union VALUETYPE *p, const struct magic *m) { DO_CVT2(d, (double)); + return 0; } /* @@ -933,21 +945,25 @@ switch (type = cvt_flip(m->type, flip)) { case FILE_BYTE: - cvt_8(p, m); + if (cvt_8(p, m) == -1) + goto out; return 1; case FILE_SHORT: - cvt_16(p, m); + if (cvt_16(p, m) == -1) + goto out; return 1; case FILE_LONG: case FILE_DATE: case FILE_LDATE: - cvt_32(p, m); + if (cvt_32(p, m) == -1) + goto out; return 1; case FILE_QUAD: case FILE_QDATE: case FILE_QLDATE: case FILE_QWDATE: - cvt_64(p, m); + if (cvt_64(p, m) == -1) + goto out; return 1; case FILE_STRING: case FILE_BESTRING16: @@ -979,65 +995,78 @@ } case FILE_BESHORT: p->h = (short)BE16(p); - cvt_16(p, m); + if (cvt_16(p, m) == -1) + goto out; return 1; case FILE_BELONG: case FILE_BEDATE: case FILE_BELDATE: p->l = (int32_t)BE32(p); - cvt_32(p, m); + if (cvt_32(p, m) == -1) + goto out; return 1; case FILE_BEQUAD: case FILE_BEQDATE: case FILE_BEQLDATE: case FILE_BEQWDATE: p->q = (uint64_t)BE64(p); - cvt_64(p, m); + if (cvt_64(p, m) == -1) + goto out; return 1; case FILE_LESHORT: p->h = (short)LE16(p); - cvt_16(p, m); + if (cvt_16(p, m) == -1) + goto out; return 1; case FILE_LELONG: case FILE_LEDATE: case FILE_LELDATE: p->l = (int32_t)LE32(p); - cvt_32(p, m); + if (cvt_32(p, m) == -1) + goto out; return 1; case FILE_LEQUAD: case FILE_LEQDATE: case FILE_LEQLDATE: case FILE_LEQWDATE: p->q = (uint64_t)LE64(p); - cvt_64(p, m); + if (cvt_64(p, m) == -1) + goto out; return 1; case FILE_MELONG: case FILE_MEDATE: case FILE_MELDATE: p->l = (int32_t)ME32(p); - cvt_32(p, m); + if (cvt_32(p, m) == -1) + goto out; return 1; case FILE_FLOAT: - cvt_float(p, m); + if (cvt_float(p, m) == -1) + goto out; return 1; case FILE_BEFLOAT: p->l = BE32(p); - cvt_float(p, m); + if (cvt_float(p, m) == -1) + goto out; return 1; case FILE_LEFLOAT: p->l = LE32(p); - cvt_float(p, m); + if (cvt_float(p, m) == -1) + goto out; return 1; case FILE_DOUBLE: - cvt_double(p, m); + if (cvt_double(p, m) == -1) + goto out; return 1; case FILE_BEDOUBLE: p->q = BE64(p); - cvt_double(p, m); + if (cvt_double(p, m) == -1) + goto out; return 1; case FILE_LEDOUBLE: p->q = LE64(p); - cvt_double(p, m); + if (cvt_double(p, m) == -1) + goto out; return 1; case FILE_REGEX: case FILE_SEARCH: @@ -1050,6 +1079,9 @@ file_magerror(ms, "invalid type %d in mconvert()", m->type); return 0; } +out: + file_magerror(ms, "zerodivide in mconvert()"); + return 0; } @@ -1066,6 +1098,12 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m) { + if (offset >= nbytes) { + file_magerror(ms, + "offset in magic %u greater than buffer size %zu", + offset, nbytes); + return -1; + } /* * Note: FILE_SEARCH and FILE_REGEX do not actually copy * anything, but setup pointers into the source @@ -1230,6 +1268,8 @@ if (m->in_op & FILE_OPINDIRECT) { const union VALUETYPE *q = CAST(const union VALUETYPE *, ((const void *)(s + offset + off))); + if (OFFSET_OOB(offset + off, nbytes, sizeof(*q))) + return 0; switch (cvt_flip(m->in_type, flip)) { case FILE_BYTE: off = q->b;