1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-09-17 15:01:40 +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>
* unposted: Config/version.mk, Etc/FAQ.yo, README: Update for

View file

@ -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;
for (;;) {
readret = read(in, inbuf, 64);
if (readret <= 0) {
if (readret < 0 && errno == EINTR)
continue;
else
break;
}
if (imeta(c)) {
*ptr++ = Meta;
c ^= 32;
cnt++;
}
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';