1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-09-19 03:31:14 +02:00

45025: fix re-entrancy problem with memory management in readoutput().

This could cause a signal received during $(...) to corrupt memory.
This commit is contained in:
Peter Stephenson 2019-12-15 19:04:04 +00:00
parent b540d74b2b
commit 1baf0d1f55
2 changed files with 42 additions and 25 deletions

View file

@ -1,3 +1,9 @@
2019-12-15 Peter Stephenson <p.w.stephenson@ntlworld.com>
* 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 <dana@dana.is> 2019-12-14 dana <dana@dana.is>
* unposted: Config/version.mk, Etc/FAQ.yo, README: Update for * unposted: Config/version.mk, Etc/FAQ.yo, README: Update for

View file

@ -4646,19 +4646,25 @@ getoutput(char *cmd, int qt)
return NULL; 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 mod_export LinkList
readoutput(int in, int qt, int *readerror) readoutput(int in, int qt, int *readerror)
{ {
LinkList ret; LinkList ret;
char *buf, *ptr; char *buf, *bufptr, *ptr, inbuf[64];
int bsiz, c, cnt = 0; int bsiz, c, cnt = 0, readret;
FILE *fin;
int q = queue_signal_level(); int q = queue_signal_level();
fin = fdopen(in, "r");
ret = newlinklist(); ret = newlinklist();
ptr = buf = (char *) hcalloc(bsiz = 64); ptr = buf = (char *) hcalloc(bsiz = 64);
/* /*
@ -4670,33 +4676,38 @@ readoutput(int in, int qt, int *readerror)
*/ */
dont_queue_signals(); dont_queue_signals();
child_unblock(); child_unblock();
while ((c = fgetc(fin)) != EOF || errno == EINTR) { for (;;) {
if (c == EOF) { readret = read(in, inbuf, 64);
errno = 0; if (readret <= 0) {
clearerr(fin); if (readret < 0 && errno == EINTR)
continue; continue;
else
break;
} }
if (imeta(c)) { for (bufptr = inbuf; bufptr < inbuf + readret; bufptr++) {
*ptr++ = Meta; c = *bufptr;
c ^= 32; if (imeta(c)) {
cnt++; *ptr++ = Meta;
} c ^= 32;
if (++cnt >= bsiz) { cnt++;
char *pp; }
queue_signals(); if (++cnt >= bsiz) {
pp = (char *) hcalloc(bsiz *= 2); char *pp;
dont_queue_signals(); queue_signals();
pp = (char *) hcalloc(bsiz *= 2);
dont_queue_signals();
memcpy(pp, buf, cnt - 1); memcpy(pp, buf, cnt - 1);
ptr = (buf = pp) + cnt - 1; ptr = (buf = pp) + cnt - 1;
}
*ptr++ = c;
} }
*ptr++ = c;
} }
child_block(); child_block();
restore_queue_signals(q); restore_queue_signals(q);
if (readerror) if (readerror)
*readerror = ferror(fin) ? errno : 0; *readerror = readret < 0 ? errno : 0;
fclose(fin); close(in);
while (cnt && ptr[-1] == '\n') while (cnt && ptr[-1] == '\n')
ptr--, cnt--; ptr--, cnt--;
*ptr = '\0'; *ptr = '\0';