From soeren at soeren-tempel.net Wed Jun 1 13:11:54 2022 From: soeren at soeren-tempel.net (soeren at soeren-tempel.net) Date: Wed, 1 Jun 2022 15:11:54 +0200 Subject: [PATCH] ash: Fix use-after-free on idx variable Message-ID: <20220601131153.30200-1-soeren@soeren-tempel.net> From: S?ren Tempel Consider the following code from ash.c: STPUTC(*idx, expdest); if (quotes && (unsigned char)*idx == CTLESC) { The idx variable points to a value in the stack string (as managed by STPUTC). STPUTC may resize this stack string via realloc(3). If this happens, the idx pointer needs to be updated. Otherwise, dereferencing idx may result in a use-after free. The valgrind output for this edge case looks as follows: Invalid read of size 1 at 0x113AD7: subevalvar (ash.c:7326) by 0x112EC7: evalvar (ash.c:7674) by 0x113219: argstr (ash.c:6891) by 0x113D10: expandarg (ash.c:8098) by 0x118989: evalcommand (ash.c:10377) by 0x116744: evaltree (ash.c:9373) by 0x1170DC: cmdloop (ash.c:13577) by 0x1191E4: ash_main (ash.c:14756) by 0x10CB3B: run_applet_no_and_exit (appletlib.c:967) by 0x10CBCA: run_applet_and_exit (appletlib.c:986) by 0x10CBCA: main (appletlib.c:1126) Address 0x48b4099 is 857 bytes inside a block of size 2,736 free'd at 0x48A6FC9: realloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so) by 0x125B03: xrealloc (xfuncs_printf.c:61) by 0x10F9D2: growstackblock (ash.c:1736) by 0x10FA4E: growstackstr (ash.c:1775) by 0x10FA71: _STPUTC (ash.c:1816) by 0x113A94: subevalvar (ash.c:7325) by 0x112EC7: evalvar (ash.c:7674) by 0x113219: argstr (ash.c:6891) by 0x113D10: expandarg (ash.c:8098) by 0x118989: evalcommand (ash.c:10377) by 0x116744: evaltree (ash.c:9373) by 0x1170DC: cmdloop (ash.c:13577) Block was alloc'd at at 0x48A26D5: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so) by 0x125AE9: xmalloc (xfuncs_printf.c:50) by 0x10ED56: stalloc (ash.c:1622) by 0x10F9FF: growstackblock (ash.c:1746) by 0x10FB2A: growstackto (ash.c:1783) by 0x10FB47: makestrspace (ash.c:1795) by 0x10FDE7: memtodest (ash.c:6390) by 0x10FE91: strtodest (ash.c:6417) by 0x112CC5: varvalue (ash.c:7558) by 0x112D80: evalvar (ash.c:7603) by 0x113219: argstr (ash.c:6891) by 0x113D10: expandarg (ash.c:8098) This patch fixes this issue by updating the pointers again via the restart label if STPUTC re-sized the stack. This issue has been reported to us at Alpine Linux downstream. See also: * https://gitlab.alpinelinux.org/alpine/aports/-/issues/13900 * http://lists.busybox.net/pipermail/busybox/2022-April/089655.html --- shell/ash.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shell/ash.c b/shell/ash.c index ef4a47afe..924729a64 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7323,6 +7323,8 @@ subevalvar(char *start, char *str, int strloc, if (idx >= end) break; STPUTC(*idx, expdest); + if (stackblock() != restart_detect) + goto restart; if (quotes && (unsigned char)*idx == CTLESC) { idx++; len++; From soeren at soeren-tempel.net Wed Jun 1 14:17:21 2022 From: soeren at soeren-tempel.net (soeren at soeren-tempel.net) Date: Wed, 1 Jun 2022 16:17:21 +0200 Subject: [PATCH v2] ash: Fix use-after-free on idx variable In-Reply-To: <20220601131153.30200-1-soeren@soeren-tempel.net> References: <20220601131153.30200-1-soeren@soeren-tempel.net> Message-ID: <20220601141720.1709-1-soeren@soeren-tempel.net> From: S?ren Tempel Consider the following code from ash.c: STPUTC(*idx, expdest); if (quotes && (unsigned char)*idx == CTLESC) { The idx variable points to a value in the stack string (as managed by STPUTC). STPUTC may resize this stack string via realloc(3). If this happens, the idx pointer needs to be updated. Otherwise, dereferencing idx may result in a use-after free. The valgrind output for this edge case looks as follows: Invalid read of size 1 at 0x113AD7: subevalvar (ash.c:7326) by 0x112EC7: evalvar (ash.c:7674) by 0x113219: argstr (ash.c:6891) by 0x113D10: expandarg (ash.c:8098) by 0x118989: evalcommand (ash.c:10377) by 0x116744: evaltree (ash.c:9373) by 0x1170DC: cmdloop (ash.c:13577) by 0x1191E4: ash_main (ash.c:14756) by 0x10CB3B: run_applet_no_and_exit (appletlib.c:967) by 0x10CBCA: run_applet_and_exit (appletlib.c:986) by 0x10CBCA: main (appletlib.c:1126) Address 0x48b4099 is 857 bytes inside a block of size 2,736 free'd at 0x48A6FC9: realloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so) by 0x125B03: xrealloc (xfuncs_printf.c:61) by 0x10F9D2: growstackblock (ash.c:1736) by 0x10FA4E: growstackstr (ash.c:1775) by 0x10FA71: _STPUTC (ash.c:1816) by 0x113A94: subevalvar (ash.c:7325) by 0x112EC7: evalvar (ash.c:7674) by 0x113219: argstr (ash.c:6891) by 0x113D10: expandarg (ash.c:8098) by 0x118989: evalcommand (ash.c:10377) by 0x116744: evaltree (ash.c:9373) by 0x1170DC: cmdloop (ash.c:13577) Block was alloc'd at at 0x48A26D5: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so) by 0x125AE9: xmalloc (xfuncs_printf.c:50) by 0x10ED56: stalloc (ash.c:1622) by 0x10F9FF: growstackblock (ash.c:1746) by 0x10FB2A: growstackto (ash.c:1783) by 0x10FB47: makestrspace (ash.c:1795) by 0x10FDE7: memtodest (ash.c:6390) by 0x10FE91: strtodest (ash.c:6417) by 0x112CC5: varvalue (ash.c:7558) by 0x112D80: evalvar (ash.c:7603) by 0x113219: argstr (ash.c:6891) by 0x113D10: expandarg (ash.c:8098) This patch fixes this issue by updating the pointers again via the restart label if STPUTC re-sized the stack. This issue has been reported to us at Alpine Linux downstream. Also: Move the second realloc-check inside the if statement that follows so it isn't done twice if the condition evaluates to false. See also: * https://gitlab.alpinelinux.org/alpine/aports/-/issues/13900 * http://lists.busybox.net/pipermail/busybox/2022-April/089655.html --- Changes since v1: Don't check for restart twice in a row if `quotes && (unsigned char)*idx == CTLESC` evaluates to false. shell/ash.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index ef4a47afe..cbc50eefe 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7323,13 +7323,15 @@ subevalvar(char *start, char *str, int strloc, if (idx >= end) break; STPUTC(*idx, expdest); + if (stackblock() != restart_detect) + goto restart; if (quotes && (unsigned char)*idx == CTLESC) { idx++; len++; STPUTC(*idx, expdest); + if (stackblock() != restart_detect) + goto restart; } - if (stackblock() != restart_detect) - goto restart; idx++; len++; rmesc++; From radoslav.kolev at suse.com Fri Jun 3 08:04:31 2022 From: radoslav.kolev at suse.com (Radoslav Kolev) Date: Fri, 3 Jun 2022 11:04:31 +0300 Subject: CVE-2022-28391 busybox: arbitrary code execution if netstat is used to print a DNS PTR record's value to a VT compatible terminal Message-ID: <078b703b-d27b-6094-e2b7-6abc88a782ed@suse.com> Hello, there is a CVE about busybox reported in April by Alpine Linux developer Ariadne Conill as well as 2 patches to fix it: https://git.alpinelinux.org/aports/plain/main/busybox/0002-nslookup-sanitize-all-printed-strings-with-printable.patch https://git.alpinelinux.org/aports/plain/main/busybox/0001-libbb-sockaddr2str-ensure-only-printable-characters-.patch Would you consider to pick these two up? Best regards, Radoslav From shane.880088.supw at gmail.com Fri Jun 3 19:17:54 2022 From: shane.880088.supw at gmail.com (FriendlyNeighborhoodShane) Date: Sat, 4 Jun 2022 00:47:54 +0530 Subject: [PATCH v6 0/2] less: fully implement -R In-Reply-To: <20220510161015.79220-1-shane.880088.supw@gmail.com> References: <20220510161015.79220-1-shane.880088.supw@gmail.com> Message-ID: It's been almost 2 months since the original patch was submitted and a few weeks since this final version was. But it hasn't received any kind of a reply/feedback from the maintainers yet (and this seems to be the case with quite a few other patches too). Is there something obvious I'm missing, some kind of filter (mental or otherwise) it's getting caught in? I honestly don't know, because there isn't anything particular mentioned on the website's lists section. From danomimanchego123 at gmail.com Sat Jun 4 00:57:38 2022 From: danomimanchego123 at gmail.com (Danomi Manchego) Date: Fri, 3 Jun 2022 20:57:38 -0400 Subject: udhcpc6 kernel listen mode is broken In-Reply-To: References: Message-ID: Sorry all, I did not realize that there was a function called d6_listen_socket() in d6_socket.c - so no new function is needed to fix DHCPv6 Renew reply processing. The correct message ID is needed and use of d6_listen_socket() rather than udhcp_listen_socket(). Regards, Danomi - On Tue, May 10, 2022 at 9:34 PM Danomi Manchego wrote: > > Hello, > > On April 1, I sent "udhcpc6 renew message copy/paste error" email > about udhcpc6 sends the wrong message ID for Renew message due to > copy/paste error from IPv4 dhcpc.c. (Was DHCPREQUEST, should be > D6_MSG_RENEW.) After fixing that, I found that the Renew is sent > correctly, and the DHCPv6 server replies, but udhcpc6 fails to get the > reply. Because there is no reply, the lease does not get extended by > Renew. I found that the issue is that the udhcp_listen_socket() in > socket.c (used for kernel listen mode in d6_dhcpc.c) is somewhat > hard-coded for IPv4. I was able to get kernel listen mode to work by > adding a new function like this to socket.c and using it in d6_dhcp.c. > My udhcp6_listen_socket() differs from udhcp_listen_socket() as > follows: > > * Use PF_INET6 instead of PF_INET. > > * Set IPPROTO_IPV6 / IPV6_V6ONLY socket option rather than broadcast option. > > * Use `struct sockaddr_in6` instead of `struct sockaddr_in`. > > * Use AF_INET6 instead of AF_INET. > > (Maybe SOCK_CLOEXEC should also be set in *both* functions when > calling xsocket since udhcpc/udhcpc6 invoke external udhcpc.script, > but I did not try it.) > > My function is pasted below. > > int FAST_FUNC udhcp6_listen_socket(/*uint32_t ip,*/ int port, const char *inf) > { > int fd; > struct sockaddr_in6 addr; > char *colon; > > log2("opening listen socket on *:%d %s", port, inf); > fd = xsocket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); > > setsockopt_reuseaddr(fd); > > if (setsockopt_1(fd, IPPROTO_IPV6, IPV6_V6ONLY) < 0) > bb_simple_perror_msg_and_die("IPPROTO_IPV6"); > > /* SO_BINDTODEVICE doesn't work on ethernet aliases (ethN:M) */ > colon = strrchr(inf, ':'); > if (colon) > *colon = '\0'; > > if (setsockopt_bindtodevice(fd, inf)) > xfunc_die(); /* warning is already printed */ > > if (colon) > *colon = ':'; > > memset(&addr, 0, sizeof(addr)); > addr.sin6_family = AF_INET6; > addr.sin6_port = htons(port); > /* addr.sin_addr.s_addr = ip; - all-zeros is INADDR_ANY */ > xbind(fd, (struct sockaddr *)&addr, sizeof(addr)); > > return fd; > } > > Regards, > Danomi - From rep.dot.nop at gmail.com Sun Jun 5 06:16:46 2022 From: rep.dot.nop at gmail.com (Bernhard Reutner-Fischer) Date: Sun, 05 Jun 2022 08:16:46 +0200 Subject: [PATCH v6 0/2] less: fully implement -R In-Reply-To: References: <20220510161015.79220-1-shane.880088.supw@gmail.com> Message-ID: <19077B7D-EE39-48A8-8E0C-78E4B233A408@gmail.com> On 3 June 2022 21:17:54 CEST, FriendlyNeighborhoodShane wrote: >It's been almost 2 months since the original patch was submitted and a >few weeks since this final version was. But it hasn't received any kind of >a reply/feedback from the maintainers yet (and this seems to be the case >with quite a few other patches too). > >Is there something obvious I'm missing, some kind of filter (mental or >otherwise) >it's getting caught in? I honestly don't know, because there isn't anything >particular mentioned on the website's lists section. Please keep in mind that busybox is a project driven by volunteers. Patches have to have a proper Signed-off-by with real names for legal reasons, I think you forgot to add that. I vaguely remember less and letting color through verbatim. Ah, here https://busybox.busybox.narkive.com/Ueypu29o/patch-1-3-less-use-esc-positive-instead-of-esc-normal and following. Specifically: ---8<--- It is not okay in Unix to pipe escape sequences to a non-tty stdout. I don't think the rest of Unix world needs to accommodate it. ---8<--- So, not sure, but I think it has become more and more common practice in the meantime? From shane.880088.supw at gmail.com Sun Jun 5 17:55:23 2022 From: shane.880088.supw at gmail.com (FriendlyNeighborhoodShane) Date: Sun, 5 Jun 2022 23:25:23 +0530 Subject: [PATCH v6 0/2] less: fully implement -R In-Reply-To: <19077B7D-EE39-48A8-8E0C-78E4B233A408@gmail.com> References: <20220510161015.79220-1-shane.880088.supw@gmail.com> <19077B7D-EE39-48A8-8E0C-78E4B233A408@gmail.com> Message-ID: On Sun, 5 Jun 2022 at 11:46, Bernhard Reutner-Fischer wrote: > Please keep in mind that busybox is a project driven by volunteers. Absolutely, I understand. To be perfectly clear, I wasn't complaining, just making sure there wasn't anything else going on. > Patches have to have a proper Signed-off-by with real names for legal reasons, I think you forgot to add that. I see. That is inconvenient, but also understandable. > I vaguely remember less and letting color through verbatim. Ah, here > > https://busybox.busybox.narkive.com/Ueypu29o/patch-1-3-less-use-esc-positive-instead-of-esc-normal > > and following. > > Specifically: > ---8<--- > It is not okay in Unix to pipe escape sequences to a non-tty stdout. > > I don't think the rest of Unix world needs to accommodate it. > ---8<--- > > So, not sure, but I think it has become more and more common practice in the meantime? This patch won't let escapes through to pipes, because this entire codepath is skipped entirely when stdout is a pipe. bbless turns into bbcat when output isn't a TTY: https://git.busybox.net/busybox/tree/miscutils/less.c?id=8d67007a4dedef77dd0cf757bcc0e6fbee267ced#n1857 Any other reason this patch was rejected way back then? I couldn't see anything definitive on the discussion there. I see code size, and the increase in size is a lot less here (mostly because I could rip out all the code that was added after that to presumably avoid having to implement -R). (sorry for dupe) From deweloper at wp.pl Mon Jun 6 12:27:45 2022 From: deweloper at wp.pl (Aleksander Mazur) Date: Mon, 6 Jun 2022 14:27:45 +0200 Subject: Let users access their home directories via ftp In-Reply-To: References: <40e6298edd4b4c3b83b7a1bbe02595da@grupawp.pl> Message-ID: <20220606142745.129cc73c@mocarz> Dnia 2022-05-01, o godz. 21:01:36 Jacob Burkholder napisa?(a): > I use a similar patch, I added option -h to enable the functionality. > > On Sun, May 1, 2022 at 2:17 PM Aleksander Mazur wrote: > > > > Hi, > > > > AFAIU ftpd just shares current working directory (unless given a path), no > > matter who logs in. I find it useful to let ftpd chroot or cd to the home > > directory of a (non-root) user who logs in. Please consider attached patch. > > I hope it won't ruin anybody's setup. Hello list, Is there any chance of accepting either mine or Jacob's patch? IMHO there is no need to add an extra option, but maybe I'm wrong. My patch should change behaviour of ftpd only if admin allowed authentication but didn't explicitly specify a path to share (relying on cwd), and a non-root user logs in. -- Aleksander Mazur From dietmar.schindler at manrolandgoss.com Tue Jun 7 05:47:15 2022 From: dietmar.schindler at manrolandgoss.com (dietmar.schindler at manrolandgoss.com) Date: Tue, 7 Jun 2022 05:47:15 +0000 Subject: [PATCH v6 0/2] less: fully implement -R In-Reply-To: <19077B7D-EE39-48A8-8E0C-78E4B233A408@gmail.com> References: <20220510161015.79220-1-shane.880088.supw@gmail.com> <19077B7D-EE39-48A8-8E0C-78E4B233A408@gmail.com> Message-ID: <3688407baac5455abb7e1a61dd6e828f@manrolandgoss.com> > -----Original Message----- > From: busybox On Behalf Of Bernhard Reutner-Fischer > Sent: Sunday, June 5, 2022 8:17 AM > ... > https://busybox.busybox.narkive.com/Ueypu29o/patch-1-3-less-use-esc-positive-instead-of-esc- > normal > > and following. > > Specifically: > ---8<--- > It is not okay in Unix to pipe escape sequences to a non-tty stdout. This statement would mean that every Unix filter program which pipes input eventually containing escape sequences unmodified to a non-tty stdout would be "not okay" - hence it can't be true. -- Best regards, Dietmar Schindler ________________________________ manroland Goss web systems GmbH | Managing Director: Franz Kriechbaum Registered Office: Augsburg | Trade Register: AG Augsburg | HRB-No.: 32609 | VAT: DE815764857 Confidentiality note: This message and any attached documents may contain confidential or proprietary information of manroland|Goss. These materials are intended only for the use of the intended recipient. If you are not the intended recipient of this transmission, you are hereby notified that any distribution, disclosure, printing, copying, storage, modification or the taking of any action in reliance upon this transmission is strictly prohibited. Delivery of this message to any person other than the intended recipient shall not compromise or waive such confidentiality, privilege or exemption from disclosure as to this communication. If you have received this communication in error, please immediately notify the sender and delete the message from your system. All liability for viruses is excluded to the fullest extent permitted by law. ________________________________ From ncopa at alpinelinux.org Tue Jun 7 19:56:27 2022 From: ncopa at alpinelinux.org (Natanael Copa) Date: Tue, 7 Jun 2022 21:56:27 +0200 Subject: [PATCH] awk: fix use after free (CVE-2022-30065) Message-ID: <20220607195627.1665-1-ncopa@alpinelinux.org> fixes https://bugs.busybox.net/show_bug.cgi?id=14781 --- editors/awk.c | 6 ++++-- testsuite/awk.tests | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/editors/awk.c b/editors/awk.c index 079d0bde5..be38289e4 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -2921,8 +2921,8 @@ static var *evaluate(node *op, var *res) */ if (opinfo & OF_RES2) { R.v = evaluate(op->r.n, TMPVAR1); - //TODO: L.v may be invalid now, set L.v to NULL to catch bugs? - //L.v = NULL; + // L.v may be invalid now, set L.v to NULL to catch bugs + L.v = NULL; if (opinfo & OF_STR2) { R.s = getvar_s(R.v); debug_printf_eval("R.s:'%s'\n", R.s); @@ -3128,6 +3128,8 @@ static var *evaluate(node *op, var *res) case XC( OC_MOVE ): debug_printf_eval("MOVE\n"); + if (L.v == NULL) + syntax_error(EMSG_POSSIBLE_ERROR); /* if source is a temporary string, jusk relink it to dest */ if (R.v == TMPVAR1 && !(R.v->type & VF_NUMBER) diff --git a/testsuite/awk.tests b/testsuite/awk.tests index 93e25d8c1..79e80176c 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests @@ -479,4 +479,10 @@ testing 'awk backslash+newline eaten with no trace' \ "Hello world\n" \ '' '' +testing 'awk use-after-free (CVE-2022-30065)' \ + "awk '\$3i\$3in\$9=\$r||\$9=i6/6-9f'" \ + "" \ + "awk: cmd. line:1: Possible syntax error" \ + 'foo' + exit $FAILCOUNT -- 2.36.1 From arjunak234 at gmail.com Wed Jun 8 19:42:17 2022 From: arjunak234 at gmail.com (Arjun AK) Date: Thu, 9 Jun 2022 01:12:17 +0530 Subject: [PATCH] httpd: Fix serving of index.html, closes 13991 Message-ID: <20220608194217.39315-1-arjunak234@gmail.com> This bug was introduced by commit 91a58b207ea04e Signed-off-by: Arjun AK --- networking/httpd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/httpd.c b/networking/httpd.c index ffc58e10b..67b4ecfe4 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -2614,7 +2614,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) /* !CGI: it can be only GET or HEAD */ #endif -#if ENABLE_FEATURE_HTTPD_BASIC_AUTH +#if ENABLE_FEATURE_HTTPD_BASIC_AUTH || ENABLE_FEATURE_HTTPD_CGI /* Restore truncated .../index.html */ if (urlp[-1] == '/') urlp[0] = index_page[0]; -- 2.36.1 From grobgrobmann at gmail.com Wed Jun 8 19:51:54 2022 From: grobgrobmann at gmail.com (Grob Grobmann) Date: Wed, 8 Jun 2022 16:51:54 -0300 Subject: [PATCH] vi: add 'ZQ' quitting command Message-ID: Busybox vi provides the 'ZZ' command to save and close the similar 'ZQ' command just exits without saving I propose this small patch to add that command. diff --git a/editors/vi.c b/editors/vi.c index 3dbe5b471..2357caa5d 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -4290,8 +4290,14 @@ static void do_cmd(int c) goto dc_i; // start inserting break; case 'Z': // Z- if modified, {write}; exit - // ZZ means to save file (if necessary), then exit c1 = get_one_char(); + // ZQ means to exit without saving + if (c1 == 'Q') { + editing=0; + optind = cmdline_filecnt; + break; + } + // ZZ means to save file (if necessary), then exit if (c1 != 'Z') { indicate_error(); break; Cheers From ncopa at alpinelinux.org Tue Jun 14 06:48:11 2022 From: ncopa at alpinelinux.org (Natanael Copa) Date: Tue, 14 Jun 2022 08:48:11 +0200 Subject: [PATCH] awk: fix use after free (CVE-2022-30065) In-Reply-To: <20220607195627.1665-1-ncopa@alpinelinux.org> References: <20220607195627.1665-1-ncopa@alpinelinux.org> Message-ID: <20220614084811.5ae77717@ncopa-desktop.lan> Hi! Is there anything else I can do to help fix CVE-2022-30065? I have created a testcase for the testsuite and proposed a fix, but I'm not that familiar with awk code so I would appreciate some help with this before pushing it to thousands (millions?) of users. Thanks! On Tue, 7 Jun 2022 21:56:27 +0200 Natanael Copa wrote: > fixes https://bugs.busybox.net/show_bug.cgi?id=14781 > --- > editors/awk.c | 6 ++++-- > testsuite/awk.tests | 6 ++++++ > 2 files changed, 10 insertions(+), 2 deletions(-) > > diff --git a/editors/awk.c b/editors/awk.c > index 079d0bde5..be38289e4 100644 > --- a/editors/awk.c > +++ b/editors/awk.c > @@ -2921,8 +2921,8 @@ static var *evaluate(node *op, var *res) > */ > if (opinfo & OF_RES2) { > R.v = evaluate(op->r.n, TMPVAR1); > - //TODO: L.v may be invalid now, set L.v to NULL to catch bugs? > - //L.v = NULL; > + // L.v may be invalid now, set L.v to NULL to catch bugs > + L.v = NULL; > if (opinfo & OF_STR2) { > R.s = getvar_s(R.v); > debug_printf_eval("R.s:'%s'\n", R.s); > @@ -3128,6 +3128,8 @@ static var *evaluate(node *op, var *res) > > case XC( OC_MOVE ): > debug_printf_eval("MOVE\n"); > + if (L.v == NULL) > + syntax_error(EMSG_POSSIBLE_ERROR); > /* if source is a temporary string, jusk relink it to dest */ > if (R.v == TMPVAR1 > && !(R.v->type & VF_NUMBER) > diff --git a/testsuite/awk.tests b/testsuite/awk.tests > index 93e25d8c1..79e80176c 100755 > --- a/testsuite/awk.tests > +++ b/testsuite/awk.tests > @@ -479,4 +479,10 @@ testing 'awk backslash+newline eaten with no trace' \ > "Hello world\n" \ > '' '' > > +testing 'awk use-after-free (CVE-2022-30065)' \ > + "awk '\$3i\$3in\$9=\$r||\$9=i6/6-9f'" \ > + "" \ > + "awk: cmd. line:1: Possible syntax error" \ > + 'foo' > + > exit $FAILCOUNT From vda.linux at googlemail.com Tue Jun 14 16:24:54 2022 From: vda.linux at googlemail.com (Denys Vlasenko) Date: Tue, 14 Jun 2022 18:24:54 +0200 Subject: [PATCH] awk: fix use after free (CVE-2022-30065) In-Reply-To: <20220614084811.5ae77717@ncopa-desktop.lan> References: <20220607195627.1665-1-ncopa@alpinelinux.org> <20220614084811.5ae77717@ncopa-desktop.lan> Message-ID: On Tue, Jun 14, 2022 at 8:55 AM Natanael Copa wrote: > Hi! > > Is there anything else I can do to help fix CVE-2022-30065? I have > created a testcase for the testsuite and proposed a fix, but I'm not > that familiar with awk code so I would appreciate some help with this > before pushing it to thousands (millions?) of users. cd testsuite && ./runtest awk fails a lot with this change. From ncopa at alpinelinux.org Thu Jun 16 10:54:56 2022 From: ncopa at alpinelinux.org (Natanael Copa) Date: Thu, 16 Jun 2022 12:54:56 +0200 Subject: [PATCH] awk: fix use after free (CVE-2022-30065) In-Reply-To: References: <20220607195627.1665-1-ncopa@alpinelinux.org> <20220614084811.5ae77717@ncopa-desktop.lan> Message-ID: <20220616125456.1ee92c05@ncopa-desktop.lan> On Tue, 14 Jun 2022 18:24:54 +0200 Denys Vlasenko wrote: > On Tue, Jun 14, 2022 at 8:55 AM Natanael Copa wrote: > > Hi! > > > > Is there anything else I can do to help fix CVE-2022-30065? I have > > created a testcase for the testsuite and proposed a fix, but I'm not > > that familiar with awk code so I would appreciate some help with this > > before pushing it to thousands (millions?) of users. > > cd testsuite && ./runtest awk > > fails a lot with this change. Indeed, sorry! I thought I ran it locally but I must have done something wrong when running them here. Need to go back to the drawing board... Valgrind also show that those (at least one of those) does not touches memory it shouldn't. Maybe we should set it to null together with free? The comment says: > //TODO: L.v may be invalid now, set L.v to NULL to catch bugs? But apparently L.v is not always invalid. How do we know when it is invalid and when it is not? Other ideas how to fix this? -nc From ncopa at alpinelinux.org Thu Jun 16 21:04:47 2022 From: ncopa at alpinelinux.org (Natanael Copa) Date: Thu, 16 Jun 2022 23:04:47 +0200 Subject: [PATCH] awk: fix use after free (CVE-2022-30065) In-Reply-To: <20220616125456.1ee92c05@ncopa-desktop.lan> References: <20220607195627.1665-1-ncopa@alpinelinux.org> <20220614084811.5ae77717@ncopa-desktop.lan> <20220616125456.1ee92c05@ncopa-desktop.lan> Message-ID: <20220616230447.2473dff2@ncopa-desktop.lan> On Thu, 16 Jun 2022 12:54:56 +0200 Natanael Copa wrote: > On Tue, 14 Jun 2022 18:24:54 +0200 > Denys Vlasenko wrote: > > > On Tue, Jun 14, 2022 at 8:55 AM Natanael Copa wrote: > > > Hi! > > > > > > Is there anything else I can do to help fix CVE-2022-30065? I have > > > created a testcase for the testsuite and proposed a fix, but I'm not > > > that familiar with awk code so I would appreciate some help with this > > > before pushing it to thousands (millions?) of users. > > > > cd testsuite && ./runtest awk > > > > fails a lot with this change. > > Indeed, sorry! I thought I ran it locally but I must have done something wrong when running them here. > > Need to go back to the drawing board... Ok, so I have made some progress and have another possible fix. I also separated the test case into a separate commit, so it becomes easier to test in different branches etc. while working on it. I also have another (valid?) testcase which passes on gawk and nawk, but fails with my fix suggestion. I also attach a WIP patch which adds some debug info of pointer values to make it visible when tmpvars are allocated and when evaluate() returns the just free'd pointer. Summary of the attached patches: 0001-awk-fix-use-after-free-CVE-2022-30065.patch: Potential fix, that prevents the use-after-free. But honestly, I don't really know what I'm doing and I don't know if this breaks any valid cases. 0002-awk-test-for-CVE-2022-30065.patch: The test case for the CVE. gawk and mawk returns syntax error for this test. This patch can be applied as is, but it will not pass until we have a proper fix. 0003-awk-add-test-for-setting-1-while-testing-it.patch: A test case that passes with mawk/gawk but fails with the proposed fix. I don't know if this is valid syntax or if it is ok to error out with syntax error. 0004-WIP-debug-awk.patch: Temp patch that adds extra printf debug info to show what happens. This patch should *not* be applied upstream, but can be used in local development git branches to help debug. With the attached debug print 0004-WIP-debug-awk.patch applied, gives the following output when running: echo | ./busybox awk '$1$1=0' # My comments are prefixed with a # # TIP: do a in browser/reader search for '0x7f52929debb0' to highlight # where the problematic address is used. fsrealloc: xrealloc(0, 512) fsrealloc: Fields=0x7f52929df030..0x7f52929df22f getvar_i: 0.000000 getvar_i: 1.000000 entered awk_getline() returning from awk_getline(): 1 getvar_i: 0.000000 getvar_i: 0.000000 entered evaluate(op=0x7f52929dff30, res=0x7f5292a77328) tmpvars=0x7f52929deb60 opinfo:00000300 opn:00000000 switch(0x3) NEWSOURCE opinfo:00000d00 opn:00000000 switch(0xd) TEST entered evaluate(op=0x7f52929dd530, res=0x7f5292a772a8) tmpvars=0x7f52929debb0 # this is where allocation happens opinfo:4a031f00 opn:00000000 entered evaluate(op=0x7f52929dd470, res=0x7f52929debb0) # the buffer is passed here tmpvars=0x7f52929dd820 opinfo:230f1500 opn:00000000 entered evaluate(op=0x7f52929dffc0, res=0x7f52929dd820) tmpvars=0x7f52929dd870 opinfo:05021700 opn:00000000 entered evaluate(op=0x7f52929dd410, res=0x7f52929dd890) tmpvars=0x7f52929dd8c0 opinfo:00002700 opn:00000000 switch(0x27) VAR returning from evaluate(): res=0x7f52929dd440, tmpvars=0x7f52929dd8c0 switch(0x17) FIELD getvar_i: 1.000000 returning from evaluate(): res=0x7f52929df030, tmpvars=0x7f52929dd870 opinfo & OF_RES1: L.v:'0x7f52929df030' L.s:'' entered evaluate(op=0x7f52929dd4a0, res=0x7f52929dd840) tmpvars=0x7f52929dd910 opinfo:05021700 opn:00000000 entered evaluate(op=0x7f52929dd4d0, res=0x7f52929dd930) tmpvars=0x7f52929dd960 opinfo:00002700 opn:00000000 switch(0x27) VAR returning from evaluate(): res=0x7f52929dd500, tmpvars=0x7f52929dd960 switch(0x17) FIELD getvar_i: 1.000000 returning from evaluate(): res=0x7f52929df030, tmpvars=0x7f52929dd910 R.s:'' switch(0x15) CONCAT / COMMA: L.s='', sep='', R.s='' returning from evaluate(): res=0x7f52929debb0, tmpvars=0x7f52929dd820 # address is return value here opinfo & OF_RES1: L.v:'0x7f52929debb0' # L.v is from TEST tmpvars here entered evaluate(op=0x7f52929dd560, res=0x7f52929debd0) tmpvars=0x7f52929dd820 opinfo:00002700 opn:00000000 switch(0x27) VAR returning from evaluate(): res=0x7f52929dd590, tmpvars=0x7f52929dd820 switch(0x1f) MOVE L.v=0x7f52929debb0, res=0x7f5292a772a8 # MOVE passes the reference here copyvar: number:0.000000 string:'(null)' # copyvar here will copy the reference to res here returning from evaluate(): res=0x7f52929debb0, tmpvars=0x7f52929debb0 # res is now set to same value as tmpvars which is free'd. # evaluate() here returns the value it just free'd. awk: cmd. line:1: Possible syntax error So, during TEST tmpvars is allocated. MOVE will do res=tmpvars, and then is tmpvars free'd and evaluate() return the free'd value. So MOVE's copyvar should may actually copy it instead of just copying the reference? If we do that, when and how is it free'd to avoid memory leaks? Should we implement a refcount of some sort? I have no idea. Kind regards, Natanael Copa -------------- next part -------------- A non-text attachment was scrubbed... Name: 0004-WIP-debug-awk.patch Type: text/x-patch Size: 2620 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: 0003-awk-add-test-for-setting-1-while-testing-it.patch Type: text/x-patch Size: 718 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: 0002-awk-test-for-CVE-2022-30065.patch Type: text/x-patch Size: 701 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: 0001-awk-fix-use-after-free-CVE-2022-30065.patch Type: text/x-patch Size: 910 bytes Desc: not available URL: From bharatkumar.bhardava at emerson.com Fri Jun 17 09:02:10 2022 From: bharatkumar.bhardava at emerson.com (Bhardava, Bharatkumar [AUTOSOL/MSOL/IN]) Date: Fri, 17 Jun 2022 09:02:10 +0000 Subject: Support required to fix for vulnerable component in busybox Message-ID: Hello BusyBox developers, I am using BusyBox(version: 1.23.2) in one of ours device. As there is vulnerability present in awk applet, I need patch for the same. Can anyone help me to find patch or can anyone provide me patch for the same. Or it is fine if you can provide me link or other source from where I will get hints/suggestions. Presently I am exploring BusyBox vulnerable code related awk applet. Your early response is highly appreciable. Thank you, Kind regards, Bharatkumar Bhardava -------------- next part -------------- An HTML attachment was scrubbed... URL: From ulrich.eckhardt at base-42.de Fri Jun 17 13:51:42 2022 From: ulrich.eckhardt at base-42.de (Ulrich Eckhardt) Date: Fri, 17 Jun 2022 15:51:42 +0200 Subject: Support required to fix for vulnerable component in busybox In-Reply-To: References: Message-ID: <20220617155142.54a4c8a9@serenity> On Fri, 17 Jun 2022 09:02:10 +0000 "Bhardava, Bharatkumar [AUTOSOL/MSOL/IN]" wrote: > I am using BusyBox(version: 1.23.2) in one of ours device. As there > is vulnerability present in awk applet, I need patch for the same. That version is pretty old, so I'd upgrade. Also, which vulnerability exactly are you referring to, is it already known and perhaps patched in the latest version? Uli From ncopa at alpinelinux.org Fri Jun 17 15:45:35 2022 From: ncopa at alpinelinux.org (Natanael Copa) Date: Fri, 17 Jun 2022 17:45:35 +0200 Subject: [PATCH v2 2/2] awk: add tests for CVE-2022-30065 In-Reply-To: <20220617154535.24188-1-ncopa@alpinelinux.org> References: <20220607195627.1665-1-ncopa@alpinelinux.org> <20220617154535.24188-1-ncopa@alpinelinux.org> Message-ID: <20220617154535.24188-2-ncopa@alpinelinux.org> Signed-off-by: Natanael Copa --- testsuite/awk.tests | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/testsuite/awk.tests b/testsuite/awk.tests index 93e25d8c1..6c3a03c37 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests @@ -479,4 +479,15 @@ testing 'awk backslash+newline eaten with no trace' \ "Hello world\n" \ '' '' +testing 'awk use-after-free (CVE-2022-30065)' \ + "awk '\$3i\$3in\$9=\$r||\$9=i6/6-9f'" \ + "" \ + "" \ + "" + +testing 'awk assign while test' \ + "awk '\$1==\$1=\"foo\" {print \$1}'" \ + "foo\n" \ + "" \ + "foo" exit $FAILCOUNT -- 2.36.1 From ncopa at alpinelinux.org Fri Jun 17 15:45:34 2022 From: ncopa at alpinelinux.org (Natanael Copa) Date: Fri, 17 Jun 2022 17:45:34 +0200 Subject: [PATCH v2 1/2] awk: fix use after free (CVE-2022-30065) In-Reply-To: <20220607195627.1665-1-ncopa@alpinelinux.org> References: <20220607195627.1665-1-ncopa@alpinelinux.org> Message-ID: <20220617154535.24188-1-ncopa@alpinelinux.org> fixes https://bugs.busybox.net/show_bug.cgi?id=14781 Signed-off-by: Natanael Copa --- editors/awk.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/editors/awk.c b/editors/awk.c index 079d0bde5..728ee8685 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -3128,6 +3128,9 @@ static var *evaluate(node *op, var *res) case XC( OC_MOVE ): debug_printf_eval("MOVE\n"); + /* make sure that we never return a temp var */ + if (L.v == TMPVAR0) + L.v = res; /* if source is a temporary string, jusk relink it to dest */ if (R.v == TMPVAR1 && !(R.v->type & VF_NUMBER) -- 2.36.1 From soeren at soeren-tempel.net Sun Jun 19 14:52:24 2022 From: soeren at soeren-tempel.net (soeren at soeren-tempel.net) Date: Sun, 19 Jun 2022 16:52:24 +0200 Subject: [PATCH] umount: Implement -O option to unmount by mount options Message-ID: <20220619145223.11321-1-soeren@soeren-tempel.net> From: S?ren Tempel This commit adds a primitive implementation of the umount -O option, as provided by util-linux's mount(8) implementation, to BusyBox. Similar to -t, the option is intended to be used in conjunction with -a thereby allowing users to filter which file systems are unmounted by mount options. Multiple options can be specified with -O, all of which need to match. Each option can be prefixed with `no` to indicate that no action should be taken for a mount point with this mount option. At Alpine, this feature is often requested by users as the OpenRC netmount service uses `umount -a -O _netdev` to amount all network file systems [1] [2]. Discussion: * There is some minor code duplication between fsopt_matches and fstype_matches. Adding some sort of utility function to resolve this may allow for a further decrease in text segment size. * The semantics of -O are not well described in the util-linux mount(8) man page. Please review this carefully to ensure that the implementation proposed here is semantically equivalent to the one provided by util-linux. [1]: https://gitlab.alpinelinux.org/alpine/aports/-/issues/9923 [2]: https://gitlab.alpinelinux.org/alpine/aports/-/issues/13789 Signed-off-by: S?ren Tempel --- I haven't tested this extensively yet. Feedback is most welcome. include/libbb.h | 1 + libbb/Kbuild.src | 1 + libbb/match_fsopts.c | 59 ++++++++++++++++++++++++++++++++++++++++++++ util-linux/umount.c | 10 +++++--- 4 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 libbb/match_fsopts.c diff --git a/include/libbb.h b/include/libbb.h index 6aeec249d..1a203861e 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1585,6 +1585,7 @@ const struct hwtype *get_hwntype(int type) FAST_FUNC; extern int fstype_matches(const char *fstype, const char *comma_list) FAST_FUNC; +extern int fsopts_matches(const char *opts_list, const char *reqopts_list) FAST_FUNC; #ifdef HAVE_MNTENT_H extern struct mntent *find_mount_point(const char *name, int subdir_too) FAST_FUNC; #endif diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src index 653025e56..4bb8260b9 100644 --- a/libbb/Kbuild.src +++ b/libbb/Kbuild.src @@ -120,6 +120,7 @@ lib-y += xrealloc_vector.o lib-$(CONFIG_MOUNT) += match_fstype.o lib-$(CONFIG_UMOUNT) += match_fstype.o +lib-$(CONFIG_UMOUNT) += match_fsopts.o lib-$(CONFIG_FEATURE_UTMP) += utmp.o diff --git a/libbb/match_fsopts.c b/libbb/match_fsopts.c new file mode 100644 index 000000000..fff236c7a --- /dev/null +++ b/libbb/match_fsopts.c @@ -0,0 +1,59 @@ +/* vi: set sw=4 ts=4: */ +/* + * Match fsopts for use in mount unmount -O. + * + * Returns 1 for a match, otherwise 0. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" + +static int FAST_FUNC fsopt_matches(const char *opts_list, const char *opt, size_t optlen) +{ + int match = 1; + + if (optlen > 2 && opt[0] == 'n' && opt[1] == '0') { + match--; + opt += 2; optlen -= 2; + } + + while (1) { + if (strncmp(opts_list, opt, optlen) == 0) { + const char *after_opt = opts_list + optlen; + if (*after_opt == '\0' || *after_opt == ',') + return match; + } + + opts_list = strchr(opts_list, ','); + if (!opts_list) + break; + opts_list++; + } + + return !match; +} + +int FAST_FUNC fsopts_matches(const char *opts_list, const char *reqopts_list) +{ + if (!reqopts_list) + return 1; /* no options requested, match anything */ + + while (1) { + size_t len; + const char *comma = strchr(reqopts_list, ','); + if (!comma) + len = strlen(reqopts_list); + else + len = comma - reqopts_list; + + if (len && !fsopt_matches(opts_list, reqopts_list, len)) + return 0; + + if (!comma) + break; + reqopts_list = ++comma; + } + + return 1; +} diff --git a/util-linux/umount.c b/util-linux/umount.c index 23da32868..7a54cafb0 100644 --- a/util-linux/umount.c +++ b/util-linux/umount.c @@ -41,7 +41,7 @@ //kbuild:lib-$(CONFIG_UMOUNT) += umount.o //usage:#define umount_trivial_usage -//usage: "[-rlf"IF_FEATURE_MTAB_SUPPORT("m")IF_FEATURE_MOUNT_LOOP("d")IF_FEATURE_UMOUNT_ALL("a")"] [-t FSTYPE] FILESYSTEM|DIRECTORY" +//usage: "[-rlf"IF_FEATURE_MTAB_SUPPORT("m")IF_FEATURE_MOUNT_LOOP("d")IF_FEATURE_UMOUNT_ALL("a")"] [-t FSTYPE] [-O FSOPT] FILESYSTEM|DIRECTORY" //usage:#define umount_full_usage "\n\n" //usage: "Unmount filesystems\n" //usage: IF_FEATURE_UMOUNT_ALL( @@ -57,6 +57,7 @@ //usage: "\n -d Free loop device if it has been used" //usage: ) //usage: "\n -t FSTYPE[,...] Unmount only these filesystem type(s)" +//usage: "\n -O FSOPT[,...] Unmount only filesystem mounted with the given options" //usage: //usage:#define umount_example_usage //usage: "$ umount /dev/hdc1\n" @@ -82,7 +83,7 @@ static struct mntent *getmntent_r(FILE* stream, struct mntent* result, #endif /* ignored: -c -v -i */ -#define OPTION_STRING "fldnrat:" "cvi" +#define OPTION_STRING "fldnrat:O:" "cvi" #define OPT_FORCE (1 << 0) // Same as MNT_FORCE #define OPT_LAZY (1 << 1) // Same as MNT_DETACH #define OPT_FREELOOP (1 << 2) @@ -96,6 +97,7 @@ int umount_main(int argc UNUSED_PARAM, char **argv) int doForce; struct mntent me; FILE *fp; + char *opts = NULL; char *fstype = NULL; int status = EXIT_SUCCESS; unsigned opt; @@ -105,7 +107,7 @@ int umount_main(int argc UNUSED_PARAM, char **argv) struct mtab_list *next; } *mtl, *m; - opt = getopt32(argv, OPTION_STRING, &fstype); + opt = getopt32(argv, OPTION_STRING, &fstype, &opts); //argc -= optind; argv += optind; @@ -133,6 +135,8 @@ int umount_main(int argc UNUSED_PARAM, char **argv) /* Match fstype (fstype==NULL matches always) */ if (!fstype_matches(me.mnt_type, fstype)) continue; + if (!fsopts_matches(me.mnt_opts, opts)) + continue; m = xzalloc(sizeof(*m)); m->next = mtl; m->device = xstrdup(me.mnt_fsname); From algore3698 at gmail.com Mon Jun 20 18:22:57 2022 From: algore3698 at gmail.com (Alex Gorinson) Date: Mon, 20 Jun 2022 14:22:57 -0400 Subject: [PATCHv3]ash: Add ifsfree to varunset and varvalue function to fix a buffer over-read Message-ID: Due to a logic error in the ifsbreakup function in ash.c when a heredoc and normal command is run one after the other by means of a semi-colon, when the second command drops into ifsbreakup the command will be evaluated with the ifslastp/ifsfirst struct that was set when the heredoc was evaluated. This results in a buffer over-read that can leak the program's heap, stack, and arena addresses which can be used to beat ASLR. Steps to Reproduce: First bug: cmd args: ~/exampleDir/example> busybox ash $ M='AAAAAAAAAAAAAAAAA' $ q00(){ $ <<000;echo $ ${D?$M$M$M$M$M$M} $ 000 $ } $ q00 Patch: Adding the following to ash.c will fix the bug. ================================ --- a/shell/ash.c +++ b/shell/ash.c @@ -7030,6 +7030,7 @@ msg = umsg; } } +ifsfree(); ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail); } @@ -7445,6 +7446,7 @@ if (discard) return -1; +ifsfree(); raise_error_syntax("bad substitution"); } ================================ From radoslav.kolev at suse.com Tue Jun 21 06:47:21 2022 From: radoslav.kolev at suse.com (Radoslav Kolev) Date: Tue, 21 Jun 2022 09:47:21 +0300 Subject: Support required to fix for vulnerable component in busybox In-Reply-To: <20220617155142.54a4c8a9@serenity> References: <20220617155142.54a4c8a9@serenity> Message-ID: <105f0bd0-3de8-b007-594e-310585228a90@suse.com> On 6/17/22 4:51 PM, Ulrich Eckhardt wrote: > That version is pretty old, so I'd upgrade. Also, which > vulnerability exactly are you referring to, is it already known and > perhaps patched in the latest version? Sometimes major version upgrades are not feasible, so patches have to be backported. In such cases it would be extremely useful to mention the related CVEs in the commit message when a commit fixes a security issue. Unfortunately that's quite rarely seen in the busybox git repo and I, for one will be thankful to any busybox developer who chooses to do so. BR, Radoslav From walter.lozano at collabora.com Fri Jun 24 20:01:00 2022 From: walter.lozano at collabora.com (Walter Lozano) Date: Fri, 24 Jun 2022 17:01:00 -0300 Subject: [PATCH v3] Improve support for long options to grep Message-ID: <20220624200100.88025-1-walter.lozano@collabora.com> In order to improve compatibility with GNU grep improve support for long options to busybox grep. Signed-off-by: Walter Lozano --- Changes in v3: - Rebase on top of latest master Changes in v2: - Decouple FEATURE_GREP_CONTEXT from LONG_OPTS. findutils/grep.c | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/findutils/grep.c b/findutils/grep.c index 0b72812f1..4ae070a01 100644 --- a/findutils/grep.c +++ b/findutils/grep.c @@ -720,17 +720,56 @@ int grep_main(int argc UNUSED_PARAM, char **argv) /* do normal option parsing */ #if ENABLE_FEATURE_GREP_CONTEXT +#if !ENABLE_LONG_OPTS /* -H unsets -h; -C unsets -A,-B */ - opts = getopt32long(argv, "^" + opts = getopt32(argv, "^" OPTSTR_GREP "\0" "H-h:C-AB", - "color\0" Optional_argument "\xff", &pattern_head, &fopt, &max_matches, &lines_after, &lines_before, &Copt , NULL ); +#else + static const char grep_longopts[] ALIGN1 = + "with-filename\0" No_argument "H" + "no-filename\0" No_argument "h" + "line-number\0" No_argument "n" + "files-without-match\0" No_argument "L" + "files-with-matches\0" No_argument "l" + "count\0" No_argument "c" + "only-matching\0" No_argument "o" + "quiet\0" No_argument "q" + "silent\0" No_argument "q" + "invert-match\0" No_argument "v" + "no-messages\0" No_argument "s" + "recursive\0" No_argument "r" + "ignore-case\0" No_argument "i" + "word-regexp\0" No_argument "w" + "line-regexp\0" No_argument "x" + "fixed-strings\0" No_argument "F" + "extended-regexp\0" No_argument "E" + "null-data\0" No_argument "z" + "max-count\0" Required_argument "m" + "after-context\0" Required_argument "A" + "before-context\0" Required_argument "B" + "context\0" Required_argument "C" + "regexp\0" Required_argument "e" + "file\0" Required_argument "f" + "color\0" Optional_argument "\xff" + ; + /* -H unsets -h; -C unsets -A,-B */ + opts = getopt32long(argv, "^" + OPTSTR_GREP + "\0" + "H-h:C-AB", + grep_longopts, + &pattern_head, &fopt, &max_matches, + &lines_after, &lines_before, &Copt + , NULL + ); +#endif if (opts & OPT_C) { /* -C unsets prev -A and -B, but following -A or -B * may override it */ -- 2.25.1 From vda.linux at googlemail.com Sun Jun 26 15:19:42 2022 From: vda.linux at googlemail.com (Denys Vlasenko) Date: Sun, 26 Jun 2022 17:19:42 +0200 Subject: [PATCH] libbb: restore special handling of nomsg errors In-Reply-To: <62610177.MFoDLFDOX9uAN1iS%rmy@pobox.com> References: <62610177.MFoDLFDOX9uAN1iS%rmy@pobox.com> Message-ID: Applied, thank you. On Thu, Apr 21, 2022 at 9:02 AM Ron Yorston wrote: > > The functions bb_perror_nomsg() and bb_perror_nomsg_and_die() are > used to print error messages where no specific information is > available. For example: > > $ busybox mktemp -p / > mktemp: (null): Permission denied > > mktemp(3) doesn't tell us the name of the file it tried to create. > > However, printing '(null)' is a regression introduced by commit > 6937487be (libbb: reduce the overhead of single parameter bb_error_msg() > calls). Restore the previous behaviour by reverting the changes to > the two functions mentioned: > > $ busybox mktemp -p / > mktemp: Permission denied > > function old new delta > bb_perror_nomsg_and_die 7 14 +7 > bb_perror_nomsg 7 14 +7 > ------------------------------------------------------------------------------ > (add/remove: 0/0 grow/shrink: 2/0 up/down: 14/0) Total: 14 bytes > > Signed-off-by: Ron Yorston > --- > libbb/perror_nomsg.c | 4 ++-- > libbb/perror_nomsg_and_die.c | 4 ++-- > 2 files changed, 4 insertions(+), 4 deletions(-) > > diff --git a/libbb/perror_nomsg.c b/libbb/perror_nomsg.c > index d7d53de44..a2a11cc8e 100644 > --- a/libbb/perror_nomsg.c > +++ b/libbb/perror_nomsg.c > @@ -12,11 +12,11 @@ > * instead of including libbb.h */ > //#include "libbb.h" > #include "platform.h" > -extern void bb_simple_perror_msg(const char *s) FAST_FUNC; > +extern void bb_perror_msg(const char *s, ...) FAST_FUNC; > > /* suppress gcc "no previous prototype" warning */ > void FAST_FUNC bb_perror_nomsg(void); > void FAST_FUNC bb_perror_nomsg(void) > { > - bb_simple_perror_msg(0); > + bb_perror_msg(0); > } > diff --git a/libbb/perror_nomsg_and_die.c b/libbb/perror_nomsg_and_die.c > index bea5f25a5..543ff5178 100644 > --- a/libbb/perror_nomsg_and_die.c > +++ b/libbb/perror_nomsg_and_die.c > @@ -12,11 +12,11 @@ > * instead of including libbb.h */ > //#include "libbb.h" > #include "platform.h" > -extern void bb_simple_perror_msg_and_die(const char *s) FAST_FUNC; > +extern void bb_perror_msg_and_die(const char *s, ...) FAST_FUNC; > > /* suppress gcc "no previous prototype" warning */ > void FAST_FUNC bb_perror_nomsg_and_die(void); > void FAST_FUNC bb_perror_nomsg_and_die(void) > { > - bb_simple_perror_msg_and_die(0); > + bb_perror_msg_and_die(0); > } > -- > 2.35.1 > > _______________________________________________ > busybox mailing list > busybox at busybox.net > http://lists.busybox.net/mailman/listinfo/busybox From vda.linux at googlemail.com Sun Jun 26 16:10:59 2022 From: vda.linux at googlemail.com (Denys Vlasenko) Date: Sun, 26 Jun 2022 18:10:59 +0200 Subject: [PATCH v2] ash,hush: use HOME for tab completion and prompts In-Reply-To: <623c6155.RK5VQqFj4WDcSJvy%rmy@pobox.com> References: <623c6155.RK5VQqFj4WDcSJvy%rmy@pobox.com> Message-ID: Applied, thank you. On Thu, Mar 24, 2022 at 1:17 PM Ron Yorston wrote: > > ash and hush correctly use the value of HOME for tilde expansion. > However the line editing code in libbb obtains the user's home > directory by calling getpwuid(). Thus tildes in tab completion > and prompts may be interpreted differently than in tilde expansion. > > When the line editing code is invoked from a shell make it use the > shell's interpretation of tilde. This is similar to how GNU readline > and bash collaborate. > > function old new delta > get_homedir_or_NULL 29 72 +43 > optschanged 119 126 +7 > hush_main 1204 1211 +7 > ------------------------------------------------------------------------------ > (add/remove: 0/0 grow/shrink: 3/0 up/down: 57/0) Total: 57 bytes > > v2: Always check for HOME before trying the password database: this > is what GNU readline does. > > Signed-off-by: Ron Yorston > --- > include/libbb.h | 11 +++-------- > libbb/lineedit.c | 12 +++++++++++- > shell/ash.c | 7 +++---- > shell/hush.c | 5 ++--- > 4 files changed, 19 insertions(+), 16 deletions(-) > > diff --git a/include/libbb.h b/include/libbb.h > index 6aeec249d..abbc9ac59 100644 > --- a/include/libbb.h > +++ b/include/libbb.h > @@ -1924,6 +1924,7 @@ unsigned size_from_HISTFILESIZE(const char *hp) FAST_FUNC; > # define MAX_HISTORY 0 > # endif > typedef const char *get_exe_name_t(int i) FAST_FUNC; > +typedef const char *sh_get_var_t(const char *name) FAST_FUNC; > typedef struct line_input_t { > int flags; > int timeout; > @@ -1937,9 +1938,8 @@ typedef struct line_input_t { > # if ENABLE_SHELL_ASH || ENABLE_SHELL_HUSH > /* function to fetch additional application-specific names to match */ > get_exe_name_t *get_exe_name; > -# define EDITING_HAS_get_exe_name 1 > -# else > -# define EDITING_HAS_get_exe_name 0 > + /* function to fetch value of shell variable */ > + sh_get_var_t *sh_get_var; > # endif > # endif > # if MAX_HISTORY > @@ -1993,11 +1993,6 @@ int read_line_input(const char* prompt, char* command, int maxsize) FAST_FUNC; > read_line_input(prompt, command, maxsize) > #endif > > -#ifndef EDITING_HAS_get_exe_name > -# define EDITING_HAS_get_exe_name 0 > -#endif > - > - > #ifndef COMM_LEN > # ifdef TASK_COMM_LEN > enum { COMM_LEN = TASK_COMM_LEN }; > diff --git a/libbb/lineedit.c b/libbb/lineedit.c > index 82624757e..fd9377327 100644 > --- a/libbb/lineedit.c > +++ b/libbb/lineedit.c > @@ -259,6 +259,16 @@ static const char *get_username_str(void) > > static NOINLINE const char *get_homedir_or_NULL(void) > { > + const char *home; > + > +#if ENABLE_SHELL_ASH || ENABLE_SHELL_HUSH > + home = state->sh_get_var ? state->sh_get_var("HOME") : getenv("HOME"); > +#else > + home = getenv("HOME"); > +#endif > + if (home != NULL && home[0] != '\0') > + return home; > + > if (!got_user_strings) > get_user_strings(); > return home_pwd_buf; > @@ -861,7 +871,7 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type) > continue; > } > # endif > -# if EDITING_HAS_get_exe_name > +# if ENABLE_SHELL_ASH || ENABLE_SHELL_HUSH > if (state->get_exe_name) { > i = 0; > for (;;) { > diff --git a/shell/ash.c b/shell/ash.c > index ef4a47afe..d29de37b7 100644 > --- a/shell/ash.c > +++ b/shell/ash.c > @@ -9720,7 +9720,7 @@ evalpipe(union node *n, int flags) > } > > /* setinteractive needs this forward reference */ > -#if EDITING_HAS_get_exe_name > +#if ENABLE_FEATURE_EDITING > static const char *get_builtin_name(int i) FAST_FUNC; > #endif > > @@ -9757,9 +9757,8 @@ setinteractive(int on) > #if ENABLE_FEATURE_EDITING > if (!line_input_state) { > line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); > -# if EDITING_HAS_get_exe_name > line_input_state->get_exe_name = get_builtin_name; > -# endif > + line_input_state->sh_get_var = lookupvar; > } > #endif > } > @@ -10262,7 +10261,7 @@ find_builtin(const char *name) > return bp; > } > > -#if EDITING_HAS_get_exe_name > +#if ENABLE_FEATURE_EDITING > static const char * FAST_FUNC > get_builtin_name(int i) > { > diff --git a/shell/hush.c b/shell/hush.c > index ae81f0da5..051b123e7 100644 > --- a/shell/hush.c > +++ b/shell/hush.c > @@ -8188,7 +8188,7 @@ static const struct built_in_command *find_builtin(const char *name) > return find_builtin_helper(name, bltins2, &bltins2[ARRAY_SIZE(bltins2)]); > } > > -#if ENABLE_HUSH_JOB && EDITING_HAS_get_exe_name > +#if ENABLE_HUSH_JOB && ENABLE_FEATURE_EDITING > static const char * FAST_FUNC get_builtin_name(int i) > { > if (/*i >= 0 && */ i < ARRAY_SIZE(bltins1)) { > @@ -10668,9 +10668,8 @@ int hush_main(int argc, char **argv) > > # if ENABLE_FEATURE_EDITING > G.line_input_state = new_line_input_t(FOR_SHELL); > -# if EDITING_HAS_get_exe_name > G.line_input_state->get_exe_name = get_builtin_name; > -# endif > + G.line_input_state->sh_get_var = get_local_var_value; > # endif > # if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0 > { > -- > 2.35.1 > > _______________________________________________ > busybox mailing list > busybox at busybox.net > http://lists.busybox.net/mailman/listinfo/busybox From vda.linux at googlemail.com Sun Jun 26 17:56:17 2022 From: vda.linux at googlemail.com (Denys Vlasenko) Date: Sun, 26 Jun 2022 19:56:17 +0200 Subject: [PATCH 2/2] vi: handle autoindent in 'cc' command In-Reply-To: <62346d5e.4PdPKgQQU1mxqlaf%rmy@pobox.com> References: <62346d03.OcUOw+6dz4sBhm+3%rmy@pobox.com> <62346d5e.4PdPKgQQU1mxqlaf%rmy@pobox.com> Message-ID: Applied both, thanks On Fri, Mar 18, 2022 at 12:31 PM Ron Yorston wrote: > > When the 'cc' command is invoked with autoindent enabled it > should use the indent of the first line being changed. > > The size of the indent has to be established before char_insert() > is called as the lines being changed are deleted. Introduce a > new global variable, newindent, to handle this. The indentcol > global is now effectively a static variable in char_insert(). > > function old new delta > do_cmd 4247 4308 +61 > vi_main 416 422 +6 > char_insert 891 875 -16 > ------------------------------------------------------------------------------ > (add/remove: 0/0 grow/shrink: 2/1 up/down: 67/-16) Total: 51 bytes > > Signed-off-by: Ron Yorston > --- > editors/vi.c | 71 ++++++++++++++++++++++++++++++++++------------------ > 1 file changed, 47 insertions(+), 24 deletions(-) > > diff --git a/editors/vi.c b/editors/vi.c > index e63ca60d4..6edff0b5a 100644 > --- a/editors/vi.c > +++ b/editors/vi.c > @@ -380,7 +380,9 @@ struct globals { > char *last_search_pattern; // last pattern from a '/' or '?' search > #endif > #if ENABLE_FEATURE_VI_SETOPTS > - int indentcol; // column of recently autoindent, 0 or -1 > + int char_insert__indentcol; // column of recent autoindent or 0 > + int newindent; // autoindent value for 'O'/'cc' commands > + // or -1 to use indent from previous line > #endif > smallint cmd_error; > > @@ -507,7 +509,8 @@ struct globals { > #define ioq_start (G.ioq_start ) > #define dotcnt (G.dotcnt ) > #define last_search_pattern (G.last_search_pattern) > -#define indentcol (G.indentcol ) > +#define char_insert__indentcol (G.char_insert__indentcol) > +#define newindent (G.newindent ) > #define cmd_error (G.cmd_error ) > > #define edit_file__cur_line (G.edit_file__cur_line) > @@ -540,10 +543,11 @@ struct globals { > > #define INIT_G() do { \ > SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ > - last_modified_count = -1; \ > + last_modified_count--; \ > /* "" but has space for 2 chars: */ \ > IF_FEATURE_VI_SEARCH(last_search_pattern = xzalloc(2);) \ > tabstop = 8; \ > + IF_FEATURE_VI_SETOPTS(newindent--;) \ > } while (0) > > #if ENABLE_FEATURE_VI_CRASHME > @@ -2112,6 +2116,7 @@ static size_t indent_len(char *p) > static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' > { > #if ENABLE_FEATURE_VI_SETOPTS > +# define indentcol char_insert__indentcol > size_t len; > int col, ntab, nspc; > #endif > @@ -2140,7 +2145,8 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' > #if ENABLE_FEATURE_VI_SETOPTS > if (autoindent) { > len = indent_len(bol); > - if (len && get_column(bol + len) == indentcol && bol[len] == '\n') { > + col = get_column(bol + len); > + if (len && col == indentcol && bol[len] == '\n') { > // remove autoindent from otherwise empty line > text_hole_delete(bol, bol + len - 1, undo); > p = bol; > @@ -2209,26 +2215,30 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' > showmatching(p - 1); > } > if (autoindent && c == '\n') { // auto indent the new line > - // use indent of current/previous line > - bol = indentcol < 0 ? p : prev_line(p); > - len = indent_len(bol); > - col = get_column(bol + len); > - > - if (len && col == indentcol) { > - // previous line was empty except for autoindent > - // move the indent to the current line > - memmove(bol + 1, bol, len); > - *bol = '\n'; > - return p; > + if (newindent < 0) { > + // use indent of previous line > + bol = prev_line(p); > + len = indent_len(bol); > + col = get_column(bol + len); > + > + if (len && col == indentcol) { > + // previous line was empty except for autoindent > + // move the indent to the current line > + memmove(bol + 1, bol, len); > + *bol = '\n'; > + return p; > + } > + } else { > + // for 'O'/'cc' commands add indent before newly inserted NL > + if (p != end - 1) // but not for 'cc' at EOF > + p--; > + col = newindent; > } > > - if (indentcol < 0) > - p--; // open above, indent before newly inserted NL > - > - if (len) { > + if (col) { > // only record indent if in insert/replace mode or for > - // the 'o'/'O' commands, which are switched to insert > - // mode early. > + // the 'o'/'O'/'cc' commands, which are switched to > + // insert mode early. > indentcol = cmd_mode != 0 ? col : 0; > if (expandtab) { > ntab = 0; > @@ -2251,6 +2261,7 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' > } > #if ENABLE_FEATURE_VI_SETOPTS > indentcol = 0; > +# undef indentcol > #endif > return p; > } > @@ -4219,6 +4230,9 @@ static void do_cmd(int c) > case 'i': // i- insert before current char > case KEYCODE_INSERT: // Cursor Key Insert > dc_i: > +#if ENABLE_FEATURE_VI_SETOPTS > + newindent = -1; > +#endif > cmd_mode = 1; // start inserting > undo_queue_commit(); // commit queue when cmd_mode changes > break; > @@ -4261,7 +4275,8 @@ static void do_cmd(int c) > case 'O': // O- open an empty line above > dot_begin(); > #if ENABLE_FEATURE_VI_SETOPTS > - indentcol = -1; > + // special case: use indent of current line > + newindent = get_column(dot + indent_len(dot)); > #endif > goto dc3; > case 'o': // o- open an empty line below > @@ -4384,14 +4399,22 @@ static void do_cmd(int c) > if (buftype == WHOLE) { > save_dot = p; // final cursor position is start of range > p = begin_line(p); > +#if ENABLE_FEATURE_VI_SETOPTS > + if (c == 'c') // special case: use indent of current line > + newindent = get_column(p + indent_len(p)); > +#endif > q = end_line(q); > } > dot = yank_delete(p, q, buftype, yf, ALLOW_UNDO); // delete word > if (buftype == WHOLE) { > if (c == 'c') { > +#if ENABLE_FEATURE_VI_SETOPTS > + cmd_mode = 1; // switch to insert mode early > +#endif > dot = char_insert(dot, '\n', ALLOW_UNDO_CHAIN); > - // on the last line of file don't move to prev line > - if (dot != (end-1)) { > + // on the last line of file don't move to prev line, > + // handled in char_insert() if autoindent is enabled > + if (dot != (end-1) && !autoindent) { > dot_prev(); > } > } else if (c == 'd') { > -- > 2.35.1 > > _______________________________________________ > busybox mailing list > busybox at busybox.net > http://lists.busybox.net/mailman/listinfo/busybox From aaro.koskinen at iki.fi Mon Jun 27 20:43:27 2022 From: aaro.koskinen at iki.fi (Aaro Koskinen) Date: Mon, 27 Jun 2022 23:43:27 +0300 Subject: Bash compatibility TODO Message-ID: <20220627204327.GA3601@darkstar.musicnaut.iki.fi> Hi all, Looks like it's not possible to build mainline Linux anymore with the busybox as "bash". :-( $ make CC scripts/mod/empty.o ./scripts/check-local-export: line 17: shopt: not found make[1]: *** [scripts/Makefile.build:249: scripts/mod/empty.o] Error 127 make[1]: *** Deleting file 'scripts/mod/empty.o' make: *** [Makefile:1199: prepare0] Error 2 It seems the requirement is to support "lastpipe" option: # Run the last element of a pipeline in the current shell. # Without this, the while-loop would be executed in a subshell, and # the changes made to 'symbol_types' and 'export_symbols' would be lost. shopt -s lastpipe and I don't think these will work either: declare -A symbol_types declare -a export_symbols A. From David.Laight at ACULAB.COM Mon Jun 27 21:10:46 2022 From: David.Laight at ACULAB.COM (David Laight) Date: Mon, 27 Jun 2022 21:10:46 +0000 Subject: Bash compatibility TODO In-Reply-To: <20220627204327.GA3601@darkstar.musicnaut.iki.fi> References: <20220627204327.GA3601@darkstar.musicnaut.iki.fi> Message-ID: <289c0e3309164e8ab971012743673ad5@AcuMS.aculab.com> From: Aaro Koskinen > Sent: 27 June 2022 21:43 > > Hi all, > > Looks like it's not possible to build mainline Linux anymore with the > busybox as "bash". :-( Have you posted that to LKML ? They really ought to solve the problem a different way. David > > $ make > CC scripts/mod/empty.o > ./scripts/check-local-export: line 17: shopt: not found > make[1]: *** [scripts/Makefile.build:249: scripts/mod/empty.o] Error 127 > make[1]: *** Deleting file 'scripts/mod/empty.o' > make: *** [Makefile:1199: prepare0] Error 2 > > It seems the requirement is to support "lastpipe" option: > > # Run the last element of a pipeline in the current shell. > # Without this, the while-loop would be executed in a subshell, and > # the changes made to 'symbol_types' and 'export_symbols' would be lost. > shopt -s lastpipe > > and I don't think these will work either: > > declare -A symbol_types > declare -a export_symbols > > A. > _______________________________________________ > busybox mailing list > busybox at busybox.net > http://lists.busybox.net/mailman/listinfo/busybox - Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales) From bernd at petrovitsch.priv.at Mon Jun 27 21:24:15 2022 From: bernd at petrovitsch.priv.at (Bernd Petrovitsch) Date: Mon, 27 Jun 2022 23:24:15 +0200 Subject: Bash compatibility TODO In-Reply-To: <289c0e3309164e8ab971012743673ad5@AcuMS.aculab.com> References: <20220627204327.GA3601@darkstar.musicnaut.iki.fi> <289c0e3309164e8ab971012743673ad5@AcuMS.aculab.com> Message-ID: Hi all! On 27/06/2022 23:10, David Laight wrote: > From: Aaro Koskinen >> Sent: 27 June 2022 21:43 [...] >> Looks like it's not possible to build mainline Linux anymore with the >> busybox as "bash". :-( > > Have you posted that to LKML ? > They really ought to solve the problem a different way. [...] >> $ make >> CC scripts/mod/empty.o >> ./scripts/check-local-export: line 17: shopt: not found >> make[1]: *** [scripts/Makefile.build:249: scripts/mod/empty.o] Error 127 >> make[1]: *** Deleting file 'scripts/mod/empty.o' >> make: *** [Makefile:1199: prepare0] Error 2 >> >> It seems the requirement is to support "lastpipe" option: >> >> # Run the last element of a pipeline in the current shell. >> # Without this, the while-loop would be executed in a subshell, and >> # the changes made to 'symbol_types' and 'export_symbols' would be lost. >> shopt -s lastpipe FWIW: Debian/Ubuntu has dash as /bin/sh and that doesn't have "shopt" too. Kind regards, Bernd -- Bernd Petrovitsch Email : bernd at petrovitsch.priv.at There is NO CLOUD, just other people's computers. - FSFE LUGA : http://www.luga.at From aaro.koskinen at iki.fi Mon Jun 27 21:47:30 2022 From: aaro.koskinen at iki.fi (Aaro Koskinen) Date: Tue, 28 Jun 2022 00:47:30 +0300 Subject: Bash compatibility TODO In-Reply-To: References: <20220627204327.GA3601@darkstar.musicnaut.iki.fi> <289c0e3309164e8ab971012743673ad5@AcuMS.aculab.com> Message-ID: <20220627214730.GB3601@darkstar.musicnaut.iki.fi> Hi, On Mon, Jun 27, 2022 at 11:24:15PM +0200, Bernd Petrovitsch wrote: > On 27/06/2022 23:10, David Laight wrote: > > From: Aaro Koskinen > > > Sent: 27 June 2022 21:43 > [...] > > > Looks like it's not possible to build mainline Linux anymore with the > > > busybox as "bash". :-( > > > > Have you posted that to LKML ? > > They really ought to solve the problem a different way. > [...] > > > $ make > > > CC scripts/mod/empty.o > > > ./scripts/check-local-export: line 17: shopt: not found > > > make[1]: *** [scripts/Makefile.build:249: scripts/mod/empty.o] Error 127 > > > make[1]: *** Deleting file 'scripts/mod/empty.o' > > > make: *** [Makefile:1199: prepare0] Error 2 > > > > > > It seems the requirement is to support "lastpipe" option: > > > > > > # Run the last element of a pipeline in the current shell. > > > # Without this, the while-loop would be executed in a subshell, and > > > # the changes made to 'symbol_types' and 'export_symbols' would be lost. > > > shopt -s lastpipe > > FWIW: Debian/Ubuntu has dash as /bin/sh and that doesn't have "shopt" > too. Yes, but that script has "#!/usr/bin/env bash". The "minimal" kernel build requirements now list bash 4.2 as mandatory. A. From rmy at pobox.com Tue Jun 28 12:40:49 2022 From: rmy at pobox.com (Ron Yorston) Date: Tue, 28 Jun 2022 13:40:49 +0100 Subject: [PATCH] lineedit: get PWD from ash Message-ID: <62baf6d1.LtQJ7QN7pNHEUtas%rmy@pobox.com> The line editing code and ash disagree when the current directory is changed to a symbolic link: ~ $ mkdir real ~ $ ln -s real link ~ $ cd link ~/real $ pwd /home/rmyf36/link Note the prompt says we're in ~/real. Bash does: [rmy at random ~]$ cd link [rmy at random link]$ pwd /home/rmyf36/link Ash uses the name supplied by the user while the line editing code calls getcwd(3). The discrepancy can be avoided by fetching the value of PWD from ash. Hush (incorrectly?) calls getcwd(3) when the directory is changed so there's no disagreement with the line editing code. function old new delta parse_and_put_prompt 921 904 -17 Signed-off-by: Ron Yorston --- libbb/lineedit.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libbb/lineedit.c b/libbb/lineedit.c index b685399f9..27b5ef30e 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -2035,7 +2035,13 @@ static void parse_and_put_prompt(const char *prmt_ptr) case 'W': /* basename of cur dir */ if (!cwd_buf) { const char *home; +#if ENABLE_SHELL_ASH + cwd_buf = state->sh_get_var ? + xstrdup(state->sh_get_var("PWD")) : + xrealloc_getcwd_or_warn(NULL); +#else cwd_buf = xrealloc_getcwd_or_warn(NULL); +#endif if (!cwd_buf) cwd_buf = (char *)bb_msg_unknown; else if ((home = get_homedir_or_NULL()) != NULL && home[0]) { -- 2.36.1 From Okaya at kernel.org Tue Jun 28 13:45:50 2022 From: Okaya at kernel.org (Sinan Kaya) Date: Tue, 28 Jun 2022 09:45:50 -0400 Subject: [PATCH] udhcpc: add support for sending DHCPINFORM requests In-Reply-To: References: Message-ID: <3e8edac1-3a4c-23ac-f26b-110d7de577ca@kernel.org> +Luca On 4/20/22 14:34, Sinan Kaya wrote: > From b906997217b363c459fdbd2824bfe6c5ac69607e Mon Sep 17 00:00:00 2001 > From: Sinan Kaya > Date: Tue, 19 Apr 2022 13:47:19 +0000 > Subject: [PATCH] udhcpc: add support for sending DHCPINFORM requests > > It is useful for applications to be able to query DHCP options > without renewing IP address. > > Tested-with: -I: for unknown DHCP server > ???????????? -I: for a specific DHCP server --server 1.2.3.4 > > Signed-off-by: Sinan Kaya > --- > ?networking/udhcp/dhcpc.c | 68 ++++++++++++++++++++++++++++++---------- > ?1 file changed, 52 insertions(+), 16 deletions(-) > > diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c > index c757fb37c..e788613fd 100644 > --- a/networking/udhcp/dhcpc.c > +++ b/networking/udhcp/dhcpc.c > @@ -75,6 +75,8 @@ static const char udhcpc_longopts[] ALIGN1 = > ???? "background\0"???? No_argument?????? "b" > ???? ) > ???? "broadcast\0"????? No_argument?????? "B" > +??? "inform\0"???????? No_argument?????? "I" > +??? "server\0"???????? Required_argument "e" > ???? IF_FEATURE_UDHCPC_ARPING("arping\0"??? Optional_argument "a") > ???? IF_FEATURE_UDHCP_PORT("client-port\0"??? Required_argument "P") > ???? ; > @@ -100,8 +102,10 @@ enum { > ???? OPT_x = 1 << 16, > ???? OPT_f = 1 << 17, > ???? OPT_B = 1 << 18, > +??? OPT_I = 1 << 19, > +??? OPT_e = 1 << 20, > ?/* The rest has variable bit positions, need to be clever */ > -??? OPTBIT_B = 18, > +??? OPTBIT_e = 20, > ???? USE_FOR_MMU(???????????? OPTBIT_b,) > ???? IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) > ???? IF_FEATURE_UDHCP_PORT(?? OPTBIT_P,) > @@ -742,14 +746,15 @@ static NOINLINE int send_discover(uint32_t > requested) > > ?/* Broadcast a DHCP request message */ > ?/* RFC 2131 3.1 paragraph 3: > - * "The client _broadcasts_ a DHCPREQUEST message..." > + * "The client _broadcasts_ a DHCPREQUEST/INFORM message..." > ? */ > ?/* NOINLINE: limit stack usage in caller */ > -static NOINLINE int send_select(uint32_t server, uint32_t requested) > +static NOINLINE int send_select(uint32_t server, uint32_t requested, > int inform) > ?{ > ???? struct dhcp_packet packet; > ???? struct in_addr temp_addr; > ???? char server_str[sizeof("255.255.255.255")]; > +??? const char *direction; > > ?/* > ? * RFC 2131 4.3.2 DHCPREQUEST message > @@ -766,11 +771,12 @@ static NOINLINE int send_select(uint32_t server, > uint32_t requested) > ???? /* Fill in: op, htype, hlen, cookie, chaddr fields, > ????? * xid field, message type option: > ????? */ > -??? init_packet(&packet, DHCPREQUEST); > +??? init_packet(&packet, inform ? DHCPINFORM: DHCPREQUEST); > > ???? udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); > > -??? udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); > +??? if (server) > +??????? udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); > > ???? /* Add options: maxsize, > ????? * "param req" option according to -O, options specified with -x > @@ -780,11 +786,19 @@ static NOINLINE int send_select(uint32_t server, > uint32_t requested) > ???? temp_addr.s_addr = server; > ???? strcpy(server_str, inet_ntoa(temp_addr)); > ???? temp_addr.s_addr = requested; > -??? bb_info_msg("broadcasting select for %s, server %s", > -??????????? inet_ntoa(temp_addr), > -??????????? server_str > +??? if (server) > +??????? direction = "unicasting"; > +??? else > +??????? direction = "broadcasting"; > + > +??? bb_info_msg("%s select for %s, server %s", > +??????? direction, > +??????? inet_ntoa(temp_addr), > +??????? server_str > ???? ); > -??? return raw_bcast_from_client_data_ifindex(&packet, INADDR_ANY); > + > +??? // return raw_bcast_from_client_data_ifindex(&packet, INADDR_ANY); > +??? return bcast_or_ucast(&packet, requested, server); > ?} > > ?/* Unicast or broadcast a DHCP renew message */ > @@ -1161,9 +1175,9 @@ static void client_background(void) > ?//usage:# define IF_UDHCP_VERBOSE(...) > ?//usage:#endif > ?//usage:#define udhcpc_trivial_usage > -//usage: "[-fbq"IF_UDHCP_VERBOSE("v")"RB]"IF_FEATURE_UDHCPC_ARPING(" > [-a[MSEC]]")" [-t N] [-T SEC] [-A SEC|-n]\n" > +//usage: "[-fbq"IF_UDHCP_VERBOSE("v")"RBI]"IF_FEATURE_UDHCPC_ARPING(" > [-a[MSEC]]")" [-t N] [-T SEC] [-A SEC|-n]\n" > ?//usage:?????? "??? [-i IFACE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" > [-s PROG] [-p PIDFILE]\n" > -//usage:?????? "??? [-oC] [-r IP] [-V VENDOR] [-F NAME] [-x > OPT:VAL]... [-O OPT]..." > +//usage:?????? "??? [-oC] [-r IP] [-e IP] [-V VENDOR] [-F NAME] [-x > OPT:VAL]... [-O OPT]..." > ?//usage:#define udhcpc_full_usage "\n" > ?//usage:???? "\n??? -i IFACE??? Interface to use (default > "CONFIG_UDHCPC_DEFAULT_INTERFACE")" > ?//usage:??? IF_FEATURE_UDHCP_PORT( > @@ -1172,6 +1186,7 @@ static void client_background(void) > ?//usage:???? "\n??? -s PROG??????? Run PROG at DHCP events (default > "CONFIG_UDHCPC_DEFAULT_SCRIPT")" > ?//usage:???? "\n??? -p FILE??????? Create pidfile" > ?//usage:???? "\n??? -B??????? Request broadcast replies" > +//usage:???? "\n??? -I??????? Request using inform" > ?//usage:???? "\n??? -t N??????? Send up to N discover packets > (default 3)" > ?//usage:???? "\n??? -T SEC??????? Pause between packets (default 3)" > ?//usage:???? "\n??? -A SEC??????? Wait if lease is not obtained > (default 20)" > @@ -1187,6 +1202,7 @@ static void client_background(void) > ?//usage:???? "\n??? -a[MSEC]??? Validate offered address with ARP ping" > ?//usage:??? ) > ?//usage:???? "\n??? -r IP??????? Request this IP address" > +//usage:???? "\n??? -e IP??????? Request this server IP address" > ?//usage:???? "\n??? -o??????? Don't request any options (unless -O is > given)" > ?//usage:???? "\n??? -O OPT??????? Request option OPT from server > (cumulative)" > ?//usage:???? "\n??? -x OPT:VAL??? Include option OPT in sent packets > (cumulative)" > @@ -1209,7 +1225,7 @@ int udhcpc_main(int argc, char **argv) > MAIN_EXTERNALLY_VISIBLE; > ?int udhcpc_main(int argc UNUSED_PARAM, char **argv) > ?{ > ???? uint8_t *message; > -??? const char *str_V, *str_F, *str_r; > +??? const char *str_V, *str_F, *str_r, *str_e; > ???? IF_FEATURE_UDHCPC_ARPING(const char *str_a = "2000";) > ???? IF_FEATURE_UDHCP_PORT(char *str_P;) > ???? uint8_t *clientid_mac_ptr; > @@ -1218,7 +1234,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) > ???? int tryagain_timeout = 20; > ???? int discover_timeout = 3; > ???? int discover_retries = 3; > -??? uint32_t server_id = server_id; /* for compiler */ > +??? int use_inform = 0; > +??? uint32_t server_id = 0; > ???? uint32_t requested_ip = 0; > ???? int packet_num; > ???? int timeout; /* must be signed */ > @@ -1244,7 +1261,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) > ???? /* Parse command line */ > ???? opt = getopt32long(argv, "^" > ???????? /* O,x: list; -T,-t,-A take numeric param */ > -??????? "CV:F:i:np:qRr:s:T:+t:+SA:+O:*ox:*fB" > +??????? "CV:F:i:np:qRr:s:T:+t:+SA:+O:*ox:*fBIe:" > ???????? USE_FOR_MMU("b") > ???????? IF_FEATURE_UDHCPC_ARPING("a::") > ???????? IF_FEATURE_UDHCP_PORT("P:") > @@ -1258,10 +1275,15 @@ int udhcpc_main(int argc UNUSED_PARAM, char > **argv) > ???????? , &discover_timeout, &discover_retries, &tryagain_timeout /* > T,t,A */ > ???????? , &list_O > ???????? , &list_x > +??????? , &str_e /* e */ > ???????? IF_FEATURE_UDHCPC_ARPING(, &str_a) > ???????? IF_FEATURE_UDHCP_PORT(, &str_P) > ???????? IF_UDHCP_VERBOSE(, &dhcp_verbose) > ???? ); > + > +??? if (opt & OPT_I) > +??????? use_inform = 1; > + > ???? if (opt & OPT_F) { > ???????? char *p; > ???????? unsigned len; > @@ -1283,6 +1305,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) > ???????? /*p[OPT_DATA + 2] = 0; */ > ???????? memcpy(p + OPT_DATA + 3, str_F, len); /* do not store NUL > byte */ > ???? } > +??? if (opt & OPT_e) > +??????? if (!inet_aton(str_e, (void*)&server_id)) > +??????????? bb_show_usage(); > ???? if (opt & OPT_r) > ???????? if (!inet_aton(str_r, (void*)&requested_ip)) > ???????????? bb_show_usage(); > @@ -1368,12 +1393,23 @@ int udhcpc_main(int argc UNUSED_PARAM, char > **argv) > ???? /* We want random_xid to be random... */ > ???? srand(monotonic_us()); > > -??? client_data.state = INIT_SELECTING; > +??? if (use_inform) { > +??????? bb_simple_info_msg("using inform"); > +??????? client_data.state = REQUESTING; > +??? } else { > +??????? client_data.state = INIT_SELECTING; > +??? } > + > ???? d4_run_script_deconfig(); > ???? packet_num = 0; > ???? timeout = 0; > ???? lease_remaining = 0; > > +??? if (use_inform) { > +??????? change_listen_mode(LISTEN_RAW); > +??????? client_data.xid = random_xid(); > +??? } > + > ???? /* Main event loop. select() waits on signal pipe and possibly > ????? * on sockfd. > ????? * "continue" statements in code below jump to the top of the loop. > @@ -1482,7 +1518,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) > ???????????? case REQUESTING: > ???????????????? if (packet_num < 3) { > ???????????????????? /* send broadcast select packet */ > -??????????????????? send_select(server_id, requested_ip); > +??????????????????? send_select(server_id, requested_ip, use_inform); > ???????????????????? timeout = discover_timeout; > ???????????????????? packet_num++; > ???????????????????? continue; From dchen at dennisc.net Wed Jun 29 05:10:44 2022 From: dchen at dennisc.net (Dennis Chen) Date: Tue, 28 Jun 2022 22:10:44 -0700 Subject: sort's -k flag is buggy when M is also passed Message-ID: All commands were run on both Ubuntu busybox v1.30.1 and Alpine busybox v1.35.0. I ran echo "3 March\n2 April" | busybox sort -k 2,2M and it returned 2 April 3 March It should return 3 March 2 April and indeed, that is what you get with GNU sort. (It doesn't seem to matter what the numbers "2" and "3" are - I replaced them both with the string "filler" and got the same result.) This seems to only happen when the field number is >1. For instance echo "March\nApril" | busybox sort -k 1,1M correctly outputs March April It also doesn't happen when M isn't passed into -k. For instance, echo "a c\nb b" | sort -k 2,2 correctly returns b b a c From mikes at guam.net Wed Jun 29 07:22:39 2022 From: mikes at guam.net (Michael D. Setzer II) Date: Wed, 29 Jun 2022 17:22:39 +1000 Subject: sort's -k flag is buggy when M is also passed In-Reply-To: References: Message-ID: <62BBFDBF.17770.9584573@mikes.guam.net> Looking at sort.c in busybox seems that static char key_separator; is just defined, but not assigned a default value? Don't know if this might resolve issue? static char key_separator=' '; On 28 Jun 2022 at 22:10, Dennis Chen wrote: Date sent: Tue, 28 Jun 2022 22:10:44 -0700 To: Subject: sort's -k flag is buggy when M is also passed From: "Dennis Chen" > All commands were run on both Ubuntu busybox v1.30.1 and Alpine busybox > v1.35.0. > > I ran > echo "3 March\n2 April" | busybox sort -k 2,2M > and it returned > 2 April > 3 March > It should return > 3 March > 2 April > and indeed, that is what you get with GNU sort. (It doesn't seem to > matter what the numbers "2" and "3" are - I replaced them both with the > string "filler" and got the same result.) > > This seems to only happen when the field number is >1. For instance > echo "March\nApril" | busybox sort -k 1,1M > correctly outputs > March > April > > It also doesn't happen when M isn't passed into -k. For instance, > echo "a c\nb b" | sort -k 2,2 > correctly returns > b b > a c > _______________________________________________ > busybox mailing list > busybox at busybox.net > http://lists.busybox.net/mailman/listinfo/busybox +------------------------------------------------------------+ Michael D. Setzer II - Computer Science Instructor (Retired) mailto:mikes at guam.net mailto:msetzerii at gmail.com Guam - Where America's Day Begins G4L Disk Imaging Project maintainer http://sourceforge.net/projects/g4l/ +------------------------------------------------------------+ From mikes at guam.net Wed Jun 29 07:11:32 2022 From: mikes at guam.net (Michael D. Setzer II) Date: Wed, 29 Jun 2022 17:11:32 +1000 Subject: sort's -k flag is buggy when M is also passed In-Reply-To: References: Message-ID: <62BBFB24.7560.94E18DF@mikes.guam.net> Did a test on Fedora 35 with busybox 1.35.0 This seems to work. echo -e "3 March\n2 April" | busybox sort -t\ -k2M Had to use -e to have it insert new line. Then found it didn't work with the default delimiter, but using -t\ got it to work. Tried it with a separate -M or the M at the end. Both work. echo -e "3 March\n2 April" | busybox sort -t\ -k2M 3 March 2 April More complete test echo -e "3 March\n2 April\n1 Jan\n5 Feb\n6 Dec\n8 Oct\n7 Jul\n6 Jun\n8 Aug\n15 May\n11 Nov\n9 Sep" | busybox sort -t\ -k2M 1 Jan 5 Feb 3 March 2 April 15 May 6 Jun 7 Jul 8 Aug 9 Sep 8 Oct 11 Nov 6 Dec Don't know if it is an issue with the delimiter default or what? Without the -t\ echo -e "3 March\n2 April\n1 Jan\n5 Feb\n6 Dec\n8 Oct\n7 Jul\n6 Jun\n8 Aug\n15 May\n11 Nov\n9 Sep" | busybox sort -k2M 1 Jan 11 Nov 15 May 2 April 3 March 5 Feb 6 Dec 6 Jun 7 Jul 8 Aug 8 Oct 9 Sep On 28 Jun 2022 at 22:10, Dennis Chen wrote: Date sent: Tue, 28 Jun 2022 22:10:44 -0700 To: Subject: sort's -k flag is buggy when M is also passed From: "Dennis Chen" > All commands were run on both Ubuntu busybox v1.30.1 and Alpine busybox > v1.35.0. > > I ran > echo "3 March\n2 April" | busybox sort -k 2,2M > and it returned > 2 April > 3 March > It should return > 3 March > 2 April > and indeed, that is what you get with GNU sort. (It doesn't seem to > matter what the numbers "2" and "3" are - I replaced them both with the > string "filler" and got the same result.) > > This seems to only happen when the field number is >1. For instance > echo "March\nApril" | busybox sort -k 1,1M > correctly outputs > March > April > > It also doesn't happen when M isn't passed into -k. For instance, > echo "a c\nb b" | sort -k 2,2 > correctly returns > b b > a c > _______________________________________________ > busybox mailing list > busybox at busybox.net > http://lists.busybox.net/mailman/listinfo/busybox +------------------------------------------------------------+ Michael D. Setzer II - Computer Science Instructor (Retired) mailto:mikes at guam.net mailto:msetzerii at gmail.com Guam - Where America's Day Begins G4L Disk Imaging Project maintainer http://sourceforge.net/projects/g4l/ +------------------------------------------------------------+ From ncopa at alpinelinux.org Wed Jun 29 09:49:57 2022 From: ncopa at alpinelinux.org (Natanael Copa) Date: Wed, 29 Jun 2022 11:49:57 +0200 Subject: [PATCH v2 1/2] awk: fix use after free (CVE-2022-30065) In-Reply-To: <20220617154535.24188-1-ncopa@alpinelinux.org> References: <20220607195627.1665-1-ncopa@alpinelinux.org> <20220617154535.24188-1-ncopa@alpinelinux.org> Message-ID: <20220629114957.58993faa@ncopa-desktop.lan> Denys, This fix passes `./runtest awk`. We have used this fix in Alpine Linux edge (development branch) for a week now and as far I know, there have been no issues due to this. Can you please have another look? And push it to the stable branch if possible. Thanks! On Fri, 17 Jun 2022 17:45:34 +0200 Natanael Copa wrote: > fixes https://bugs.busybox.net/show_bug.cgi?id=14781 > > Signed-off-by: Natanael Copa > --- > editors/awk.c | 3 +++ > 1 file changed, 3 insertions(+) > > diff --git a/editors/awk.c b/editors/awk.c > index 079d0bde5..728ee8685 100644 > --- a/editors/awk.c > +++ b/editors/awk.c > @@ -3128,6 +3128,9 @@ static var *evaluate(node *op, var *res) > > case XC( OC_MOVE ): > debug_printf_eval("MOVE\n"); > + /* make sure that we never return a temp var */ > + if (L.v == TMPVAR0) > + L.v = res; > /* if source is a temporary string, jusk relink it to dest */ > if (R.v == TMPVAR1 > && !(R.v->type & VF_NUMBER) From dchen at dennisc.net Wed Jun 29 17:18:10 2022 From: dchen at dennisc.net (Dennis Chen) Date: Wed, 29 Jun 2022 10:18:10 -0700 Subject: sort's -k flag is buggy when M is also passed In-Reply-To: <62BBFB24.7560.94E18DF@mikes.guam.net> References: <62BBFB24.7560.94E18DF@mikes.guam.net> Message-ID: > Had to use -e to have it insert new line. FWIW, I was able to get your tests to work without -e. (Alpine, busybox 1.35.0) > Looking at sort.c in busybox seems that > static char key_separator; is just defined, but not > assigned a default value? > Don't know if this might resolve issue? > static char key_separator=' '; Using -t ' ' might work for some cases, but consider abc March 3 de April 2 This example is a little contrived, but you might easily see something like this in the real world (think logfiles). From mikes at guam.net Wed Jun 29 17:37:08 2022 From: mikes at guam.net (Michael D. Setzer II) Date: Thu, 30 Jun 2022 03:37:08 +1000 Subject: sort's -k flag is buggy when M is also passed In-Reply-To: References: , <62BBFB24.7560.94E18DF@mikes.guam.net>, Message-ID: <62BC8DC4.31286.B8AD8E5@mikes.guam.net> On 29 Jun 2022 at 10:18, Dennis Chen wrote: Date sent: Wed, 29 Jun 2022 10:18:10 -0700 Copies to: Subject: Re: sort's -k flag is buggy when M is also passed From: "Dennis Chen" To: , > > Had to use -e to have it insert new line. > > FWIW, I was able to get your tests to work without -e. (Alpine, busybox 1.35.0) > > > Looking at sort.c in busybox seems that > > static char key_separator; is just defined, but not > > assigned a default value? > > Don't know if this might resolve issue? > > static char key_separator=' '; > > Using -t ' ' might work for some cases, but consider > abc March 3 > de April 2 > This example is a little contrived, but you might easily see something > like this in the real world (think logfiles). Good point think the regular sort talks about the separator been change from blank non-blank, and that would ge a little more of a issue. I had modified the sort.c with the =' '; and it seemed to work. For you issue I inserted a tr -s ' ' that would convert multiple spaces to a single space. If added spaces before number would need to change the 2 to 3 I believe. echo -e "3 March\n2 April\n1 Jan\n5 Feb\n6 Dec\n8 Oct\n7 Jul\n6 Jun\n8 Aug\n15 May\n11 Nov\n9 Sep" | tr -s ' ' |./busybox sort -k2M 1 Jan 5 Feb 3 March 2 April 15 May 6 Jun 7 Jul 8 Aug 9 Sep 8 Oct 11 Nov 6 Dec echo -e " 3 March\n 2 April\n 1 Jan\n 5 Feb\n 6 Dec\n 8 Oct\n 7 Jul\n 6 Jun\n 8 Aug\n 15 May\n 11 Nov\n 9 Sep" | tr -s ' ' |./busybox sort -k3M 1 Jan 5 Feb 3 March 2 April 15 May 6 Jun 7 Jul 8 Aug 9 Sep 8 Oct 11 Nov 6 Dec +------------------------------------------------------------+ Michael D. Setzer II - Computer Science Instructor (Retired) mailto:mikes at guam.net mailto:msetzerii at gmail.com Guam - Where America's Day Begins G4L Disk Imaging Project maintainer http://sourceforge.net/projects/g4l/ +------------------------------------------------------------+