diff -Nru busybox-1.30.1/debian/changelog busybox-1.30.1/debian/changelog --- busybox-1.30.1/debian/changelog 2020-11-11 12:15:02.000000000 +0000 +++ busybox-1.30.1/debian/changelog 2021-11-24 19:02:55.000000000 +0000 @@ -1,3 +1,22 @@ +busybox (1:1.30.1-4ubuntu6.4) focal-security; urgency=medium + + * SECURITY UPDATE: invalid free or segfault via gzip data + - debian/patches/CVE-2021-28831.patch: fix DoS if gzip is corrupt in + archival/libarchive/decompress_gunzip.c. + - CVE-2021-28831 + * SECURITY UPDATE: OOB read in unlzma + - debian/patches/CVE-2021-42374.patch: fix a case where we could read + before beginning of buffer in archival/libarchive/decompress_unlzma.c, + testsuite/unlzma.tests. + - CVE-2021-42374 + * SECURITY UPDATE: multiple security issues in awk + - debian/patches/CVE-2021-423xx-awk.patch: backport awk.c from + busybox 1.34.1. + - CVE-2021-42378, CVE-2021-42379, CVE-2021-42380, CVE-2021-42381, + CVE-2021-42382, CVE-2021-42384, CVE-2021-42385, CVE-2021-42386 + + -- Marc Deslauriers Wed, 24 Nov 2021 14:02:55 -0500 + busybox (1:1.30.1-4ubuntu6.3) focal; urgency=medium * cherry-pick settimeofday for glibc v2.31+ compatibility fix for upstream diff -Nru busybox-1.30.1/debian/patches/CVE-2021-28831.patch busybox-1.30.1/debian/patches/CVE-2021-28831.patch --- busybox-1.30.1/debian/patches/CVE-2021-28831.patch 1970-01-01 00:00:00.000000000 +0000 +++ busybox-1.30.1/debian/patches/CVE-2021-28831.patch 2021-11-24 19:02:38.000000000 +0000 @@ -0,0 +1,45 @@ +Backport of: + +From f25d254dfd4243698c31a4f3153d4ac72aa9e9bd Mon Sep 17 00:00:00 2001 +From: Samuel Sapalski +Date: Wed, 3 Mar 2021 16:31:22 +0100 +Subject: decompress_gunzip: Fix DoS if gzip is corrupt + +On certain corrupt gzip files, huft_build will set the error bit on +the result pointer. If afterwards abort_unzip is called huft_free +might run into a segmentation fault or an invalid pointer to +free(p). + +In order to mitigate this, we check in huft_free if the error bit +is set and clear it before the linked list is freed. + +Signed-off-by: Samuel Sapalski +Signed-off-by: Peter Kaestle +Signed-off-by: Denys Vlasenko +--- + archival/libarchive/decompress_gunzip.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +--- a/archival/libarchive/decompress_gunzip.c ++++ b/archival/libarchive/decompress_gunzip.c +@@ -222,10 +222,20 @@ static const uint8_t border[] ALIGN1 = { + * each table. + * t: table to free + */ ++#define BAD_HUFT(p) ((uintptr_t)(p) & 1) ++#define ERR_RET ((huft_t*)(uintptr_t)1) + static void huft_free(huft_t *p) + { + huft_t *q; + ++ /* ++ * If 'p' has the error bit set we have to clear it, otherwise we might run ++ * into a segmentation fault or an invalid pointer to free(p) ++ */ ++ if (BAD_HUFT(p)) { ++ p = (huft_t*)((uintptr_t)(p) ^ (uintptr_t)(ERR_RET)); ++ } ++ + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + while (p) { + q = (--p)->v.t; diff -Nru busybox-1.30.1/debian/patches/CVE-2021-42374.patch busybox-1.30.1/debian/patches/CVE-2021-42374.patch --- busybox-1.30.1/debian/patches/CVE-2021-42374.patch 1970-01-01 00:00:00.000000000 +0000 +++ busybox-1.30.1/debian/patches/CVE-2021-42374.patch 2021-11-24 19:02:45.000000000 +0000 @@ -0,0 +1,64 @@ +Backport of: + +From 04f052c56ded5ab6a904e3a264a73dc0412b2e78 Mon Sep 17 00:00:00 2001 +From: Denys Vlasenko +Date: Tue, 15 Jun 2021 15:07:57 +0200 +Subject: unlzma: fix a case where we could read before beginning of buffer + +Testcase: + + 21 01 01 00 00 00 00 00 e7 01 01 01 ef 00 df b6 + 00 17 02 10 11 0f ff 00 16 00 00 + +Unfortunately, the bug is not reliably causing a segfault, +the behavior depends on what's in memory before the buffer. + +function old new delta +unpack_lzma_stream 2762 2768 +6 + +Signed-off-by: Denys Vlasenko +--- + archival/libarchive/decompress_unlzma.c | 5 ++++- + testsuite/unlzma.tests | 17 +++++++++++++---- + testsuite/unlzma_issue_3.lzma | Bin 0 -> 27 bytes + 3 files changed, 17 insertions(+), 5 deletions(-) + create mode 100644 testsuite/unlzma_issue_3.lzma + +--- a/archival/libarchive/decompress_unlzma.c ++++ b/archival/libarchive/decompress_unlzma.c +@@ -290,8 +290,11 @@ unpack_lzma_stream(transformer_state_t * + uint32_t pos; + + pos = buffer_pos - rep0; +- if ((int32_t)pos < 0) ++ if ((int32_t)pos < 0) { + pos += header.dict_size; ++ if ((int32_t)pos < 0) ++ goto bad; ++ } + match_byte = buffer[pos]; + do { + int bit; +--- a/testsuite/unlzma.tests ++++ b/testsuite/unlzma.tests +@@ -8,14 +8,16 @@ + + # Damaged encrypted streams + testing "unlzma (bad archive 1)" \ +- "unlzma /dev/null; echo \$?" \ +-"1 ++ "unlzma &1 >/dev/null; echo \$?" \ ++"unlzma: corrupted data ++1 + " "" "" + + # Damaged encrypted streams + testing "unlzma (bad archive 2)" \ +- "unlzma /dev/null; echo \$?" \ +-"1 ++ "unlzma &1 >/dev/null; echo \$?" \ ++"unlzma: corrupted data ++1 + " "" "" + + exit $FAILCOUNT diff -Nru busybox-1.30.1/debian/patches/CVE-2021-423xx-awk.patch busybox-1.30.1/debian/patches/CVE-2021-423xx-awk.patch --- busybox-1.30.1/debian/patches/CVE-2021-423xx-awk.patch 1970-01-01 00:00:00.000000000 +0000 +++ busybox-1.30.1/debian/patches/CVE-2021-423xx-awk.patch 2021-11-24 19:02:49.000000000 +0000 @@ -0,0 +1,285 @@ +Description: fix multiple security issues in awk +Origin: backported awk.c from busybox 1.34.1 + +--- a/editors/awk.c ++++ b/editors/awk.c +@@ -272,21 +272,25 @@ typedef struct tsplitter_s { + /* if previous token class is CONCAT1 and next is CONCAT2, concatenation */ + /* operator is inserted between them */ + #define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM \ +- | TC_STRING | TC_NUMBER | TC_UOPPOST) ++ | TC_STRING | TC_NUMBER | TC_UOPPOST \ ++ | TC_LENGTH) + #define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE) + +-#define OF_RES1 0x010000 +-#define OF_RES2 0x020000 +-#define OF_STR1 0x040000 +-#define OF_STR2 0x080000 +-#define OF_NUM1 0x100000 +-#define OF_CHECKED 0x200000 ++#define OF_RES1 0x010000 ++#define OF_RES2 0x020000 ++#define OF_STR1 0x040000 ++#define OF_STR2 0x080000 ++#define OF_NUM1 0x100000 ++#define OF_CHECKED 0x200000 ++#define OF_REQUIRED 0x400000 ++ + + /* combined operator flags */ + #define xx 0 + #define xV OF_RES2 + #define xS (OF_RES2 | OF_STR2) + #define Vx OF_RES1 ++#define Rx (OF_RES1 | OF_NUM1 | OF_REQUIRED) + #define VV (OF_RES1 | OF_RES2) + #define Nx (OF_RES1 | OF_NUM1) + #define NV (OF_RES1 | OF_NUM1 | OF_RES2) +@@ -401,7 +405,7 @@ static const char tokenlist[] ALIGN1 = + + #define OC_B OC_BUILTIN + +-static const uint32_t tokeninfo[] = { ++static const uint32_t tokeninfo[] ALIGN4 = { + 0, + 0, + OC_REGEXP, +@@ -425,7 +429,7 @@ static const uint32_t tokeninfo[] = { + 0, + 0, /* \n */ + ST_IF, ST_DO, ST_FOR, OC_BREAK, +- OC_CONTINUE, OC_DELETE|Vx, OC_PRINT, ++ OC_CONTINUE, OC_DELETE|Rx, OC_PRINT, + OC_PRINTF, OC_NEXT, OC_NEXTFILE, + OC_RETURN|Vx, OC_EXIT|Nx, + ST_WHILE, +@@ -593,7 +597,7 @@ static const char EMSG_UNEXP_EOS[] ALIGN + static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token"; + static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero"; + static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier"; +-static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin"; ++static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments"; + static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array"; + static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error"; + static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function"; +@@ -1067,8 +1071,10 @@ static uint32_t next_token(uint32_t expe + const uint32_t *ti; + + if (t_rollback) { ++ debug_printf_parse("%s: using rolled-back token\n", __func__); + t_rollback = FALSE; + } else if (concat_inserted) { ++ debug_printf_parse("%s: using concat-inserted token\n", __func__); + concat_inserted = FALSE; + t_tclass = save_tclass; + t_info = save_info; +@@ -1197,7 +1203,11 @@ static uint32_t next_token(uint32_t expe + goto readnext; + + /* insert concatenation operator when needed */ +- if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) { ++ debug_printf_parse("%s: %x %x %x concat_inserted?\n", __func__, ++ (ltclass & TC_CONCAT1), (tc & TC_CONCAT2), (expected & TC_BINOP)); ++ if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP) ++ && !(ltclass == TC_LENGTH && tc == TC_SEQSTART) /* but not for "length(..." */ ++ ) { + concat_inserted = TRUE; + save_tclass = tc; + save_info = t_info; +@@ -1205,6 +1215,7 @@ static uint32_t next_token(uint32_t expe + t_info = OC_CONCAT | SS | P(35); + } + ++ debug_printf_parse("%s: t_tclass=tc=%x\n", __func__, t_tclass); + t_tclass = tc; + } + ltclass = t_tclass; +@@ -1215,6 +1226,7 @@ static uint32_t next_token(uint32_t expe + EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN); + } + ++ debug_printf_parse("%s: returning, ltclass:%x t_double:%f\n", __func__, ltclass, t_double); + return ltclass; + #undef concat_inserted + #undef save_tclass +@@ -1265,7 +1277,7 @@ static node *parse_expr(uint32_t iexp) + debug_printf_parse("%s(%x)\n", __func__, iexp); + + sn.info = PRIMASK; +- sn.r.n = glptr = NULL; ++ sn.r.n = sn.a.n = glptr = NULL; + xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp; + + while (!((tc = next_token(xtc)) & iexp)) { +@@ -1279,7 +1291,7 @@ static node *parse_expr(uint32_t iexp) + glptr = NULL; + + } else if (tc & (TC_BINOP | TC_UOPPOST)) { +- debug_printf_parse("%s: TC_BINOP | TC_UOPPOST\n", __func__); ++ debug_printf_parse("%s: TC_BINOP | TC_UOPPOST tc:%x\n", __func__, tc); + /* for binary and postfix-unary operators, jump back over + * previous operators with higher priority */ + vn = cn; +@@ -1287,6 +1299,7 @@ static node *parse_expr(uint32_t iexp) + || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON)) + ) { + vn = vn->a.n; ++ if (!vn->a.n) syntax_error(EMSG_UNEXP_TOKEN); + } + if ((t_info & OPCLSMASK) == OC_TERNARY) + t_info += P(6); +@@ -1346,8 +1359,10 @@ static node *parse_expr(uint32_t iexp) + v = cn->l.v = xzalloc(sizeof(var)); + if (tc & TC_NUMBER) + setvar_i(v, t_double); +- else ++ else { + setvar_s(v, t_string); ++ xtc &= ~TC_UOPPOST; /* "str"++ is not allowed */ ++ } + break; + + case TC_REGEXP: +@@ -1383,7 +1398,12 @@ static node *parse_expr(uint32_t iexp) + + case TC_LENGTH: + debug_printf_parse("%s: TC_LENGTH\n", __func__); +- next_token(TC_SEQSTART | TC_OPTERM | TC_GRPTERM); ++ next_token(TC_SEQSTART /* length(...) */ ++ | TC_OPTERM /* length; (or newline)*/ ++ | TC_GRPTERM /* length } */ ++ | TC_BINOPX /* length NUM */ ++ | TC_COMMA /* print length, 1 */ ++ ); + rollback_token(); + if (t_tclass & TC_SEQSTART) { + /* It was a "(" token. Handle just like TC_BUILTIN */ +@@ -1425,7 +1445,11 @@ static void chain_expr(uint32_t info) + node *n; + + n = chain_node(info); ++ + n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM); ++ if ((info & OF_REQUIRED) && !n->l.n) ++ syntax_error(EMSG_TOO_FEW_ARGS); ++ + if (t_tclass & TC_GRPTERM) + rollback_token(); + } +@@ -1605,12 +1629,25 @@ static void parse_program(char *p) + f = newfunc(t_string); + f->body.first = NULL; + f->nargs = 0; +- while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) { ++ /* Match func arg list: a comma sep list of >= 0 args, and a close paren */ ++ while (next_token(TC_VARIABLE | TC_SEQTERM | TC_COMMA)) { ++ /* Either an empty arg list, or trailing comma from prev iter ++ * must be followed by an arg */ ++ if (f->nargs == 0 && t_tclass == TC_SEQTERM) ++ break; ++ ++ /* TC_SEQSTART/TC_COMMA must be followed by TC_VARIABLE */ ++ if (t_tclass != TC_VARIABLE) ++ syntax_error(EMSG_UNEXP_TOKEN); ++ + v = findvar(ahash, t_string); + v->x.aidx = f->nargs++; + ++ /* Arg followed either by end of arg list or 1 comma */ + if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM) + break; ++ if (t_tclass != TC_COMMA) ++ syntax_error(EMSG_UNEXP_TOKEN); + } + seq = &f->body; + chain_group(); +@@ -1726,12 +1763,34 @@ static void fsrealloc(int size) + nfields = size; + } + ++static int regexec1_nonempty(const regex_t *preg, const char *s, regmatch_t pmatch[]) ++{ ++ int r = regexec(preg, s, 1, pmatch, 0); ++ if (r == 0 && pmatch[0].rm_eo == 0) { ++ /* For example, happens when FS can match ++ * an empty string (awk -F ' *'). Logically, ++ * this should split into one-char fields. ++ * However, gawk 5.0.1 searches for first ++ * _non-empty_ separator string match: ++ */ ++ size_t ofs = 0; ++ do { ++ ofs++; ++ if (!s[ofs]) ++ return REG_NOMATCH; ++ regexec(preg, s + ofs, 1, pmatch, 0); ++ } while (pmatch[0].rm_eo == 0); ++ pmatch[0].rm_so += ofs; ++ pmatch[0].rm_eo += ofs; ++ } ++ return r; ++} ++ + static int awk_split(const char *s, node *spl, char **slist) + { +- int l, n; ++ int n; + char c[4]; + char *s1; +- regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough... + + /* in worst case, each char would be a separate field */ + *slist = s1 = xzalloc(strlen(s) * 2 + 3); +@@ -1748,29 +1807,31 @@ static int awk_split(const char *s, node + return n; /* "": zero fields */ + n++; /* at least one field will be there */ + do { ++ int l; ++ regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough... ++ + l = strcspn(s, c+2); /* len till next NUL or \n */ +- if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0 ++ if (regexec1_nonempty(icase ? spl->r.ire : spl->l.re, s, pmatch) == 0 + && pmatch[0].rm_so <= l + ) { ++ /* if (pmatch[0].rm_eo == 0) ... - impossible */ + l = pmatch[0].rm_so; +- if (pmatch[0].rm_eo == 0) { +- l++; +- pmatch[0].rm_eo++; +- } + n++; /* we saw yet another delimiter */ + } else { + pmatch[0].rm_eo = l; + if (s[l]) + pmatch[0].rm_eo++; + } +- memcpy(s1, s, l); +- /* make sure we remove *all* of the separator chars */ +- do { +- s1[l] = '\0'; +- } while (++l < pmatch[0].rm_eo); +- nextword(&s1); ++ s1 = mempcpy(s1, s, l); ++ *s1++ = '\0'; + s += pmatch[0].rm_eo; + } while (*s); ++ ++ /* echo a-- | awk -F-- '{ print NF, length($NF), $NF }' ++ * should print "2 0 ": ++ */ ++ *s1 = '\0'; ++ + return n; + } + if (c[0] == '\0') { /* null split */ +@@ -1974,7 +2035,7 @@ static int ptest(node *pattern) + static int awk_getline(rstream *rsm, var *v) + { + char *b; +- regmatch_t pmatch[2]; ++ regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough... + int size, a, p, pp = 0; + int fd, so, eo, r, rp; + char c, *m, *s; diff -Nru busybox-1.30.1/debian/patches/series busybox-1.30.1/debian/patches/series --- busybox-1.30.1/debian/patches/series 2020-11-11 12:15:02.000000000 +0000 +++ busybox-1.30.1/debian/patches/series 2021-11-24 19:02:49.000000000 +0000 @@ -25,3 +25,6 @@ stime-is-clock_settime.patch 45fa3f18adf57ef9d743038743d9c90573aeeb91.patch CVE-2018-1000500-2.patch +CVE-2021-28831.patch +CVE-2021-42374.patch +CVE-2021-423xx-awk.patch