From 1baf0d1f553631ecb641e98f4bf48bc2a44e5b82 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sun, 15 Dec 2019 19:04:04 +0000 Subject: 45025: fix re-entrancy problem with memory management in readoutput(). This could cause a signal received during $(...) to corrupt memory. --- ChangeLog | 6 ++++++ Src/exec.c | 61 ++++++++++++++++++++++++++++++++++++------------------------- 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3b3b9c65b..d241323b2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2019-12-15 Peter Stephenson + + * 45025: Src/exec.c: fix re-entrancy problem with memory + management in readoutput(). This could cause a signal + received during $(...) to corrupt memory. + 2019-12-14 dana * unposted: Config/version.mk, Etc/FAQ.yo, README: Update for diff --git a/Src/exec.c b/Src/exec.c index 9dc91a71e..64eee7dc4 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -4646,19 +4646,25 @@ getoutput(char *cmd, int qt) return NULL; } -/* read output of command substitution */ +/* read output of command substitution + * + * The file descriptor "in" is closed by the function. + * + * "qt" indicates if the substitution was in double quotes. + * + * "readerror", if not NULL, is used to return any error that + * occurred during the read. + */ /**/ mod_export LinkList readoutput(int in, int qt, int *readerror) { LinkList ret; - char *buf, *ptr; - int bsiz, c, cnt = 0; - FILE *fin; + char *buf, *bufptr, *ptr, inbuf[64]; + int bsiz, c, cnt = 0, readret; int q = queue_signal_level(); - fin = fdopen(in, "r"); ret = newlinklist(); ptr = buf = (char *) hcalloc(bsiz = 64); /* @@ -4670,33 +4676,38 @@ readoutput(int in, int qt, int *readerror) */ dont_queue_signals(); child_unblock(); - while ((c = fgetc(fin)) != EOF || errno == EINTR) { - if (c == EOF) { - errno = 0; - clearerr(fin); - continue; - } - if (imeta(c)) { - *ptr++ = Meta; - c ^= 32; - cnt++; + for (;;) { + readret = read(in, inbuf, 64); + if (readret <= 0) { + if (readret < 0 && errno == EINTR) + continue; + else + break; } - if (++cnt >= bsiz) { - char *pp; - queue_signals(); - pp = (char *) hcalloc(bsiz *= 2); - dont_queue_signals(); + for (bufptr = inbuf; bufptr < inbuf + readret; bufptr++) { + c = *bufptr; + if (imeta(c)) { + *ptr++ = Meta; + c ^= 32; + cnt++; + } + if (++cnt >= bsiz) { + char *pp; + queue_signals(); + pp = (char *) hcalloc(bsiz *= 2); + dont_queue_signals(); - memcpy(pp, buf, cnt - 1); - ptr = (buf = pp) + cnt - 1; + memcpy(pp, buf, cnt - 1); + ptr = (buf = pp) + cnt - 1; + } + *ptr++ = c; } - *ptr++ = c; } child_block(); restore_queue_signals(q); if (readerror) - *readerror = ferror(fin) ? errno : 0; - fclose(fin); + *readerror = readret < 0 ? errno : 0; + close(in); while (cnt && ptr[-1] == '\n') ptr--, cnt--; *ptr = '\0'; -- cgit 1.4.1