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. --- Src/exec.c | 61 ++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 25 deletions(-) (limited to 'Src') 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