diff --git a/CVE-2018-10254.patch b/CVE-2018-10254.patch new file mode 100644 index 0000000000000000000000000000000000000000..bdf6bd13b6850e2a053ddfcabe92493ebfcba6ae --- /dev/null +++ b/CVE-2018-10254.patch @@ -0,0 +1,345 @@ +commit cfa3559b8ec9e693142638eedb4d6340ecf01c90 +Author: Adam Majer +Date: Thu Jun 28 13:03:06 2018 +0200 + + Verify we do not read longer than the buffer + + Netwide Assembler (NASM) 2.13 has a stack-based buffer over-read + in the disasm function of the disasm/disasm.c file. + + Bug: 3392475 + Signed-off-by: Adam Majer + +diff --git a/disasm/disasm.c b/disasm/disasm.c +index a75d839e..a503434b 100644 +--- a/disasm/disasm.c ++++ b/disasm/disasm.c +@@ -474,8 +474,10 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize, + * stream in data. Return the number of bytes matched if so. + */ + #define case4(x) case (x): case (x)+1: case (x)+2: case (x)+3 ++#define check_can_read_data_byte() if (--remaining_bytes < 0) return 0 ++#define check_can_read_data_bytes(n) { if (remaining_bytes < n) return 0; remaining_bytes -= n; } while(0) + +-static int matches(const struct itemplate *t, uint8_t *data, ++static int matches(const struct itemplate *t, uint8_t *data, int remaining_bytes, + const struct prefix_info *prefix, int segsize, insn *ins) + { + uint8_t *r = (uint8_t *)(t->code); +@@ -525,9 +527,11 @@ static int matches(const struct itemplate *t, uint8_t *data, + case 02: + case 03: + case 04: +- while (c--) ++ while (c--) { ++ check_can_read_data_byte(); + if (*r++ != *data++) + return 0; ++ } + break; + + case 05: +@@ -538,7 +542,9 @@ static int matches(const struct itemplate *t, uint8_t *data, + + case4(010): + { +- int t = *r++, d = *data++; ++ int d, t = *r++; ++ check_can_read_data_byte(); ++ d = *data++; + if (d < t || d > t + 7) + return 0; + else { +@@ -555,28 +561,34 @@ static int matches(const struct itemplate *t, uint8_t *data, + break; + + case4(0274): ++ check_can_read_data_byte(); + opx->offset = (int8_t)*data++; + opx->segment |= SEG_SIGNED; + break; + + case4(020): ++ check_can_read_data_byte(); + opx->offset = *data++; + break; + + case4(024): ++ check_can_read_data_byte(); + opx->offset = *data++; + break; + + case4(030): ++ check_can_read_data_bytes(2); + opx->offset = getu16(data); + data += 2; + break; + + case4(034): + if (osize == 32) { ++ check_can_read_data_bytes(4); + opx->offset = getu32(data); + data += 4; + } else { ++ check_can_read_data_bytes(2); + opx->offset = getu16(data); + data += 2; + } +@@ -585,11 +597,13 @@ static int matches(const struct itemplate *t, uint8_t *data, + break; + + case4(040): ++ check_can_read_data_bytes(4); + opx->offset = getu32(data); + data += 4; + break; + + case4(0254): ++ check_can_read_data_bytes(4); + opx->offset = gets32(data); + data += 4; + break; +@@ -597,18 +611,21 @@ static int matches(const struct itemplate *t, uint8_t *data, + case4(044): + switch (asize) { + case 16: ++ check_can_read_data_bytes(2); + opx->offset = getu16(data); + data += 2; + if (segsize != 16) + opx->disp_size = 16; + break; + case 32: ++ check_can_read_data_bytes(4); + opx->offset = getu32(data); + data += 4; + if (segsize == 16) + opx->disp_size = 32; + break; + case 64: ++ check_can_read_data_bytes(8); + opx->offset = getu64(data); + opx->disp_size = 64; + data += 8; +@@ -617,16 +634,19 @@ static int matches(const struct itemplate *t, uint8_t *data, + break; + + case4(050): ++ check_can_read_data_byte(); + opx->offset = gets8(data++); + opx->segment |= SEG_RELATIVE; + break; + + case4(054): ++ check_can_read_data_bytes(8); + opx->offset = getu64(data); + data += 8; + break; + + case4(060): ++ check_can_read_data_bytes(2); + opx->offset = gets16(data); + data += 2; + opx->segment |= SEG_RELATIVE; +@@ -637,6 +657,7 @@ static int matches(const struct itemplate *t, uint8_t *data, + opx->segment |= SEG_RELATIVE; + /* In long mode rel is always 32 bits, sign extended. */ + if (segsize == 64 || osize == 32) { ++ check_can_read_data_bytes(4); + opx->offset = gets32(data); + data += 4; + if (segsize != 64) +@@ -644,6 +665,7 @@ static int matches(const struct itemplate *t, uint8_t *data, + opx->type = (opx->type & ~SIZE_MASK) + | (segsize == 64 ? BITS64 : BITS32); + } else { ++ check_can_read_data_bytes(2); + opx->offset = gets16(data); + data += 2; + opx->segment &= ~SEG_32BIT; +@@ -652,6 +674,7 @@ static int matches(const struct itemplate *t, uint8_t *data, + break; + + case4(070): ++ check_can_read_data_bytes(4); + opx->offset = gets32(data); + data += 4; + opx->segment |= SEG_32BIT | SEG_RELATIVE; +@@ -662,11 +685,19 @@ static int matches(const struct itemplate *t, uint8_t *data, + case4(0120): + case4(0130): + { +- int modrm = *data++; ++ int modrm; ++ uint8_t *new_data; ++ ++ check_can_read_data_byte(); ++ modrm = *data++; + opx->segment |= SEG_RMREG; +- data = do_ea(data, modrm, asize, segsize, eat, opy, ins); +- if (!data) ++ new_data = do_ea(data, modrm, asize, segsize, eat, opy, ins); ++ if (!new_data) ++ return 0; ++ remaining_bytes = data + remaining_bytes - new_data; ++ if (remaining_bytes < 0) + return 0; ++ data = new_data; + opx->basereg = ((modrm >> 3) & 7) + (ins->rex & REX_R ? 8 : 0); + if ((ins->rex & REX_EV) && (segsize == 64)) + opx->basereg += (ins->evex_p[0] & EVEX_P0RP ? 0 : 16); +@@ -675,7 +706,10 @@ static int matches(const struct itemplate *t, uint8_t *data, + + case 0172: + { +- uint8_t ximm = *data++; ++ uint8_t ximm; ++ ++ check_can_read_data_byte(); ++ ximm = *data++; + c = *r++; + ins->oprs[c >> 3].basereg = (ximm >> 4) & regmask; + ins->oprs[c >> 3].segment |= SEG_RMREG; +@@ -685,7 +719,10 @@ static int matches(const struct itemplate *t, uint8_t *data, + + case 0173: + { +- uint8_t ximm = *data++; ++ uint8_t ximm; ++ ++ check_can_read_data_byte(); ++ ximm = *data++; + c = *r++; + + if ((c ^ ximm) & 15) +@@ -698,7 +735,10 @@ static int matches(const struct itemplate *t, uint8_t *data, + + case4(0174): + { +- uint8_t ximm = *data++; ++ uint8_t ximm; ++ ++ check_can_read_data_byte(); ++ ximm = *data++; + + opx->basereg = (ximm >> 4) & regmask; + opx->segment |= SEG_RMREG; +@@ -714,12 +754,20 @@ static int matches(const struct itemplate *t, uint8_t *data, + case4(0230): + case4(0234): + { +- int modrm = *data++; ++ int modrm; ++ uint8_t *new_data; ++ ++ check_can_read_data_byte(); ++ modrm = *data++; + if (((modrm >> 3) & 07) != (c & 07)) + return 0; /* spare field doesn't match up */ +- data = do_ea(data, modrm, asize, segsize, eat, opy, ins); +- if (!data) ++ new_data = do_ea(data, modrm, asize, segsize, eat, opy, ins); ++ if (!new_data) ++ return 0; ++ remaining_bytes = data + remaining_bytes - new_data; ++ if (remaining_bytes < 0) + return 0; ++ data = new_data; + break; + } + +@@ -935,7 +983,10 @@ static int matches(const struct itemplate *t, uint8_t *data, + + case 0330: + { +- int t = *r++, d = *data++; ++ int t = *r++, d; ++ ++ check_can_read_data_byte(); ++ d = *data++; + if (d < t || d > t + 15) + return 0; + else +@@ -1126,6 +1177,8 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, + bool end_prefix; + bool is_evex; + ++ int remaining_bytes = INSN_MAX; ++ + memset(&ins, 0, sizeof ins); + + /* +@@ -1141,6 +1194,8 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, + + end_prefix = false; + while (!end_prefix) { ++ check_can_read_data_byte(); ++ + switch (*data) { + case 0xF2: + case 0xF3: +@@ -1185,6 +1240,7 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, + + case 0xC4: + case 0xC5: ++ check_can_read_data_byte(); + if (segsize == 64 || (data[1] & 0xc0) == 0xc0) { + prefix.vex[0] = *data++; + prefix.vex[1] = *data++; +@@ -1193,6 +1249,7 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, + prefix.vex_c = RV_VEX; + + if (prefix.vex[0] == 0xc4) { ++ check_can_read_data_byte(); + prefix.vex[2] = *data++; + prefix.rex |= (~prefix.vex[1] >> 5) & 7; /* REX_RXB */ + prefix.rex |= (prefix.vex[2] >> (7-3)) & REX_W; +@@ -1213,7 +1270,8 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, + + case 0x62: + { +- if (segsize == 64 || ((data[1] & 0xc0) == 0xc0)) { ++ if (segsize == 64 || (remaining_bytes > 3 && (data[1] & 0xc0) == 0xc0)) { ++ check_can_read_data_bytes(3); + data++; /* 62h EVEX prefix */ + prefix.evex[0] = *data++; + prefix.evex[1] = *data++; +@@ -1235,8 +1293,10 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, + } + + case 0x8F: +- if ((data[1] & 030) != 0 && ++ check_can_read_data_byte(); ++ if ((data[1] & 030) != 0 && + (segsize == 64 || (data[1] & 0xc0) == 0xc0)) { ++ check_can_read_data_byte(); + prefix.vex[0] = *data++; + prefix.vex[1] = *data++; + prefix.vex[2] = *data++; +@@ -1280,6 +1340,7 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, + break; + + default: ++ remaining_bytes++; /* didn't actually use the last byte */ + end_prefix = true; + break; + } +@@ -1293,14 +1354,17 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, + return 0; /* No instruction table at all... */ + + dp = data; ++ ++ check_can_read_data_byte(); + ix += *dp++; + while (ix->n == -1) { ++ check_can_read_data_byte(); + ix = (const struct disasm_index *)ix->p + *dp++; + } + + p = (const struct itemplate * const *)ix->p; + for (n = ix->n; n; n--, p++) { +- if ((length = matches(*p, data, &prefix, segsize, &tmp_ins))) { ++ if ((length = matches(*p, data, remaining_bytes, &prefix, segsize, &tmp_ins))) { + works = true; + /* + * Final check to make sure the types of r/m match up. diff --git a/nasm.spec b/nasm.spec index a2555d7862daf6fd539cb66533ec294e243b1669..36ee470f0c7f7380158808716437d489f59bb40f 100644 --- a/nasm.spec +++ b/nasm.spec @@ -6,15 +6,16 @@ %bcond_without documentation %endif -Name: nasm -Version: 2.13.03 -Release: 4 -Summary: The Netwide Assembler, a portable x86 assembler with Intel-like syntax -License: BSD -URL: http://www.nasm.us -Source0: http://www.nasm.us/pub/nasm/releasebuilds/%{version}/%{name}-%{version}.tar.bz2 -Source1: http://www.nasm.us/pub/nasm/releasebuilds/%{version}/%{name}-%{version}-xdoc.tar.bz2 - +Name: nasm +Version: 2.13.03 +Release: 4 +Summary: The Netwide Assembler, a portable x86 assembler with Intel-like syntax +License: BSD +URL: http://www.nasm.us +Source0: http://www.nasm.us/pub/nasm/releasebuilds/%{version}/%{name}-%{version}.tar.bz2 +Source1: http://www.nasm.us/pub/nasm/releasebuilds/%{version}/%{name}-%{version}-xdoc.tar.bz2 +#https://bugzilla.nasm.us/attachment.cgi?id=411648 +Patch0000:CVE-2018-10254.patch BuildRequires: perl(Env) autoconf asciidoc xmlto gcc make git Provides: %{name}-rdoff @@ -83,6 +84,9 @@ make INSTALLROOT=%{buildroot} install install_rdf %{_mandir}/man1/ld* %changelog +* Fri Mar 20 2020 shijian - 2.13.03-5 +- fix CVE-2018-10254 + * Mon Jan 13 2020 openEuler BuildTeam - 2.13.03-4 - build without documentation