c: fix buffer overflow in load_file on non-seekable inputs
Bash process substitution <(...) passes /proc/self/fd/N — a pipe, not a regular file. load_file used fseek(SEEK_END)+ftell to size a single- read buffer; on a pipe ftell returns -1, which casts to SIZE_MAX as fread's nbyte argument and blows the heap. Glibc fortify caught it as '*** buffer overflow detected ***'. Detect non-seekable input via the fseek return code and fall back to a doubling growable buffer instead. Seekable path unchanged. Repro: ~/git/lumbda/c/lumbda <(echo '(display 1)(newline)')
This commit is contained in:
parent
03a3534f0e
commit
a95277cef4
1 changed files with 30 additions and 7 deletions
37
c/eval.c
37
c/eval.c
|
|
@ -1636,13 +1636,36 @@ void load_file(const char *path, Env *env) {
|
|||
FILE *f = fopen(path, "r");
|
||||
if (!f) lisp_error("file not found: %s", path);
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
long sz = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
char *src = (char *)ul_malloc(sz + 1);
|
||||
size_t nread = fread(src, 1, sz, f);
|
||||
src[nread] = '\0';
|
||||
/* Seekable files (regular): size up-front, single read.
|
||||
* Non-seekable files (pipes, FIFOs, sockets — e.g. bash process
|
||||
* substitution <(...) yields /proc/self/fd/N pointing at a pipe):
|
||||
* ftell returns -1, which silently casts to SIZE_MAX inside fread
|
||||
* and overruns the heap. Stream-read into a growable buffer instead. */
|
||||
char *src = NULL;
|
||||
long sz = -1;
|
||||
if (fseek(f, 0, SEEK_END) == 0) {
|
||||
sz = ftell(f);
|
||||
if (fseek(f, 0, SEEK_SET) != 0) sz = -1;
|
||||
}
|
||||
if (sz >= 0) {
|
||||
src = (char *)ul_malloc((size_t)sz + 1);
|
||||
size_t nread = fread(src, 1, (size_t)sz, f);
|
||||
src[nread] = '\0';
|
||||
} else {
|
||||
size_t cap = 4096;
|
||||
size_t len = 0;
|
||||
src = (char *)ul_malloc(cap);
|
||||
for (;;) {
|
||||
if (len + 1 >= cap) {
|
||||
cap *= 2;
|
||||
src = (char *)ul_realloc(src, cap);
|
||||
}
|
||||
size_t got = fread(src + len, 1, cap - 1 - len, f);
|
||||
len += got;
|
||||
if (got == 0) break;
|
||||
}
|
||||
src[len] = '\0';
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
int count;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue